Compare commits

...

403 Commits

Author SHA1 Message Date
f0c35d16f3 Merge branch 'master' into temp_bmesh_multires 2021-09-17 20:13:39 -07:00
d3bba94bf2 Commit current working copy; having
weird file system issues
2021-09-17 14:43:00 -07:00
04c3690299 Sculpt dyntopo: Roughed out skeleton of new brush engine API
Command Lists

* The new system will be based on command lists
  generated by (eventually) a node editor.
* For now, the lists will be hardcoded.
* Idea is to make a minimal viable
  brush engine that won't cause file breakage
  when the upgrade to node-based brushes happen.

Brush Channels

* Wrote new structures and API to wrange
  brush parameters: BrushChannel.
* Supports, floats, ints, enums, bitmasks,
  with plans for vec3 and vec4.
* This will replace UnifiedPaintStruct,
  most of the members of Brush and the
  DynTopoSettings struct.
* Brush channels can
  be mapped to various input device
  channels (e.g. pen pressure); each
  mapping has its own associated curve
  (CurveMapping instance) and bounds.

Brush channel inheritence chaining

* Brush channels can form inheritence chains
* Channel sets are stored in three places:
  in the scene toolsettings, in Brush, and in
  individual brush commands.
* Node groups will also have a channel set.
* Channels in each set can be flagged to
  inherit from the parent set.
* Inheritence happens in seperate merged
  channel sets at runtime.  The final
  Brush channels live in Brush->channels_final,
  while the final command channels live in
  BrushCommand->params_final.
2021-09-16 20:29:33 -07:00
627edd1efa Merge branch 'master' into temp_bmesh_multires 2021-09-16 13:44:21 -07:00
445889676b commit prior to merge 2021-09-16 10:42:30 -07:00
350e783668 Add skeletal beginnings of C++ sculpt refactor
design study (note that it's #ifdef'd out).

Basic idea is to put all the sculpt brush code
in a single large template.  This template
takes a PBVH adaptor class (of which there
would be three, one per PBVH_XXX type)
as a template argument.

Basically we're using the compiler to generate
three complete copies of every brush implementation.
C++20 concepts are used to validate the pbvh classes.

An example brush implementation:

    pbvh->forVertsInRange(
        {
          .brush = ss->cache->brush,
          .radius = radius,
          .use_threads = true,
          .use_original = false
        },

        [&offset](auto viter, int node_i, void *userdata) {
          //add offset to vertex coordinates

          madd_v3_v3fl(viter.co, offset, viter.fade);
        },

        [](PBVHNode *node, int node_i, void *userdata) {
          BKE_pbvh_node_mark_update(node);
        });
2021-09-15 14:56:19 -07:00
0b2aee5841 Sculpt dyntopo: Fix a few issues from last commit
* Fixed crashing on entering sculpt mode
* Fixed transitioning between sculpt and
  another undo system type sometimes
  corrupting stack.
2021-09-15 02:50:32 -07:00
ecdd6a302e Sculpt dyntopo: fix missing bit from last commit
* BM_mesh_bm_to_me now saves id layers by default.
2021-09-15 02:16:03 -07:00
173f5f94ff Sculpt dyntopo:
Seperate enabling PBVH_BMESH from enabling DynTopo:

* Created a new option to globally disabled
  DynTopo.
* The DynTopo panel header now reads "Dynamic Mode",
  to hopefully signal that turning on PBVH_BMESH is
  a seperate step from enabling or disabling DynTopo
  itself.
* The first checkbox in the panel is "DynTopo" so it
  should be clear enough (it's on by default, with multiple
  layers of file versioning checks).

PBVH_BMesh's undo system:

* CD_MESH_ID layers are now permanently saved once
  they are created (by default they are not).  This
  fixed a *lot* of bugs:

  Before this the undo system had to save maps between
  mesh indices and mesh IDs on transitioning
  between sculpt and global undo steps.  This was
  extremely error prone, and it simply wasn't possible
  to cover all of the corner cases

* Note that there is still an odd bug where the first
  global undo push after a sculpt step gets ignored,
  I dunno what's up with this.

* Dyntopo undo should be nearly (hopefully completely)
  bug-free after this commit.

C++20

* Made a few small changes to get blender to compile
  with c++20.  std::result_of was removed, had to
  replace a couple of usages of it with std::invoke_result.

* I'm planning to do some design studies on rewriting
  sculpt into C++.

* I strongly suspect we are going to need C++20'a new
  concepts feature if we move sculpt into C++.
  I'm planning to do some design studies on how
  that might work.
2021-09-15 01:41:03 -07:00
0eeaeb3fc2 Sculpt dyntopo: fix nasty node splitting bug 2021-09-13 20:14:46 -07:00
3df335d330 Sculpt dyntopo:
* Fixed noise on using autosmooth with tools that use original
  coorinates.  While this was most prominent with DynTopo,
  it did happen with other tools.
* The solution is to smooth the original coordinates as well
  as the explicit coordinates if the active tool requires
  original data.

* I decided to replace the original coordinates system for
  PBVH_FACES and PBVH_GRIDS with the same MDynTopoVert structure
  DynTopo uses.  The alternative would have been extremely messy
  code.

* Todo: Rename MDynTopoVert to. . .SculptInfoVert?
* Todo: Cache boundary flag and corner info in MDynTopoVert->flag
        for PBVH_FACES/GRIDS similar to PBVH_BMESH.
2021-09-13 19:24:21 -07:00
0676928408 Sculpt dyntopo: more collapse fixes
The edge cases just never end.
2021-09-13 02:31:33 -07:00
e68667a835 Sculpt dyntopo:
* A few more collapse fixes
* Fixed boudary handling in surface_smooth_v_safe
2021-09-12 23:39:49 -07:00
86972d294f Dyntopo sculpt: fix bug with boundary flags 2021-09-11 13:38:42 -07:00
f52a03dd71 Sculpt dyntopo: Added a 'hard edge mode' option
to forcibly set autosmooth_fset_slide to zero
(i.e. treat face set boundaries as hard edges
and not project them on the surface).
2021-09-09 10:06:24 -08:00
a52f89a446 Add more int casts for linux 2021-09-08 23:21:57 -08:00
9f3bafc4ab Sculpt dyntopo
* Non-manifold "fins" are now detected and automatically
  deleted.
* Fixed compile error on linux.
2021-09-08 23:18:07 -08:00
bb1096f475 Sculpt dyntopo:
* Collapse now uses code from decimate to detect
  degenerate cases.
* Remaining, unknown (and rare) degenerate cases
  are now detected (via presence of duplicate verts
  in faces) and fixed.
* DynTopo fills in undo size properly now,
  so undo memory limiting works.
2021-09-08 15:51:56 -08:00
3e6edf5278 Sculpt dyntopo:
* BLI_table_gset now internally uses a SmallHash instead of
  a GHash.  Profiling revealed this to be quite a bit
  faster.
* This is something of a stopgap until C++-afication of
  pbvh, when we'll have our pick of a bunch of
  really nice C++ hashmap libs.
* pbvh_collapse_edge bites the dust; dyntopo now uses
  BM_collapse_edge.  Of the three topology operations
  (subdivide edge, collapse edge, dissolve 3/4 valence
  vertex) only dissolve still has a dyntopo-specific
  implementation.
* Fixed a bunch of annoying memory corruption bugs.
* Non-manifold triangles are now detected in more
  places.

SmallHash changes:

* Enabled removal
* Fixed infinite loop bug caused by
  improperly counting free*d* cells
  versus free cells.
* Added a BLI_smallhash_ensure_p method
  that works just like the GHash version.

Sculpt replay system

* Roughed out a simple system to record and
  play back sculpt strokes using a simple
  text format.
* This is exclusively for
  performance profiling and unit tests.
* For each brush stroke the system saves a copy
  of the active StrokeCache and PaintStroke
  and parts of Sculpt.

This should make profiling DRAM thrashing a lot
easier.
2021-09-07 23:49:54 -08:00
37bce7b701 commit working code 2021-09-02 23:19:11 -07:00
6febbd7a55 Linux's gcc's flags are evil 2021-09-02 11:42:06 -07:00
416c7a32d8 Fix warnings 2021-09-02 11:32:46 -07:00
d4badd4b22 Fix compile error 2021-09-02 11:26:28 -07:00
4e43e09cca Sculpt dyntopo: increment subversion. 2021-09-02 11:08:28 -07:00
21b6d78cd2 Sculpt dyntopo: change brush defaults and fix bug
* Changed brush defaults a bit.  New defaults
  are for organic modeling.
* autosmooth_fset_slide now defaults to 1, so
  face set boundaries are smoothed but stick to mesh
  surface (if 0 they would function as hard edges).
* Weight by area smooth mode is on by default for all
  brushes.
* Cleaned up versioning code and made it
  kick in at 3.00:21, with some simple checks to
  try and detect existing data from beta testers.

* Also fixed a small crash bug.
2021-09-02 11:02:44 -07:00
2b20931707 Merge branch 'master' into temp_bmesh_multires 2021-09-02 00:02:20 -07:00
416686707f commit before merge 2021-09-01 21:32:43 -07:00
8bfbbc467a Sculpt dyntopo
* Wrote a simple fix for drawing face sets
  in inverse (ctrl) mode with face set automasking
  on.

* Various fixes related to hard edges and smoothing.

* Started writing some code to defragment bmesh mempools.
  Need to figure out how to avoid triggering excessive
  PBVH node rebuilds.
2021-09-01 11:47:03 -07:00
baa24243a5 Sculpt dyntopo: Dynamic field-propegated topology rake
I might write a paper on this.  Topology rake now locally
updates a vector field, which it uses to smooth the input
and constrain to mesh (including face set) boundaries.
This can make an enormous difference for things like
smoothing.

Note that this is different from the existing 'curvature rake'
mode, which also builds a field and which is fed into the input
of this new one.

The only oddity is that the field is stored in a CD_PROP_COLOR
since we don't have a CD_PROP_FLOAT4, and this shows up in the UI
(not sure if I'm messing up the CD_TEMPORARY flags or if the UI
doesn't check for them).
2021-08-30 15:04:43 -07:00
73529fb1bb Sculpy dyntopo: fixed various topology bugs
* Fixed crash in dyntopo collapse.  The
  loops around vertex iterator dyntopo uses
  doesn't actually work on non-manifold meshes,
  or meshes with invalid normals, this was not
  being checked in pbvh_bmesh_collapse_edge.
* Rotate tool now works with dyntopo.
2021-08-29 16:05:26 -07:00
381ef09073 Sculpt dyntopo: another bugfix from today's earlier commits 2021-08-28 15:33:41 -07:00
56ba339cd8 Fix a few bugs in lat commit 2021-08-28 14:59:54 -07:00
055fa3fa5e fix missing curly braces 2021-08-28 13:59:00 -07:00
7d5c3beb06 Sculpt dyntopo: Fix bug with edge collapse 2021-08-28 13:30:46 -07:00
39b0e9df81 Sculpt dyntopo: Add edge API
* Added a minimal edge API to query edge
  boundary states.
* This is necassary because the previous approximation,
  testing if two adjacent verts are boundaries, breaks
  for triangles.
2021-08-28 12:14:59 -07:00
b21595cdf9 Tweak last commit to not affect base face set. 2021-08-27 21:54:15 -07:00
e4b36fb6bc Sculpt dyntopo: split face set boundaries on mirror boundary
Added an option to split face set boundaries on mirror
boundaries; currently only DynTopo supports this.

Very useful for making hard edges along mirror lines.
2021-08-27 20:02:20 -07:00
966e4ba9ae Sculpt dyntopo: improved boundary smoothing
It's kind of hackish mathematically.
2021-08-27 18:13:18 -07:00
268682527f Sculpt dyntopo: added a smoothing factor for sharp boundaries
Works by projecting non-boundary verts onto boundary vert
normals and weighting by boundary_smooth_Factor.
2021-08-27 14:18:50 -07:00
cdb52aee9f Missed an ATTR_NONNULL fix 2021-08-27 01:59:34 -07:00
8b02ab86f1 change 'error' to 'warning' in a printf 2021-08-27 01:57:13 -07:00
019700583b Sculpt dyntopo: undo bugfixes
* Fixed nasty undo bug related
  to now rewinding BMLogEntry subchains properly.
* Fixed bug in dyntopo collapse
2021-08-27 01:51:56 -07:00
31d2b04411 Sculpt dyntopo: Who knew gcc's nonnull attribute is 1-based 2021-08-26 20:23:17 -07:00
3508c699fb Sculpt dyntopo: Cleanup past few commits
* Removed some ATTR_NO_OPTs
* Made pbvh_split_edges disallowed
  4-valence splits if cleanup topology
  mode is on
2021-08-26 20:10:54 -07:00
8ea7c93a37 Sculpt dyntopo: support sharp edge flags
* Sharp edge flags are now supported and are
  treated much the same as face set boundaries:
 + Dyntopo preserves them
 + Interior smoothing treats them as boundaries
 + Corners are detected and pinned in smoothing
 + TODO: add a brush flag to ignore sharp boundaries
   for smoothing.
* Seams are also preserved, but don't affect smoothing.
* BMLog now saves edges.
* The new edge split function is enabled.
* Dyntopo now pushes new combined BMLog entries in
  its top-level function, to avoid scary id reuse
  edge cases.
* SCULPT_vertex_is_boundary/corner now take a bitmask
  of which types of boundaries you wish to query instead
  of check_face_sets.
2021-08-26 18:00:29 -07:00
12f87d02c6 commit prior to small cleanup 2021-08-25 03:01:56 -07:00
9680edf77c * Implemented bounday/face set corner handling.
* New function SCULPT_vertex_is_corner, similar to
  SCULPT_vertex_is_boundary it takes argument to
  check face sets.  PBVH_FACES/GRIDS version is
  incomplete.  It returns a bitmask of whether
  the vert is a boundary corner and/or a face
  set one.
* PBVH_BMESH uses a somewhat more expensive
  calculation to detect corners of face set islands by
  edge angle. This is currently not done for boundary
  corners.

Corner pinning now happens in:

* The internal smoother dyntopo uses for stability reasons.
* SCULPT_vertex_neighbor_average_interior.
* Topology rake.
* Dyntopo collapse.

Note that DynTopo always pins face set corners
but everything else only does so if preserve face
sets is on.
2021-08-24 13:18:36 -07:00
a00bfa8976 Sculpt dyntopo: more smooth stuff
* All of the smooth brushes now use the SculptCustomLayer
  system for temporary data, so all work with dyntopo now.
* You can now use a flat array in SculptCustomLayer with
  PBVH_BMESH (though you have to build the structure manually).
  The mesh filter code uses this.
* Smooth (and autosmooth) now have an option to preserve face
  set boundaries.  Corners are currently not handled.
* Simplify brush has preserve face set boundaries autosmooth
  flag set by default.
* SCULPT_vertex_is_boundary now takes an addition argument
  for whether to check for face set boundaries.
2021-08-23 22:55:17 -07:00
bde54e127e Sculpt dyntopo: Smooth improvements and bug fixes
* Added an option to weight smooth by face areas
* Dyntopo now caches face areas in a CD_PROP_FLOAT layer
* Dyntopo also caches number of edges around verts inside of
  MDynTopoVert.  To avoid increasing the struct size flag was
  made a short.
* Cleanup mode (dissolves 3/4-valence verts) now piggybacks on
  subdivide code to build list of verts; this is much faster.
2021-08-23 21:06:10 -07:00
9b8c82e2ed Sculpt dyntopo: fix mem cache test function, how did this
ever work
2021-08-23 02:28:19 -07:00
5866a4680d Dyntopo Sculpt: Wrote new edge split code, currently disabled 2021-08-23 01:19:55 -07:00
d795144f54 I hate default int 2021-08-22 13:31:05 -07:00
de6258c618 Silly me, don't use alloca in this situation 2021-08-22 13:16:10 -07:00
d912ceeb40 Fix compile error on linux 2021-08-22 13:15:08 -07:00
9a197a1185 Sculpt dyntopo: Temp fix for nasty GCC compiler bug on linux.
I'll file a bug report with GCC tomorrow.
2021-08-22 12:51:53 -07:00
36785c83f0 Sculpt dyntopo: Fix a dumb mistake I made in space_toolsystem_toolbar.py 2021-08-22 10:29:36 -07:00
8eb7a04150 fix signed/unsigned warning 2021-08-21 20:46:08 -07:00
97c3e5944c Sculpt dyntopo: Finished bmesh cache coherency tester
To run, in the python console enter:

bpy.msgbus.pbvh_bmesh_do_cache_test()

The output will be in the regular console.  The test
build a half-million vert cube and smooths it. It runs
several passes (all of which perform the same smoothing
operation):

1; Randomized order pass
2. Ordered pass (by vertex clustering)
3. Same as 2 but with a purely data-oriented version
   of the bmesh structs.
4. Same as 2, but using a version of the bmesh structs
   with all pointers replaced by integer indices.

At least on my laptop #3 and #2 are about a third faster
then #1, and #2 tends to be around 15%.
2021-08-21 20:40:22 -07:00
6f523ffacb Sculpt dyntopo: Don't allow dyntopo when multires modfier exists
Note that thoeretically we could support multires in dyntopo,
but numerical instability would probably make the grid data
explode.
2021-08-21 15:19:15 -07:00
04562794df Sculpt dyntopo: disable mem cache test executable
from compiling altogether
2021-08-20 20:52:22 -07:00
93004c7b19 Dyntopo: Disable mem cache test executable for now as it
doens't link on mac
2021-08-20 20:49:29 -07:00
0d542db1e1 Sculpt dyntopo:
* Fixed multires apply base feeding bad original coordinates to
  deform modifiers.
* Roughed out some code for cache performance testing.
* Wrote skeleton code for a PBVH texel API; hasn't been tested
  yet and may be removed.
2021-08-20 20:36:04 -07:00
de1f2c41fa * BM_mesh_remap can now reorder loops
* Wrote yet another BKE_pbvh_reorder_bmesh function
2021-08-18 21:43:59 -07:00
106f542ac4 Sculpt dyntopo: yet another undo bug
BKE_pbvh_bmesh_add_face had a branch where it ignored
the log_face argument, leading to corruption in
BMLog.
2021-08-17 14:58:37 -07:00
83f94ebb6f Sculpt dyntopo: remove debug ATTR_NO_OPT's 2021-08-17 00:31:04 -07:00
954aa88ba4 Sculpt dyntopo: more undo fixes
Yay for massively overdetermined bugs.
2021-08-17 00:09:43 -07:00
9503751c83 Sculpt dyntopo
* Added a limited "fast draw" mode to pbvh drawing
  that tries to limit data sent to the GPU.
 - Facesets and mask data are disabled.
 - Indexed mode is forced.
 - Does not work (at all) for multires.

* Finally fixed some outstanding bmesh sculpt undo bugs:
 - Forgot to mark pbvh nodes to update their bounds, which
   produced a bug I had thought was caused by something else.
 - Hopefully fixed a long-standing occasional memory corruption
   bug.
2021-08-16 20:50:02 -07:00
dcaba4c5e3 Sculpt dyntopo: fix various faceset init operator bugs
that crept in.
2021-08-16 16:34:35 -07:00
fb463a13cd Sculpt dyntopo: Fix memory corruption caused by improperly disabled
code.
2021-08-16 02:12:30 -07:00
b5100e73c8 Sculpt dyntopo: Fix boundary brush for multires
This commit fixes boundary brush for multires which
broke two commits ago.

This required implementing the geodesic api for PBVH_GRIDS,
which I did by building topology maps in a rather. . .
haphazard fashion.

Basically I built a vert->edge map and then used it to
derive a pseudo edge to quads mapping (it maps edges
to all the verts in the two surrounding quads except
the edge's own verts).

Just for fun I enabled geodesic mode in mask expand;
it seems to work.
2021-08-16 01:44:31 -07:00
ab632243e6 Merge branch 'master' into temp_bmesh_multires 2021-08-15 18:14:41 -07:00
8510c77b9c Sculpt dyntopo: improve boundary brush for irregular topology
(still a wip)

The boundary brush now builds a geodesic distance
  field (from the boundary) from which it derives a tangent
  field:

* These now define the rotation plane for bend mode.
* Rotation origins snap to these planes.

There is also typedef'd code for visualization tangents
in a temporary object (note the sculpt object), to enable
define VISBM in sculpt_boundary.c.  This will be removed
lated.

Additional changes:

* Added a function to get the number of edges around verts,
  SCULPT_vertex_valence_get.
* Added an API to calculate cotangent weights for vert fans,
  SCULPT_cotangents_begin (call in main thread first) and
  SCULPT_get_cotangents.
* Sculpt neighbors for PBVH_FACES now uses ss->vemap if it exists.
* The Mesh topology mapping code now takes extra parameters for
  sorting vert/edge cycles geometrically.
* Similarly, there is now a function to sort BMesh edge cycles,
  BM_sort_disk_cycle.
* MDynTopoVert->flag now has a bitflag for when the disk cycle
  sorting needs to be redone, DYNVERT_NEED_DISK_SORT.
* The sculpt geodesic code now supports passing in custom vertex
  coordinates.
* The geodesic API can also build an optional map of which vertex
  in the initial vertex list is closest to any other vertex.
2021-08-15 18:02:16 -07:00
40aa321dc7 Sculpt dyntopo: fix bug with dyntopo geometry undo push 2021-08-11 22:51:09 -07:00
a80c381ec5 Sculpt Dyntopo: PBVH draw fixes
* The PBVH draw subsystem is now told whether any viewports
  have drawtype >= OB_MATERIAL before anything in any windows
  are drawn.  There are no alternatives given the design
  constraints of sculpting, where simply uploading data to the GPU
  quickly becomes a bottleneck.

* Fixed flat vcol shading mode.
2021-08-07 22:28:00 -07:00
1e9a7383ef * Don't rely on BMLog's stored normals, instead flag pbvh nodes to
update normals on undo/redo.
2021-08-07 19:25:36 -07:00
dc738de90c Sculpt dyntopo: Fix bug in cleanup_valence_3_4 2021-08-06 18:39:54 -07:00
8ed4c5fc61 Merge branch 'master' into temp_bmesh_multires
Also fixed a pbvh corruption bug
2021-08-06 12:51:18 -07:00
76bd253be7 Dyntopo sculpt: add dev operator to debug memory cache coherency 2021-08-06 09:58:46 -07:00
b243eb2646 Merge branch 'master' into temp_bmesh_multires
Also:

* added BMLog function to save mesh IDs.
  - Used by SCULPT_UNDO_DYNTOPO_BEGIN/END instead of
    saving the whole mesh, which was the previous behavior.
* SCULPT_UNDO_DYNTOPO_BEGIN no longer pushes a non-dyntopo
  geomtry undo node, as this is no longer necassary.

This greatly speeds up going into/out of sculpt mode
with dyntopo enabled, as before it was copying
the mesh twice.
2021-07-29 16:08:14 -07:00
af71984942 sculpt dyntopo: fix memory corruption and associated memory leak 2021-07-25 05:28:54 -07:00
ec4b9dff19 Add 'projection' option for volume-preserving smoothing to
smooth corrective modifier
2021-07-23 15:46:01 -07:00
70a4956020 Sculpt dyntopo: Removed triangle limit for PBVH_BMESH
* PBVH_BMESH now supports faces other then triangles;

* Dyntopo triangulates faces as it finds them.
  - I looked into methods of preserving quads and failed to
    find anything that worked well in practice; it actually
    worked better to use topology rake to align triangles
    into quads and then mark diagonal edges for later dissolving
    then to try to preserve quads explicitly (I've not
    implementated that here, that was research code).
  - To avoid excessive cache-destroying loops over vertex-faces,
    DynTopo flags which verts have non-triangle faces.

* PBVHTriBuf now builds edge buffers so we can avoid drawing
  tesselation phantom edges.

* BMLog also now supports arbitrary faces.  It still does not
  support edges though.

TODO:

* Fix vcol cell shading mode
* Make sure indexed drawing works
2021-07-20 19:46:00 -07:00
7cd74015f8 Sculpt dyntopo: Another fix for faceset boundary handling
* Turned out pbvh->cd_faceset_offset wasn't being updated
  correctly.
2021-07-20 05:47:08 -07:00
7bd521a5c4 Sculpt dyntopo: Another small fix 2021-07-20 04:56:29 -07:00
7dda5ac5ba A few small fixes for last commit 2021-07-20 04:29:23 -07:00
1694e2aca4 Sculpt dyntopo: Face set boundaries are now presered with dyntopo
* Face set boundaries are now preserved on dyntopo remeshing.
* MDynTopoVert->flag now has a DYNVERT_FSET_BOUNDARY flag
  in addition to DYNVERT_BOUNDARY.
* Instrumented uiBut with ASAN poison regions to hopefully
  find the super evil memory corruption bug that's been driving
  me insane.  It's frustratingly intermittent.  There are five
  poison regions.
2021-07-20 04:14:59 -07:00
2fddbebf93 Sculpt dyntopo: Dyntopo now handles mesh boundaries in a more
intelligent way.
2021-07-19 15:32:41 -07:00
4247a56cde Add back hackish fix for clang bug. I should probably
file a bug report with the clang people.
2021-07-18 13:15:43 -07:00
e3b58b6451 Sculpt dyntopo: Split off dyntopo stuff from pbvh_bmesh.c into a new file, dyntopo.c. 2021-07-18 13:12:08 -07:00
5b10d08db3 Sculpt dyntopo:
* Prototyped a threaded bmesh->Mesh converter function.  It's about
  20-30% faster.  Currently disabled.
* Tried to fix more of the bugs when stepping between sculpt and
  other undo step types in the global undo stack.
2021-07-17 04:10:28 -07:00
7c4eb4f8db Merge branch 'master' into temp_bmesh_multires 2021-07-17 00:44:01 -07:00
792292e3de Sculpt dyntopo: BLI_mempool now adds redzones when compiled with ASAN 2021-07-16 23:29:28 -07:00
4ca249018d More msvc errors 2021-07-12 16:03:22 -04:00
d529e13d65 Sculpt dyntopo: fix msvc compiler error 2021-07-12 16:01:17 -04:00
4e797dbc69 Definitely going to modify BLI_strict_types.h 2021-07-12 12:30:23 -04:00
1b9a835893 Make gcc happy 2021-07-11 23:57:14 -04:00
320a1b6f35 Fix bug in previous commit; customdata_bmesh_set_default now ignores
CD_MESH_ID layers
2021-07-11 23:28:19 -04:00
f07f56aa37 BM_mesh_create will now add mesh_id customdata layers when asked,
instead of leaving that to the client.

Also semi-fixed uninitialized memory bug in bmesh unit test (dunno
how best to memset a C struct in C++ won't won't run afoul of some
random compiler somewhere).
2021-07-11 22:02:52 -04:00
4e91e72d53 Let's try that again 2021-07-11 21:21:10 -04:00
58b4688c34 Weird linux compile error 2021-07-11 21:20:37 -04:00
2f862bc7b9 Fix more dyntopo sculpt undo memory corruption 2021-07-11 21:14:49 -04:00
4674795591 Sculpt dyntopo: another attempt to fix undo memory corruption bug 2021-07-11 13:14:24 -04:00
be9017c349 Fix implicit int error 2021-07-11 06:01:39 -04:00
4c2f5b80b7 Remove extraneous code 2021-07-11 05:25:41 -04:00
0502b0103f Merge branch 'master' into temp_bmesh_multires 2021-07-11 05:23:24 -04:00
e8b717ee42 Sculpt dyntopo: Exposed UV smooth bruth in experimental features prefs.
* Also got undo working for it
2021-07-11 04:12:20 -04:00
4b4ac93acd Sculpt dyntopo: Wrote a little UV smoother sculpt brush.
It uses a simple LSCM-like solver; hold ctrl to do simple
laplacian relaxation.

There are some interesting artistic possibilities to using
DynTopo with UV maps, the point of this tool is to help
explore them.

Note that I'm not planning to merge this into master with
the rest of this branch.  When the time comes I plan to
move it into a new branch for sculpt research stuff.
2021-07-11 03:43:47 -04:00
57286eed8d Sculpt dyntopo: Add support for multiple materials to dyntopo
pbvh drawing.

* Dyntopo now stores a list of PBVHTriBufs in leaf nodes, one per material
  used by the node.
* Actual drawing buffers live in a new mat_draw_buffers PBVHNode member.
2021-07-02 13:14:00 -07:00
d0759840a0 Merge branch 'master' into temp_bmesh_multires 2021-06-30 21:38:18 -07:00
5b19b2cb56 remove debug printf 2021-06-30 21:25:46 -07:00
dcb00bf529 * Enable mask/fset extract for dyntopo]
* Fix nasty memory corruption bug
2021-06-30 21:13:24 -07:00
d66d5b431e Clean up a few warnings 2021-06-29 05:50:40 -07:00
43a0fe378f Merge branch 'master' into temp_bmesh_multires 2021-06-29 04:35:53 -07:00
fb6636c812 Sculpt dyntopo: fix bug with automasking being needlessly initialized 2021-06-26 23:46:47 -07:00
adc8980dec Sculpt dyntopo: fix symmetrix undo bug from last commit 2021-06-26 22:52:35 -07:00
48c41b189a fix type of code line being after the parenthesis
instead of before
2021-06-26 21:40:07 -07:00
7562ad5777 Sculpt dyntopo: BMLog now uses the new bmesh unique id system
A few notes:

* MESH_ID layers are not saved on conversion to Mesh unless
  you ask for it in BM_mesh_bm_to_me's params.
* Still need to test the box/lasso trim tools.
* Need to find some way to test loop/edge ids, which aren't
  used by dyntopo.
2021-06-26 21:26:33 -07:00
27986e9b56 Sculpt dyntopo: Added a function to add multiple customdata
layers to a bmesh at once.  Helpful since bmesh customdata
layers are allocated in single blocks, thus adding
layers individually can lead to lots of memory
copying.
2021-06-26 19:12:07 -07:00
dba4f30328 Sculpt dyntopo: Added (optional) support for unique mesh id tracking in
bmesh

* System is per element type.  So you can have unique ids for verts and
  faces, but not edges and loops.
* Supports an optional id to element lookup table.
* Uses single id space for all elements
* Added a new CD_FLAG_ELEM_NOCOPY flag to tell
  customdata_bmesh_copy_data to ignore that layer.
* IDs are stored as a temporary customdata layer with
  CD_FLAG_ELEM_NOCOPY set.
2021-06-26 18:24:00 -07:00
83c491f044 Merge branch 'master' into temp_bmesh_multires 2021-06-26 13:00:26 -07:00
7ef7843ada Sculpt Dyntopo: Fix memory corruption in dyntopo undo
ss->active_XXX_index wasn't being handled properly.
2021-06-25 17:10:12 -07:00
5a7b9adef1 Dyntopo sculpt: add support for asan to mempool 2021-06-25 15:04:09 -07:00
d293de425f Sculpt Dyntopo: fix bug in dyntopo brush spacing. 2021-06-25 11:49:28 -07:00
17d4c7abb1 Sculpt dyntopo:
* Got automasking to work with dyntopo properly.
  - AutomaskingCache->factor
    has been replaced with the new temp layer API (which works for all
    PBVH modes).
  - AutomaskingCache->factor is, however, only initialized for
    topology and face set boundary modes (if DynTopo is enabled)
    since it's probably better to calculate the rest dynamically
    in that case.
* Fixed stats bug
2021-06-24 23:50:49 -07:00
ca4ac36c59 Merge branch 'master' into temp_bmesh_multires 2021-06-20 15:58:24 -07:00
00fd823bcd Sculpt dyntopo: Don't calculate curvature info in topology rake if curvature
mode is not enabled.
2021-06-19 23:54:51 -07:00
8ca52a7757 Merge branch 'master' into temp_bmesh_multires 2021-06-07 16:57:33 -07:00
4adc0a7798 Dyntopo: do a little bit of code cleanup 2021-05-31 10:53:22 -07:00
552e44bd25 Fix implicit int error 2021-05-27 14:30:45 -07:00
1f19a86150 DynTopo:
* Fixed failed patch reversion from a while ago
* Also tweaked a few comments.
2021-05-27 12:15:49 -07:00
3ca3098ed7 DynTopo: Enable BLI_linklist_stack type checking for clang-cl
and fix a few errors.
2021-05-24 11:40:05 -07:00
995702da48 Let's try that again. 2021-05-23 21:39:37 -07:00
33066542ca MIssed a flag in bli_strict_types.h 2021-05-23 21:34:20 -07:00
5a26ea0961 DynTopo: Attempt to fix compiling on macos 2021-05-23 21:02:29 -07:00
1e3e79fe7b Fix one more strict flags violation 2021-05-23 20:52:25 -07:00
d4292bbd28 * Added clang-cl support to BLI_strict_flags.h 2021-05-23 20:39:52 -07:00
a97c5d7daa DynTopo: started refactoring pbvh drawing to handle customdata layers in
a more generic (and maintainable) way.
2021-05-23 16:11:16 -07:00
6b009b8890 Merge branch 'master' into temp_bmesh_multires 2021-05-23 14:30:32 -07:00
3d16099a77 Dyntopo:
Fix multires not setting pbvh->depth_limit
2021-05-20 17:59:09 -07:00
4352980b0f Dyntopo
* Got threaded mesh->bmesh conversion working (it's disabled
  pending further testing however).

Note that SCULPT_dynamic_topology_enable_ex calls BKE_scene_graph_update_tagged,
which in tests was adding ~1 second to conversion time for larger
meshes.  Do we need this call?
2021-05-19 14:36:00 -07:00
3d6ac0bd7b Dyntopo: code cleanup 2021-05-19 12:21:46 -07:00
71959181ad * Fix bug with symmetrize creating non-manifold geometry.
* Fix bug in pbvh face create
2021-05-18 22:26:49 -07:00
daa4a33383 Merge branch 'master' into temp_bmesh_multires 2021-05-17 19:48:16 -07:00
d3695eb12c * Fix corner case in last commit 2021-05-17 14:23:02 -07:00
c1f236dcd4 BMLogFace now stores the face normal. 2021-05-17 14:02:31 -07:00
a90533e9b8 Cleanup failed patch reversion 2021-05-17 00:45:07 -07:00
9bea7259e1 Merge branch 'master' into temp_bmesh_multires 2021-05-16 23:32:35 -07:00
7fca310f25 Dyntopo now updates the existing pbvh on undo instead of building
a new one from scratch, an operation that can be slow despite being
  threaded.

PBVH building is a memory bound operation (not just on the CPU side
either, remember the draw buffers have to be fully regenerated too).
Incrementally updating it this way is enormously faster (about as fast
as non-dyntopo undo).

The downside is we don't have the convienience of users regularly
building the pbvh from scratch anymore.  Dyntopo does try to
join empty PBVH nodes (which happens after every stroke), but
that's not a complete substitute for a decent tree balancer.
That's on the todo list.
2021-05-15 21:19:20 -07:00
27f4f761e7 Tried to make pbvh bmesh normals calc a bit more efficient. 2021-05-15 11:51:14 -07:00
17fafe2f63 fix memory leak 2021-05-14 21:21:01 -07:00
89d56ea225 fix missing null pointer check. 2021-05-14 21:12:23 -07:00
cfd6d48aab * Prototyped a faster smooth algo, currently disabled.
* Wrote a new API for wrangling temporary customdata layers across pbvh types:
  - SCULPT_temp_customlayer_ensure: makes sure a (named) customdata
    layer exists.  Works for multires; since these are temporary
    layers we can safely allocate them in a temporary CustomData
    structure (in ss->temp_vdata).
  - SCULPT_temp_customlayer_get: initializes a special structure,
    SculptCustomLayer, that is used to get per elem customdata.
  - SCULPT_temp_cdata_get: Uses a SculptCustomLayer ref along with
    a SculptVertexRef to look up the data.
2021-05-14 18:26:41 -07:00
6be2c079c1 Did some profiling with VTune.
* Sculpt code seems to be memory bandwidth bound.
  * Some key topology loops will have to be written manually
    instead of using BM_ITER.

I wrote a function to re-allocate a bmesh with elements ordered by
PBVH leaf nodes, SCULPT_reorder_bmesh.  It's currently disabled.

This is going to take more profiling, but my original proxy refactor
idea might be worth revisiting.  Might be more cache efficient.

The good news is that the worst case is the smooth code, which I can speed
up significantly by keeping a bit of state around.
2021-05-14 15:56:04 -07:00
32ceaa7919 Update ATTR_NO_OPT macro 2021-05-12 22:27:35 -07:00
ec4786d00b Dyntopo branch
* Sculpt expand now works with dyntopo in more cases
* Fixed various dyntopo face set bugs

Stuff from several commits ago:

* There is now an API to get face sets using SculptFaceRef's.
  + SCULPT_face_set_get
  + SCULPT_face_set_set

* Prototyped a faster geodesic propagation function, but it currently
  doesn't work.

* Dyntopo triangulation now preserves face flags (took some work as BM_triangulate_face explicitly prevents selection flags from being preserved).
* Also face smooth flags are no longer being overriden.
* Most of the faceset create operators work (I'm not sure I've tested
  all of them though).
* SCULPT_face_set.c now has helper functions that checks if a pbvh
  is *not* PBVH_BMESH, in which case it builds a temporary bmesh,
  otherwise ss->bm is used (sculpt_faceset_bm_begin and sculpt_faceset_bm_end).
  + Note that some functions were able to use SCULPT_face_set_XXX
    instead and avoid bmesh entirely.
2021-05-12 16:22:39 -07:00
582c30d32f Fix nasty edge case for BMLog. 2021-05-11 22:57:06 -07:00
b047b333b0 Remove yet more debugging crap . . . 2021-05-11 21:48:14 -07:00
f2c9706781 Get rid of various ATTR_NO_OPT debug attributes left from two
commits ago.
2021-05-11 21:46:44 -07:00
fa06238aa7 Fix bug in last commit. 2021-05-11 21:45:43 -07:00
b8a8e4f9b1 Today I ran outside screaming and an hour later came back in and made BMLog
reference counted.  This fixes various undo bugs caused by dyntopo
needing to execute an undo push but not being able too (e.g. during
file load, and I think it also happens sometimes with global undo).

A much better way of fixing this would be to add unique IDs to mesh
verts and faces, perhaps as a customdata layer.

The root problem is that BMLog assigns unique IDs to mesh elements,
which it does via a series of GHash's.  I imagine this is a fairly
serious violation of the undo system's design rules, since it means
BMLogs are tied to specific instances of the bmesh in SculptSession->bm.

There were some hacks to try and get around this, but they were buggy
and needed to push the unstack stack to work, which wasn't possible in
all cases (e.g. if G_MAIN->wm.first->undo_stack is NULL, as it is during
file loading and apparently global undo).

Anyway, long story short each chain of SculptUndoNodes needs some way
to reconstruct their ID GHash's when exiting/entering the chain. The
only way I could think to do this was to make BMLog reference counted,
with BMLogEntry the users.

Like I said, having a proper system to assign unique IDs to mesh
elements would be *much* better.
2021-05-11 21:14:45 -07:00
dbe767f5d9 Merge branch 'master' into temp_bmesh_multires 2021-05-11 14:18:48 -07:00
7cf3b1f472 Get face set create operator working for dyntopo 2021-05-07 07:04:19 -07:00
6c3b29a14c Merge branch 'master' into temp_bmesh_multires 2021-05-05 08:52:14 -07:00
febfaecd97 * Added new paint API method paint_stroke_apply_subspacing, for various
things that need custom spacing (that is coaser than the brush radius),
  and refactored the existing dyntopo spacing code to use it.

* Added option to topology rake to ignore brush falloff settings
  (it forcibly uses Smooth falloff).

* Smooth and topology rake support custom spacing now.
  + This is especially important for the clay brush, which works
    better at smaller spacings and with a bit of autosmoothing.
    Now you can tell it to override the smooth spacing to be coarser,
    leading to much better performance.

* Topology rake now has a projection setting similar to autosmooth
  which defaults to 1.0 (to preserve current behavior).

The main motivation for this commit was to make topology rake work
better for normal brushes.  This is now possible, however it tends to
make the brush slower and also the settings are a bit fiddly.
We might want to make dedicated brush presets for this.

Btw, the UI for brush settings are becoming a real mess. Help!
2021-05-02 14:29:30 -07:00
2d98802905 * Added a "projection" option to smooth/autosmooth. It works by
projection neighboring vertices onto the current smooth vert's normal
  plane, multiplied by a "projection" factor.  This is extremely similar
  to what the surface laplacian produces, but is much simpler, uses
  no temporary state and thus can be used in more places.
2021-05-02 10:54:12 -07:00
f70a8c1581 Merge branch 'master' into temp_bmesh_multires
Also fixed a pose brush bug that may or may not have been
the result of the merge nixing code, need to check master.
2021-04-29 10:17:22 -07:00
8eeacca9cb Fix a few cast warnings 2021-04-29 08:01:32 -07:00
82847af9f9 Fix invalid parameter type in bmlog. 2021-04-29 06:28:37 -07:00
ee19a80041 * Eeek, left in an ATTR_NO_OPT attribute 2021-04-28 19:31:43 -07:00
013eee7ec6 * The dyntopo remesher is now a bit smarter about avoiding
certain degenerate cases that produce lots of bad geometry (and
  also bad PBVHs that slows down the whole mesh).
 + A very small amount of surface smoothing is now applied by dyntopo.
 + The recursive functions that expand the region considered by dyntopo
   now ignore "front face only" for depths less then 5.
 + The number of edges dyntopo can split or collapse in one run has been cut in
   half to 4k.
   - This limit is also now dynamically adjusted by a measure
     of how skinny the edges are.
2021-04-28 19:11:23 -07:00
83a855a8a1 fix compile error 2021-04-27 13:38:14 -07:00
9e46eebcf1 Fix last commit flipping the order of booleans. 2021-04-27 13:20:36 -07:00
786781304c * Got box trim tool working for dyntopo
- This required implementing SCULPT_UNDO_GEOMETRY for dyntopo.
    That turned out to be more work then I expected.  Basically
    it writes an entire Mesh to BMLogEntry, which can be swapped
    with current bmesh.  Tricky part was patching bm log ids.
2021-04-27 13:04:36 -07:00
3028d53865 Edit face set brush now works for pbvh bmesh 2021-04-27 09:51:49 -07:00
02b4df9827 Enable color filter brush for pbvh bmesh 2021-04-27 09:12:35 -07:00
815d77192f One more null ptr check 2021-04-27 09:07:00 -07:00
9fab16f0f3 * Fix null ptr bug in automasking code 2021-04-27 09:01:32 -07:00
82f5e0200c * Fix bug in last commit where boundary flags weren't properly
updated after symmetrize.
2021-04-26 17:44:38 -07:00
032a35fb50 Fix memory corruption in sculpt neighbors code 2021-04-25 15:12:11 -07:00
8a700673db * Boundary info is no longer initialized with
SCULPT_boundary_info_ensure, instead PBVH_BMESH keeps
  track of boundary vert flags internally.  This prevents
  nasty first-click lag on the smooth brush as well as anything
  with autosmooth.
2021-04-25 14:51:31 -07:00
0386350de6 * Fixed SCULPT_dynamic_topology_sync_layers to properly sync
active/render/clone/mask layers indices.
* Fixed sculpt color bugs in pbvh drawing for bmesh.
2021-04-25 14:02:39 -07:00
97fc606c65 Fix nasty crash in dyntopo with non-manifold geometry. 2021-04-21 10:00:02 -07:00
14be52f0fc * Fixed vcol drawing in indexed smooth shading mode 2021-04-20 15:40:03 -07:00
73c590e1eb Added detail_size to local dyntopo brush settings 2021-04-20 06:34:35 -07:00
fdc6fb2c53 SCULPT_calc_principle_curvatures now has option to use
slower but more accurate BLI_eigen_solve_selfadjoint_m3 solver.
2021-04-17 20:25:51 -07:00
237ac342c9 Merge branch 'master' into temp_bmesh_multires 2021-04-14 22:07:27 -07:00
465e804193 commit prior to merge 2021-04-14 22:04:36 -07:00
4ab8614cd1 Last attempt at fixing boundary brush for now. Unassigned boundary
verts now get bend data from their neighbors.  Still isn't quite
satisfactory but better then before.
2021-04-14 22:02:32 -07:00
dabff9af7d * Fix crash in boundary sculpt tool
* For some reason boundary tool sometimes fails to match verts to
  boundary verts.  It now simply freezes them in place if that happens
2021-04-14 18:41:23 -07:00
384a0930d1 Commit current code state 2021-04-14 15:55:09 -07:00
a5fa9ec310 Fix another crash 2021-04-13 01:44:29 -07:00
ed15d0c1b9 Fix infinite loop bug 2021-04-13 01:08:05 -07:00
e07a95b86d Fix extremely nastly memory corruption bug in pbvh 2021-04-12 04:19:49 -07:00
b52e04f794 * Fix bug in last commit, broke draw brush 2021-04-11 23:39:25 -07:00
e74c298cf9 Fix dyntopo undo bug 2021-04-11 22:03:16 -07:00
cd485a7c6f fix last commit 2021-04-11 21:44:00 -07:00
06341c19c4 Fix crash 2021-04-11 21:42:47 -07:00
a527bd5f48 Get rid of various __attribute__((optnone)) I had scattered throughout
the code
2021-04-11 19:29:06 -07:00
7f14d519c0 * Dyntopo cleanup mode is now on by default.
* Fixed undo bug
2021-04-11 18:19:13 -07:00
64337d087d * Merge branch 'master' into temp_bmesh_multires
* Implemented DynTopo option to dissolve 3 and 4-valence
  vertices.
* Fixed bug in dyntopo collapse customdata snapping.
2021-04-11 17:59:16 -07:00
e1fae3cbee Fix do_versions check 2021-04-11 12:34:15 -07:00
7dbb4c9b2d Fix issues with last commit. Also, simplify brush now
uses dyntopo local overrides to always enable collapse instead
of being hardcoded.
2021-04-11 12:27:02 -07:00
fe67ca56d6 * Fixed wireframe drawing in vcol cell drawing mode
* Added UI for editing local brush dyntopo settings.
2021-04-11 11:38:27 -07:00
881df30a46 Cavity masking now has a checkbox in the UI, instead of simply turning
itself on if the concave mask factor is > 0.
2021-04-07 22:49:39 -07:00
6f91eaad39 * Fixed an annoying number of undo bugs
* Original data for bmesh pbvh is no longer handled by the undo code.
  This should eliminate a whole class of subtle and hard to track down
  bugs.
2021-04-07 20:39:16 -07:00
55045ed85a SCULPT_dyntopo_ensure_templayer no longer returns a customdata offset.
Making multiply layers sequentially can lead to corrupted offsets.
Instead, ensure all layers exist with SCULPT_dyntopo_ensure_templayer
first,

then get all the offsets at once.
2021-04-07 02:03:32 -07:00
2582090824 Fix bug in previous commit, code was being subject to inside
brush test that should not ahve been.
2021-04-07 01:46:10 -07:00
55415cd62a * Layer brush now supports dyntopo.
- To do this I made a little API to make scratch
    customdata layers: SCULPT_dyntopo_[ensure/get]_templayer.
    Takes a customdata type and a layer name (e.g.
    '__dyntopo_bleh") and returns a customdata offset.
  - Note that I also did this for the persistent base code.

* Added a macro to check if a tool supports splitting the PBVH
  during a stroke, DYNTOPO_HAS_DYNAMIC_SPLIT.  It is in sculpt_intern.h
  (for now) to avoid the enormous amount of recompiling that is
  triggered if DNA_brush_enum.h is modified.

* TODO: Right now the undo code resets original vertex coordinates for
  bmesh PBVH.  This means tools that rely on original data (sharp and
  layer) can't split the pbvh during the stroke, since that will
  allocate new undo nodes and reset original coords.

  The solution is to move the original data API entirely out of the undo
  code.
2021-04-07 01:20:21 -07:00
8aac19cab5 Merge branch 'master' into temp_bmesh_multires 2021-04-05 21:26:04 -07:00
b4536d274c Forgot to increase array size for data transfer modifier struct. 2021-04-05 21:24:38 -07:00
f5588dfb70 Merge branch 'master' into temp_bmesh_multires 2021-04-03 19:29:12 -07:00
4b308888d8 Add support for sculpt colors to the data transfer modifier 2021-04-03 19:23:15 -07:00
fdfa2045ec Add a paranoia check 2021-04-02 13:55:48 -07:00
33af94dc46 Fixed an out of bounds read error. 2021-04-02 13:42:29 -07:00
8ea624aeaf fix gcc build errors 2021-04-01 15:58:56 -07:00
e29cd298fe Fix last commit to handle symmetrical brushing properly 2021-04-01 15:09:50 -07:00
7bba304c57 * Dyntopo now has its own brush spacing. This is a huge performance
boost for brushes with fine spacing, e.g. the clay brush.
2021-04-01 14:51:10 -07:00
0dc09668ce Finished curvature rake. 2021-04-01 13:07:10 -07:00
cfa6753518 wrote a fast and inaccurate distance to triangle function
for DynTopo.  Profiling consistently showed it to be a bottleneck.
I've now written scalar versions of this function four times.

For now I'm committing this inaccuration version.  I'm also committing
code for a vectorized version I found in a paper.  Still need to rejigger
the dyntopo code to use it though.
2021-03-30 19:00:08 -07:00
2cf8c35578 Merge branch 'master' into temp_bmesh_multires 2021-03-30 00:57:43 -07:00
aa116ba5ba Added per-brush DynTopo settings which are stored in a new DynTopoSettings struct.
This system is designed to inherit settings from scene dyntopo defaults
in a highly flexible way; settings can be individually overridden via the
.inherit bitmask.

At stroke time the scene settings and brush->dyntopo are merged
and stored in brush->cached_dyntopo.

Note that brush->flag has a bit flag, DYNTOPO_DISABLED, with a few
subtlies.  It does not switch the PBVH back to PBVH_FACES mode, it
simply disbles dyntopo topology update.  It also doesn't inherit from
any default settings.  And it's the only setting
that's currently exposed in the UI.
2021-03-30 00:08:09 -07:00
7be027075f Add this file 2021-03-26 14:23:31 -07:00
215c346017 Only send all vcol layers to gpu (for pbvh drawing) in a material
draw mode.
2021-03-25 17:38:27 -07:00
7c9235d0e0 * Sculpt color layers are now properly handle by pbvh bmesh draw code.
Before only the active layer was uploaded to the GPU, now all of them
  (except the autogenerated original color layer) are.
2021-03-25 17:17:42 -07:00
e254cc23b2 Code cleanup 2021-03-25 11:32:20 -07:00
dee286fc7e clean up code a bit 2021-03-24 17:01:53 -07:00
ab9b89ac5d Fixed two remaining performance bugs with dyntopo:
* Normals are now updated in threads.
* The sculpt neighbor code was using the slower BM_LOOPS_OF_VERT
  instead of BM_EDGES_OF_VERT, fixed.
2021-03-24 14:09:02 -07:00
924b13b03a * Added a new CustomData type for dyntopo vertex data: MDynTopoVert.
It stores:
   - Original coordiates, colors and mask (which were previously four
     seperate layers).
   - A bitmask with (currently) one bitflag, whether or not a vertex is
     on a boundary.

I needed to cache calculating vertex boundary state (which involves
iterating over the edges surrounding a vertex) and got fed up with
having so many CD layers for dyntopo.  This struct consolidates them
and saves having yet another layer just to store a flag.
2021-03-21 16:26:38 -07:00
75a1116b51 Merge from master 2021-03-19 18:01:12 -07:00
f6cda6bf88 Merge branch 'master' into temp_bmesh_multires 2021-03-19 10:57:32 -07:00
cb0f159155 Merge branch 'master' into temp_bmesh_multires
Merge not finished, but need to commit to move to different computer;
laptop being sent in for repairs
2021-03-08 13:57:21 -08:00
8a98189bfb commit before merge 2021-03-07 04:00:14 -08:00
1f2b48eb45 Add a little todo list 2021-03-05 16:54:19 -08:00
148b39caec Added some code to calculate principle curvature direction for
uniform triangle tesselations (dyntopo).  This will be used for
a version of topological rake that aligns edge flows to lines of curvature
automatically.
2021-03-01 01:09:27 -08:00
e9f9217f75 Merge from master 2021-02-28 17:05:35 -08:00
dd45a4bc6e Merge branch 'master' into temp_bmesh_multires 2021-02-28 04:59:03 -08:00
1ccd92d0bb commit prior to merge 2021-02-28 04:23:45 -08:00
1a17c578a8 Merge branch 'master' into temp_bmesh_multires 2021-02-07 23:17:09 -08:00
56e1ae1afa * Yet another attempt at writing a faster distance to tri function.
I think I will end up writing a less accurate version and be done
  with it.  This is a consistent hotspot in profiling.
* Fixed a few more undo bugs
2021-02-07 23:01:09 -08:00
35092510ba Merge branch 'master' into temp_bmesh_multires 2020-12-26 04:24:54 -08:00
5385455e6a Fixed undo bugs caused by SculptVertRef refactor. I need to figure out
the right way to make assigning a pointer to a SculptVertRef to an int*
spit out a compiler error.
2020-12-22 22:47:50 -08:00
2c54c641a3 Added a new cavity automasking mode for sculpt colors painting.
In theory it should also work with other sculpt tools (the
automasking code is fairly general) though it doesn't seem
to do much.
2020-12-22 14:11:11 -08:00
b3fff9b07a Merge remote-tracking branch 'origin/master' into temp_bmesh_multires
Also redid vcol boundary tool icon, and made a little icon for sculpt
color paint.
2020-12-21 01:08:24 -08:00
681e2b6134 Fixes from merge 2020-12-08 13:37:00 -08:00
49bd2228cb Merge branch 'master' into temp_bmesh_multires 2020-12-07 13:04:19 -08:00
0a140ec66e Commit before merge 2020-12-07 11:48:32 -08:00
f30225725d Some multires stuff 2020-11-18 18:34:08 -08:00
a1ac104f02 add NULL pointer check 2020-11-11 05:19:35 -08:00
d823f6e2cf Added an "Exponent" slider to Color Boundary brush. 2020-11-09 22:25:03 -08:00
3042f6e608 Tweaked value for smoothing in vcol boundary tool (a slight amount of
smoothing is applied to prevent normal discontiuties from perfectly
colinear triangles).

Also reverted some CLANG compiling stuff.
2020-11-09 18:30:24 -08:00
6115091103 View3D: take clipping into account for Frame All
Clamp the min/max used for Frame All/Selected
by the clipping region if it's set.

Resolve T81050
2020-11-07 02:54:23 -08:00
78ef2d0d84 Cleanup: move plane array intersection into a function
Also add check to ensure a point isn't occluded by it's own plane,
which could happen if a small epsilon values are passed in.
2020-11-07 02:54:23 -08:00
9d92a97562 Cleanup: Rename render texture files to texture_* 2020-11-07 02:54:23 -08:00
192670e8ce Cleanup: Remove unused variable 2020-11-07 02:54:23 -08:00
7ae1cc23fc Cleanup: remove unused includes in readfile.c and writefile.c 2020-11-07 02:54:23 -08:00
ebb6648bda Fix missing include warning
Caused by rB580ff2cb937daf43699908afe1190baea8d117aa
2020-11-07 02:54:23 -08:00
384f2956e5 Cleanup: fix naming and remove unnecessary code 2020-11-07 02:54:23 -08:00
2ba90cf717 Refactor: move Screen .blend data read to blenkernel
Ref T76372.
2020-11-07 02:54:23 -08:00
e5af8597e5 Refactor: move Ipo .blend I/O to IDTypeInfo callbacks 2020-11-07 02:54:23 -08:00
1f6a7785f6 Refactor: move Object .blend I/O to IDTypeInfo callbacks 2020-11-07 02:54:23 -08:00
0ee053fb12 Cleanup: Clang-Tidy modernize-use-nullptr
Replace `NULL` with `nullptr` in C++ code.

No functional changes.
2020-11-07 02:54:20 -08:00
8cd4776764 Clang-Tidy: error out when executable not found
Stop with an error when the Clang-Tidy executable cannot be found.

Without this check, CMake will happily report "Found Clang-Tidy" but with
the fallback version (0, 0, 0), when `CLANG_TIDY_EXECUTABLE` points to a
non-existing executable.
2020-11-07 02:53:25 -08:00
f32bde6bd9 Refactor: move Pose .blend I/O to blenkernel
Ref T76372.
2020-11-07 02:53:25 -08:00
Yevgeny Makarov
8b808cefae UI: Improved macOS Application Icon Progress Bar
Nicer appearance for the progress bar that is drawn over the application icon during long processes on macOS.

Differential Revision: https://developer.blender.org/D9398

Reviewed by Brecht Van Lommel
2020-11-07 02:53:24 -08:00
f8466b6284 Refactor: move Constraint .blend I/O to blenkernel
Ref T76372.
2020-11-07 02:53:24 -08:00
4a2d7a2f89 Refactor: move MotionPath .blend I/O to blenkernel
Ref T76372.
2020-11-07 02:53:24 -08:00
67defe866b Fix T81997: Subsurf Optimal Display sticks after object conversion
When using Optimal Display, some edges are not flagged `ME_EDGEDRAW` |
`ME_EDGERENDER`.
When the modifier is applied through the UI in the modifier stack this is
not an issue because the `modifyMesh` callback is run with
`MOD_APPLY_TO_BASE_MESH` (this will effectively turn of Optimal
Display).
When converting to mesh though, this will just get an evaluated mesh
(where the edge flags are still the same as with the subdivision
modifier).
Now ensure every edge is flagged to draw after conversion.

Maniphest Tasks: T81997

Differential Revision: https://developer.blender.org/D9331
2020-11-07 02:53:24 -08:00
b6575fed92 Refactor: move gpencil modifier .blend I/O to blenkernel
Ref T76372.
2020-11-07 02:53:24 -08:00
d6735bfae0 Refactor: move modifier .blend I/O to blenkernel
Ref T76372.
2020-11-07 02:53:24 -08:00
e4c45d0c5e Fix T82251: Outliner Material Drag&Drop missing tree update
Caused by rBb077de086e14.

Not entirely sure why this was rebuilding the tree prior to above
commit, but sending an ND_OB_SHADING notifier is appropriate (and also
what the Outliners listener listens to).

Maniphest Tasks: T82251

Differential Revision: https://developer.blender.org/D9396
2020-11-07 02:53:24 -08:00
c4668b750c Fix T82220 Missing viewport update after manual "HDRI Preview Size" input
This is caused by the TAA being reset after the init phase, leading to
1 sample being kept as valid when it is clearly not.

To fix this, we run the lookdev validation before TAA init.

Reviewed By: Jeroen Bakker

Differential Revision: https://developer.blender.org/D9452
2020-11-07 02:53:24 -08:00
81a85233a7 Cleanup: Clang-Tidy, modernize-make-unique 2020-11-07 02:53:24 -08:00
89f62e5dc3 Cleanup: Sort includes after recent render module cleanup 2020-11-07 02:53:23 -08:00
408e13783d Cleanup: remove unused functions 2020-11-07 02:53:23 -08:00
3900734063 Refactor: move ShaderFx .blend I/O to blenkernel
Ref T76372.
2020-11-07 02:53:23 -08:00
fa688ac593 Cleanup: Render Module: combine intern/ source & include 2020-11-07 02:53:23 -08:00
787f952ef4 Cleanup: whitespace 2020-11-07 02:53:23 -08:00
63241d25b9 Cleanup: Render Module: move header files to main directory
Move headers files from `render/extern/` to `render/`

Part of T73586
2020-11-07 02:53:23 -08:00
Paul Melis
98166b5c98 Add background rectangle option to video sequencer Text strip
This adds a Box option to the Text strip's style properties, plus related Box Margin value:

{F9208309}

When enabled the text is placed on top of a solid-filled rectangle of a chosen color, as shown below:

{F9208324}

When the box option is disabled the text strip works the same as it does now. When the box option is enabled the meaning of the Shadow option changes to provide a drop-shadow on the rectangle (and not on the text itself). The latter made more sense to me.

The box margin is specified as a fraction of the image width. The offset of the drop-down box shadow is fixed to a specific fraction of the image width as well.

I tested this feature on a movie of a couple of minutes containing dozens of text strips (all with box background), edge cases like multi-line strings and text overlapping the image edges.

Reviewed By: ISS

Differential Revision: https://developer.blender.org/D9468
2020-11-07 02:53:23 -08:00
229849af0f Refactor: move ParticleSystem .blend I/O to blenkernel
Ref T76372.
2020-11-07 02:53:23 -08:00
0a1fc855bc Sequencer: Make naming consistent in header and implementation files 2020-11-07 02:53:23 -08:00
46ccaff9a3 VSE: Don't store proxy images in cache
Proxies are expected to be fast to read. Storing them in cache has
little to no effect on performance.

This change also allows to omit invalidation of cache when user switch
between proxies and original media.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D9473
2020-11-07 02:53:23 -08:00
9c8b0a20c1 Refactor: move Scene .blend expand to IDTypeInfo callback 2020-11-07 02:53:22 -08:00
a42cf75ecb Refactor: move Scene .blend lib reading to IDTypeInfo callback 2020-11-07 02:53:22 -08:00
d77e884bd7 Cleanup: rename time related variables
Variables renaned:
 - cfra -> timeline_frame
 - nr -> frame index
 - cfra_over -> overlap_frame

Function seq_give_stripelem_index was renamed to seq_give_frame_index.
2020-11-07 02:53:22 -08:00
e2111233f0 Blenloader: access report list via api 2020-11-07 02:53:22 -08:00
e4efd04063 Blenloader: expose BLO_reportf_wrap in api
This function is used by a couple of functions that are moved out of blenloader.
2020-11-07 02:53:22 -08:00
8edd20274e Refactor: move Scene .blend data reading to IDTypeInfo callback 2020-11-07 02:53:22 -08:00
9be60839cd Refactor: move Scene .blend writing to IDTypeInfo callback 2020-11-07 02:53:22 -08:00
af934d751d CMake: Fix wrong library used for dependency
Was causing compilation failure on fresh builds.
2020-11-07 02:53:22 -08:00
5ac07c31f0 Refactor: move PointCache .blend I/O to blenkernel
Ref T76372.
2020-11-07 02:53:22 -08:00
f3a7d9375d Cleanup: Fluid engine API return types
Use bool return type where possible instead of int (the return values from fluid object are already boolean instead of int).

Also removed several if guards in API functions. If one of the arguments is in fact invalid / nullptr (should not happen though), it better to catch them directly where they failed and not silently escape them.
2020-11-07 02:53:22 -08:00
a033a0eaaf Cleanup: Clang-Tidy, modernize-use-bool-literals 2020-11-07 02:53:22 -08:00
c137b53569 Refactor: move sequencer modifier .blend I/O to sequencer module
Ref T76372.
2020-11-07 02:53:21 -08:00
f0a9986ccf Cleanup: Alembic, simplify expression
Change `1 + current_mat++` to `++current_mat`.

No functional changes.
2020-11-07 02:53:21 -08:00
f639ffe795 Cleanup: Alembic, simplify material assignment code
Refactor material assignment code such that:
- `build_mat_map()` just returns the built map (instead of relying on
  modifying a map passed as parameter),
- `LISTBASE_FOREACH` is used to loop over a `ListBase` (instead of a
  hand-crafted for-loop),
- just `return` when not enough material slots can be created (instead
  of setting a boolean to false, then doing some useless work, then
  checking the boolean),
- reorder some code for clarity, and
- rename `mat_map` to `matname_to_material` so that the semantics are
  clearer.

No functional changes.
2020-11-07 02:53:21 -08:00
326381bfe1 Refactor: move Paint lib linking to blenkernel
Ref T76372.
2020-11-07 02:53:21 -08:00
174e3c6b65 Refactor: move color settings .blend I/O to blenkernel
Ref T76372.
2020-11-07 02:53:21 -08:00
5c899dcc92 Cleanup: Clang-Tidy, modernize-use-emplace 2020-11-07 02:53:21 -08:00
24ee80f077 Fix compilation error of bf_draw
Similar to previous commit, missing build dependency.
2020-11-07 02:53:21 -08:00
22b69af796 Fix compilation error when building from scratch
Make sure the DNA offset files is ready at a time bf_windowmanager
need it.
2020-11-07 02:53:21 -08:00
0758c006ec Cleanup: Clang-Tidy, modernize-redundant-void-arg 2020-11-07 02:53:21 -08:00
c2a329ec07 Refactor: move LightCache .blend I/O to eevee_lightcache.c
Ref T76372.
2020-11-07 02:53:21 -08:00
bdaee543f3 Refactor: move remaining ViewLayer .blend I/O to blenkernel
Ref T76372.
2020-11-07 02:53:21 -08:00
44d358c384 Cleanup: remove unnecessary function 2020-11-07 02:53:21 -08:00
f87123a6eb Refactor: move Paint .blend I/O to blenkernel
Ref T76372.
2020-11-07 02:53:21 -08:00
f2fc2cd521 Refactor: move wmWindowManager .blend I/O to IDTypeInfo callbacks 2020-11-07 02:53:20 -08:00
af92a39e37 Fix T82364: Widget anim state not updated when deleting channel in Graph Editor
So a keyframed e.g. location slider would stay yellow/green even if its
corresponding channel was removed.

Needs a appropriate notifier so the listeners (e.g.
buttons_area_listener, view3d_buttons_region_listener) would cause a
redraw.

Maniphest Tasks: T82364

Differential Revision: https://developer.blender.org/D9438
2020-11-07 02:53:20 -08:00
49cbb23855 Fix T82457: Python error when clicking on a tool in the viewport
Ths variable was initialized for false, while it was expected to be
true.
2020-11-07 02:53:20 -08:00
9cb84de509 Clang Tidy: Expand modernize category
Gives an idea of which warnings are affecting Blender code base.
2020-11-07 02:53:20 -08:00
53f6991de8 Cleanup: Use nullptr everywhere in fluid code
Switched from NULL to nullptr.
2020-11-07 02:53:20 -08:00
5b696c2bd8 Fix T82407: Negative number input gives syntax error for velocities and
accelerations

Caused by rB45dbc38a8b15.

Above commit would place parentheses surrounding a block until the next
operator was found.
For velocities and accelerations though, the '/' in 'm/s' or 'ft/s'
should not be considered an operator.

Maniphest Tasks: T82407

Differential Revision: https://developer.blender.org/D9467
2020-11-07 02:53:20 -08:00
b95a5c2e68 Fix T82387: Crash loading file saved with recent master in old versions
This fix makes sure new files save `wmWindow.global_areas` under a different
name, so old Blender versions don't recognize and 0-initialize it.

Since enabling global area writing (ef4aa42ea4), loading a file in old
Blender versions would cause `wmWindow.global_areas` to be read, because there
was already reading code for it and `ScrAreaMap` was in SDNA.
However the `ScrArea.global` of the global areas would be NULL, because it was
*not* in SDNA (`ScrGlobalAreaData` was excluded).
Now, issue is that the code assumes that areas in the global area-map have a
valid ScrArea.global pointer.

Think this was a mistake in rB5f6c45498c92. We should have cleared all this data
on reading, until the global area writing was enabled.

Differential Revision: https://developer.blender.org/D9442

Reviewed by: Brecht Van Lommel
2020-11-07 02:53:20 -08:00
080e78d205 Cleanup: Clang-Tidy, readability-redundant-member-init 2020-11-07 02:53:20 -08:00
a55a69f81a Fix Outliner editbone selection with 'Sync Selection'
When editbones were selected from the Outliner (and they were connected
to a parent) with the 'Sync Selection' option turned ON, they could not
get duplicated.

For duplication to work, the (connected) parent bone's tip also has to
be selected [which was not the case when selection is done from the
Outliner under above circumstances]. The reason being that
armature_duplicate_selected_exec ->
ED_armature_edit_sync_selection clears the BONE_ROOTSEL flag if the
parent bone's BONE_TIPSEL is not set.

Caused by rB71eb65328078 btw.

The correct "parent-tip-selection" would actually happen in activation
- `tree_element_active_ebone`
-- `tree_element_active_ebone__sel`
but for 'Sync Selection' this happens [also] in
- `outliner_sync_selection_from_outliner`
-- `outliner_select_sync_to_edit_bone`
which did not do the "flushing" to the parent bone's tip

Now use existing dedicated function for this.

ref. T82347

Reviewers: Zachman

Differential Revision: https://developer.blender.org/D9470
2020-11-07 02:53:20 -08:00
596fea8afd Cleanup: Clang-Tidy warnings 2020-11-07 02:53:19 -08:00
47e4adde5a Fix compilation error in GHOST
ELEM macro isn't available in GHOST library.
2020-11-07 02:53:19 -08:00
a349943cd7 Cleanup: Fix the order of info_cfg_option. 2020-11-07 02:53:19 -08:00
360faf5c3c Cleanup: add missing doxygen group 2020-11-07 02:53:19 -08:00
9cf97857d1 Cleanup: Fix wrong doxygen groups
Was missed in rB9b6088cb9da4df1a893361997fc1a22986bf6f2e
2020-11-07 02:53:19 -08:00
44bdf515ba CMake: configue_file() to pass strings for build-info
Using configue_file(..) would have avoided the breakage from
1daa3c3f0a, caused by buildinfo not properly escaping quotes.

Rely on CMake to escaping strings instead using configure_file().
2020-11-07 02:53:19 -08:00
45ccdebad3 Fix uninitialized value
Own mistake in rB74188e65028d268af887ab2140e4253087410c1e
2020-11-07 02:53:19 -08:00
d242d33571 Cleanup: use 'BKE_' prefix for initialization functions 2020-11-07 02:53:19 -08:00
731eaa68d3 Cleanup: use doxy sections for node_group.c 2020-11-07 02:53:19 -08:00
344963bf23 Cleanup: use if/else check for property poll 2020-11-07 02:53:19 -08:00
aaca5731fb Cleanup: replace STREQLEN with STRPREFIX for constant strings 2020-11-07 02:53:19 -08:00
aa7147f665 Cleanup: use STR_ELEM macro 2020-11-07 02:53:19 -08:00
0fb50afdc5 Cleanup: Use LISTBASE_FOREACH macro 2020-11-07 02:53:18 -08:00
f3cc74d216 Cleanup: Use descriptive variable names 2020-11-07 02:53:18 -08:00
0946a8da3b Cleanup: de-duplicate code for instancing objects when linking
Ref D8843
2020-11-07 02:53:18 -08:00
a8e5e63f45 Cleanup: doxygen comments 2020-11-07 02:53:18 -08:00
e52f8ac7ce Cleanup: doxygen comments in ghost
Use colon after parameters, use hash to reference symbols.
2020-11-07 02:53:18 -08:00
71a088582a Cleanup: use ELEM macro (>2 args) 2020-11-07 02:53:18 -08:00
3aab8dd731 Cleanup: clang-format
Missed this last commit.
2020-11-07 02:53:18 -08:00
56d57b2e9d Cleanup: use ELEM macro 2020-11-07 02:53:18 -08:00
b16eb9d7ad Cleanup: follow our code style for float literals 2020-11-07 02:53:17 -08:00
3fcd3d41c4 Cleanup: use bool argument in BLI_noise 2020-11-07 02:53:17 -08:00
0b0bfa0628 Cleanup: BLI_noise
Use common prefix as this collided with existing API's (eg BLI_voronoi).

Also expand some non-obvious abbreviations:

- 'g'  -> 'generic'
- 'vl' -> 'variable_lacunarity'
- 'V'  -> 'v3'
2020-11-07 02:53:17 -08:00
ff9ce5fd98 Cleanup: remove unused BLI_turbulence1
A slightly modified version of BLI_turbulence1, unused for years.
2020-11-07 02:53:17 -08:00
2d99e118b4 Cleanup: use snake case for BLI_args API 2020-11-07 02:53:17 -08:00
a93add61b0 Cleanup: remove unused BLI_argsArgv 2020-11-07 02:53:17 -08:00
7f28a99dd5 Cleanup: use string APPEND/PREPEND
Replace 'set' with 'string(APPEND/PREPEND ...)'.
This avoids duplicating the variable name.
2020-11-07 02:53:10 -08:00
9aaf9857a0 Cleanup: transform.h comments, use doxy sections 2020-11-07 02:52:23 -08:00
e2595de761 Cleanup: sort structs, files 2020-11-07 02:52:23 -08:00
40c4942901 Cleanup: clang-format 2020-11-07 02:52:23 -08:00
2e188dc504 Cleanup: unused variable 2020-11-07 02:52:23 -08:00
Yevgeny Makarov
dfce29b809 UI: Tweaks to the Warning Icon
Warning Sign Alert Icon given a more rounded border.

Differential Revision: https://developer.blender.org/D9443

Reviewed by Pablo Vazquez
2020-11-07 02:52:23 -08:00
decf7adcf6 Fix T81915: Draw Face Sets not working with deformed sculpt mesh
The draw face sets brush uses the poly center when used in meshes to increase
its precision when working in low poly geometry. For this to work with deformed
meshes, the deformed coordinates from the PBVH should be used instead.

Reviewed By: sergey

Maniphest Tasks: T81915

Differential Revision: https://developer.blender.org/D9424
2020-11-07 02:52:23 -08:00
81531d5e76 Fix memory leaks in sculpt mode trimming tools
BKE_mesh_free() seems to not free the meshes correctly, so using BKE_id_free() instead.
The looptri array was also not freed.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D9426
2020-11-07 02:52:23 -08:00
15bc0b7d5d Fix T82400: Dyntopo detail size edit operator visual glitch
Just a missing immUnbindProgram

Reviewed By: sergey

Maniphest Tasks: T82400

Differential Revision: https://developer.blender.org/D9459
2020-11-07 02:52:23 -08:00
17dec471c5 Fix Dyntopo detail size preview orientation not matching the cursor
Used the sampled cursor normal when available instead of the raycast face normal.
This makes the preview match the previous orientation of the cursor.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D9460
2020-11-07 02:52:23 -08:00
81f05aca29 Move "Camera Parent Lock" from preferences to Object Relations
"Camera Parent Lock" can be useful when rigging cameras, but it is not
intuitive, and has also generated a lot of confusion (bug reports).
This is because it breaks the fundamental parent <-> child relationship
conventions in Blender, and there is no indication that it's intended
without diving into the preferences.

This commit moves the setting to the object level, and exposes it in
the relations panel in the property editor. It is exposed for every
object type because any object type can be "View Locked" in the 3D view.
The property description is also updated to reflect this change and be
more specific without getting too long.

In the future this could become a more general feature of the transform
system, but for now it is limited to "Lock Camera to View".

Differential Revision: https://developer.blender.org/D9239
2020-11-07 02:52:22 -08:00
d1270925a5 Fix T82423: Add modifier key back into keymap
Commit rBf5080c82dd915db6c7b9dd68a52aaaccf2600137
accidentally remove the Shift modifier key from
the `AUTOCONSTRAINPLANE` shortcut.

Differential Revision: https://developer.blender.org/D9480
2020-11-07 02:52:22 -08:00
9e09ae7aff Fix T82164: Knife tool draws huge vertices after using bgl.glPointSize
Since it is possible to have multiple draw callbacks, (some of which
use bgl and others gpu), check and force the reset of the drawing status
at the end of each callback.

Differential Revision: https://developer.blender.org/D9476
2020-11-07 02:52:22 -08:00
Robert Guetzkow
c51a5e1066 Fix T82423: Replace duplicate name in keymap
The two entries `TFM_MODAL_AUTOCONSTRAINT` and
`TFM_MODAL_AUTOCONSTRAINTPLANE` had the same name
displayed in the UI. The latter is now includes
"plane" in it's name.

Reviewed By: mano-wii

Differential Revision: https://developer.blender.org/D9474
2020-11-07 02:52:22 -08:00
758452ffba Fix T80043: missing Cycles displacement update when relinking output sockets 2020-11-07 02:52:22 -08:00
c7cd82c356 Cleanup: Reduce variable scope
Differential Revision: https://developer.blender.org/D9475
2020-11-07 02:52:22 -08:00
cc554eea75 Fix T82428: Cycles crashes when building volume meshes
The Volume Node did not have all of the sockets from its Mesh base class
which are now required due to the recent socket API change.
2020-11-07 02:52:21 -08:00
0d770432d6 pre-merge commit 2020-11-07 02:48:34 -08:00
b2cb9d4b1b Fixed handling of edge seam flags in dyntopo, for some reason did the
code was not brought over from trimesh branch.
2020-11-06 16:23:12 -08:00
08e19c6bc0 Added debug option in dyntopo to draw sculpt colors as solid cells
instead of interpolating (it's next to "draw smooth" in the dyntopo
settings panel).
2020-11-06 03:17:45 -08:00
b928f58849 Made vcol boundary tool avoid perfectly degenerate triangles. 2020-11-06 01:35:52 -08:00
228c1e5345 Replace call to BMLog with origco CD layer.
Also fixed SCULPT_HIDE_FACE_SETS.  It was 1<<16, which overlaps
SCULPT_DYNTOPO_DETAIL_MANUAL.  Changed it to 1<<17.  Someone should do
this in master too.
2020-11-05 16:35:42 -08:00
488af21ae0 Merge remote-tracking branch 'origin' into temp_bmesh_multires 2020-11-05 09:05:02 -08:00
b54d7bfad8 Fix redraw error for dyntopo smooth brush 2020-11-05 09:03:56 -08:00
2babf80ae6 Fixed sculpt colors undo for mesh pbvh. 2020-11-04 21:27:21 -08:00
022dcb8e6c Added autosmooth-like option to run vcol boundary tool in paint tool 2020-11-04 20:36:43 -08:00
6d66e81667 Fixed color boundary tool for faces pbvh 2020-11-04 03:05:38 -08:00
91a5e1aef8 Added an icon for new sculpt colors boundary smooth tool 2020-11-04 02:34:18 -08:00
6d704d57ad Merge remote-tracking branch 'origin' into temp_bmesh_multires 2020-11-03 22:41:57 -08:00
a1b1c840a0 Adjust weighting for color boundary tool 2020-11-03 19:41:18 -08:00
901654dcbf * Added a "color boundary" tool that tries to smooth out vcol boundaries 2020-11-03 19:08:37 -08:00
37a657a45f Added face set support to dyntopo. Still need to finish "edit face
sets" tool and do more testing.
2020-11-03 16:05:38 -08:00
e07bb3955e Enabled dyntopo for sharp brush. Also fixed paint brush strength being
too strong with dyntopo enabled.
2020-11-03 00:47:19 -08:00
7834b59598 Merge remote-tracking branch 'origin' into temp_bmesh_multires 2020-11-02 14:33:52 -08:00
0c8d40d2de Fixed bug with multires editmode code messing up loop indices for draw
code.

Also fixed a bug in dyntopo ray tracing, where r_active_vertex_index
wasn't always being set.
2020-11-02 14:29:45 -08:00
1014b6f455 More fixes for sculpt vertex color undo. Moved one of the undo pushes
outside a thread, since dyntopo undo is not thread safe.
2020-10-31 11:06:15 -07:00
093e29f3c2 Tried to fix sculpt vcol paint undo. It's better, but I still need to
go through and thorougly analyze just what the undo stack is doing.
2020-10-30 20:06:05 -07:00
0f0d1f8e2a Paint brush no long SCULPT_undo_push_node per dab (except for first
stroke) for dyntopo.  Instead it updates the original vertex color
customdata layer.

Calling into the undo system destroys threading with dyntopo, as its
undo code is single-threaded.
2020-10-30 19:37:22 -07:00
43ccbe353f Try to make SCULPT_orig_vert_data_init avoid allocating undo nodes,
which calls into BMLog which, while now threadsafe (ish?) causes
threads to get bogged down in lock contention.
2020-10-30 19:17:03 -07:00
2d861122e1 Remove debugging clang keyword. It's not #ifdef'd code, but still. 2020-10-29 22:39:06 -07:00
66f8852e30 * Edge queue creation for dyntopo edge split/collapse is now
multithreaded.
* Worked on ProxyVert system, but it still needs more work.  Issue is keeping
  topological layers (reasonably) up to date without it being slow.
* Fixed memory leak in bmlog.
2020-10-29 22:33:57 -07:00
54ddb01299 Fixed a variety of memory corruption bugs 2020-10-29 04:28:03 -07:00
3d47323162 Fixed bug with original coordinates/normals not being set when
dyntopo pbvh is first built
2020-10-27 01:38:59 -07:00
5c77439264 * Fix bug in BKE_pbvh_node_color_buffer_get. 2020-10-27 00:20:07 -07:00
e2c92c1341 More fixes for dyntopo undo and vertices (face data still isn't
implemented).
2020-10-26 18:46:12 -07:00
faf8402c19 Added initial support for customdata to dyntopo undo (BMLog).
TODO:
 - Handle face (loop) data
 - Figure out what to do about edge data (warn user? actually handle
   it?)
 - Handle sculpt color undo push nodes properly (shouldn't be hard).
2020-10-26 02:45:56 -07:00
4c0bcc3d13 PBVH drawing now properly names attributes.
NOTE: I've added a new function, DRW_make_cdlayer_attr_aliases, for
this.  It's patterned after extract_uvs.  The appropriate devs from the
draw engine team should take a look.
2020-10-26 00:19:14 -07:00
4fc4a7e1f4 Fixed SCULPT_dynamic_topology_sync_layers from last commit. 2020-10-25 22:55:46 -07:00
f9859a3b2a Got sculpt colors to work, needs more testing 2020-10-25 22:35:02 -07:00
6da9fa1bf2 pre-valgrind commit 2020-10-25 20:00:42 -07:00
5c6407c268 Fixed broken customdata interpolation in dyntopo collapse.
Also added support for uvs to dyntopo gpu buffer building code.
2020-10-25 04:31:06 -07:00
3214b1114f Added support for customdata interpolation to dyntopo.
It seems fast enough for simple cases, I make no promises that it
will be fast in crazy cases lots if there's lots of vgroup layers.

Note I still need to interface properly with the sculpt colors code.
2020-10-25 01:37:52 -07:00
bfbe9a0d55 Fix bugs in last commit. 2020-10-25 01:07:05 -07:00
f482afadab Refactored sculpt code to use a new type, SculptVertRef, that replaces
much of the usage of integer indices.  Meshes and grids simply store the
index here, but bmesh stores a pointer to a BMVert.  This greatly speeds
up DynTopo by reducing the need to maintain flat pointer arrays in bmesh.

To prevent the accidental casting of ScuptVertexRef to indices and vice
versa SculptVertRef is defined as a struct:

typedef struct {intptr_t i} SculptVertRef;

There are also two functions to convert flat index indices to
SculptVertRefs and back:

ScultpVertRef BKE_pbvh_table_index_to_vertex(PBVH *pbvh, int index);
int BKE_pbvh_vertex_index_to_table(PBVH *pbvh, SculptVertRef *ref);

Note that these functions require the aforementioned maintanance of
flat pointer arrays in bmesh, so make sure to call
SCULPT_ensure_vertex_random_access().
2020-10-25 00:32:59 -07:00
661dcd813c Merge performance improvements from trimesh branch into this one. 2020-10-24 19:41:54 -07:00
5541de9a3a Submodule update 2020-10-24 16:03:05 -07:00
3791afa29c Merge remote-tracking branch 'origin' into temp_bmesh_multires 2020-10-24 16:01:45 -07:00
3ae8229843 commit before merge 2020-10-24 16:01:08 -07:00
f61d4b2e3a * Improved multires projection some more in bmesh_interp.c 2020-10-18 18:10:16 -07:00
49f57d8de8 COde cleanup 2020-10-18 16:12:02 -07:00
64c7bad391 New branch to fix multires topology editing. WIP
Changes:
* Brought back bmesh_mdisps_space_set, written from scratch using
  subdiv api, not ccg.
* Wrote a function to smooth multigres grids from within bmesh.  I might
  not need it; unless anyone thinks of a use for it I'll go ahead and
  delete it.

Todo:
* Purge code of all usages of CCG for multires.

This commit:
* Wrote a utility function to dump multires displacements into a (new)
  scene object.
* Consequently, I now know that the CCG_based multires code is not
  compatible with the OpenSubdiv based code.  The former produces gaps
  between grids when converting displacements to object space.
2020-10-17 15:11:02 -07:00
4659855b0f commit multires patch 2020-10-17 01:24:34 -07:00
248 changed files with 38575 additions and 4652 deletions

View File

@@ -263,6 +263,7 @@ ForEachMacros:
- SET_SLOT_PROBING_BEGIN
- MAP_SLOT_PROBING_BEGIN
- VECTOR_SET_SLOT_PROBING_BEGIN
- TGSET_ITER
StatementMacros:
- PyObject_HEAD

View File

@@ -578,6 +578,12 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/7.0.0/lib/windows
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/6.0.0/lib/windows
)
find_library(
COMPILER_ASAN_LIBRARY_THUNK NAMES clang_rt.asan_dll_thunk-x86_64
PATHS
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/7.0.0/lib/windows
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/6.0.0/lib/windows
)
elseif(APPLE)
execute_process(COMMAND ${CMAKE_CXX_COMPILER}
-print-file-name=lib
@@ -598,6 +604,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
)
endif()
mark_as_advanced(COMPILER_ASAN_LIBRARY_THUNK)
mark_as_advanced(COMPILER_ASAN_LIBRARY)
endif()
endif()
@@ -918,9 +925,9 @@ if(NOT CMAKE_BUILD_TYPE MATCHES "Release")
unset(_list_COMPILER_ASAN_CFLAGS)
unset(_is_CONFIG_DEBUG)
elseif(COMPILER_ASAN_LIBRARY)
set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};${COMPILER_ASAN_LIBRARY}")
set(PLATFORM_LINKFLAGS "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}")
set(PLATFORM_LINKFLAGS_DEBUG "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}")
set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};\"${COMPILER_ASAN_LIBRARY}\" \"${COMPILER_ASAN_LIBRARY_THUNK}\"")
set(PLATFORM_LINKFLAGS "\"${COMPILER_ASAN_LIBRARY}\" \"${COMPILER_ASAN_LIBRARY_THUNK}\" ${COMPILER_ASAN_LINKER_FLAGS}")
set(PLATFORM_LINKFLAGS_DEBUG "\"${COMPILER_ASAN_LIBRARY}\" \"${COMPILER_ASAN_LIBRARY_THUNK}\" ${COMPILER_ASAN_LINKER_FLAGS}")
endif()
endif()
endif()

View File

@@ -389,7 +389,7 @@
// Does the compiler support result_of?
#ifndef EIGEN_HAS_STD_RESULT_OF
#if EIGEN_MAX_CPP_VER>=11 && ((__has_feature(cxx_lambdas) || (defined(__cplusplus) && __cplusplus >= 201103L)))
#if __cplusplus < 201703L && EIGEN_MAX_CPP_VER>=11 && ((__has_feature(cxx_lambdas) || (defined(__cplusplus) && __cplusplus >= 201103L && __cplusplus)))
#define EIGEN_HAS_STD_RESULT_OF 1
#else
#define EIGEN_HAS_STD_RESULT_OF 0

View File

@@ -221,7 +221,7 @@ AUD_API void AUD_Device_setListenerVelocity(AUD_Device* device, const float valu
AUD_API double AUD_Device_getRate(AUD_Device* device)
{
auto dev = device ? *device : DeviceManager::getDevice();
return dev->getSpecs().rate;
return dev ? dev->getSpecs().rate : 0.0;
}
AUD_API float AUD_Device_getSpeedOfSound(AUD_Device* device)

View File

@@ -87,11 +87,17 @@ public:
* \param args The arguments of the task.
* \return A future of the same type as the return type of the task.
*/
#if __cplusplus > 201703L
template<class T, class... Args>
std::future<typename std::invoke_result<T, Args...>::type> enqueue(T&& t, Args&&... args)
{
using pkgdTask = std::packaged_task<typename std::invoke_result<T, Args...>::type()>;
#else
template<class T, class... Args>
std::future<typename std::result_of<T(Args...)>::type> enqueue(T&& t, Args&&... args)
{
using pkgdTask = std::packaged_task<typename std::result_of<T(Args...)>::type()>;
#endif
std::shared_ptr<pkgdTask> task = std::make_shared<pkgdTask>(std::bind(std::forward<T>(t), std::forward<Args>(args)...));
auto result = task->get_future();

View File

@@ -67,7 +67,7 @@ SET(LEMON_ENABLE_ILOG YES CACHE STRING "Enable ILOG (CPLEX) solver backend.")
SET(LEMON_ENABLE_COIN YES CACHE STRING "Enable COIN solver backend.")
SET(LEMON_ENABLE_SOPLEX YES CACHE STRING "Enable SoPlex solver backend.")
IF(LEMON_ENABLE_GLPK)
IF(LEMON_ENABLE_GLPK)
FIND_PACKAGE(GLPK 4.33)
ENDIF(LEMON_ENABLE_GLPK)
IF(LEMON_ENABLE_ILOG)

View File

@@ -4,7 +4,7 @@ FIND_PATH(ILOG_ROOT_DIR
PATHS /opt/ibm/ILOG /usr/local/ibm/ILOG /usr/local/ILOG /usr/local/ilog
PATHS "$ENV{HOME}/ILOG" "$ENV{HOME}/.local/ILOG"
PATHS "$ENV{HOME}/ibm/ILOG" "$ENV{HOME}/.local/ibm/ILOG"
PATHS "C:/Program Files/IBM/ILOG"
PATHS "C:/Program Files/IBM/ILOG"
PATH_SUFFIXES "CPLEX_Studio126" "CPLEX_Studio125"
"CPLEX_Studio124" "CPLEX_Studio123" "CPLEX_Studio122"
NO_DEFAULT_PATH

View File

@@ -16,3 +16,4 @@ LINK_DIRECTORIES(
# ADD_EXECUTABLE(myprog myprog-main.cc)
# TARGET_LINK_LIBRARIES(myprog lemon)

View File

@@ -88,3 +88,4 @@ INSTALL(
FILES ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc
DESTINATION lib/pkgconfig
)

View File

@@ -10,6 +10,7 @@
#include <fstream>
#include <unordered_map>
#include <functional>
namespace qflow {
@@ -69,7 +70,7 @@ void load(const char* filename, MatrixXd& V, MatrixXi& F)
};
/// Hash function for obj_vertex
struct obj_vertexHash {
struct obj_vertexHash : std::function<size_t(obj_vertex)> {
std::size_t operator()(const obj_vertex &v) const {
size_t hash = std::hash<uint32_t>()(v.p);
hash = hash * 37 + std::hash<uint32_t>()(v.uv);

View File

@@ -49,27 +49,27 @@
/* Unsigned */
ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x) + x;
return (uint64_t)(InterlockedExchangeAdd64((int64_t *)p, (int64_t)x) + (int64_t)x);
}
ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x)) - x;
return (uint64_t)(InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x)) - (int64_t)x);
}
ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new)
{
return InterlockedCompareExchange64((int64_t *)v, _new, old);
return (uint64_t)(InterlockedCompareExchange64((int64_t *)v, _new, old));
}
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x);
return (uint64_t)InterlockedExchangeAdd64((int64_t *)p, (int64_t)x);
}
ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x));
return (uint64_t)InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x));
}
/* Signed */
@@ -103,32 +103,32 @@ ATOMIC_INLINE int64_t atomic_fetch_and_sub_int64(int64_t *p, int64_t x)
/* Unsigned */
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
{
return InterlockedExchangeAdd(p, x) + x;
return (uint32_t)InterlockedExchangeAdd(p, x) + x;
}
ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x)
{
return InterlockedExchangeAdd(p, -((int32_t)x)) - x;
return (uint32_t)InterlockedExchangeAdd(p, -((int32_t)x)) - x;
}
ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new)
{
return InterlockedCompareExchange((long *)v, _new, old);
return (uint32_t)InterlockedCompareExchange((long *)v, _new, old);
}
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
{
return InterlockedExchangeAdd(p, x);
return (uint32_t)InterlockedExchangeAdd(p, x);
}
ATOMIC_INLINE uint32_t atomic_fetch_and_or_uint32(uint32_t *p, uint32_t x)
{
return InterlockedOr((long *)p, x);
return (uint32_t)InterlockedOr((long *)p, x);
}
ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x)
{
return InterlockedAnd((long *)p, x);
return (uint32_t)InterlockedAnd((long *)p, x);
}
/* Signed */
@@ -205,9 +205,9 @@ ATOMIC_INLINE uint8_t atomic_fetch_and_or_uint8(uint8_t *p, uint8_t b)
ATOMIC_INLINE int8_t atomic_fetch_and_and_int8(int8_t *p, int8_t b)
{
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
return InterlockedAnd8((char *)p, (char)b);
return (int8_t)InterlockedAnd8((char *)p, (char)b);
#else
return _InterlockedAnd8((char *)p, (char)b);
return (int8_t)_InterlockedAnd8((char *)p, (char)b);
#endif
}
@@ -215,9 +215,9 @@ ATOMIC_INLINE int8_t atomic_fetch_and_and_int8(int8_t *p, int8_t b)
ATOMIC_INLINE int8_t atomic_fetch_and_or_int8(int8_t *p, int8_t b)
{
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
return InterlockedOr8((char *)p, (char)b);
return (int8_t)InterlockedOr8((char *)p, (char)b);
#else
return _InterlockedOr8((char *)p, (char)b);
return (int8_t)_InterlockedOr8((char *)p, (char)b);
#endif
}

View File

@@ -21,6 +21,7 @@
set(INC
.
../atomic
../../source/blender/blenlib
)
set(INC_SYS

View File

@@ -409,7 +409,7 @@ static void print_memhead_backtrace(MemHead *memh)
(void)memh; /* Ignored. */
}
# endif /* defined(__linux__) || defined(__APPLE__) */
#endif /* DEBUG_BACKTRACE */
#endif /* DEBUG_BACKTRACE */
static void make_memhead_header(MemHead *memh, size_t len, const char *str)
{

View File

@@ -30,6 +30,7 @@
/* to ensure strict conversions */
#include "../../source/blender/blenlib/BLI_strict_flags.h"
#include "../../source/blender/blenlib/BLI_asan.h"
#include "atomic_ops.h"
#include "mallocn_intern.h"
@@ -59,6 +60,9 @@ enum {
#define MEMHEAD_ALIGNED_FROM_PTR(ptr) (((MemHeadAligned *)ptr) - 1)
#define MEMHEAD_IS_ALIGNED(memhead) ((memhead)->len & (size_t)MEMHEAD_ALIGN_FLAG)
#define MEM_POISON_MEMHEAD(vmemh) BLI_asan_poison(MEMHEAD_FROM_PTR(vmemh), sizeof(MemHead))
#define MEM_UNPOISON_MEMHEAD(vmemh) BLI_asan_unpoison(MEMHEAD_FROM_PTR(vmemh), sizeof(MemHead))
/* Uncomment this to have proper peak counter. */
#define USE_ATOMIC_MAX
@@ -93,7 +97,13 @@ print_error(const char *str, ...)
size_t MEM_lockfree_allocN_len(const void *vmemh)
{
if (vmemh) {
return MEMHEAD_FROM_PTR(vmemh)->len & ~((size_t)(MEMHEAD_ALIGN_FLAG));
size_t ret;
MEM_UNPOISON_MEMHEAD(vmemh);
ret = MEMHEAD_FROM_PTR(vmemh)->len & ~((size_t)(MEMHEAD_ALIGN_FLAG));
MEM_POISON_MEMHEAD(vmemh);
return ret;
}
return 0;
@@ -119,6 +129,8 @@ void MEM_lockfree_freeN(void *vmemh)
atomic_sub_and_fetch_u(&totblock, 1);
atomic_sub_and_fetch_z(&mem_in_use, len);
MEM_UNPOISON_MEMHEAD(vmemh);
if (UNLIKELY(malloc_debug_memset && len)) {
memset(memh + 1, 255, len);
}
@@ -137,6 +149,9 @@ void *MEM_lockfree_dupallocN(const void *vmemh)
if (vmemh) {
MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
const size_t prev_size = MEM_lockfree_allocN_len(vmemh);
MEM_UNPOISON_MEMHEAD(vmemh);
if (UNLIKELY(MEMHEAD_IS_ALIGNED(memh))) {
MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
newp = MEM_lockfree_mallocN_aligned(
@@ -145,6 +160,8 @@ void *MEM_lockfree_dupallocN(const void *vmemh)
else {
newp = MEM_lockfree_mallocN(prev_size, "dupli_malloc");
}
MEM_POISON_MEMHEAD(vmemh);
memcpy(newp, vmemh, prev_size);
}
return newp;
@@ -158,6 +175,8 @@ void *MEM_lockfree_reallocN_id(void *vmemh, size_t len, const char *str)
MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
size_t old_len = MEM_lockfree_allocN_len(vmemh);
MEM_UNPOISON_MEMHEAD(vmemh);
if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) {
newp = MEM_lockfree_mallocN(len, "realloc");
}
@@ -166,6 +185,8 @@ void *MEM_lockfree_reallocN_id(void *vmemh, size_t len, const char *str)
newp = MEM_lockfree_mallocN_aligned(len, (size_t)memh_aligned->alignment, "realloc");
}
MEM_POISON_MEMHEAD(vmemh);
if (newp) {
if (len < old_len) {
/* shrink */
@@ -194,6 +215,8 @@ void *MEM_lockfree_recallocN_id(void *vmemh, size_t len, const char *str)
MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
size_t old_len = MEM_lockfree_allocN_len(vmemh);
MEM_UNPOISON_MEMHEAD(vmemh);
if (LIKELY(!MEMHEAD_IS_ALIGNED(memh))) {
newp = MEM_lockfree_mallocN(len, "recalloc");
}
@@ -201,6 +224,7 @@ void *MEM_lockfree_recallocN_id(void *vmemh, size_t len, const char *str)
MemHeadAligned *memh_aligned = MEMHEAD_ALIGNED_FROM_PTR(vmemh);
newp = MEM_lockfree_mallocN_aligned(len, (size_t)memh_aligned->alignment, "recalloc");
}
MEM_POISON_MEMHEAD(vmemh);
if (newp) {
if (len < old_len) {
@@ -241,6 +265,7 @@ void *MEM_lockfree_callocN(size_t len, const char *str)
atomic_add_and_fetch_z(&mem_in_use, len);
update_maximum(&peak_mem, mem_in_use);
MEM_POISON_MEMHEAD(PTR_FROM_MEMHEAD(memh));
return PTR_FROM_MEMHEAD(memh);
}
print_error("Calloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",
@@ -286,6 +311,8 @@ void *MEM_lockfree_mallocN(size_t len, const char *str)
atomic_add_and_fetch_z(&mem_in_use, len);
update_maximum(&peak_mem, mem_in_use);
MEM_POISON_MEMHEAD(PTR_FROM_MEMHEAD(memh));
return PTR_FROM_MEMHEAD(memh);
}
print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",
@@ -357,6 +384,8 @@ void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str
atomic_add_and_fetch_z(&mem_in_use, len);
update_maximum(&peak_mem, mem_in_use);
MEM_POISON_MEMHEAD(PTR_FROM_MEMHEAD(memh));
return PTR_FROM_MEMHEAD(memh);
}
print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n",

View File

@@ -70,9 +70,9 @@ static int check_if_canceled(float progress,
return cancel;
}
void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
void (*update_cb)(void *, float progress, int *cancel),
void *update_cb_data)
ATTR_NO_OPT void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
void (*update_cb)(void *, float progress, int *cancel),
void *update_cb_data)
{
Parametrizer field;
VertexMap vertexMap;
@@ -80,6 +80,12 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
/* Get remeshing parameters. */
int faces = qrd->target_faces;
field.flag_adaptive_scale = 1;
field.flag_minimum_cost_flow = 1;
field.flag_preserve_boundary = 1;
field.flag_preserve_sharp = 1;
// field.flag_aggresive_sat = 1;
if (qrd->preserve_sharp) {
field.flag_preserve_sharp = 1;
}
@@ -106,6 +112,7 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
/* Copy mesh to quadriflow data structures. */
std::vector<Vector3d> positions;
std::vector<uint32_t> indices;
std::vector<uint32_t> eflags;
std::vector<ObjVertex> vertices;
for (int i = 0; i < qrd->totverts; i++) {
@@ -114,16 +121,18 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
}
for (int q = 0; q < qrd->totfaces; q++) {
Vector3i f(qrd->faces[q * 3], qrd->faces[q * 3 + 1], qrd->faces[q * 3 + 2]);
Vector3i f(qrd->faces[q].v[0], qrd->faces[q].v[1], qrd->faces[q].v[2]);
ObjVertex tri[6];
int nVertices = 3;
const int nVertices = 3;
tri[0] = ObjVertex(f[0]);
tri[1] = ObjVertex(f[1]);
tri[2] = ObjVertex(f[2]);
for (int i = 0; i < nVertices; ++i) {
eflags.push_back(qrd->faces[q].eflag[i]);
const ObjVertex &v = tri[i];
VertexMap::const_iterator it = vertexMap.find(v);
if (it == vertexMap.end()) {
@@ -138,7 +147,10 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
}
field.F.resize(3, indices.size() / 3);
// field.FF.resize(3, indices.size() / 3);
memcpy(field.F.data(), indices.data(), sizeof(uint32_t) * indices.size());
// memcpy(field.FF.data(), eflags.data(), sizeof(uint32_t) * eflags.size());
field.V.resize(3, vertices.size());
for (uint32_t i = 0; i < vertices.size(); ++i) {
@@ -157,12 +169,17 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
return;
}
const int steps = 2;
/* Setup mesh boundary constraints if needed */
if (field.flag_preserve_boundary) {
#if 0
if (true) { // field.flag_preserve_boundary) {
Hierarchy &mRes = field.hierarchy;
mRes.clearConstraints();
for (uint32_t i = 0; i < 3 * mRes.mF.cols(); ++i) {
if (mRes.mE2E[i] == -1) {
if (mRes.mFF((i) % 3, i / 3) & QFLOW_CONSTRAINED) {
// if (mRes.mE2E[i] == -1) {
uint32_t i0 = mRes.mF(i % 3, i / 3);
uint32_t i1 = mRes.mF((i + 1) % 3, i / 3);
Vector3d p0 = mRes.mV[0].col(i0), p1 = mRes.mV[0].col(i1);
@@ -172,15 +189,20 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
mRes.mCO[0].col(i0) = p0;
mRes.mCO[0].col(i1) = p1;
mRes.mCQ[0].col(i0) = mRes.mCQ[0].col(i1) = edge;
mRes.mCQw[0][i0] = mRes.mCQw[0][i1] = mRes.mCOw[0][i0] = mRes.mCOw[0][i1] = 1.0;
mRes.mCQw[0][i0] = mRes.mCQw[0][i1] = mRes.mCOw[0][i0] = mRes.mCOw[0][i1] = 0.1;
}
}
}
mRes.propagateConstraints();
for (int j = 0; j < 10; j++) {
mRes.propagateConstraints();
}
}
#endif
/* Optimize the mesh field orientations (tangental field etc) */
Optimizer::optimize_orientations(field.hierarchy);
for (int i = 0; i < steps; i++) {
Optimizer::optimize_orientations(field.hierarchy);
}
field.ComputeOrientationSingularities();
if (check_if_canceled(0.3f, update_cb, update_cb_data)) {
@@ -195,11 +217,13 @@ void QFLOW_quadriflow_remesh(QuadriflowRemeshData *qrd,
return;
}
Optimizer::optimize_scale(field.hierarchy, field.rho, field.flag_adaptive_scale);
field.flag_adaptive_scale = 1;
Optimizer::optimize_positions(field.hierarchy, field.flag_adaptive_scale);
for (int i = 0; i < steps; i++) {
Optimizer::optimize_scale(field.hierarchy, field.rho, field.flag_adaptive_scale);
}
for (int i = 0; i < steps; i++) {
Optimizer::optimize_positions(field.hierarchy, field.flag_adaptive_scale);
}
field.ComputePositionSingularities();
if (check_if_canceled(0.5f, update_cb, update_cb_data)) {

View File

@@ -23,9 +23,16 @@
extern "C" {
#endif
enum { QFLOW_CONSTRAINED = 1 };
typedef struct QuadriflowFace {
int v[3];
char eflag[3];
} QuadriflowFace;
typedef struct QuadriflowRemeshData {
float *verts;
int *faces;
QuadriflowFace *faces;
int totfaces;
int totverts;

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -549,15 +549,27 @@ def brush_settings(layout, context, brush, popover=False):
if context.preferences.experimental.use_sculpt_tools_tilt and capabilities.has_tilt:
layout.prop(brush, "tilt_strength_factor", slider=True)
UnifiedPaintPanel.prop_unified(
layout,
context,
brush,
"hard_edge_mode",
slider=True,
unified_name="use_unified_hard_edge_mode",
)
row = layout.row(align=True)
row.prop(brush, "hardness", slider=True)
row.prop(brush, "invert_hardness_pressure", text="")
row.prop(brush, "use_hardness_pressure", text="")
# auto_smooth_factor and use_inverse_smooth_pressure
if capabilities.has_auto_smooth:
box = layout.box().column() #.column() is a bit more compact
UnifiedPaintPanel.prop_unified(
layout,
box,
context,
brush,
"auto_smooth_factor",
@@ -565,13 +577,70 @@ def brush_settings(layout, context, brush, popover=False):
slider=True,
)
# topology_rake_factor
box.prop(brush, "boundary_smooth_factor")
box.prop(brush, "use_weighted_smooth")
box.prop(brush, "preserve_faceset_boundary")
if brush.preserve_faceset_boundary:
box.prop(brush, "autosmooth_fset_slide")
box.prop(brush, "use_custom_auto_smooth_spacing", text="Custom Spacing")
if brush.use_custom_auto_smooth_spacing:
UnifiedPaintPanel.prop_unified(
box,
context,
brush,
"auto_smooth_spacing",
slider=True,
text="Spacing"
)
UnifiedPaintPanel.prop_unified(
box,
context,
brush,
"auto_smooth_projection",
slider=True
)
UnifiedPaintPanel.prop_unified(
box,
context,
brush,
"auto_smooth_radius_factor",
slider=True
)
elif brush.sculpt_tool == "SMOOTH":
UnifiedPaintPanel.prop_unified(
layout,
context,
brush,
"auto_smooth_projection",
slider=True
)
if capabilities.has_vcol_boundary_smooth:
layout.prop(brush, "vcol_boundary_factor", slider=True)
if (
capabilities.has_topology_rake and
context.sculpt_object.use_dynamic_topology_sculpting
):
layout.prop(brush, "topology_rake_factor", slider=True)
box = layout.box().column() #.column() is a bit more compact
box.prop(brush, "topology_rake_factor", slider=True)
box.prop(brush, "use_custom_topology_rake_spacing", text="Custom Spacing")
if brush.use_custom_topology_rake_spacing:
box.prop(brush, "topology_rake_spacing", text="Spacing")
box.prop(brush, "topology_rake_projection")
box.prop(brush, "topology_rake_radius_factor", slider=True)
box.prop(brush, "use_curvature_rake")
box.prop(brush, "ignore_falloff_for_topology_rake")
if context.sculpt_object.use_dynamic_topology_sculpting:
layout.prop(brush.dyntopo, "disabled", text="Disable Dyntopo")
# normal_weight
if capabilities.has_normal_weight:
layout.prop(brush, "normal_weight", slider=True)
@@ -630,6 +699,10 @@ def brush_settings(layout, context, brush, popover=False):
# Per sculpt tool options.
if sculpt_tool == "VCOL_BOUNDARY":
row = layout.row()
row.prop(brush, "vcol_boundary_exponent")
if sculpt_tool == 'CLAY_STRIPS':
row = layout.row()
row.prop(brush, "tip_roundness")
@@ -756,7 +829,15 @@ def brush_settings(layout, context, brush, popover=False):
elif sculpt_tool == 'SMOOTH':
col = layout.column()
col.prop(brush, "boundary_smooth_factor")
col.prop(brush, "use_weighted_smooth")
col.prop(brush, "preserve_faceset_boundary")
if brush.preserve_faceset_boundary:
col.prop(brush, "autosmooth_fset_slide")
col.prop(brush, "smooth_deform_type")
if brush.smooth_deform_type == 'SURFACE':
col.prop(brush, "surface_smooth_shape_preservation")
col.prop(brush, "surface_smooth_current_vertex")
@@ -916,6 +997,14 @@ def brush_settings_advanced(layout, context, brush, popover=False):
# topology automasking
col.prop(brush, "use_automasking_topology", text="Topology")
col.prop(brush, "use_automasking_concave")
col2 = col.column()
col2.enabled = brush.use_automasking_concave
col2.prop(brush, "concave_mask_factor", text="Cavity Factor")
col2.prop(brush, "invert_automasking_concavity", text="Invert Cavity Mask")
# face masks automasking
col.prop(brush, "use_automasking_face_sets", text="Face Sets")

View File

@@ -1294,7 +1294,9 @@ class _defs_sculpt:
# Use 'bpy.context' instead of 'context' since it can be None.
prefs = bpy.context.preferences
if not prefs.experimental.use_sculpt_vertex_colors:
exclude_filter = {'PAINT', 'SMEAR'}
exclude_filter = {'PAINT' : True, 'SMEAR' : True}
if not prefs.experimental.use_sculpt_uvsmooth:
exclude_filter['UV_SMOOTH'] = True
return generate_from_enum_ex(
context,

View File

@@ -2248,6 +2248,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
self._draw_items(
context, (
({"property": "use_sculpt_vertex_colors"}, "T71947"),
({"property": "use_sculpt_uvsmooth"}, ""),
({"property": "use_sculpt_tools_tilt"}, "T82877"),
({"property": "use_extended_asset_browser"}, ("project/view/130/", "Project Page")),
({"property": "use_override_templates"}, ("T73318", "Milestone 4")),

View File

@@ -171,6 +171,7 @@ class VIEW3D_HT_tool_header(Header):
row.popover(panel="VIEW3D_PT_tools_weightpaint_symmetry_for_topbar", text="")
elif mode_string == 'SCULPT':
row.popover(panel="VIEW3D_PT_sculpt_symmetry_for_topbar", text="")
layout.prop(context.object.data, "use_fset_boundary_mirror");
elif mode_string == 'PAINT_VERTEX':
row.popover(panel="VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar", text="")

View File

@@ -17,7 +17,7 @@
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
from bpy.types import Menu, Panel, UIList
from bpy.types import Menu, Panel, UIList, WindowManager
from bl_ui.properties_grease_pencil_common import (
GreasePencilSculptOptionsPanel,
GreasePencilDisplayPanel,
@@ -754,10 +754,78 @@ class VIEW3D_PT_tools_brush_falloff_normal(View3DPaintPanel, Panel):
layout.prop(ipaint, "normal_angle", text="Angle")
# TODO, move to space_view3d.py
class VIEW3D_PT_sculpt_dyntopo_advanced(Panel, View3DPaintPanel):
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
bl_label = "Dyntopo (Advanced)"
#bl_options = {'DEFAULT_CLOSED'}
bl_ui_units_x = 12
@classmethod
def poll(cls, context):
paint_settings = cls.paint_settings(context)
return (context.sculpt_object and context.tool_settings.sculpt and paint_settings)
def draw_header(self, context):
pass
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
tool_settings = context.tool_settings
sculpt = tool_settings.sculpt
settings = self.paint_settings(context)
brush = settings.brush
col = layout.column()
col.label(text="Local Brush Settings")
row = col.row()
row.prop(brush.dyntopo, "disabled", text="Disable Dyntopo locally for this brush")
col.label(text="Overrides")
inherit_all = "ALL" in brush.dyntopo.inherit
col.prop_enum(brush.dyntopo, "inherit", value="ALL", text="Use All Defaults", icon="LOCKED" if inherit_all else "UNLOCKED")
def do_prop(key):
row = col.row()
if key.upper() in brush.dyntopo.inherit:
icon = "UNLOCKED"
else:
icon = "LOCKED"
row.prop_enum(brush.dyntopo, "inherit", value=key.upper(), icon=icon, text="")
row2 = row.row()
row2.prop(brush.dyntopo, key)
if icon == "UNLOCKED":
row2.enabled = False
if inherit_all:
row.enabled = False
col = layout.column()
do_prop("subdivide")
do_prop("collapse")
do_prop("cleanup")
do_prop("spacing")
do_prop("local_subdivide")
do_prop("local_collapse")
do_prop("detail_size")
do_prop("detail_range")
do_prop("detail_percent")
do_prop("constant_detail")
do_prop("mode")
do_prop("radius_scale")
# TODO, move to space_view3d.py
class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
bl_label = "Dyntopo"
bl_label = "Dynamic Mode"
bl_options = {'DEFAULT_CLOSED'}
bl_ui_units_x = 12
@@ -789,6 +857,8 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
col = layout.column()
col.active = context.sculpt_object.use_dynamic_topology_sculpting
col.prop(sculpt, "use_dyntopo");
sub = col.column()
sub.active = (brush and brush.sculpt_tool != 'MASK')
if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
@@ -806,7 +876,12 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
col.operator("sculpt.detail_flood_fill")
col.prop(sculpt, "use_dyntopo_cleanup")
col.prop(sculpt, "use_smooth_shading")
col.prop(sculpt, "use_flat_vcol_shading")
col.prop(sculpt, "dyntopo_spacing")
col.prop(sculpt, "dyntopo_radius_scale");
class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
@@ -865,6 +940,7 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
col = layout.column(heading="Display", align=True)
col.prop(sculpt, "show_low_resolution")
col.prop(sculpt, "use_sculpt_delay_updates")
col.prop(sculpt, "use_fast_draw")
col.prop(sculpt, "use_deform_only")
col.separator()
@@ -938,6 +1014,7 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
row.prop(sculpt, "tile_z", text="Z", toggle=True)
layout.prop(sculpt, "use_symmetry_feather", text="Feather")
layout.prop(mesh, "use_fset_boundary_mirror")
layout.prop(sculpt, "radial_symmetry", text="Radial")
layout.prop(sculpt, "tile_offset", text="Tile Offset")
@@ -945,6 +1022,7 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
layout.prop(sculpt, "symmetrize_direction")
layout.operator("sculpt.symmetrize")
layout.prop(WindowManager.operator_properties_last("sculpt.symmetrize"), "merge_tolerance")
class VIEW3D_PT_sculpt_symmetry_for_topbar(Panel):
@@ -2278,6 +2356,7 @@ classes = (
VIEW3D_PT_tools_grease_pencil_brush_vertex_color,
VIEW3D_PT_tools_grease_pencil_brush_vertex_palette,
VIEW3D_PT_tools_grease_pencil_brush_vertex_falloff,
VIEW3D_PT_sculpt_dyntopo_advanced
)
if __name__ == "__main__": # only for live edit.

View File

@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 22
#define BLENDER_FILE_SUBVERSION 23
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@@ -36,6 +36,8 @@ struct Main;
struct Scene;
struct ToolSettings;
struct UnifiedPaintSettings;
struct DynTopoSettings;
struct Sculpt;
// enum eCurveMappingPreset;
@@ -151,6 +153,13 @@ void BKE_brush_scale_size(int *r_brush_size,
/* debugging only */
void BKE_brush_debug_print_state(struct Brush *br);
void BKE_brush_get_dyntopo(struct Brush *brush, struct Sculpt *sd, struct DynTopoSettings *out);
bool BKE_brush_hard_edge_mode_get(const struct Scene *scene, const struct Brush *brush);
void BKE_brush_hard_edge_mode_set(struct Scene *scene, struct Brush *brush, bool val);
float BKE_brush_fset_slide_get(const struct Scene *scene, const struct Brush *brush);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,129 @@
#pragma once
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*/
/** \file
* \ingroup bke
* \brief New brush engine for sculpt
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "RNA_types.h"
/*
The new brush engine is based on command lists. These lists
will eventually be created by a node editor.
Key is the concept of BrushChannels. A brush channel is
a logical parameter with a type, input settings (e.g. pen),
a falloff curve, etc.
Brush channels have a concept of inheritance. There is a
BrushChannelSet (collection of channels) in Sculpt,
in Brush, and in BrushCommand. Inheritence behavior
is controller via BrushChannel->flag.
This should completely replace UnifiedPaintSettings.
*/
struct BrushChannel;
#include "BLO_read_write.h"
#include "DNA_sculpt_brush_types.h"
typedef struct BrushMappingDef {
int curve;
bool enabled;
bool inv;
float min, max;
int blendmode;
} BrushMappingDef;
typedef struct BrushMappingPreset {
// must match order of BRUSH_MAPPING_XXX enums
struct BrushMappingDef pressure, xtilt, ytilt, angle, speed;
} BrushMappingPreset;
#define MAX_BRUSH_ENUM_DEF 32
typedef struct BrushEnumDef {
EnumPropertyItem items[MAX_BRUSH_ENUM_DEF];
} BrushEnumDef;
typedef struct BrushChannelType {
char name[32], idname[32];
float min, max, soft_min, soft_max;
BrushMappingPreset mappings;
int type, flag;
int ivalue;
float fvalue;
BrushEnumDef enumdef; // if an enum type
} BrushChannelType;
typedef struct BrushCommand {
int tool;
struct BrushChannelSet *params;
struct BrushChannelSet *params_final;
int totparam;
} BrushCommand;
typedef struct BrushCommandList {
BrushCommand *commands;
int totcommand;
} BrushCommandList;
void BKE_brush_channel_free(BrushChannel *ch);
void BKE_brush_channel_copy(BrushChannel *dst, BrushChannel *src);
void BKE_brush_channel_init(BrushChannel *ch, BrushChannelType *def);
BrushChannelSet *BKE_brush_channelset_create();
void BKE_brush_channelset_free(BrushChannelSet *chset);
void BKE_brush_channelset_add(BrushChannelSet *chset, BrushChannel *ch);
BrushChannel *BKE_brush_channelset_lookup(BrushChannelSet *chset, const char *idname);
bool BKE_brush_channelset_has(BrushChannelSet *chset, const char *idname);
void BKE_brush_channelset_add_builtin(BrushChannelSet *chset, const char *idname);
bool BKE_brush_channelset_ensure_builtin(BrushChannelSet *chset, const char *idname);
void BKE_brush_channelset_merge(BrushChannelSet *dst,
BrushChannelSet *child,
BrushChannelSet *parent);
void BKE_brush_resolve_channels(struct Brush *brush, struct Sculpt *sd);
int BKE_brush_channel_get_int(BrushChannelSet *chset, char *idname);
float BKE_brush_channel_get_float(BrushChannelSet *chset, char *idname);
float BKE_brush_channel_set_float(BrushChannelSet *chset, char *idname, float val);
void BKE_brush_init_toolsettings(struct Sculpt *sd);
void BKE_brush_builtin_create(struct Brush *brush, int tool);
BrushCommandList *BKE_brush_commandlist_create();
void BKE_brush_commandlist_free(BrushCommandList *cl);
BrushCommand *BKE_brush_commandlist_add(BrushCommandList *cl);
BrushCommand *BKE_brush_command_init(BrushCommand *command, int tool);
void BKE_builtin_commandlist_create(BrushChannelSet *chset, BrushCommandList *cl, int tool);
void BKE_brush_channelset_read(BlendDataReader *reader, BrushChannelSet *cset);
void BKE_brush_channelset_write(BlendWriter *writer, BrushChannelSet *cset);
#ifdef __cplusplus
}
#endif

View File

@@ -105,6 +105,8 @@ bool CustomData_has_math(const struct CustomData *data);
bool CustomData_has_interp(const struct CustomData *data);
bool CustomData_bmesh_has_free(const struct CustomData *data);
bool CustomData_layout_is_same(const struct CustomData *_a, const struct CustomData *_b);
/**
* Checks if any of the customdata layers is referenced.
*/
@@ -141,6 +143,10 @@ void CustomData_copy(const struct CustomData *source,
/* BMESH_TODO, not really a public function but readfile.c needs it */
void CustomData_update_typemap(struct CustomData *data);
/* copies all customdata layers without allocating data,
* and without respect to type masks or NO_COPY/etc flags*/
void CustomData_copy_all_layout(const struct CustomData *source, struct CustomData *dest);
/* same as the above, except that this will preserve existing layers, and only
* add the layers that were not there yet */
bool CustomData_merge(const struct CustomData *source,
@@ -277,6 +283,16 @@ void CustomData_copy_data_named(const struct CustomData *source,
int dest_index,
int count);
void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count);
// ignores CD_MESH_ID layer if it exists
void CustomData_bmesh_swap_data(struct CustomData *source,
struct CustomData *dest,
void *src_block,
void **dest_block);
// simple pointer swap; will unswaps ids if a CD_MESH_ID layer exists
void CustomData_bmesh_swap_data_simple(CustomData *data, void **block1, void **block2);
void CustomData_bmesh_copy_data(const struct CustomData *source,
struct CustomData *dest,
void *src_block,
@@ -605,6 +621,11 @@ void CustomData_blend_write(struct BlendWriter *writer,
struct ID *id);
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
void CustomData_unmark_temporary_nocopy(struct CustomData *data);
void CustomData_mark_temporary_nocopy(struct CustomData *data);
int CustomData_get_elem_size(CustomDataLayer *layer);
#ifdef __cplusplus
}
#endif

View File

@@ -54,9 +54,11 @@ enum {
DT_TYPE_UV = 1 << 24,
DT_TYPE_SHARP_FACE = 1 << 25,
DT_TYPE_FREESTYLE_FACE = 1 << 26,
#define DT_TYPE_MAX 27
DT_TYPE_PROPCOL = 1 << 27,
#define DT_TYPE_MAX 28
DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT,
DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT |
DT_TYPE_PROPCOL,
DT_TYPE_EDGE_ALL = DT_TYPE_SHARP_EDGE | DT_TYPE_SEAM | DT_TYPE_CREASE | DT_TYPE_BWEIGHT_EDGE |
DT_TYPE_FREESTYLE_EDGE,
DT_TYPE_LOOP_ALL = DT_TYPE_VCOL | DT_TYPE_LNOR | DT_TYPE_UV,
@@ -74,7 +76,7 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type);
int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type);
#define DT_DATATYPE_IS_VERT(_dt) \
ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_SKIN, DT_TYPE_BWEIGHT_VERT)
ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_SKIN, DT_TYPE_BWEIGHT_VERT, DT_TYPE_PROPCOL)
#define DT_DATATYPE_IS_EDGE(_dt) \
ELEM(_dt, \
DT_TYPE_CREASE, \
@@ -94,7 +96,8 @@ enum {
DT_MULTILAYER_INDEX_SHAPEKEY = 1,
DT_MULTILAYER_INDEX_VCOL = 2,
DT_MULTILAYER_INDEX_UV = 3,
DT_MULTILAYER_INDEX_MAX = 4,
DT_MULTILAYER_INDEX_PROPCOL = 4,
DT_MULTILAYER_INDEX_MAX = 5,
};
/* Below we keep positive values for real layers idx (generated dynamically). */

View File

@@ -0,0 +1,24 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
/** \file
* \ingroup bke
* \brief Dynamic topology remeshing API
*/
typedef struct DynTopo DynTopo;

View File

@@ -78,8 +78,12 @@ typedef struct FModifierTypeInfo {
short size;
/** #eFMI_Action_Types. */
short acttype;
#ifdef __cplusplus
short requires_;
#else
/** #eFMI_Requirement_Flags. */
short requires;
#endif
/** name of modifier in interface. */
char name[64];
/** name of struct for SDNA. */

View File

@@ -69,7 +69,8 @@ extern "C" {
/* *** mesh.c *** */
struct BMesh *BKE_mesh_to_bmesh_ex(const struct Mesh *me,
struct BMesh *BKE_mesh_to_bmesh_ex(const struct Object *ob,
const struct Mesh *me,
const struct BMeshCreateParams *create_params,
const struct BMeshFromMeshParams *convert_params);
struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me,
@@ -636,7 +637,7 @@ void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
/* In DerivedMesh.cc */
void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval,
const CustomData_MeshMasks *cd_mask_finalize);
const struct CustomData_MeshMasks *cd_mask_finalize);
/* **** Depsgraph evaluation **** */

View File

@@ -105,20 +105,28 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const struct MPoly *mpoly,
UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v);
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap);
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
const struct MLoop *mloop,
int totvert,
int totpoly,
int totloop);
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
const struct MLoop *mloop,
int totvert,
int totpoly,
int totloop);
void BKE_mesh_vert_poly_map_create(
MeshElemMap **r_map,
int **r_mem,
const struct MVert *mvert, // only needed if sort_disk_cycles is true
const struct MEdge *medge, // only needed if sort_disk_cycles is true
const struct MPoly *mpoly,
const struct MLoop *mloop,
int totvert,
int totpoly,
int totloop,
const bool sort_disk_cycles); // put polys in sorted geometric order
void BKE_mesh_vert_loop_map_create(
MeshElemMap **r_map,
int **r_mem,
const struct MVert *mvert, // only needed if sort_disk_cycles is true
const struct MEdge *medge, // only needed if sort_disk_cycles is true
const struct MPoly *mpoly,
const struct MLoop *mloop,
int totvert,
int totpoly,
int totloop,
const bool sort_disk_cycles); // put loops in sorted geometric order
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MVert *mvert,
@@ -128,7 +136,13 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
const struct MLoop *mloop,
const int totloop);
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
MeshElemMap **r_map,
int **r_mem,
const struct MVert *mvert, // only needed if sort_disk_cycles is true
const struct MEdge *medge,
int totvert,
int totedge,
bool sort_disk_cycles); // sort verts in geometric order around edges
void BKE_mesh_vert_edge_vert_map_create(
MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,

View File

@@ -32,7 +32,7 @@ struct Mesh;
struct MirrorModifierData;
struct Object;
struct Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(struct MirrorModifierData *mmd,
struct Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(struct Object *ob, struct MirrorModifierData *mmd,
const struct Mesh *mesh,
int axis,
const float plane_co[3],

View File

@@ -39,6 +39,7 @@ struct MultiresModifierData;
struct Object;
struct Scene;
struct SubdivCCG;
struct BMesh;
struct MLoop;
struct MLoopTri;
@@ -217,6 +218,7 @@ BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3]
const float dPdv[3],
const int corner);
void BKE_multires_bmesh_space_set(struct Object *ob, struct BMesh *bm, int mode);
/* Versioning. */
/* Convert displacement which is stored for simply-subdivided mesh to a Catmull-Clark

View File

@@ -25,6 +25,8 @@
#include "BLI_sys_types.h"
#include "DNA_object_enums.h"
#include "DNA_userdef_types.h"
#include "BKE_lib_id.h"
#ifdef __cplusplus
extern "C" {
@@ -154,8 +156,8 @@ bool BKE_object_obdata_is_libdata(const struct Object *ob);
struct Object *BKE_object_duplicate(struct Main *bmain,
struct Object *ob,
uint dupflag,
const uint duplicate_options);
eDupli_ID_Flags dupflag,
const eLibIDDuplicateFlags duplicate_options);
void BKE_object_obdata_size_init(struct Object *ob, const float size);

View File

@@ -23,15 +23,18 @@
* \ingroup bke
*/
#include "BKE_pbvh.h"
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
#include "DNA_brush_enums.h"
#include "DNA_customdata_types.h"
#include "DNA_object_enums.h"
#ifdef __cplusplus
extern "C" {
#endif
struct MDynTopoVert;
struct BMFace;
struct BMesh;
struct BlendDataReader;
@@ -342,6 +345,11 @@ typedef struct SculptClothSimulation {
/** #PBVHNode pointer as a key, index in #SculptClothSimulation.node_state as value. */
struct GHash *node_state_index;
eSculptClothNodeSimState *node_state;
// persistent base customdata layer offsets
int cd_pers_co;
int cd_pers_no;
int cd_pers_disp;
} SculptClothSimulation;
typedef struct SculptPersistentBase {
@@ -360,7 +368,8 @@ typedef struct SculptVertexInfo {
typedef struct SculptBoundaryEditInfo {
/* Vertex index from where the topology propagation reached this vertex. */
int original_vertex;
SculptVertRef original_vertex;
int original_vertex_i;
/* How many steps were needed to reach this vertex from the boundary. */
int num_propagation_steps;
@@ -371,13 +380,23 @@ typedef struct SculptBoundaryEditInfo {
/* Edge for drawing the boundary preview in the cursor. */
typedef struct SculptBoundaryPreviewEdge {
int v1;
int v2;
SculptVertRef v1;
SculptVertRef v2;
} SculptBoundaryPreviewEdge;
#define MAX_STORED_COTANGENTW_EDGES 7
typedef struct StoredCotangentW {
float static_weights[MAX_STORED_COTANGENTW_EDGES];
float *weights;
int length;
} StoredCotangentW;
typedef struct SculptBoundary {
/* Vertex indices of the active boundary. */
int *vertices;
SculptVertRef *vertices;
int *vertex_indices;
int vertices_capacity;
int num_vertices;
@@ -386,6 +405,14 @@ typedef struct SculptBoundary {
* a distance of 0. */
float *distance;
float (*smoothco)[3];
float *boundary_dist; // distances from verts to boundary
float (*boundary_tangents)[3];
StoredCotangentW *boundary_cotangents;
SculptVertRef *boundary_closest;
int sculpt_totvert;
/* Data for drawing the preview. */
SculptBoundaryPreviewEdge *edges;
int edges_capacity;
@@ -395,12 +422,12 @@ typedef struct SculptBoundary {
bool forms_loop;
/* Initial vertex in the boundary which is closest to the current sculpt active vertex. */
int initial_vertex;
SculptVertRef initial_vertex;
/* Vertex that at max_propagation_steps from the boundary and closest to the original active
* vertex that was used to initialize the boundary. This is used as a reference to check how much
* the deformation will go into the mesh and to calculate the strength of the brushes. */
int pivot_vertex;
SculptVertRef pivot_vertex;
/* Stores the initial positions of the pivot and boundary initial vertex as they may be deformed
* during the brush action. This allows to use them as a reference positions and vectors for some
@@ -418,7 +445,7 @@ typedef struct SculptBoundary {
/* Bend Deform type. */
struct {
float (*pivot_rotation_axis)[3];
float (*pivot_positions)[3];
float (*pivot_positions)[4];
} bend;
/* Slide Deform type. */
@@ -440,7 +467,7 @@ typedef struct SculptFakeNeighbors {
float current_max_distance;
/* Indexed by vertex, stores the vertex index of its fake neighbor if available. */
int *fake_neighbor_index;
SculptVertRef *fake_neighbor_index;
} SculptFakeNeighbors;
@@ -459,8 +486,15 @@ typedef struct SculptSession {
/* These are always assigned to base mesh data when using PBVH_FACES and PBVH_GRIDS. */
struct MVert *mvert;
struct MPoly *mpoly;
struct MEdge *medge;
struct MLoop *mloop;
struct MPoly *mpoly;
// only assigned in PBVH_FACES and PBVH_GRIDS
CustomData *vdata, *edata, *ldata, *pdata;
// for grids
CustomData temp_vdata, temp_pdata;
/* These contain the vertex and poly counts of the final mesh. */
int totvert, totpoly;
@@ -495,8 +529,13 @@ typedef struct SculptSession {
/* BMesh for dynamic topology sculpting */
struct BMesh *bm;
int cd_dyn_vert;
int cd_vert_node_offset;
int cd_face_node_offset;
int cd_vcol_offset;
int cd_faceset_offset;
int cd_face_areas;
bool bm_smooth_shading;
/* Undo/redo log for dynamic topology sculpting */
struct BMLog *bm_log;
@@ -524,9 +563,9 @@ typedef struct SculptSession {
struct ExpandCache *expand_cache;
/* Cursor data and active vertex for tools */
int active_vertex_index;
SculptVertRef active_vertex_index;
SculptFaceRef active_face_index;
int active_face_index;
int active_grid_index;
/* When active, the cursor draws with faded colors, indicating that there is an action enabled.
@@ -548,9 +587,12 @@ typedef struct SculptSession {
struct RegionView3D *rv3d;
struct View3D *v3d;
struct Scene *scene;
int cd_origvcol_offset;
int cd_origco_offset;
int cd_origno_offset;
/* Dynamic mesh preview */
int *preview_vert_index_list;
SculptVertRef *preview_vert_index_list;
int preview_vert_index_count;
/* Pose Brush Preview */
@@ -612,6 +654,13 @@ typedef struct SculptSession {
*/
char needs_flush_to_id;
// id of current stroke, used to detect
// if vertex original data needs to be updated
int stroke_id, boundary_symmetry;
bool fast_draw; // hides facesets/masks and forces smooth to save GPU bandwidth
struct MDynTopoVert *mdyntopo_verts; // for non-bmesh
int mdyntopo_verts_size;
} SculptSession;
void BKE_sculptsession_free(struct Object *ob);
@@ -619,6 +668,7 @@ void BKE_sculptsession_free_deformMats(struct SculptSession *ss);
void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
bool BKE_sculptsession_check_mdyntopo(SculptSession *ss, int totvert);
/* Create new color layer on object if it doesn't have one and if experimental feature set has
* sculpt vertex color enabled. Returns truth if new layer has been added, false otherwise. */
@@ -655,6 +705,8 @@ void BKE_sculpt_ensure_orig_mesh_data(struct Scene *scene, struct Object *object
bool BKE_sculptsession_use_pbvh_draw(const struct Object *ob, const struct View3D *v3d);
char BKE_get_fset_boundary_symflag(struct Object *object);
enum {
SCULPT_MASK_LAYER_CALC_VERT = (1 << 0),
SCULPT_MASK_LAYER_CALC_LOOP = (1 << 1),

View File

@@ -22,20 +22,97 @@
*/
#include "BLI_bitmap.h"
#include "BLI_compiler_compat.h"
#include "BLI_ghash.h"
/* For embedding CCGKey in iterator. */
#include "BKE_ccg.h"
#include <stdint.h>
//#define DEFRAGMENT_MEMORY
#ifdef __cplusplus
extern "C" {
#endif
// experimental feature to detect quad diagonals and mark (but not dissolve) them
//#define SCULPT_DIAGONAL_EDGE_MARKS
typedef struct SculptVertRef {
intptr_t i;
} SculptVertRef;
typedef struct SculptEdgeRef {
intptr_t i;
} SculptEdgeRef;
typedef struct SculptFaceRef {
intptr_t i;
} SculptFaceRef;
#if 0
typedef struct SculptLoopRef {
intptr_t i;
} SculptLoopRef;
#endif
BLI_INLINE SculptVertRef BKE_pbvh_make_vref(intptr_t i)
{
SculptVertRef ret = {i};
return ret;
}
BLI_INLINE SculptEdgeRef BKE_pbvh_make_eref(intptr_t i)
{
SculptEdgeRef ret = {i};
return ret;
}
BLI_INLINE SculptFaceRef BKE_pbvh_make_fref(intptr_t i)
{
SculptFaceRef ret = {i};
return ret;
}
#define SCULPT_REF_NONE ((intptr_t)-1)
#ifdef DEFRAGMENT_MEMORY
# include "BLI_smallhash.h"
#endif
typedef struct PBVHTri {
int v[3]; // references into PBVHTriBuf->verts
intptr_t l[3]; // loops
int eflag; // bitmask of which edges in the tri are real edges in the mesh
float no[3];
SculptFaceRef f;
} PBVHTri;
typedef struct PBVHTriBuf {
PBVHTri *tris;
SculptVertRef *verts;
int *edges;
int totvert, totedge, tottri;
int verts_size, edges_size, tris_size;
SmallHash vertmap; // maps vertex ptrs to indices within verts
// private field
intptr_t *loops;
int totloop, mat_nr;
float min[3], max[3];
} PBVHTriBuf;
struct BMLog;
struct BMesh;
struct BMVert;
struct BMEdge;
struct BMFace;
struct CCGElem;
struct CCGKey;
struct CustomData;
struct TableGSet;
struct DMFlagMat;
struct GPU_PBVH_Buffers;
struct IsectRayPrecalc;
@@ -52,12 +129,86 @@ struct TaskParallelSettings;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
//#define PROXY_ADVANCED
// experimental performance test of "data-based programming" approach
#ifdef PROXY_ADVANCED
typedef struct ProxyKey {
int node;
int pindex;
} ProxyKey;
# define MAX_PROXY_NEIGHBORS 12
typedef struct ProxyVertArray {
float **ownerco;
short **ownerno;
float (*co)[3];
float (*fno)[3];
short (*no)[3];
float *mask, **ownermask;
SculptVertRef *index;
float **ownercolor, (*color)[4];
ProxyKey (*neighbors)[MAX_PROXY_NEIGHBORS];
int size;
int datamask;
bool neighbors_dirty;
GHash *indexmap;
} ProxyVertArray;
typedef enum {
PV_OWNERCO = 1,
PV_OWNERNO = 2,
PV_CO = 4,
PV_NO = 8,
PV_MASK = 16,
PV_OWNERMASK = 32,
PV_INDEX = 64,
PV_OWNERCOLOR = 128,
PV_COLOR = 256,
PV_NEIGHBORS = 512
} ProxyVertField;
typedef struct ProxyVertUpdateRec {
float *co, *no, *mask, *color;
SculptVertRef index, newindex;
} ProxyVertUpdateRec;
# define PBVH_PROXY_DEFAULT CO | INDEX | MASK
struct SculptSession;
void BKE_pbvh_ensure_proxyarrays(
struct SculptSession *ss, PBVH *pbvh, PBVHNode **nodes, int totnode, int mask);
void BKE_pbvh_load_proxyarrays(PBVH *pbvh, PBVHNode **nodes, int totnode, int mask);
void BKE_pbvh_ensure_proxyarray(
struct SculptSession *ss,
struct PBVH *pbvh,
struct PBVHNode *node,
int mask,
struct GHash
*vert_node_map, // vert_node_map maps vertex SculptVertRefs to PBVHNode indices; optional
bool check_indexmap,
bool force_update);
void BKE_pbvh_gather_proxyarray(PBVH *pbvh, PBVHNode **nodes, int totnode);
void BKE_pbvh_free_proxyarray(struct PBVH *pbvh, struct PBVHNode *node);
void BKE_pbvh_update_proxyvert(struct PBVH *pbvh, struct PBVHNode *node, ProxyVertUpdateRec *rec);
ProxyVertArray *BKE_pbvh_get_proxyarrays(struct PBVH *pbvh, struct PBVHNode *node);
#endif
typedef struct {
float (*co)[3];
} PBVHProxyNode;
typedef struct {
float (*color)[4];
int size;
} PBVHColorBufferNode;
typedef enum {
@@ -78,6 +229,15 @@ typedef enum {
PBVH_UpdateTopology = 1 << 13,
PBVH_UpdateColor = 1 << 14,
PBVH_Delete = 1 << 15,
PBVH_UpdateCurvatureDir = 1 << 16,
PBVH_UpdateTris = 1 << 17,
PBVH_RebuildNodeVerts = 1 << 18,
/* tri areas are not guaranteed to be up to date, tools should
update all nodes on first step of brush*/
PBVH_UpdateTriAreas = 1 << 19,
PBVH_UpdateOtherVerts = 1 << 20
} PBVHNodeFlags;
typedef struct PBVHFrustumPlanes {
@@ -98,6 +258,9 @@ typedef void (*BKE_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *
typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float *tmin);
void BKE_pbvh_get_nodes(PBVH *pbvh, int flag, PBVHNode ***r_array, int *r_totnode);
PBVHNode *BKE_pbvh_get_node(PBVH *pbvh, int node);
/* Building */
PBVH *BKE_pbvh_new(void);
@@ -106,27 +269,57 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
const struct MPoly *mpoly,
const struct MLoop *mloop,
struct MVert *verts,
struct MDynTopoVert *mdyntopo_verts,
int totvert,
struct CustomData *vdata,
struct CustomData *ldata,
struct CustomData *pdata,
const struct MLoopTri *looptri,
int looptri_num);
int looptri_num,
bool fast_draw);
void BKE_pbvh_build_grids(PBVH *pbvh,
struct CCGElem **grids,
int totgrid,
struct CCGKey *key,
void **gridfaces,
struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
unsigned int **grid_hidden,
bool fast_draw);
void BKE_pbvh_build_bmesh(PBVH *pbvh,
struct BMesh *bm,
bool smooth_shading,
struct BMLog *log,
const int cd_vert_node_offset,
const int cd_face_node_offset);
const int cd_face_node_offset,
const int cd_dyn_vert,
const int cd_face_areas,
bool fast_draw);
void BKE_pbvh_update_offsets(PBVH *pbvh,
const int cd_vert_node_offset,
const int cd_face_node_offset,
const int cd_dyn_vert,
const int cd_face_areas);
void BKE_pbvh_free(PBVH *pbvh);
void BKE_pbvh_set_bm_log(PBVH *pbvh, struct BMLog *log);
/** update original data, only data whose r_** parameters are passed in will be updated*/
void BKE_pbvh_bmesh_update_origvert(
PBVH *pbvh, struct BMVert *v, float **r_co, float **r_no, float **r_color, bool log_undo);
void BKE_pbvh_update_origcolor_bmesh(PBVH *pbvh, PBVHNode *node);
void BKE_pbvh_update_origco_bmesh(PBVH *pbvh, PBVHNode *node);
/**
checks if original data needs to be updated for v, and if so updates it. Stroke_id
is provided by the sculpt code and is used to detect updates. The reason we do it
inside the verts and not in the nodes is to allow splitting of the pbvh during the stroke.
*/
bool BKE_pbvh_bmesh_check_origdata(PBVH *pbvh, struct BMVert *v, int stroke_id);
/** used so pbvh can differentiate between different strokes,
see BKE_pbvh_bmesh_check_origdata */
void BKE_pbvh_set_stroke_id(PBVH *pbvh, int stroke_id);
/* Hierarchical Search in the BVH, two methods:
* - for each hit calling a callback
* - gather nodes in an array (easy to multithread) */
@@ -150,7 +343,8 @@ void BKE_pbvh_raycast(PBVH *pbvh,
void *data,
const float ray_start[3],
const float ray_normal[3],
bool original);
bool original,
int stroke_id);
bool BKE_pbvh_node_raycast(PBVH *pbvh,
PBVHNode *node,
@@ -160,11 +354,13 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
int *active_vertex_index,
int *active_face_grid_index,
float *face_normal);
SculptVertRef *active_vertex_index,
SculptFaceRef *active_face_grid_index,
float *face_normal,
int stroke_id);
bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
bool BKE_pbvh_bmesh_node_raycast_detail(PBVH *pbvh,
PBVHNode *node,
const float ray_start[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
@@ -189,7 +385,8 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
const float ray_start[3],
const float ray_normal[3],
float *depth,
float *dist_sq);
float *dist_sq,
int stroke_id);
/* Drawing */
@@ -238,22 +435,60 @@ int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh);
/* Only valid for type == PBVH_BMESH */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size);
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size, float detail_range);
typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
PBVH_Subdivide = 1 << 0,
PBVH_Collapse = 1 << 1,
PBVH_Cleanup = 1 << 2, // dissolve verts surrounded by either 3 or 4 triangles then triangulate
PBVH_LocalSubdivide = 1 << 3,
PBVH_LocalCollapse = 1 << 4
} PBVHTopologyUpdateMode;
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
const float view_normal[3],
float radius,
const bool use_frontface,
const bool use_projected);
typedef float (*DyntopoMaskCB)(SculptVertRef vertex, void *userdata);
bool BKE_pbvh_bmesh_update_topology(
PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
const float view_normal[3],
float radius,
const bool use_frontface,
const bool use_projected,
int symaxis,
bool updatePBVH,
DyntopoMaskCB mask_cb,
void *mask_cb_data,
int custom_max_steps); // if 0, will use defaul hueristics for max steps
bool BKE_pbvh_bmesh_update_topology_nodes(PBVH *pbvh,
bool (*searchcb)(PBVHNode *node, void *data),
void (*undopush)(PBVHNode *node, void *data),
void *searchdata,
PBVHTopologyUpdateMode mode,
const float center[3],
const float view_normal[3],
float radius,
const bool use_frontface,
const bool use_projected,
int sym_axis,
bool updatePBVH,
DyntopoMaskCB mask_cb,
void *mask_cb_data);
/* Node Access */
void BKE_pbvh_check_tri_areas(PBVH *pbvh, PBVHNode *node);
// updates boundaries and valences for whole mesh
void BKE_pbvh_bmesh_on_mesh_change(PBVH *pbvh);
bool BKE_pbvh_bmesh_check_valence(PBVH *pbvh, SculptVertRef vertex);
void BKE_pbvh_bmesh_update_valence(int cd_dyn_vert, SculptVertRef vertex);
void BKE_pbvh_bmesh_update_all_valence(PBVH *pbvh);
void BKE_pbvh_bmesh_flag_all_disk_sort(PBVH *pbvh);
bool BKE_pbvh_bmesh_mark_update_valence(PBVH *pbvh, SculptVertRef vertex);
void BKE_pbvh_node_mark_update_tri_area(PBVHNode *node);
void BKE_pbvh_update_all_tri_areas(PBVH *pbvh);
void BKE_pbvh_node_mark_update(PBVHNode *node);
void BKE_pbvh_node_mark_update_mask(PBVHNode *node);
void BKE_pbvh_node_mark_update_color(PBVHNode *node);
@@ -292,10 +527,14 @@ bool BKE_pbvh_node_frustum_contain_AABB(PBVHNode *node, void *frustum);
/* test if AABB is at least partially outside the PBVHFrustumPlanes volume */
bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *frustum);
struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, PBVHNode *node);
struct TableGSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct TableGSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
struct TableGSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
void BKE_pbvh_bmesh_regen_node_verts(PBVH *pbvh);
void BKE_pbvh_bmesh_mark_node_regen(PBVH *pbvh, PBVHNode *node);
// now generated PBVHTris
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
/* Update Bounding Box/Redraw and clear flags */
@@ -343,6 +582,7 @@ typedef struct PBVHVertexIter {
int gy;
int i;
int index;
SculptVertRef vertex;
bool respect_hide;
/* grid */
@@ -362,10 +602,14 @@ typedef struct PBVHVertexIter {
float *vmask;
/* bmesh */
struct GSetIterator bm_unique_verts;
struct GSetIterator bm_other_verts;
int bi;
struct TableGSet *bm_cur_set;
struct TableGSet *bm_unique_verts, *bm_other_verts;
struct CustomData *bm_vdata;
int cd_dyn_vert;
int cd_vert_mask_offset;
int cd_vcol_offset;
/* result: these are all computed in the macro, but we assume
* that compiler optimization's will skip the ones we don't use */
@@ -379,6 +623,8 @@ typedef struct PBVHVertexIter {
bool visible;
} PBVHVertexIter;
#define BKE_PBVH_DYNVERT(cd_dyn_vert, v) ((MDynTopoVert *)BM_ELEM_CD_GET_VOID_P(v, cd_dyn_vert))
void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int mode);
#define BKE_pbvh_vertex_iter_begin(pbvh, node, vi, mode) \
@@ -388,7 +634,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
if (vi.grids) { \
vi.width = vi.gridsize; \
vi.height = vi.gridsize; \
vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
vi.vertex.i = vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \
vi.grid = vi.grids[vi.grid_indices[vi.g]]; \
if (mode == PBVH_ITER_UNIQUE) { \
vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \
@@ -407,6 +653,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi.mask = vi.key.has_mask ? CCG_elem_mask(&vi.key, vi.grid) : NULL; \
vi.grid = CCG_elem_next(&vi.key, vi.grid); \
vi.index++; \
vi.vertex.i++; \
vi.visible = true; \
if (vi.gh) { \
if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) { \
@@ -427,7 +674,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
} \
vi.co = vi.mvert->co; \
vi.no = vi.mvert->no; \
vi.index = vi.vert_indices[vi.i]; \
vi.index = vi.vertex.i = vi.vert_indices[vi.i]; \
if (vi.vmask) { \
vi.mask = &vi.vmask[vi.index]; \
} \
@@ -436,22 +683,41 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
} \
} \
else { \
if (!BLI_gsetIterator_done(&vi.bm_unique_verts)) { \
vi.bm_vert = BLI_gsetIterator_getKey(&vi.bm_unique_verts); \
BLI_gsetIterator_step(&vi.bm_unique_verts); \
BMVert *bv = NULL; \
while (!bv) { \
if (!vi.bm_cur_set->elems || vi.bi >= vi.bm_cur_set->cur) { \
if (vi.bm_cur_set != vi.bm_other_verts && mode != PBVH_ITER_UNIQUE) { \
vi.bm_cur_set = vi.bm_other_verts; \
vi.bi = 0; \
if (!vi.bm_cur_set->elems || vi.bi >= vi.bm_other_verts->cur) { \
break; \
} \
} \
else { \
break; \
} \
} \
else { \
bv = vi.bm_cur_set->elems[vi.bi++]; \
} \
} \
else { \
vi.bm_vert = BLI_gsetIterator_getKey(&vi.bm_other_verts); \
BLI_gsetIterator_step(&vi.bm_other_verts); \
if (!bv) { \
continue; \
} \
vi.bm_vert = bv; \
if (vi.cd_vcol_offset >= 0) { \
MPropCol *vcol = BM_ELEM_CD_GET_VOID_P(bv, vi.cd_vcol_offset); \
vi.col = vcol->color; \
} \
vi.vertex.i = (intptr_t)bv; \
vi.index = BM_elem_index_get(vi.bm_vert); \
vi.visible = !BM_elem_flag_test_bool(vi.bm_vert, BM_ELEM_HIDDEN); \
if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \
continue; \
} \
vi.co = vi.bm_vert->co; \
vi.fno = vi.bm_vert->no; \
vi.index = BM_elem_index_get(vi.bm_vert); \
vi.mask = BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \
vi.mask = (float *)BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \
}
#define BKE_pbvh_vertex_iter_end \
@@ -460,24 +726,28 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
} \
((void)0)
#define BKE_pbvh_vertex_index_to_table(pbvh, v) \
(BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != -1 ? BM_elem_index_get((BMVert *)(v.i)) : (v.i))
SculptVertRef BKE_pbvh_table_index_to_vertex(PBVH *pbvh, int idx);
#define BKE_pbvh_face_index_to_table(pbvh, v) \
(BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != -1 ? BM_elem_index_get((BMFace *)(v.i)) : (v.i))
SculptFaceRef BKE_pbvh_table_index_to_face(PBVH *pbvh, int idx);
void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count);
void BKE_pbvh_node_free_proxies(PBVHNode *node);
PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *pbvh, PBVHNode *node);
void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot);
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]);
bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node);
// void BKE_pbvh_node_BB_reset(PBVHNode *node);
// void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);
bool pbvh_has_mask(const PBVH *pbvh);
bool BKE_pbvh_draw_mask(const PBVH *pbvh);
void pbvh_show_mask_set(PBVH *pbvh, bool show_mask);
bool pbvh_has_face_sets(PBVH *pbvh);
bool BKE_pbvh_draw_face_sets(PBVH *pbvh);
void pbvh_show_face_sets_set(PBVH *pbvh, bool show_face_sets);
/* Parallelization */
@@ -490,6 +760,150 @@ struct MVert *BKE_pbvh_get_verts(const PBVH *pbvh);
PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
int BKE_pbvh_get_node_index(PBVH *pbvh, PBVHNode *node);
int BKE_pbvh_get_node_id(PBVH *pbvh, PBVHNode *node);
void BKE_pbvh_set_flat_vcol_shading(PBVH *pbvh, bool value);
#define DYNTOPO_CD_INTERP
void SCULPT_update_flat_vcol_shading(struct Object *ob, struct Scene *scene);
void BKE_pbvh_curvature_update_set(PBVHNode *node, bool state);
bool BKE_pbvh_curvature_update_get(PBVHNode *node);
int BKE_pbvh_get_totnodes(PBVH *pbvh);
bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node);
PBVHTriBuf *BKE_pbvh_bmesh_get_tris(PBVH *pbvh, PBVHNode *node);
void BKE_pbvh_bmesh_free_tris(PBVH *pbvh, PBVHNode *node);
/*recalculates boundary flags for *all* vertices. used by
symmetrize.*/
void BKE_pbvh_recalc_bmesh_boundary(PBVH *pbvh);
void BKE_pbvh_bmesh_remove_face(PBVH *pbvh, struct BMFace *f, bool log_face);
void BKE_pbvh_bmesh_remove_vertex(PBVH *pbvh, struct BMVert *v, bool log_vert);
void BKE_pbvh_bmesh_add_face(PBVH *pbvh, struct BMFace *f, bool log_face, bool force_tree_walk);
// note that e_tri and f_example are allowed to be NULL
struct BMFace *BKE_pbvh_face_create_bmesh(PBVH *pbvh,
struct BMVert *v_tri[3],
struct BMEdge *e_tri[3],
const struct BMFace *f_example);
// if node is NULL, one will be foudn in the pbvh, which potentially can be slow
struct BMVert *BKE_pbvh_vert_create_bmesh(
PBVH *pbvh, float co[3], float no[3], PBVHNode *node, struct BMVert *v_example);
PBVHNode *BKE_pbvh_node_from_face_bmesh(PBVH *pbvh, struct BMFace *f);
PBVHNode *BKE_pbvh_node_from_index(PBVH *pbvh, int node_i);
struct BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh);
void BKE_pbvh_update_vert_boundary(int cd_dyn_vert,
int cd_faceset_offset,
struct BMVert *v,
int symmetry);
#define DYNTOPO_DYNAMIC_TESS
PBVHNode *BKE_pbvh_get_node_leaf_safe(PBVH *pbvh, int i);
void BKE_pbvh_get_vert_face_areas(PBVH *pbvh, SculptVertRef vertex, float *r_areas, int valence);
void BKE_pbvh_set_symmetry(PBVH *pbvh, int symmetry, int boundary_symmetry);
#if 0
typedef enum {
SCULPT_TEXTURE_UV = 1 << 0, // per-uv
// SCULPT_TEXTURE_PTEX?
} SculptTextureType;
typedef int TexLayerRef;
/*
Texture points are texels projected into 3d.
*/
typedef intptr_t TexPointRef;
void *BKE_pbvh_get_tex_settings(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
void *BKE_pbvh_get_tex_data(PBVH *pbvh, PBVHNode *node, TexPointRef vdm);
typedef struct SculptTextureDef {
SculptTextureType type;
int settings_size;
void (*build_begin)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
/*vdms can cache data per node, which is freed to maintain memory limit.
they store cache in the same structure they return in buildNodeData.*/
void (*freeCachedData)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
void (*ensuredCachedData)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
/*builds all data that isn't cached.*/
void *(*buildNodeData)(PBVH *pbvh, PBVHNode *node);
bool (*validate)(PBVH *pbvh, TexLayerRef vdm);
void (*getPointsFromNode)(PBVH *pbvh,
PBVHNode *node,
TexLayerRef vdm,
TexPointRef **r_ids,
float ***r_cos,
float ***r_nos,
int *r_totpoint);
void (*releaseNodePoints)(
PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, float **cos, float **nos);
# if 0
int (*getTrisFromNode)(PBVH *pbvh,
PBVHNode *node,
TexLayerRef vdm,
TexPointRef *((*r_tris)[3]),
TexPointRef **r_ids,
int tottri,
int totid);
void (*getTriInterpWeightsFromNode)(PBVH *pbvh,
PBVHNode *node,
TexLayerRef vdm,
float *((*r_tris)[3]),
SculptLoopRef ***r_src_loops,
int tottri,
int totloop);
int (*getTriCount)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm);
# endif
void (*getPointNeighbors)(PBVH *pbvh,
PBVHNode *node,
TexLayerRef vdm,
TexPointRef id,
TexPointRef **r_neighbor_ids,
int *r_totneighbor,
int maxneighbors,
TexPointRef **r_duplicates_id,
int r_totduplicate,
int maxduplicates);
void (*getPointValence)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef id);
void (*freeNodeData)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, void *settings);
void (*getPointsFromIds)(
PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, int totid);
/*displacement texture stuff*/
// can be tangent, object space displacement, whatever
void (*worldToDelta)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, int totid);
void (*deltaToWorld)(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm, TexPointRef *ids, int totid);
} SculptDisplacementDef;
typedef struct SculptLayerEntry {
char name[64];
int type;
void *settings;
float factor;
struct SculptLayerEntry *parent;
} SculptLayerEntry;
#endif
int BKE_pbvh_do_fset_symmetry(int fset, const int symflag, const float *co);
bool BKE_pbvh_check_vert_boundary(PBVH *pbvh, struct BMVert *v);
#ifdef __cplusplus
}
#endif

View File

@@ -124,6 +124,7 @@ set(SRC
intern/displist.cc
intern/displist_tangent.c
intern/dynamicpaint.c
intern/dyntopo.c
intern/editlattice.c
intern/editmesh.c
intern/editmesh_bvh.c
@@ -235,6 +236,7 @@ set(SRC
intern/particle_system.c
intern/pbvh.c
intern/pbvh_bmesh.c
intern/pbvh_displacement.c
intern/pointcache.c
intern/pointcloud.cc
intern/preferences.c
@@ -287,6 +289,7 @@ set(SRC
intern/workspace.c
intern/world.c
intern/writeavi.c
intern/brush_engine.c
BKE_DerivedMesh.h
BKE_action.h
@@ -449,6 +452,7 @@ set(SRC
BKE_workspace.h
BKE_world.h
BKE_writeavi.h
BKE_brush_engine.h
nla_private.h
particle_private.h
@@ -794,3 +798,75 @@ if(WITH_GTESTS)
include(GTestTesting)
blender_add_test_lib(bf_blenkernel_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB}")
endif()
if(false)
set(PBVH_CACHE_TEST_INC
.
../blenfont
../blenlib
../blenloader
../blentranslation
../bmesh
../depsgraph
../draw
../functions
../gpencil_modifiers
../gpu
../ikplugin
../imbuf
../makesdna
../makesrna
../modifiers
../nodes
../render
../sequencer
../shader_fx
../simulation
../../../intern/eigen
../../../intern/ghost
../../../intern/glew-mx
../../../intern/guardedalloc
../../../intern/iksolver/extern
../../../intern/atomic
../../../intern/clog
../../../intern/libmv
../../../intern/mantaflow/extern
../../../intern/memutil
../../../intern/mikktspace
../../../intern/opensubdiv
../../../extern/curve_fit_nd
)
set(PBVH_CACHE_TEST_SRC
intern/pbvh_cache_test_main.c
)
setup_libdirs()
add_executable(pbvh_cache_test ${PBVH_CACHE_TEST_SRC} ${PBVH_CACHE_TEST_INC})
setup_platform_linker_flags(pbvh_cache_test)
target_link_libraries(pbvh_cache_test bf_blenkernel bf_bmesh bf_intern_ghost bf_blenlib bf_intern_guardedalloc)
if(WIN32)
set_target_properties(pbvh_cache_test PROPERTIES VS_GLOBAL_VcpkgEnabled "false")
set_target_properties(pbvh_cache_test PROPERTIES
PDB_NAME "pbvh_cache_test_private"
PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
if(WITH_WINDOWS_PDB AND WITH_WINDOWS_STRIPPED_PDB)
# This is slightly messy, but single target generators like ninja will not have the
# CMAKE_CFG_INTDIR variable and multitarget generators like msbuild will not have
# CMAKE_BUILD_TYPE. This can be simplified by target_link_options and the $<CONFIG>
# generator expression in newer cmake (2.13+) but until that time this fill have suffice.
if(CMAKE_BUILD_TYPE)
set_property(TARGET pbvh_cache_test APPEND_STRING PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/pbvh_cache_test_public.pdb")
else()
set_property(TARGET pbvh_cache_test APPEND_STRING PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/pbvh_cache_test_public.pdb")
endif()
endif()
endif()
if (WIN32)
target_link_libraries(pbvh_cache_test Vfw32.lib Imm32.lib Version.lib Comctl32.lib Shcore.lib Pathcch.lib)
endif()
endif()

View File

@@ -1140,7 +1140,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
unsupported = true;
}
if (scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM) {
if (scene->toolsettings->sculpt && scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM) {
unsupported |= (mti->type != eModifierTypeType_OnlyDeform);
}

View File

@@ -425,7 +425,7 @@ void BKE_animdata_copy_id_action(Main *bmain, ID *id)
void BKE_animdata_duplicate_id_action(struct Main *bmain,
struct ID *id,
const eDupli_ID_Flags duplicate_flags)
const uint duplicate_flags)
{
if (duplicate_flags & USER_DUP_ACT) {
animdata_copy_id_action(bmain, id, true, (duplicate_flags & USER_DUP_LINKED_ID) != 0);

View File

@@ -34,6 +34,7 @@
#include "BLT_translation.h"
#include "BKE_brush.h"
#include "BKE_brush_engine.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
@@ -262,12 +263,47 @@ static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_addres
if (brush->gradient) {
BLO_write_struct(writer, ColorBand, brush->gradient);
}
if (brush->channels) {
BKE_brush_channelset_write(writer, brush->channels);
}
}
static void brush_blend_read_data(BlendDataReader *reader, ID *id)
ATTR_NO_OPT static void brush_blend_read_data(BlendDataReader *reader, ID *id)
{
Brush *brush = (Brush *)id;
if (brush->channels) {
BLO_read_data_address(reader, &brush->channels);
BKE_brush_channelset_read(reader, brush->channels);
}
else {
BKE_brush_builtin_create(brush, brush->sculpt_tool);
}
if (brush->dyntopo.radius_scale == 0.0f) {
brush->dyntopo.radius_scale = 1.0f;
brush->dyntopo.inherit |= DYNTOPO_INHERIT_RADIUS_SCALE;
}
// detect old file data
if (brush->autosmooth_radius_factor == 0.0f) {
brush->autosmooth_radius_factor = 1.0f;
}
if (brush->topology_rake_radius_factor == 0.0f) {
brush->topology_rake_radius_factor = 1.0f;
}
if (brush->autosmooth_spacing == 0.0f) {
brush->autosmooth_spacing = 12;
}
if (brush->topology_rake_spacing == 0.0f) {
brush->topology_rake_spacing = 12;
brush->topology_rake_projection = 1.0f;
}
/* Falloff curve. */
BLO_read_data_address(reader, &brush->curve);
@@ -464,7 +500,13 @@ static void brush_defaults(Brush *brush)
FROM_DEFAULT(alpha);
FROM_DEFAULT(hardness);
FROM_DEFAULT(autosmooth_factor);
FROM_DEFAULT(autosmooth_projection);
FROM_DEFAULT(autosmooth_radius_factor);
FROM_DEFAULT(autosmooth_spacing);
FROM_DEFAULT(topology_rake_factor);
FROM_DEFAULT(topology_rake_radius_factor);
FROM_DEFAULT(topology_rake_projection);
FROM_DEFAULT(topology_rake_spacing);
FROM_DEFAULT(crease_pinch_factor);
FROM_DEFAULT(normal_radius_factor);
FROM_DEFAULT(wet_paint_radius_factor);
@@ -495,6 +537,7 @@ static void brush_defaults(Brush *brush)
FROM_DEFAULT(stencil_dimension);
FROM_DEFAULT(mtex);
FROM_DEFAULT(mask_mtex);
FROM_DEFAULT(dyntopo);
#undef FROM_DEFAULT
#undef FROM_DEFAULT_PTR
@@ -1662,6 +1705,8 @@ void BKE_brush_debug_print_state(Brush *br)
BR_TEST(plane_offset, f);
BR_TEST(autosmooth_factor, f);
BR_TEST(autosmooth_projection, f);
BR_TEST(autosmooth_radius_factor, f);
BR_TEST(topology_rake_factor, f);
@@ -1703,6 +1748,12 @@ void BKE_brush_sculpt_reset(Brush *br)
* assign this so logic below can remain the same. */
br->alpha = 0.5f;
bool disable_dyntopo = false;
// basic face set setup for all organic brushes
br->autosmooth_fset_slide = 1.0f;
br->flag2 |= BRUSH_SMOOTH_PRESERVE_FACE_SETS | BRUSH_SMOOTH_USE_AREA_WEIGHT;
/* Brush settings */
switch (br->sculpt_tool) {
case SCULPT_TOOL_DRAW_SHARP:
@@ -1714,11 +1765,16 @@ void BKE_brush_sculpt_reset(Brush *br)
br->curve_preset = BRUSH_CURVE_SMOOTHER;
br->spacing = 10;
br->alpha = 1.0f;
disable_dyntopo = true;
break;
case SCULPT_TOOL_SLIDE_RELAX:
br->spacing = 10;
br->alpha = 1.0f;
br->slide_deform_type = BRUSH_SLIDE_DEFORM_DRAG;
disable_dyntopo = true;
break;
case SCULPT_TOOL_CLAY:
br->flag |= BRUSH_SIZE_PRESSURE;
@@ -1766,18 +1822,29 @@ void BKE_brush_sculpt_reset(Brush *br)
break;
case SCULPT_TOOL_ROTATE:
br->alpha = 1.0;
disable_dyntopo = true;
break;
case SCULPT_TOOL_SMOOTH:
br->flag &= ~BRUSH_SPACE_ATTEN;
br->flag2 |= BRUSH_SMOOTH_PRESERVE_FACE_SETS | BRUSH_SMOOTH_USE_AREA_WEIGHT;
br->spacing = 5;
br->alpha = 0.7f;
br->surface_smooth_shape_preservation = 0.5f;
br->surface_smooth_current_vertex = 0.5f;
br->surface_smooth_iterations = 4;
disable_dyntopo = true;
break;
case SCULPT_TOOL_SNAKE_HOOK:
br->alpha = 1.0f;
br->rake_factor = 1.0f;
br->dyntopo.inherit = DYNTOPO_INHERIT_BITMASK &
~(DYNTOPO_INHERIT_ALL | DYNTOPO_LOCAL_COLLAPSE |
DYNTOPO_INHERIT_DETAIL_RANGE);
br->dyntopo.flag |= DYNTOPO_LOCAL_COLLAPSE;
br->dyntopo.detail_range = 0.4f;
break;
case SCULPT_TOOL_THUMB:
br->size = 75;
@@ -1791,6 +1858,8 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
disable_dyntopo = true;
break;
case SCULPT_TOOL_POSE:
br->pose_smooth_iterations = 4;
@@ -1799,18 +1868,24 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
disable_dyntopo = true;
break;
case SCULPT_TOOL_BOUNDARY:
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
br->curve_preset = BRUSH_CURVE_CONSTANT;
disable_dyntopo = true;
break;
case SCULPT_TOOL_DRAW_FACE_SETS:
br->alpha = 0.5f;
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
disable_dyntopo = true;
break;
case SCULPT_TOOL_GRAB:
br->alpha = 0.4f;
@@ -1818,6 +1893,8 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE;
br->flag &= ~BRUSH_SPACE_ATTEN;
disable_dyntopo = true;
break;
case SCULPT_TOOL_CLOTH:
br->cloth_mass = 1.0f;
@@ -1826,6 +1903,8 @@ void BKE_brush_sculpt_reset(Brush *br)
br->cloth_sim_falloff = 0.75f;
br->cloth_deform_type = BRUSH_CLOTH_DEFORM_DRAG;
br->flag &= ~(BRUSH_ALPHA_PRESSURE | BRUSH_SIZE_PRESSURE);
disable_dyntopo = true;
break;
case SCULPT_TOOL_LAYER:
br->flag &= ~BRUSH_SPACE_ATTEN;
@@ -1843,6 +1922,8 @@ void BKE_brush_sculpt_reset(Brush *br)
br->density = 1.0f;
br->flag &= ~BRUSH_SPACE_ATTEN;
zero_v3(br->rgb);
disable_dyntopo = true;
break;
case SCULPT_TOOL_SMEAR:
br->alpha = 1.0f;
@@ -1850,6 +1931,18 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE_ATTEN;
br->curve_preset = BRUSH_CURVE_SPHERE;
disable_dyntopo = true;
break;
case SCULPT_TOOL_VCOL_BOUNDARY:
br->flag &= ~BRUSH_SPACE_ATTEN;
br->spacing = 5;
br->alpha = 0.7f;
br->surface_smooth_shape_preservation = 0.5f;
br->surface_smooth_current_vertex = 0.5f;
br->surface_smooth_iterations = 4;
disable_dyntopo = true;
break;
case SCULPT_TOOL_DISPLACEMENT_SMEAR:
br->alpha = 1.0f;
@@ -1858,11 +1951,17 @@ void BKE_brush_sculpt_reset(Brush *br)
br->flag &= ~BRUSH_ALPHA_PRESSURE;
br->flag &= ~BRUSH_SPACE_ATTEN;
br->curve_preset = BRUSH_CURVE_SMOOTHER;
disable_dyntopo = true;
break;
default:
break;
}
if (disable_dyntopo) {
// disabled flag is never inherited
br->dyntopo.flag |= DYNTOPO_DISABLED;
}
/* Cursor colors */
/* Default Alpha */
@@ -1919,6 +2018,20 @@ void BKE_brush_sculpt_reset(Brush *br)
break;
case SCULPT_TOOL_SIMPLIFY:
// don't use DYNTOPO_INHERIT_BITMASK, we want to include
// future bits
br->flag2 |= BRUSH_SMOOTH_PRESERVE_FACE_SETS | BRUSH_SMOOTH_USE_AREA_WEIGHT |
BRUSH_CURVATURE_RAKE;
br->dyntopo.inherit = 0x7FFFFFFF &
~(DYNTOPO_INHERIT_ALL | DYNTOPO_SUBDIVIDE | DYNTOPO_COLLAPSE);
br->dyntopo.flag |= DYNTOPO_COLLAPSE | DYNTOPO_SUBDIVIDE;
br->autosmooth_factor = 0.05;
br->topology_rake_factor = 0.35;
br->topology_rake_projection = 0.975;
break;
case SCULPT_TOOL_VCOL_BOUNDARY:
case SCULPT_TOOL_PAINT:
case SCULPT_TOOL_MASK:
case SCULPT_TOOL_DRAW_FACE_SETS:
@@ -2554,3 +2667,158 @@ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool
return im;
}
void BKE_brush_get_dyntopo(Brush *brush, Sculpt *sd, DynTopoSettings *out)
{
*out = brush->dyntopo;
// detect unconverted file data
if (!out->inherit && !out->detail_range) {
// reload default dyntopo settings
Brush brush2 = *brush;
// don't copy heap allocd data
brush2.curve = NULL;
brush2.icon_imbuf = NULL;
brush2.gpencil_settings = NULL;
brush2.gradient = NULL;
brush2.preview = NULL;
BKE_brush_sculpt_reset(&brush2);
brush->dyntopo = *out = brush2.dyntopo;
brush_free_data((ID *)&brush2);
}
else if (!out->detail_size) {
brush->dyntopo.inherit |= DYNTOPO_INHERIT_DETAIL_SIZE;
brush->dyntopo.detail_size = 8.0f;
}
int inherit = out->inherit;
if (inherit & DYNTOPO_INHERIT_ALL) {
inherit = 0x7FFFFFFF;
}
if (!(sd->flags & SCULPT_DYNTOPO_ENABLED)) {
out->flag |= DYNTOPO_DISABLED;
}
if (inherit & DYNTOPO_INHERIT_MODE) {
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
out->mode = DYNTOPO_DETAIL_CONSTANT;
}
else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
out->mode = DYNTOPO_DETAIL_BRUSH;
}
else if (sd->flags & SCULPT_DYNTOPO_DETAIL_MANUAL) {
out->mode = DYNTOPO_DETAIL_MANUAL;
}
else {
out->mode = DYNTOPO_DETAIL_RELATIVE;
}
}
if (inherit & DYNTOPO_INHERIT_RADIUS_SCALE) {
out->radius_scale = sd->dyntopo_radius_scale;
}
if (inherit & DYNTOPO_INHERIT_DETAIL_SIZE) {
out->detail_size = sd->detail_size;
}
if (inherit & DYNTOPO_INHERIT_DETAIL_RANGE) {
out->detail_range = sd->detail_range;
}
if (inherit & DYNTOPO_INHERIT_DETAIL_PERCENT) {
out->detail_percent = sd->detail_percent;
}
if (inherit & DYNTOPO_INHERIT_SPACING) {
out->spacing = sd->dyntopo_spacing;
}
if (inherit & DYNTOPO_INHERIT_CONSTANT_DETAIL) {
out->constant_detail = sd->constant_detail;
}
if (inherit & DYNTOPO_SUBDIVIDE) {
if (sd->flags & SCULPT_DYNTOPO_SUBDIVIDE) {
out->flag |= DYNTOPO_SUBDIVIDE;
}
else {
out->flag &= ~DYNTOPO_SUBDIVIDE;
}
}
if (inherit & DYNTOPO_LOCAL_COLLAPSE) {
if (sd->flags & SCULPT_DYNTOPO_LOCAL_COLLAPSE) {
out->flag |= DYNTOPO_LOCAL_COLLAPSE;
}
else {
out->flag &= ~DYNTOPO_LOCAL_COLLAPSE;
}
}
if (inherit & DYNTOPO_LOCAL_SUBDIVIDE) {
if (sd->flags & SCULPT_DYNTOPO_LOCAL_SUBDIVIDE) {
out->flag |= DYNTOPO_LOCAL_SUBDIVIDE;
}
else {
out->flag &= ~DYNTOPO_LOCAL_SUBDIVIDE;
}
}
if (inherit & DYNTOPO_COLLAPSE) {
if (sd->flags & SCULPT_DYNTOPO_COLLAPSE) {
out->flag |= DYNTOPO_COLLAPSE;
}
else {
out->flag &= ~DYNTOPO_COLLAPSE;
}
}
if (inherit & DYNTOPO_CLEANUP) {
if (sd->flags & SCULPT_DYNTOPO_CLEANUP) {
out->flag |= DYNTOPO_CLEANUP;
}
else {
out->flag &= ~DYNTOPO_CLEANUP;
}
}
};
bool BKE_brush_hard_edge_mode_get(const Scene *scene, const Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
bool ret = (ups->flag & UNIFIED_PAINT_FLAG_HARD_EDGE_MODE) ? ups->hard_edge_mode :
brush->flag2 & BRUSH_HARD_EDGE_MODE;
return ret;
}
void BKE_brush_hard_edge_mode_set(Scene *scene, Brush *brush, bool val)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
if (ups->flag & UNIFIED_PAINT_FLAG_HARD_EDGE_MODE) {
ups->hard_edge_mode = val;
}
else {
if (val) {
brush->flag2 |= BRUSH_HARD_EDGE_MODE;
}
else {
brush->flag2 &= ~BRUSH_HARD_EDGE_MODE;
}
}
}
float BKE_brush_fset_slide_get(const Scene *scene, const Brush *brush)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
return BKE_brush_hard_edge_mode_get(scene, brush) ? 0.0f : brush->autosmooth_fset_slide;
}

View File

@@ -0,0 +1,683 @@
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
#include "BLI_array.h"
#include "BLI_bitmap.h"
#include "BLI_compiler_attrs.h"
#include "BLI_compiler_compat.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
#include "DNA_color_types.h"
#include "DNA_curveprofile_types.h"
#include "DNA_node_types.h"
#include "DNA_sculpt_brush_types.h"
#include "BKE_brush.h"
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_brush_engine.h"
#include "BKE_curveprofile.h"
#include "BLO_read_write.h"
#define ICON_NONE -1
/*
Brush command lists.
Command lists are built dynamically from
brush flags, pen input settings, etc.
Eventually they will be generated by node
networks. BrushCommandPreset will be
generated from the node group inputs.
*/
/* clang-format off */
BrushChannelType brush_builtin_channels[] = {
{
.name = "Radius",
.idname = "RADIUS",
.min = 0.001f,
.type = BRUSH_CHANNEL_FLOAT,
.max = 2048.0f,
.soft_min = 0.1f,
.soft_max = 1024.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Strength",
.idname = "STRENGTH",
.min = -1.0f,
.type = BRUSH_CHANNEL_FLOAT,
.max = 4.0f,
.soft_min = 0.0f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = true},
}
},
{
.name = "Spacing",
.idname = "SPACING",
.min = 0.001f,
.type = BRUSH_CHANNEL_FLOAT,
.max = 4.0f,
.soft_min = 0.005f,
.soft_max = 2.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = true},
}
},
{
.name = "Autosmooth",
.idname = "AUTOSMOOTH",
.type = BRUSH_CHANNEL_FLOAT,
.min = -1.0f,
.max = 4.0f,
.soft_min = 0.0f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false, .inv = true},
}
},
{
.name = "Topology Rake",
.idname = "TOPOLOGY_RAKE",
.type = BRUSH_CHANNEL_FLOAT,
.min = -1.0f,
.max = 4.0f,
.soft_min = 0.0f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Autosmooth Radius Scale",
.idname = "AUTOSMOOTH_RADIUS_SCALE",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 25.0f,
.soft_min = 0.1f,
.soft_max = 4.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Rake Radius Scale",
.idname = "TOPOLOGY_RAKE_RADIUS_SCALE",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 25.0f,
.soft_min = 0.1f,
.soft_max = 4.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Face Set Slide",
.idname = "FSET_SLIDE",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 1.0f,
.soft_min = 0.1f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Boundary Smooth",
.idname = "BOUNDARY_SMOOTH",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 1.0f,
.soft_min = 0.1f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Projection",
.idname = "PROJECTION",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.0001f,
.max = 1.0f,
.soft_min = 0.1f,
.soft_max = 1.0f,
.mappings = {
.pressure = {.curve = CURVE_PRESET_SMOOTH, .min = 0.0f, .max = 1.0f, .enabled = false},
}
},
{
.name = "Topology Rake Mode",
.idname = "TOPOLOGY_RAKE_MODE",
.type = BRUSH_CHANNEL_ENUM,
.enumdef = {.items = {
{0, "BRUSH_DIRECTION", ICON_NONE, "Stroke", "Stroke Direction"},
{1, "CURVATURE", ICON_NONE, "Curvature", "Follow mesh curvature"},
{-1, 0}
}}
},
{
.name = "Automasking",
.idname = "AUTOMASKING",
.flag = BRUSH_CHANNEL_INHERIT_IF_UNSET | BRUSH_CHANNEL_INHERIT,
.type = BRUSH_CHANNEL_BITMASK,
.enumdef = {.items = {
{BRUSH_AUTOMASKING_BOUNDARY_EDGES, "BOUNDARY_EDGE", ICON_NONE, "Boundary Edges", ""},
{BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS, "BOUNDARY_FACE_SETS", ICON_NONE, "Boundary Face Sets", ""},
{BRUSH_AUTOMASKING_CONCAVITY, "CONCAVITY", ICON_NONE, "Concave", ""},
{BRUSH_AUTOMASKING_INVERT_CONCAVITY, "INVERT_CONCAVITY", ICON_NONE, "Invert Concave", "Invert Concave Map"},
{BRUSH_AUTOMASKING_FACE_SETS, "FACE_SETS", ICON_NONE, "Face Sets", ""},
{BRUSH_AUTOMASKING_TOPOLOGY, "TOPOLOGY", ICON_NONE, "Topology", ""}
}}
},
{
.name = "Disable Dyntopo",
.idname = "DYNTOPO_DISABLED",
.type = BRUSH_CHANNEL_INT,
.flag = BRUSH_CHANNEL_NO_MAPPINGS,
.ivalue = 0
},
{
.name = "Detail Range",
.idname = "DYNTOPO_DETAIL_RANGE",
.type = BRUSH_CHANNEL_FLOAT,
.min = 0.001,
.max = 0.99,
.ivalue = 0
},
};
/* clang-format on */
const int builtin_channel_len = ARRAY_SIZE(brush_builtin_channels);
void BKE_brush_channel_free(BrushChannel *ch)
{
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
BKE_curvemapping_free_data(&ch->mappings[i].curve);
}
}
ATTR_NO_OPT void BKE_brush_channel_copy(BrushChannel *dst, BrushChannel *src)
{
*dst = *src;
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
BKE_curvemapping_copy_data(&dst->mappings[i].curve, &src->mappings[i].curve);
}
}
ATTR_NO_OPT void BKE_brush_channel_init(BrushChannel *ch, BrushChannelType *def)
{
memset(ch, 0, sizeof(*ch));
strcpy(ch->name, def->name);
strcpy(ch->idname, def->idname);
ch->flag = def->flag;
ch->fvalue = def->fvalue;
ch->ivalue = def->ivalue;
ch->def = def;
for (int i = 0; i < BRUSH_MAPPING_MAX; i++) {
BrushMapping *map = ch->mappings + i;
CurveMapping *curve = &map->curve;
memset(curve, 0, sizeof(*curve));
float min, max;
BrushMappingDef *mdef = (&def->mappings.pressure) + i;
if (mdef->min != mdef->max) {
min = mdef->min;
max = mdef->max;
}
else {
min = 0.0f;
max = 1.0f;
}
if (mdef->inv) {
ch->mappings[i].flag |= BRUSH_MAPPING_INVERT;
}
int slope = CURVEMAP_SLOPE_POSITIVE;
for (int i = 0; i < 4; i++) {
BKE_curvemap_reset(&curve->cm[i],
&(struct rctf){.xmax = 0, .ymax = min, .xmax = 1, .ymax = max},
mdef->curve,
slope);
}
BKE_curvemapping_init(curve);
map->blendmode = mdef->blendmode;
map->factor = 1.0f;
if (mdef->enabled) {
map->flag |= BRUSH_MAPPING_ENABLED;
}
}
}
BrushChannelSet *BKE_brush_channelset_create()
{
return (BrushChannelSet *)MEM_callocN(sizeof(BrushChannelSet), "BrushChannelSet");
}
void BKE_brush_channelset_free(BrushChannelSet *chset)
{
if (chset->channels) {
for (int i = 0; i < chset->totchannel; i++) {
BKE_brush_channel_free(chset->channels + i);
}
MEM_freeN(chset->channels);
}
MEM_freeN(chset);
}
void BKE_brush_channelset_add(BrushChannelSet *chset, BrushChannel *ch)
{
chset->totchannel++;
if (!chset->channels) {
chset->channels = MEM_callocN(sizeof(BrushChannel) * chset->totchannel, "chset->channels");
}
else {
chset->channels = MEM_recallocN(chset->channels, sizeof(BrushChannel) * chset->totchannel);
}
memcpy(chset->channels + chset->totchannel - 1, ch, sizeof(BrushChannel));
}
ATTR_NO_OPT BrushChannel *BKE_brush_channelset_lookup(BrushChannelSet *chset, const char *idname)
{
for (int i = 0; i < chset->totchannel; i++) {
if (STREQ(chset->channels[i].idname, idname)) {
return chset->channels + i;
}
}
return NULL;
}
bool BKE_brush_channelset_has(BrushChannelSet *chset, const char *idname)
{
return BKE_brush_channelset_lookup(chset, idname) != NULL;
}
ATTR_NO_OPT void BKE_brush_channelset_add_builtin(BrushChannelSet *chset, const char *idname)
{
BrushChannelType *def = NULL;
for (int i = 0; i < builtin_channel_len; i++) {
BrushChannelType *def2 = brush_builtin_channels + i;
if (STREQ(def2->idname, idname)) {
def = def2;
break;
}
}
if (!def) {
printf("%s: Could not find brush %s\n", __func__, idname);
return;
}
BrushChannel ch;
BKE_brush_channel_init(&ch, def);
BKE_brush_channelset_add(chset, &ch);
}
bool BKE_brush_channelset_ensure_builtin(BrushChannelSet *chset, const char *idname)
{
if (!BKE_brush_channelset_has(chset, idname)) {
BKE_brush_channelset_add_builtin(chset, idname);
return true;
}
return false;
}
#define ADDCH(name) BKE_brush_channelset_ensure_builtin(chset, name)
#define GETCH(name) BKE_brush_channelset_lookup(chset, name)
void BKE_brush_channelset_merge(BrushChannelSet *dst,
BrushChannelSet *child,
BrushChannelSet *parent)
{
// first add missing channels
for (int step = 0; step < 2; step++) {
BrushChannelSet *chset = step ? parent : child;
for (int i = 0; i < chset->totchannel; i++) {
BrushChannel *ch = chset->channels + i;
if (BKE_brush_channelset_has(dst, ch->idname)) {
continue;
}
BrushChannel ch2;
BKE_brush_channel_copy(&ch2, ch);
BKE_brush_channelset_add(chset, &ch2);
}
}
for (int i = 0; i < child->totchannel; i++) {
BrushChannel *ch = child->channels + i;
BrushChannel *mch = BKE_brush_channelset_lookup(dst, ch->idname);
BrushChannel *pch = BKE_brush_channelset_lookup(parent, ch->name);
bool ok = ch->flag & BRUSH_CHANNEL_INHERIT;
if (ch->flag & BRUSH_CHANNEL_INHERIT) {
BKE_brush_channel_free(mch);
BKE_brush_channel_copy(mch, pch);
continue;
}
if (ch->type == BRUSH_CHANNEL_BITMASK && (ch->flag & BRUSH_CHANNEL_INHERIT_IF_UNSET)) {
mch->ivalue = ch->ivalue | pch->ivalue;
}
}
}
void BKE_brush_resolve_channels(Brush *brush, Sculpt *sd)
{
if (brush->channels_final) {
BKE_brush_channelset_free(brush->channels_final);
}
brush->channels_final = BKE_brush_channelset_create();
BKE_brush_channelset_merge(brush->channels_final, brush->channels, sd->channels);
if (!brush->commandlist) {
return;
}
BrushCommandList *cl = brush->commandlist;
for (int i = 0; i < cl->totcommand; i++) {
BrushCommand *command = cl->commands + i;
if (command->params_final) {
BKE_brush_channelset_free(command->params_final);
}
command->params_final = BKE_brush_channelset_create();
BKE_brush_channelset_merge(command->params_final, command->params, brush->channels_final);
}
}
int BKE_brush_channel_get_int(BrushChannelSet *chset, char *idname)
{
BrushChannel *ch = BKE_brush_channelset_lookup(chset, idname);
if (!ch) {
printf("%s, unknown channel %s", __func__, idname);
return 0;
}
return ch->ivalue;
}
float BKE_brush_channel_get_float(BrushChannelSet *chset, char *idname)
{
BrushChannel *ch = BKE_brush_channelset_lookup(chset, idname);
if (!ch) {
printf("%s, unknown channel %s", __func__, idname);
return 0;
}
return ch->fvalue;
}
float BKE_brush_channel_set_float(BrushChannelSet *chset, char *idname, float val)
{
BrushChannel *ch = BKE_brush_channelset_lookup(chset, idname);
if (!ch) {
printf("%s, unknown channel %s", __func__, idname);
return 0;
}
float old = ch->fvalue;
ch->fvalue = val;
return old;
}
void BKE_brush_init_toolsettings(Sculpt *sd)
{
BrushChannelSet *chset = sd->channels = BKE_brush_channelset_create();
ADDCH("RADIUS");
ADDCH("STRENGTH");
ADDCH("AUTOMASKING");
ADDCH("DYNTOPO_DISABLED");
ADDCH("DYNTOPO_DETAIL_RANGE");
}
void BKE_brush_builtin_create(Brush *brush, int tool)
{
if (brush->channels) {
BKE_brush_channelset_free(brush->channels);
}
BrushChannelSet *chset = brush->channels = BKE_brush_channelset_create();
ADDCH("RADIUS");
ADDCH("STRENGTH");
ADDCH("AUTOSMOOTH");
ADDCH("TOPOLOGY_RAKE");
ADDCH("AUTOSMOOTH_RADIUS_SCALE");
ADDCH("TOPOLOGY_RAKE_RADIUS_SCALE");
ADDCH("AUTOMASKING");
switch (tool) {
case SCULPT_TOOL_DRAW: {
BrushChannel *ch = GETCH("STRENGTH");
ch->mappings[BRUSH_MAPPING_PRESSURE].flag &= ~BRUSH_MAPPING_ENABLED;
ch->flag = BRUSH_CHANNEL_INHERIT;
break;
}
default: {
// implement me!
BKE_brush_channelset_free(chset);
brush->channels = NULL;
break;
}
}
}
BrushCommandList *BKE_brush_commandlist_create()
{
return MEM_callocN(sizeof(BrushCommandList), "BrushCommandList");
}
void BKE_brush_commandlist_free(BrushCommandList *cl)
{
for (int i = 0; i < cl->totcommand; i++) {
BrushCommand *cmd = cl->commands + i;
if (cmd->params) {
BKE_brush_channelset_free(cmd->params);
}
if (cmd->params_final) {
BKE_brush_channelset_free(cmd->params_final);
}
}
MEM_SAFE_FREE(cl->commands);
MEM_freeN(cl);
}
BrushCommand *BKE_brush_commandlist_add(BrushCommandList *cl)
{
cl->totcommand++;
if (!cl->commands) {
cl->commands = MEM_callocN(sizeof(BrushCommand) * cl->totcommand, "BrushCommand");
}
else {
cl->commands = MEM_recallocN(cl->commands, sizeof(BrushCommand) * cl->totcommand);
}
BrushCommand *cmd = cl->commands + cl->totcommand - 1;
cmd->params = BKE_brush_channelset_create();
cmd->params_final = NULL;
return cmd;
}
BrushCommand *BKE_brush_command_init(BrushCommand *command, int tool)
{
BrushChannelSet *chset = command->params;
ADDCH("SPACING");
switch (tool) {
case SCULPT_TOOL_DRAW:
ADDCH("RADIUS");
ADDCH("STRENGTH");
break;
case SCULPT_TOOL_SMOOTH:
ADDCH("RADIUS");
ADDCH("STRENGTH");
ADDCH("FSET_SLIDE");
ADDCH("BOUNDARY_SMOOTH");
ADDCH("PROJECTION");
break;
case SCULPT_TOOL_TOPOLOGY_RAKE:
ADDCH("RADIUS");
ADDCH("STRENGTH");
// ADDCH("FSET_SLIDE");
// ADDCH("BOUNDARY_SMOOTH");
ADDCH("PROJECTION");
ADDCH("TOPOLOGY_RAKE_MODE");
break;
case SCULPT_TOOL_DYNTOPO:
break;
}
return command;
}
void BKE_builtin_commandlist_create(BrushChannelSet *chset, BrushCommandList *cl, int tool)
{
BrushCommand *cmd;
cmd = BKE_brush_commandlist_add(cl);
BKE_brush_command_init(cmd, tool);
for (int i = 0; i < cmd->totparam; i++) {
// inherit from brush channels for main tool
cmd->params->channels[i].flag |= BRUSH_CHANNEL_INHERIT;
}
float radius = BKE_brush_channel_get_float(chset, "RADIUS");
float autosmooth_scale = BKE_brush_channel_get_float(chset, "AUTOSMOOTH_RADIUS_SCALE");
float autosmooth = BKE_brush_channel_get_float(chset, "AUTOSMOOTH");
if (autosmooth > 0.0f) {
cmd = BKE_brush_command_init(BKE_brush_commandlist_add(cl), SCULPT_TOOL_SMOOTH);
BKE_brush_channel_set_float(cmd->params, "STRENGTH", autosmooth);
BKE_brush_channel_set_float(cmd->params, "RADIUS", radius * autosmooth_scale);
BKE_brush_channel_set_float(
cmd->params, "PROJECTION", BKE_brush_channel_get_float(chset, "AUTOSMOOTH_PROJECTION"));
}
}
void BKE_brush_channelset_read(BlendDataReader *reader, BrushChannelSet *cset)
{
BLO_read_data_address(reader, &cset->channels);
for (int i = 0; i < cset->totchannel; i++) {
BrushChannel *ch = cset->channels + i;
for (int j = 0; j < BRUSH_MAPPING_MAX; j++) {
BKE_curvemapping_blend_read(reader, &ch->mappings[j].curve);
}
}
}
void BKE_brush_channelset_write(BlendWriter *writer, BrushChannelSet *cset)
{
BLO_write_struct(writer, BrushChannelSet, cset);
BLO_write_struct_array_by_name(writer, "BrushChannel", cset->totchannel, cset->channels);
for (int i = 0; i < cset->totchannel; i++) {
BrushChannel *ch = cset->channels + i;
for (int j = 0; j < BRUSH_MAPPING_MAX; j++) {
BKE_curvemapping_blend_write(writer, &ch->mappings[j].curve);
}
}
}
/* clang-format on */
/* idea for building built-in preset node graphs:
from brush_builder import Builder;
def build(input, output):
input.add("Strength", "float", "strength").range(0.0, 3.0)
input.add("Radius", "float", "radius").range(0.01, 1024.0)
input.add("Autosmooth", "float", "autosmooth").range(0.0, 4.0)
input.add("Topology Rake", "float", "topology rake").range(0.0, 4.0)
input.add("Smooth Radius Scale", "float", "autosmooth_radius_scale").range(0.01, 5.0)
input.add("Rake Radius Scale", "float", "toporake_radius_scale").range(0.01, 5.0)
draw = input.make.tool("DRAW")
draw.radius = input.radius
draw.strength = input.strength
smooth = input.make.tool("SMOOTH")
smooth.radius = input.radius * input.autosmooth_radius_scale
smooth.strength = input.autosmooth;
smooth.flow = draw.outflow
rake = input.make.tool("TOPORAKE")
rake.radius = input.radius * input.toporake_radius_scale
rake.strength = input.topology;
rake.flow = smooth.outflow
output.out = rake.outflow
preset = Builder(build)
*/
/*
bNodeType sculpt_tool_node = {
.idname = "SculptTool",
.ui_name = "SculptTool",
};*/
/* cland-format on */

View File

@@ -171,8 +171,16 @@ static const MeshElemMap *cdDM_getPolyMap(Object *ob, DerivedMesh *dm)
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->mvert,
me->medge,
me->mpoly,
me->mloop,
me->totvert,
me->totpoly,
me->totloop,
false);
}
return cddm->pmap;

View File

@@ -688,9 +688,12 @@ static Collection *collection_duplicate_recursive(Main *bmain,
Collection *BKE_collection_duplicate(Main *bmain,
Collection *parent,
Collection *collection,
eDupli_ID_Flags duplicate_flags,
eLibIDDuplicateFlags duplicate_options)
const uint duplicate_flags_in, // it's not const!! - joeedh
const uint duplicate_options_in) // not const!
{
uint duplicate_flags = duplicate_flags_in;
uint duplicate_options = duplicate_options_in;
const bool is_subprocess = (duplicate_options & LIB_ID_DUPLICATE_IS_SUBPROCESS) != 0;
const bool is_root_id = (duplicate_options & LIB_ID_DUPLICATE_IS_ROOT_ID) != 0;

View File

@@ -100,7 +100,7 @@ static void curve_bevel_make_extrude_and_fill(const Curve *cu,
* for #Curve.bevresol is 32. */
float *quarter_coords_x = alloca(sizeof(float) * (cu->bevresol + 1));
float *quarter_coords_y = alloca(sizeof(float) * (cu->bevresol + 1));
bevel_quarter_fill(cu, quarter_coords_x, quarter_coords_y);
bevel_quarter_fill((Curve *)cu, quarter_coords_x, quarter_coords_y);
int nr;
if (fill_type == FULL) {

View File

@@ -35,6 +35,7 @@
#include "DNA_meshdata_types.h"
#include "BLI_bitmap.h"
#include "BLI_compiler_attrs.h"
#include "BLI_endian_switch.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
@@ -73,6 +74,32 @@ BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "siz
static CLG_LogRef LOG = {"bke.customdata"};
bool CustomData_layout_is_same(const CustomData *_a, const CustomData *_b)
{
CustomData a = *_a;
CustomData b = *_b;
a.layers = b.layers = NULL;
a.pool = b.pool = NULL;
if (memcmp((void *)&a, (void *)&b, sizeof(CustomData)) != 0) {
return false;
}
for (int i = 0; i < a.totlayer; i++) {
CustomDataLayer cla = _a->layers[i];
CustomDataLayer clb = _b->layers[i];
cla.data = clb.data = NULL;
if (memcmp((void *)&cla, (void *)&clb, sizeof(CustomDataLayer)) != 0) {
return false;
}
}
return true;
}
/** 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)
@@ -1475,6 +1502,93 @@ static bool layerValidate_propfloat2(void *data, const uint totitems, const bool
return has_errors;
}
static void layerDynTopoVert_copy(const void *source, void *dest, int count)
{
const MDynTopoVert *mv = (MDynTopoVert *)dest;
memcpy(dest, source, count * sizeof(MDynTopoVert));
}
static void layerDynTopoVert_interp(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
float co[3], no[3], origmask, color[4];
MDynTopoVert *mv = (MDynTopoVert *)dest;
float totweight = 0.0f;
if (count == 0) {
memset(mv, 0, sizeof(*mv));
return;
}
zero_v3(co);
zero_v3(no);
origmask = 0.0f;
zero_v4(color);
for (int i = 0; i < count; i++) {
MDynTopoVert *mv2 = (MDynTopoVert *)sources[i];
float w;
if (i == 0) { // copy flag from first source
mv->flag = mv2->flag;
mv->stroke_id = mv2->stroke_id;
}
if (sub_weights) {
w = sub_weights[i];
}
else {
w = 1.0f;
}
madd_v3_v3fl(co, mv2->origco, w);
madd_v3_v3fl(no, mv2->origno, w);
madd_v4_v4fl(color, mv2->origcolor, w);
origmask += mv2->origmask * w;
totweight += w;
}
float mul = 1.0f / totweight;
mul_v3_fl(co, mul);
normalize_v3(no);
mul_v4_fl(color, mul);
origmask *= mul;
copy_v3_v3(mv->origco, co);
copy_v3_v3(mv->origno, no);
copy_v4_v4(mv->origcolor, color);
mv->origmask = origmask;
}
static void layerCopy_noop(const void *UNUSED(source), void *UNUSED(dest), int UNUSED(count))
{
// do nothing
}
static void layerInterp_noop(const void **UNUSED(sources),
const float *UNUSED(weights),
const float *UNUSED(sub_weights),
int UNUSED(count),
void *UNUSED(dest))
{
// do nothing
}
static void layerDefault_mesh_id(void *data, int count)
{
int *val = (int *)data;
for (int i = 0; i < count; i++) {
// val[i] = -1;
val[i] = 0;
}
}
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */
{sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
@@ -1856,7 +1970,24 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
NULL,
NULL,
NULL},
};
/* 51 CD_DYNTOPO_VERT */
{sizeof(MDynTopoVert),
"MDynTopoVert",
1,
NULL, // flag singleton layer
layerDynTopoVert_copy,
NULL,
layerDynTopoVert_interp},
/*52 CD_MESH_ID */
{sizeof(unsigned int),
"MIntProperty",
1,
NULL, // flag singleton layer
layerCopy_propInt,
NULL,
layerInterp_noop,
NULL,
layerDefault_mesh_id}};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 0-4 */ "CDMVert",
@@ -1912,62 +2043,65 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDPropFloat3",
"CDPropFloat2",
"CDPropBoolean",
};
"CDDyntopoVert"};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
.vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT,
.emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT,
.vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_MESH_ID,
.emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_MESH_ID,
.fmask = 0,
.lmask = CD_MASK_MLOOP,
.pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP,
.lmask = CD_MASK_MLOOP | CD_MASK_MESH_ID,
.pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_MESH_ID,
};
const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
.vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
.emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
.vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX | CD_MASK_MESH_ID,
.emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX | CD_MASK_MESH_ID,
.fmask = 0,
.lmask = CD_MASK_MLOOP,
.pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX,
.lmask = CD_MASK_MLOOP | CD_MASK_MESH_ID,
.pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX | CD_MASK_MESH_ID,
};
const CustomData_MeshMasks CD_MASK_MESH = {
.vmask = (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
.emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_MESH_ID),
.emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_MESH_ID),
.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_PROP_ALL),
CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL |
CD_MASK_MESH_ID),
.pmask = (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
CD_MASK_SCULPT_FACE_SETS),
CD_MASK_SCULPT_FACE_SETS | CD_MASK_MESH_ID),
};
const CustomData_MeshMasks CD_MASK_EDITMESH = {
.vmask = (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
.emask = (CD_MASK_PROP_ALL),
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_MESH_ID),
.emask = (CD_MASK_PROP_ALL | CD_MASK_MESH_ID),
.fmask = 0,
.lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
.pmask = (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_MESH_ID),
.pmask = (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS | CD_MASK_MESH_ID),
};
const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
.vmask = (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
CD_MASK_PROP_COLOR),
.emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
CD_MASK_PROP_COLOR | CD_MASK_MESH_ID),
.emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_MESH_ID),
.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_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_PROP_ALL |
CD_MASK_MESH_ID), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
.pmask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
CD_MASK_SCULPT_FACE_SETS),
CD_MASK_SCULPT_FACE_SETS | CD_MASK_MESH_ID),
};
const CustomData_MeshMasks CD_MASK_BMESH = {
.vmask = (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
.emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR |
CD_MASK_DYNTOPO_VERT | CD_MASK_MESH_ID),
.emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL |
CD_MASK_MESH_ID),
.fmask = 0,
.lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_MESH_ID),
.pmask = (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
CD_MASK_SCULPT_FACE_SETS),
CD_MASK_SCULPT_FACE_SETS | CD_MASK_MESH_ID),
};
/**
* cover values copied by #mesh_loops_to_tessdata
@@ -2009,6 +2143,11 @@ static const LayerTypeInfo *layerType_getInfo(int type)
return &LAYERTYPEINFO[type];
}
int CustomData_get_elem_size(CustomDataLayer *layer)
{
return layerType_getInfo(layer->type)->size;
}
static const char *layerType_getName(int type)
{
if (type < 0 || type >= CD_NUMTYPES) {
@@ -2093,6 +2232,26 @@ static bool customdata_typemap_is_valid(const CustomData *data)
}
#endif
/* copies all customdata layers without allocating data,
* and without respect to type masks or NO_COPY/etc flags*/
void CustomData_copy_all_layout(const struct CustomData *source, struct CustomData *dest)
{
*dest = *source;
if (dest->pool) {
dest->pool = NULL;
}
if (source->layers) {
dest->layers = MEM_mallocN(sizeof(*dest->layers) * source->totlayer, __func__);
for (int i = 0; i < source->totlayer; i++) {
dest->layers[i] = source->layers[i];
dest->layers[i].data = NULL;
}
}
}
bool CustomData_merge(const struct CustomData *source,
struct CustomData *dest,
CustomDataMask mask,
@@ -2883,6 +3042,24 @@ bool CustomData_is_referenced_layer(struct CustomData *data, int type)
return (layer->flag & CD_FLAG_NOFREE) != 0;
}
void CustomData_unmark_temporary_nocopy(CustomData *data)
{
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].flag & CD_FLAG_TEMPORARY) {
data->layers[i].flag &= ~CD_FLAG_NOCOPY;
}
}
}
void CustomData_mark_temporary_nocopy(CustomData *data)
{
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].flag & CD_FLAG_TEMPORARY) {
data->layers[i].flag |= CD_FLAG_NOCOPY;
}
}
}
void CustomData_free_temporary(CustomData *data, int totelem)
{
int i, j;
@@ -3739,6 +3916,12 @@ static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n
int offset = data->layers[n].offset;
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type);
/* can't allow this to be called on CD_MESH_ID */
if (data->layers[n].type == CD_MESH_ID) {
return;
}
if (typeInfo->set_default) {
typeInfo->set_default(POINTER_OFFSET(*block, offset), 1);
}
@@ -3758,6 +3941,95 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
}
}
void CustomData_bmesh_swap_data_simple(CustomData *data, void **block1, void **block2)
{
int cd_id = data->typemap[CD_MESH_ID];
cd_id = cd_id >= 0 ? data->layers[cd_id].offset : -1;
void *tmp = *block1;
*block1 = *block2;
*block2 = tmp;
// unswap ids if they exist
if (cd_id != -1 && *block1 && *block2) {
int *id1 = (int *)(((char *)*block1) + cd_id);
int *id2 = (int *)(((char *)*block2) + cd_id);
tmp = *id1;
*id1 = *id2;
*id2 = tmp;
}
}
void CustomData_bmesh_swap_data(CustomData *source,
CustomData *dest,
void *src_block,
void **dest_block)
{
int src_i = 0;
int dest_i = 0;
int dest_i_start = 0;
if (*dest_block == NULL) {
CustomData_bmesh_alloc_block(dest, dest_block);
if (*dest_block) {
memset(*dest_block, 0, dest->totsize);
CustomData_bmesh_set_default(dest, dest_block);
}
}
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_start < dest->totlayer &&
dest->layers[dest_i_start].type < source->layers[src_i].type) {
dest_i_start++;
}
if (source->layers[src_i].type == CD_MESH_ID) {
// do not swap ids
continue;
}
/* if there are no more dest layers, we're done */
if (dest_i_start >= dest->totlayer) {
return;
}
dest_i = dest_i_start;
while (dest_i < dest->totlayer && dest->layers[dest_i].type == source->layers[src_i].type) {
/* 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)) {
void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
const uint size = typeInfo->size;
// swap data
char *bsrc = (char *)src_data;
char *bdst = (char *)dest_data;
for (int j = 0; j < size; j++) {
char t = *bsrc;
*bsrc = *bdst;
*bdst = t;
bsrc++;
bdst++;
}
break;
}
dest_i++;
}
}
}
void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
CustomData *dest,
void *src_block,
@@ -3775,50 +4047,59 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
}
}
for (int dest_i = 0; dest_i < dest->totlayer; dest_i++) {
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
dest_i++;
}
/* copies a layer at a time */
int dest_i = 0;
int dest_i_start = 0;
for (int 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) {
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
dest_i++;
while (dest_i_start < dest->totlayer &&
dest->layers[dest_i_start].type < source->layers[src_i].type) {
dest_i_start++;
}
/* if there are no more dest layers, we're done */
if (dest_i >= dest->totlayer) {
if (dest_i_start >= 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)) {
if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) {
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);
const LayerTypeInfo *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);
int dest_i = dest_i_start;
/*Previously this code was only checking one source layer against one destination.
Now it scans all the layers of that type. - joeedh
*/
while (dest_i < dest->totlayer && dest->layers[dest_i].type == source->layers[src_i].type) {
/* if we found a matching layer, copy the data */
if (STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) {
if (dest->layers[dest_i].flag & CD_FLAG_ELEM_NOCOPY) {
break;
}
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);
const LayerTypeInfo *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);
}
}
break;
}
/* 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++;
}
}
while (dest_i < dest->totlayer) {
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
dest_i++;
}
}
void CustomData_bmesh_copy_data(const CustomData *source,

View File

@@ -150,6 +150,7 @@ bool BKE_object_data_transfer_get_dttypes_capacity(const int dtdata_types,
case DT_TYPE_UV:
ret = true;
break;
case DT_TYPE_PROPCOL:
case DT_TYPE_VCOL:
*r_advanced_mixing = true;
*r_threshold = true;
@@ -230,12 +231,12 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
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;
case DT_TYPE_PROPCOL:
return CD_PROP_COLOR;
default:
BLI_assert(0);
}
@@ -253,6 +254,8 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type)
return DT_MULTILAYER_INDEX_UV;
case DT_TYPE_VCOL:
return DT_MULTILAYER_INDEX_VCOL;
case DT_TYPE_PROPCOL:
return DT_MULTILAYER_INDEX_PROPCOL;
default:
return DT_MULTILAYER_INDEX_INVALID;
}

File diff suppressed because it is too large Load Diff

View File

@@ -184,7 +184,7 @@ static void idp_repr_fn_recursive(struct ReprState *state, const IDProperty *pro
const ID *id = prop->data.pointer;
if (id != NULL) {
STR_APPEND_STR("bpy.data.");
STR_APPEND_STR(BKE_idtype_idcode_to_name_plural(GS(id->name)));
STR_APPEND_STR(BKE_idtype_idcode_to_name_plural((short)GS(id->name)));
STR_APPEND_STR("[");
STR_APPEND_STR_QUOTE(id->name + 2);
STR_APPEND_STR("]");

View File

@@ -674,7 +674,7 @@ ID *BKE_id_copy(Main *bmain, const ID *id)
* Invokes the appropriate copy method for the block and returns the result in
* newid, unless test. Returns true if the block can be copied.
*/
ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const eDupli_ID_Flags duplicate_flags)
ID *BKE_id_copy_for_duplicate(Main *bmain, ID *id, const uint duplicate_flags)
{
if (id == NULL) {
return id;

View File

@@ -1123,14 +1123,15 @@ Mesh *BKE_mesh_copy_for_eval(const Mesh *source, bool reference)
return result;
}
BMesh *BKE_mesh_to_bmesh_ex(const Mesh *me,
BMesh *BKE_mesh_to_bmesh_ex(const Object *ob,
const Mesh *me,
const struct BMeshCreateParams *create_params,
const struct BMeshFromMeshParams *convert_params)
{
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
BMesh *bm = BM_mesh_create(&allocsize, create_params);
BM_mesh_bm_from_me(bm, me, convert_params);
BM_mesh_bm_from_me((Object *)ob, bm, me, convert_params);
return bm;
}
@@ -1140,7 +1141,8 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me,
const bool add_key_index,
const struct BMeshCreateParams *params)
{
return BKE_mesh_to_bmesh_ex(me,
return BKE_mesh_to_bmesh_ex(ob,
me,
params,
&(struct BMeshFromMeshParams){
.calc_face_normal = false,
@@ -1156,8 +1158,13 @@ Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
{
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);
BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
BM_mesh_bm_to_me(NULL, NULL, bm, mesh, params);
if (me_settings) {
BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
}
return mesh;
}

View File

@@ -213,11 +213,14 @@ class MeshFairingContext : public FairingContext {
mloop_ = mesh->mloop;
BKE_mesh_vert_loop_map_create(&vlmap_,
&vlmap_mem_,
mesh->mvert,
mesh->medge,
mesh->mpoly,
mesh->mloop,
mesh->totvert,
mesh->totpoly,
mesh->totloop);
mesh->totloop,
false);
/* Deformation coords. */
co_.reserve(mesh->totvert);

View File

@@ -26,12 +26,16 @@
#include "DNA_meshdata_types.h"
#include "DNA_vec_types.h"
#include "BLI_alloca.h"
#include "BLI_bitmap.h"
#include "BLI_buffer.h"
#include "BLI_math.h"
#include "BLI_sort.h"
#include "BLI_sort_utils.h"
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BLI_memarena.h"
@@ -194,6 +198,270 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
}
}
typedef struct DiskCycleSortData {
float th;
int i, elem;
const float *co;
} DiskCycleSortData;
/**
* Calculate a normal from a vertex cloud.
*
* \note We could make a higher quality version that takes all vertices into account.
* Currently it finds 4 outer most points returning its normal.
*/
static void calc_cloud_normal(DiskCycleSortData *varr,
int varr_len,
float r_normal[3],
float r_center[3],
int *r_index_tangent)
{
const float varr_len_inv = 1.0f / (float)varr_len;
/* Get the center point and collect vector array since we loop over these a lot. */
float center[3] = {0.0f, 0.0f, 0.0f};
for (int i = 0; i < varr_len; i++) {
madd_v3_v3fl(center, varr[i].co, varr_len_inv);
}
/* Find the 'co_a' point from center. */
int co_a_index = 0;
const float *co_a = NULL;
{
float dist_sq_max = -1.0f;
for (int i = 0; i < varr_len; i++) {
const float dist_sq_test = len_squared_v3v3(varr[i].co, center);
if (!(dist_sq_test <= dist_sq_max)) {
co_a = varr[i].co;
co_a_index = i;
dist_sq_max = dist_sq_test;
}
}
}
float dir_a[3];
sub_v3_v3v3(dir_a, co_a, center);
normalize_v3(dir_a);
const float *co_b = NULL;
float dir_b[3] = {0.0f, 0.0f, 0.0f};
{
float dist_sq_max = -1.0f;
for (int i = 0; i < varr_len; i++) {
if (varr[i].co == co_a) {
continue;
}
float dir_test[3];
sub_v3_v3v3(dir_test, varr[i].co, center);
project_plane_normalized_v3_v3v3(dir_test, dir_test, dir_a);
const float dist_sq_test = len_squared_v3(dir_test);
if (!(dist_sq_test <= dist_sq_max)) {
co_b = varr[i].co;
dist_sq_max = dist_sq_test;
copy_v3_v3(dir_b, dir_test);
}
}
}
if (varr_len <= 3) {
normal_tri_v3(r_normal, center, co_a, co_b);
goto finally;
}
normalize_v3(dir_b);
const float *co_a_opposite = NULL;
const float *co_b_opposite = NULL;
{
float dot_a_min = FLT_MAX;
float dot_b_min = FLT_MAX;
for (int i = 0; i < varr_len; i++) {
const float *co_test = varr[i].co;
float dot_test;
if (co_test != co_a) {
dot_test = dot_v3v3(dir_a, co_test);
if (dot_test < dot_a_min) {
dot_a_min = dot_test;
co_a_opposite = co_test;
}
}
if (co_test != co_b) {
dot_test = dot_v3v3(dir_b, co_test);
if (dot_test < dot_b_min) {
dot_b_min = dot_test;
co_b_opposite = co_test;
}
}
}
}
normal_quad_v3(r_normal, co_a, co_b, co_a_opposite, co_b_opposite);
finally:
if (r_center != NULL) {
copy_v3_v3(r_center, center);
}
if (r_index_tangent != NULL) {
*r_index_tangent = co_a_index;
}
}
static bool build_disk_cycle_face(const MPoly *mpoly,
const MLoop *mloop,
const MEdge *medge,
const MVert *mvert,
int vertex_i,
MeshElemMap *elem,
int *doneset,
int *donelen,
DiskCycleSortData *sortdata)
{
*donelen = 0;
for (int i = 0; i < elem->count; i++) {
const MPoly *mp = mpoly + elem->indices[i];
unsigned int loops[2];
if (poly_get_adj_loops_from_vert(mp, mloop, (unsigned int)vertex_i, loops)) {
for (int j = 0; j < 2; j++) {
if (loops[j] != (unsigned int)vertex_i) {
bool ok = true;
for (int k = 0; k < *donelen; k++) {
if ((unsigned int)doneset[k] == loops[j]) {
ok = false;
}
}
if (ok) {
doneset[*donelen] = (int)loops[j];
sortdata[*donelen].elem = elem->indices[i];
sortdata[*donelen].co = mvert[loops[j]].co;
(*donelen)++;
break;
}
}
}
}
else {
printf("sort error in sort_disk_cycle_face\n");
continue;
}
}
return *donelen == elem->count;
}
static bool build_disk_cycle_loop(const MPoly *mpoly,
const MLoop *mloop,
const MEdge *medge,
const MVert *mvert,
int vertex_i,
MeshElemMap *elem,
int *doneset,
int *donelen,
DiskCycleSortData *sortdata)
{
*donelen = 0;
for (int i = 0; i < elem->count; i++) {
int l1 = elem->indices[i];
const MLoop *ml = mloop + l1;
const MEdge *me = medge + ml->e;
unsigned int v = me->v1 != (unsigned int)vertex_i ? me->v1 : me->v2;
sortdata[i].co = mvert[v].co;
sortdata[i].elem = l1;
sortdata[i].i = i;
(*donelen)++;
}
return *donelen == elem->count;
}
static bool build_disk_cycle_edge(const MPoly *mpoly,
const MLoop *mloop,
const MEdge *medge,
const MVert *mvert,
int vertex_i,
MeshElemMap *elem,
int *doneset,
int *donelen,
DiskCycleSortData *sortdata)
{
*donelen = 0;
for (int i = 0; i < elem->count; i++) {
const MEdge *me = medge + elem->indices[i];
unsigned int v = me->v1 != (unsigned int)vertex_i ? me->v1 : me->v2;
sortdata[i].co = mvert[v].co;
sortdata[i].elem = elem->indices[i];
sortdata[i].i = i;
(*donelen)++;
}
return *donelen == elem->count;
}
static bool sort_disk_cycle(const MPoly *mpoly,
const MLoop *mloop,
const MEdge *medge,
const MVert *mvert,
int vertex_i,
MeshElemMap *elem,
bool is_loops,
bool is_edges)
{
DiskCycleSortData *sortdata = BLI_array_alloca(sortdata, (unsigned int)elem->count);
int *doneset = BLI_array_alloca(doneset, (unsigned int)elem->count);
int donelen = 0;
if (is_loops) {
if (!build_disk_cycle_face(
mpoly, mloop, medge, mvert, vertex_i, elem, doneset, &donelen, sortdata)) {
return false;
}
}
else if (is_edges) {
if (!build_disk_cycle_edge(
mpoly, mloop, medge, mvert, vertex_i, elem, doneset, &donelen, sortdata)) {
return false;
}
}
else {
if (!build_disk_cycle_loop(
mpoly, mloop, medge, mvert, vertex_i, elem, doneset, &donelen, sortdata)) {
return false;
}
}
float no[3], cent[3];
int vadj;
calc_cloud_normal(sortdata, donelen, no, cent, &vadj);
for (int i = 0; i < donelen; i++) {
sortdata[i].th = angle_signed_on_axis_v3v3v3_v3(sortdata[vadj].co, cent, sortdata[i].co, no);
}
qsort((void *)sortdata, (size_t)donelen, sizeof(DiskCycleSortData), BLI_sortutil_cmp_float);
for (int i = 0; i < donelen; i++) {
elem->indices[i] = sortdata[i].elem;
}
return true;
}
/**
* Generates a map where the key is the vertex and the value is a list
* of polys or loops that use that vertex as a corner. The lists are allocated
@@ -203,12 +471,15 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
*/
static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const MVert *mvert,
const MEdge *medge,
const MPoly *mpoly,
const MLoop *mloop,
int totvert,
int totpoly,
int totloop,
const bool do_loops)
const bool do_loops,
const bool sort_disk_cycles)
{
MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
int *indices, *index_iter;
@@ -246,6 +517,12 @@ static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
}
}
if (sort_disk_cycles) {
for (i = 0; i < totvert; i++) {
sort_disk_cycle(mpoly, mloop, medge, mvert, i, map + i, do_loops, false);
}
}
*r_map = map;
*r_mem = indices;
}
@@ -257,13 +534,26 @@ static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
*/
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const MVert *mvert,
const MEdge *medge,
const MPoly *mpoly,
const MLoop *mloop,
int totvert,
int totpoly,
int totloop)
int totloop,
const bool sort_disk_cycles)
{
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,
mvert,
medge,
mpoly,
mloop,
totvert,
totpoly,
totloop,
false,
sort_disk_cycles);
}
/**
@@ -273,13 +563,17 @@ void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
*/
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const MVert *mvert,
const MEdge *medge,
const MPoly *mpoly,
const MLoop *mloop,
int totvert,
int totpoly,
int totloop)
int totloop,
const bool sort_disk_cycles)
{
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, mvert, medge, mpoly, mloop, totvert, totpoly, totloop, true, sort_disk_cycles);
}
/**
@@ -336,8 +630,13 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
* is a list of edges that use that vertex as an endpoint.
* 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)
void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map,
int **r_mem,
const MVert *mvert,
const MEdge *medge,
int totvert,
int totedge,
bool sort_disk_cycles)
{
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");
@@ -371,6 +670,12 @@ void BKE_mesh_vert_edge_map_create(
map[v[1]].count++;
}
if (sort_disk_cycles) {
for (i = 0; i < totvert; i++) {
sort_disk_cycle(NULL, NULL, medge, mvert, i, map + i, false, true);
}
}
*r_map = map;
*r_mem = indices;
}

View File

@@ -379,8 +379,16 @@ Mesh *BKE_mesh_merge_verts(Mesh *mesh,
/* Can we optimize 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);
BKE_mesh_vert_poly_map_create(&poly_map,
&poly_map_mem,
mesh->mvert,
mesh->medge,
mesh->mpoly,
mesh->mloop,
totvert,
totpoly,
totloop,
false);
} /* done preparing for fast poly compare */
mp = mesh->mpoly;

View File

@@ -41,7 +41,8 @@
#include "MOD_modifiertypes.h"
Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mmd,
Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(Object *ob,
MirrorModifierData *mmd,
const Mesh *mesh,
int axis,
const float plane_co[3],
@@ -58,7 +59,8 @@ Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mm
BMIter viter;
BMVert *v, *v_next;
bm = BKE_mesh_to_bmesh_ex(mesh,
bm = BKE_mesh_to_bmesh_ex(ob,
mesh,
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -102,7 +104,8 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
const int axis,
const float dist)
{
BMesh *bm = BKE_mesh_to_bmesh_ex(mesh,
BMesh *bm = BKE_mesh_to_bmesh_ex(NULL,
mesh,
&(struct BMeshCreateParams){
.use_toolflags = 1,
},
@@ -121,6 +124,7 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
true);
BM_mesh_bm_to_me(bmain,
NULL,
bm,
mesh,
(&(struct BMeshToMeshParams){
@@ -207,7 +211,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
Mesh *mesh_bisect = NULL;
if (do_bisect) {
mesh_bisect = BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(
mmd, mesh, axis, plane_co, plane_no);
ob, mmd, mesh, axis, plane_co, plane_no);
mesh = mesh_bisect;
}

View File

@@ -773,9 +773,11 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
BKE_mesh_vert_edge_map_create(&vert_to_edge_src_map,
&vert_to_edge_src_map_mem,
NULL,
edges_src,
num_verts_src,
num_edges_src);
num_edges_src,
false);
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
nearest.index = -1;
@@ -1431,19 +1433,25 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
if (use_from_vert) {
BKE_mesh_vert_loop_map_create(&vert_to_loop_map_src,
&vert_to_loop_map_src_buff,
verts_src,
edges_src,
polys_src,
loops_src,
num_verts_src,
num_polys_src,
num_loops_src);
num_loops_src,
false);
if (mode & MREMAP_USE_POLY) {
BKE_mesh_vert_poly_map_create(&vert_to_poly_map_src,
&vert_to_poly_map_src_buff,
verts_src,
edges_src,
polys_src,
loops_src,
num_verts_src,
num_polys_src,
num_loops_src);
num_loops_src,
false);
}
}

View File

@@ -43,6 +43,7 @@
#include "BKE_editmesh.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remesh_voxel.h" /* own include */
#include "BKE_mesh_runtime.h"
@@ -65,17 +66,28 @@ using blender::MutableSpan;
using blender::Span;
#ifdef WITH_QUADRIFLOW
static Mesh *remesh_quadriflow(const Mesh *input_mesh,
int target_faces,
int seed,
bool preserve_sharp,
bool preserve_boundary,
bool adaptive_scale,
void (*update_cb)(void *, float progress, int *cancel),
void *update_cb_data)
ATTR_NO_OPT static Mesh *remesh_quadriflow(const Mesh *input_mesh,
int target_faces,
int seed,
bool preserve_sharp,
bool preserve_boundary,
bool adaptive_scale,
void (*update_cb)(void *, float progress, int *cancel),
void *update_cb_data)
{
/* Ensure that the triangulated mesh data is up to data */
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh);
MeshElemMap *epmap = nullptr;
int *epmem = nullptr;
BKE_mesh_edge_poly_map_create(&epmap,
&epmem,
input_mesh->medge,
input_mesh->totedge,
input_mesh->mpoly,
input_mesh->totpoly,
input_mesh->mloop,
input_mesh->totloop);
/* Gather the required data for export to the internal quadriflow mesh format. */
MVertTri *verttri = (MVertTri *)MEM_callocN(
@@ -86,17 +98,63 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh,
const int totfaces = BKE_mesh_runtime_looptri_len(input_mesh);
const int totverts = input_mesh->totvert;
Array<float3> verts(totverts);
Array<int> faces(totfaces * 3);
Array<QuadriflowFace> faces(totfaces);
for (const int i : IndexRange(totverts)) {
verts[i] = input_mesh->mvert[i].co;
}
int *fsets = (int *)CustomData_get_layer(&input_mesh->pdata, CD_SCULPT_FACE_SETS);
for (const int i : IndexRange(totfaces)) {
MVertTri &vt = verttri[i];
faces[i * 3] = vt.tri[0];
faces[i * 3 + 1] = vt.tri[1];
faces[i * 3 + 2] = vt.tri[2];
faces[i].eflag[0] = faces[i].eflag[1] = faces[i].eflag[2] = 0;
faces[i].v[0] = vt.tri[0];
faces[i].v[1] = vt.tri[1];
faces[i].v[2] = vt.tri[2];
for (const int j : IndexRange(3)) {
MLoop *l = input_mesh->mloop + looptri[i].tri[j];
MEdge *e = input_mesh->medge + l->e;
if (e->flag & ME_SHARP) {
faces[i].eflag[j] |= QFLOW_CONSTRAINED;
continue;
}
MeshElemMap *melem = epmap + looptri[i].poly;
if (melem->count == 1) {
faces[i].eflag[j] |= QFLOW_CONSTRAINED;
continue;
}
int fset = 0;
int mat_nr = 0;
for (int k : IndexRange(melem->count)) {
MPoly *p = input_mesh->mpoly + melem->indices[k];
if (k > 0 && p->mat_nr != mat_nr) {
faces[i].eflag[j] |= QFLOW_CONSTRAINED;
continue;
}
mat_nr = (int)p->mat_nr;
if (fsets) {
int fset2 = fsets[melem->indices[k]];
if (k > 0 && abs(fset) != abs(fset2)) {
faces[i].eflag[j] |= QFLOW_CONSTRAINED;
break;
}
fset = fset2;
}
}
}
}
/* Fill out the required input data */
@@ -158,6 +216,14 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh,
MEM_freeN(qrd.out_faces);
MEM_freeN(qrd.out_verts);
if (epmap) {
MEM_freeN((void *)epmap);
}
if (epmem) {
MEM_freeN((void *)epmem);
}
return mesh;
}
#endif
@@ -415,7 +481,7 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)
BMeshFromMeshParams bmesh_from_mesh_params{};
bmesh_from_mesh_params.calc_face_normal = true;
BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params);
BM_mesh_bm_from_me(NULL, bm, mesh, &bmesh_from_mesh_params);
BMVert *v;
BMEdge *ed, *ed_next;
@@ -449,7 +515,7 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)
if (BM_elem_flag_test(ed, BM_ELEM_TAG)) {
float co[3];
mid_v3_v3v3(co, ed->v1->co, ed->v2->co);
BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true);
BMVert *vc = BM_edge_collapse(bm, ed, ed->v1, true, true, false);
copy_v3_v3(vc->co, co);
}
}

View File

@@ -33,22 +33,31 @@
#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
#include "BLI_edgehash.h"
#include "BLI_math.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BKE_ccg.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_scene.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subdiv_eval.h"
#include "BKE_subsurf.h"
#include "BKE_object.h"
@@ -57,6 +66,8 @@
#include "DEG_depsgraph_query.h"
#include "bmesh.h"
#include "multires_inline.h"
#include "multires_reshape.h"
#include <math.h>
@@ -846,17 +857,461 @@ static void grid_tangent_matrix(float mat[3][3], const CCGKey *key, int x, int y
typedef struct MultiresThreadedData {
DispOp op;
MultiResSpace bmop;
BMesh *bm;
int lvl;
CCGElem **gridData, **subGridData;
CCGKey *key;
CCGKey *sub_key;
Subdiv *sd;
MPoly *mpoly;
MDisps *mdisps;
GridPaintMask *grid_paint_mask;
int *gridOffset;
int cd_mdisps_off, cd_mask_off;
int gridSize, dGridSize, dSkip;
float (*smat)[3];
bool has_grid_mask;
} MultiresThreadedData;
Object *multires_dump_grids_bmesh(Object *bmob, BMesh *bm)
{
if (!CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
printf("multires_dump_grids_bmesh: error: no multires grids\n");
return NULL;
}
bool spaceset = false;
if (bm->multiresSpace != MULTIRES_SPACE_ABSOLUTE) {
BKE_multires_bmesh_space_set(bmob, bm, MULTIRES_SPACE_ABSOLUTE);
spaceset = true;
}
Main *bmain = G.main;
char *name = "multires_dump";
bContext *ctx = CTX_create();
CTX_data_main_set(ctx, bmain);
CTX_wm_manager_set(ctx, G.main->wm.first);
CTX_data_scene_set(ctx, G.main->scenes.first);
ViewLayer *view_layer = CTX_data_view_layer(ctx);
Object *ob = BKE_object_add_only_object(bmain, OB_MESH, name);
LayerCollection *layer_collection;
ob->data = BKE_object_obdata_add_from_type(bmain, OB_MESH, name);
DEG_id_tag_update_ex(
bmain, &ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
// DEG_id_tag_update_ex(
// bmain, &ob->data, 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);
DEG_id_type_tag(bmain, ID_OB);
DEG_relations_tag_update(bmain);
if (ob->data != NULL) {
DEG_id_tag_update_ex(bmain, (ID *)ob->data, ID_RECALC_EDITORS);
}
ob->modifiers.first = ob->modifiers.last = NULL;
zero_v3(ob->loc);
printf("users: %d\n", ob->id.us);
Mesh *me = ob->data;
BMIter iter;
BMFace *f;
int cd_mdisp_off = CustomData_get_offset(&bm->ldata, CD_MDISPS);
int dimen = 0;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BMLoop *l = f->l_first;
MDisps *md = BM_ELEM_CD_GET_VOID_P(l, cd_mdisp_off);
dimen = (int)floor(sqrt(md->totdisp) + 0.00001);
break;
}
if (!dimen) {
printf("multires_dump_grids_bmesh: error: corrupted multires data\n");
return NULL;
}
int totvert = bm->totloop * dimen * dimen;
int totface = bm->totloop * (dimen - 1) * (dimen - 1);
int totloop = totface * 4;
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);
me->totvert = totvert;
me->totpoly = totface;
me->totloop = totloop;
me->totedge = totvert + totface;
me->totface = 0;
me->act_face = -1;
EdgeHash *eh = BLI_edgehash_new_ex("multires_dump_bmesh", me->totedge);
MVert *mvert = me->totvert ?
MEM_callocN(sizeof(MVert) * me->totvert, "multires_dump_grids_bmesh.vert") :
NULL;
MEdge *medge = me->totedge ?
MEM_callocN(sizeof(MEdge) * me->totedge, "multires_dump_grids_bmesh.edge") :
NULL;
MLoop *mloop = me->totloop ?
MEM_callocN(sizeof(MLoop) * me->totloop, "multires_dump_grids_bmesh.loop") :
NULL;
MPoly *mpoly = me->totpoly ?
MEM_callocN(sizeof(MPoly) * me->totpoly, "multires_dump_grids_bmesh.poly") :
NULL;
me->cd_flag = 0;
CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop);
CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly);
BKE_mesh_update_customdata_pointers(me, 0);
int loopi = 0;
int outli = 0;
int medi = 0;
#define VINDEX(i, j) (loopi * dimen * dimen + ((j)*dimen + (i)))
// CustomData_daata_
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BMLoop *l = f->l_first;
do {
MDisps *md = BM_ELEM_CD_GET_VOID_P(l, cd_mdisp_off);
for (int i = 0; i < dimen; i++) {
for (int j = 0; j < dimen; j++) {
int vidx = loopi * dimen * dimen + (j * dimen + i);
int idx = j * dimen + i;
float *co = md->disps[idx];
MVert *mv = mvert + vidx;
copy_v3_v3(mv->co, co);
}
}
for (int i = 0; i < dimen - 1; i++) {
for (int j = 0; j < dimen - 1; j++) {
// do face
int fidx = loopi * (dimen - 1) * (dimen - 1) + (j * (dimen - 1) + i);
MPoly *mp = mpoly + fidx;
mp->totloop = 4;
mp->loopstart = outli;
MLoop *ml = mloop + outli;
ml[0].v = VINDEX(i, j);
ml[1].v = VINDEX(i, j + 1);
ml[2].v = VINDEX(i + 1, j + 1);
ml[3].v = VINDEX(i + 1, j);
for (int i2 = 0; i2 < 4; i2++) {
int a = ml[i2].v, b = ml[(i2 + 1) % 4].v;
int e;
if (!BLI_edgehash_haskey(eh, a, b)) {
BLI_edgehash_insert(eh, a, b, (void *)medi);
e = medi;
MEdge *med = medge + medi;
med->v1 = a;
med->v2 = b;
medi++;
}
else {
e = (int)BLI_edgehash_lookup(eh, a, b);
}
ml[i2].e = e;
}
outli += 4;
}
}
loopi++;
l = l->next;
} while (l != f->l_first);
}
for (int i = 0; i < me->totpoly; i++) {
if (!mpoly[i].totloop) {
printf("error 1! %d %d\n", i, me->totpoly);
}
if (mpoly[i].loopstart >= me->totloop) {
printf(
"error 2! %d %d l: %d totl: %d\n", i, me->totpoly, mpoly[i].loopstart, mpoly[i].totloop);
}
}
if (spaceset) {
BKE_multires_bmesh_space_set(bmob, bm, MULTIRES_SPACE_TANGENT);
}
BKE_mesh_calc_normals(me);
BKE_mesh_tessface_calc(me);
return ob;
}
//#define LIMIT_MAX_DISPLACEMENT
static void multires_bmesh_space_set_cb(void *__restrict userdata,
const int pidx,
const TaskParallelTLS *__restrict UNUSED(tls))
{
MultiresThreadedData *tdata = userdata;
int cd_mdisps_off = tdata->cd_mdisps_off;
BMesh *bm = tdata->bm;
MultiResSpace op = tdata->bmop;
BMFace *f = bm->ftable[pidx];
int gridSize = tdata->gridSize;
int S, x, y;
BMLoop *l;
#ifdef LIMIT_MAX_DISPLACEMENT
l = f->l_first;
float cent[3];
int tot = 0;
// get face center to calculate maximum allowable displacement length
zero_v3(cent);
do {
add_v3_v3(cent, l->v->co);
tot++;
l = l->next;
} while (l != f->l_first);
mul_v3_fl(cent, 1.0f / (float)tot);
#endif
l = f->l_first;
S = 0;
do {
MDisps *mdisp = BM_ELEM_CD_GET_VOID_P(l, cd_mdisps_off);
float(*dispgrid)[3] = NULL;
dispgrid = mdisp->disps;
#ifdef LIMIT_MAX_DISPLACEMENT
/*try to limit numerical instability by clamping max displacement*/
float maxlen = len_v3v3(l->v->co, cent) * 15.0f;
maxlen = MAX2(maxlen, 0.00001f);
#endif
for (y = 0; y < gridSize; y++) {
for (x = 0; x < gridSize; x++) {
float sco[8], udv[3], vdv[3];
float *data = dispgrid[gridSize * y + x];
float mat[3][3], disp[3];
float grid_u = (float)x / (float)(gridSize - 1);
float grid_v = (float)y / (float)(gridSize - 1);
float u, v;
int corner = S;
if (f->len == 4) {
BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, &u, &v);
}
else {
u = 1.0 - grid_v;
v = 1.0 - grid_u;
}
BKE_subdiv_eval_limit_point_and_derivatives(tdata->sd, l->head.index, u, v, sco, udv, vdv);
BKE_multires_construct_tangent_matrix(mat, udv, vdv, f->len == 4 ? corner : 0);
copy_v3_v3(disp, data);
switch (op) {
case MULTIRES_SPACE_ABSOLUTE:
/* Convert displacement to object space
* and add to grid points */
mul_v3_m3v3(disp, mat, data);
add_v3_v3v3(data, disp, sco);
break;
case MULTIRES_SPACE_TANGENT:
/* Calculate displacement between new and old
* grid points and convert to tangent space */
invert_m3(mat);
sub_v3_v3v3(disp, data, sco);
mul_v3_m3v3(data, mat, disp);
// try to prevent errors
float len = len_v3(data);
#ifdef LIMIT_MAX_DISPLACEMENT
if (len > maxlen) {
mul_v3_fl(data, maxlen / len);
}
else if (isnan(len)) {
zero_v3(data);
}
#else
if (isnan(len)) {
zero_v3(data);
}
#endif
break;
}
}
}
S++;
l = l->next;
} while (l != f->l_first);
}
/* The original version of this function was broken (and subsequently removed)
because it didn't properly set the subdivision level; it also used the old
multires system. The new subdiv API is now used instead.
*/
void BKE_multires_bmesh_space_set(Object *ob, BMesh *bm, int mode)
{
if (!bm->totface || !CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
return;
}
// get multires settings
MultiresModifierData *mmd = bm->haveMultiResSettings ? &bm->multires : NULL;
if (!mmd && ob) {
mmd = get_multires_modifier(NULL, ob, true);
}
if (!mmd || !CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
return;
}
// cache multires settings in bmesh
bm->multiresSpace = mode;
// create temporary mesh structure
Mesh _me, *me = &_me;
memset(me, 0, sizeof(Mesh));
CustomData_reset(&me->vdata);
CustomData_reset(&me->edata);
CustomData_reset(&me->ldata);
CustomData_reset(&me->fdata);
CustomData_reset(&me->pdata);
CustomData_MeshMasks extra = CD_MASK_DERIVEDMESH;
extra.lmask |= CD_MASK_MDISPS;
BM_mesh_bm_to_me_for_eval(bm, me, &extra);
SubdivSettings settings2;
// copy the settings and then set subdivision level to max
MultiresModifierData mmdcpy = *mmd;
mmdcpy.lvl = mmdcpy.sculptlvl = mmdcpy.renderlvl = mmdcpy.totlvl;
// set up subdivision surface
BKE_multires_subdiv_settings_init(&settings2, &mmdcpy);
Subdiv *sd = BKE_subdiv_new_from_mesh(&settings2, me);
BKE_subdiv_eval_begin_from_mesh(sd, me, NULL);
// create a fake object with .sculpt set to NULL
Object fakeob;
if (ob) {
fakeob = *ob;
fakeob.sculpt = NULL;
}
else {
memset(&fakeob, 0, sizeof(fakeob));
fakeob.data = me;
BLI_addtail(&fakeob.modifiers, &mmdcpy);
}
int i, gridSize;
int totpoly = bm->totface;
// force paranoia recalc of indices and lookup tables
bm->elem_index_dirty |= BM_FACE;
bm->elem_table_dirty |= BM_FACE;
BM_mesh_elem_index_ensure(bm, BM_FACE);
BM_mesh_elem_table_ensure(bm, BM_FACE);
gridSize = multires_side_tot[mmd->totlvl];
int cd_disp_off = CustomData_get_offset(&bm->ldata, CD_MDISPS);
BMFace *f;
BMIter iter;
i = 0;
/*check that all grids are allocated and also set some indices*/
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BMIter iter2;
BMLoop *l;
f->head.index = i;
BM_ITER_ELEM (l, &iter2, f, BM_LOOPS_OF_FACE) {
MDisps *mdisp = BM_ELEM_CD_GET_VOID_P(l, cd_disp_off);
/* allocate new disps, this can happen with newly created faces */
if (!mdisp->disps) {
multires_reallocate_mdisps(1, mdisp, mmd->totlvl);
}
l->head.index = i;
if (f->len != 4) {
i++;
}
}
if (f->len == 4) {
i++;
}
}
// do the space conversion
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.min_iter_per_thread = CCG_TASK_LIMIT;
MultiresThreadedData data = {
.bmop = mode,
.sd = sd,
.lvl = mmd->totlvl,
.bm = bm,
.cd_mdisps_off = cd_disp_off,
.gridSize = gridSize,
};
BLI_task_parallel_range(0, totpoly, &data, multires_bmesh_space_set_cb, &settings);
BKE_mesh_free_data_for_undo(me);
BKE_subdiv_free(sd);
bm->elem_index_dirty |= BM_FACE | BM_LOOP;
bm->elem_table_dirty |= BM_FACE | BM_LOOP;
}
static void multires_disp_run_cb(void *__restrict userdata,
const int pidx,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -1218,7 +1673,7 @@ void multires_stitch_grids(Object *ob)
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);
// XXX BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces);
MEM_freeN(faces);
}
}
@@ -1334,7 +1789,7 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u,
urat = u - x;
vrat = v - y;
uopp = 1 - urat;
uopp = 1.0f - urat;
mul_v3_v3fl(d[0], disps[y * st + x], uopp);
mul_v3_v3fl(d[1], disps[y * st + x2], urat);
@@ -1343,7 +1798,7 @@ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u,
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[0], 1.0f - vrat);
mul_v3_fl(d2[1], vrat);
add_v3_v3v3(out, d2[0], d2[1]);

View File

@@ -292,6 +292,12 @@ void multiresModifier_base_apply(struct Depsgraph *depsgraph,
multires_reshape_apply_base_update_mesh_coords(&reshape_context);
multires_reshape_apply_base_refit_base_mesh(&reshape_context);
/**
* Tag update so deform modifiers (e.g. smooth corrective)
* get updated original coordinates
*/
DEG_id_tag_update((ID *)object, ID_RECALC_GEOMETRY);
/* Reshape to the stored final state.
* Not that the base changed, so the subdiv is to be refined to the new positions. Unfortunately,
* this can not be done foe entirely cheap: if there were deformation modifiers prior to the

View File

@@ -87,11 +87,14 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape
int *pmap_mem;
BKE_mesh_vert_poly_map_create(&pmap,
&pmap_mem,
base_mesh->mvert,
base_mesh->medge,
base_mesh->mpoly,
base_mesh->mloop,
base_mesh->totvert,
base_mesh->totpoly,
base_mesh->totloop);
base_mesh->totloop,
false);
float(*origco)[3] = MEM_calloc_arrayN(
base_mesh->totvert, sizeof(float[3]), "multires apply base origco");

View File

@@ -48,6 +48,39 @@
#include "atomic_ops.h"
#include "subdiv_converter.h"
bool debug_invert_m3_m3(float m1[3][3], const float m2[3][3], const char *func, int line)
{
float det;
int a, b;
bool success;
/* calc adjoint */
adjoint_m3_m3(m1, m2);
/* then determinant old matrix! */
det = determinant_m3_array(m2);
if (det > -0.0001 && det < 0.0001) {
fprintf(stderr, "matrix inverse error %s:%i\n\n", func, line);
}
success = (det != 0.0f);
if (LIKELY(det != 0.0f)) {
det = 1.0f / det;
for (a = 0; a < 3; a++) {
for (b = 0; b < 3; b++) {
m1[a][b] *= det;
}
}
}
return success;
}
//#define invert_m3_m3(m1, m2) debug_invert_m3_m3(m1, m2, __func__, __LINE__)
/* -------------------------------------------------------------------- */
/** \name Local Structs
* \{ */

View File

@@ -315,6 +315,8 @@ void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_contex
void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
{
ModifierData *md;
if (reshape_context->need_free_subdiv) {
BKE_subdiv_free(reshape_context->subdiv);
}

View File

@@ -881,7 +881,8 @@ static BMesh *get_bmesh_from_mesh(Mesh *mesh)
.use_toolflags = true,
}));
BM_mesh_bm_from_me(bm,
BM_mesh_bm_from_me(NULL,
bm,
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
@@ -1151,6 +1152,7 @@ bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context)
/* Store the new base-mesh as a mesh in context, free bmesh. */
context->base_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
BM_mesh_bm_to_me(NULL,
NULL,
bm_base_mesh,
context->base_mesh,
(&(struct BMeshToMeshParams){

View File

@@ -51,6 +51,7 @@
#include "BKE_context.h"
#include "BKE_crazyspace.h"
#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
@@ -67,6 +68,7 @@
#include "BKE_pbvh.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
#include "BKE_undo_system.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -77,6 +79,15 @@
#include "bmesh.h"
// XXX todo: figure out bad cross module refs
void SCULPT_dynamic_topology_sync_layers(Object *ob, Mesh *me);
void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss);
void SCULPT_dyntopo_node_layers_add(SculptSession *ss);
BMesh *SCULPT_dyntopo_empty_bmesh();
void SCULPT_undo_ensure_bmlog(Object *ob);
static void init_mdyntopo_layer(SculptSession *ss, int totvert);
static void palette_init_data(ID *id)
{
Palette *palette = (Palette *)id;
@@ -1075,7 +1086,8 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
paint->symmetry_flags |= PAINT_SYMM_X;
/* Make sure at least dyntopo subdivision is enabled */
data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE | SCULPT_DYNTOPO_CLEANUP |
SCULPT_DYNTOPO_ENABLED;
}
else if ((GpPaint **)r_paint == &ts->gp_paint) {
GpPaint *data = MEM_callocN(sizeof(*data), __func__);
@@ -1375,20 +1387,23 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
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,
}));
Mesh *me = BKE_object_get_original_mesh(ob);
BM_mesh_bm_to_me(
NULL,
NULL,
ss->bm,
ob->data,
(&(struct BMeshToMeshParams){.calc_object_remap = false,
/*
for memfile undo steps we need to
save id and temporary layers
*/
.copy_temp_cdlayers = true,
.ignore_mesh_id_layers = false,
.cd_mask_extra = CD_MASK_MESH_ID | CD_MASK_DYNTOPO_VERT
}));
}
}
}
@@ -1466,7 +1481,19 @@ void BKE_sculptsession_free(Object *ob)
if (ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
if (ss->mdyntopo_verts) {
MEM_freeN(ss->mdyntopo_verts);
ss->mdyntopo_verts = NULL;
}
if (ss->bm_log && BM_log_free(ss->bm_log, true)) {
ss->bm_log = NULL;
}
/*try to save current mesh*/
if (ss->bm) {
SCULPT_on_sculptsession_bmesh_free(ss);
BKE_sculptsession_bm_to_me(ob, true);
BM_mesh_free(ss->bm);
}
@@ -1482,10 +1509,6 @@ void BKE_sculptsession_free(Object *ob)
MEM_SAFE_FREE(ss->vemap);
MEM_SAFE_FREE(ss->vemap_mem);
if (ss->bm_log) {
BM_log_free(ss->bm_log);
}
MEM_SAFE_FREE(ss->texcache);
if (ss->tex_pool) {
@@ -1608,6 +1631,12 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
return false;
}
char BKE_get_fset_boundary_symflag(Object *object)
{
const Mesh *mesh = BKE_mesh_from_object(object);
return mesh->flag & ME_SCULPT_MIRROR_FSET_BOUNDARIES ? mesh->symmetry : 0;
}
/**
* \param need_mask: So that the evaluated mesh that is returned has mask data.
*/
@@ -1621,7 +1650,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
Scene *scene = DEG_get_input_scene(depsgraph);
Sculpt *sd = scene->toolsettings->sculpt;
SculptSession *ss = ob->sculpt;
const Mesh *me = BKE_object_get_original_mesh(ob);
Mesh *me = BKE_object_get_original_mesh(ob);
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0;
@@ -1645,6 +1674,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
}
ss->shapekey_active = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
ss->boundary_symmetry = (int)BKE_get_fset_boundary_symflag(ob);
/* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path,
* so no extra checks is needed here. */
@@ -1659,14 +1689,16 @@ static void sculpt_update_object(Depsgraph *depsgraph,
/* These are assigned to the base mesh in Multires. This is needed because Face Sets operators
* and tools use the Face Sets data from the base mesh when Multires is active. */
ss->mvert = me->mvert;
ss->mpoly = me->mpoly;
ss->medge = me->medge;
ss->mloop = me->mloop;
ss->mpoly = me->mpoly;
}
else {
ss->totvert = me->totvert;
ss->totpoly = me->totpoly;
ss->totfaces = me->totpoly;
ss->mvert = me->mvert;
ss->medge = me->medge;
ss->mpoly = me->mpoly;
ss->mloop = me->mloop;
ss->multires.active = false;
@@ -1674,6 +1706,11 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->multires.level = 0;
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
ss->vcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
ss->vdata = &me->vdata;
ss->edata = &me->edata;
ss->ldata = &me->ldata;
ss->pdata = &me->pdata;
}
/* Sculpt Face Sets. */
@@ -1686,8 +1723,10 @@ static void sculpt_update_object(Depsgraph *depsgraph,
}
ss->subdiv_ccg = me_eval->runtime.subdiv_ccg;
ss->fast_draw = (scene->toolsettings->sculpt->flags & SCULPT_FAST_DRAW) != 0;
PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
BLI_assert(pbvh == ss->pbvh);
UNUSED_VARS_NDEBUG(pbvh);
@@ -1697,8 +1736,16 @@ static void sculpt_update_object(Depsgraph *depsgraph,
BKE_pbvh_face_sets_color_set(ss->pbvh, me->face_sets_color_seed, me->face_sets_color_default);
if (need_pmap && ob->type == OB_MESH && !ss->pmap) {
BKE_mesh_vert_poly_map_create(
&ss->pmap, &ss->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
BKE_mesh_vert_poly_map_create(&ss->pmap,
&ss->pmap_mem,
me->mvert,
me->medge,
me->mpoly,
me->mloop,
me->totvert,
me->totpoly,
me->totloop,
false);
}
pbvh_show_mask_set(ss->pbvh, ss->show_mask);
@@ -1793,6 +1840,7 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval)
BLI_assert(me_eval != NULL);
sculpt_update_object(depsgraph, ob_orig, me_eval, false, false, false);
SCULPT_dynamic_topology_sync_layers(ob_orig, me_eval);
}
void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
@@ -1809,17 +1857,19 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, orig_me->totvert);
BKE_mesh_update_customdata_pointers(orig_me, true);
DEG_id_tag_update(&orig_me->id, ID_RECALC_GEOMETRY_ALL_MODES);
SCULPT_dynamic_topology_sync_layers(object, orig_me);
}
/** \warning Expects a fully evaluated depsgraph. */
void BKE_sculpt_update_object_for_edit(
Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool need_colors)
{
BLI_assert(ob_orig == DEG_get_original_object(ob_orig));
/* Update from sculpt operators and undo, to update sculpt session
* and PBVH after edits. */
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_orig);
Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
BLI_assert(me_eval != NULL);
Mesh *me_eval = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
BLI_assert(ob_orig == DEG_get_original_object(ob_orig));
sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask, need_colors);
}
@@ -1896,11 +1946,30 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
Sculpt *sd = scene->toolsettings->sculpt;
if (!sd->detail_size) {
sd->detail_size = 12;
sd->detail_size = 8.0f;
}
if (!sd->dyntopo_radius_scale) {
sd->dyntopo_radius_scale = 1.0f;
}
// we check these flags here in case versioning code fails
if (!sd->detail_range || !sd->dyntopo_spacing) {
sd->flags |= SCULPT_DYNTOPO_CLEANUP | SCULPT_DYNTOPO_ENABLED;
}
if (!sd->detail_range) {
sd->detail_range = 0.4f;
}
if (!sd->detail_percent) {
sd->detail_percent = 25;
}
if (!sd->dyntopo_spacing) {
sd->dyntopo_spacing = 35;
}
if (sd->constant_detail == 0.0f) {
sd->constant_detail = 3.0f;
}
@@ -2094,14 +2163,21 @@ void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object)
static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
{
PBVH *pbvh = BKE_pbvh_new();
BKE_pbvh_set_symmetry(pbvh, 0, (int)BKE_get_fset_boundary_symflag(ob));
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);
ob->sculpt->cd_face_node_offset,
ob->sculpt->cd_dyn_vert,
ob->sculpt->cd_face_areas,
ob->sculpt->fast_draw);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, false);
return pbvh;
}
@@ -2118,17 +2194,21 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
BKE_sculpt_sync_face_set_visibility(me, NULL);
BKE_sculptsession_check_mdyntopo(ob->sculpt, me->totvert);
BKE_pbvh_build_mesh(pbvh,
me,
me->mpoly,
me->mloop,
me->mvert,
ob->sculpt->mdyntopo_verts,
me->totvert,
&me->vdata,
&me->ldata,
&me->pdata,
looptri,
looptris_num);
looptris_num,
ob->sculpt->fast_draw);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
@@ -2160,18 +2240,50 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
&key,
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden);
subdiv_ccg->grid_hidden,
ob->sculpt->fast_draw);
BKE_sculptsession_check_mdyntopo(ob->sculpt, BKE_pbvh_get_grid_num_vertices(pbvh));
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
return pbvh;
}
bool BKE_sculptsession_check_mdyntopo(SculptSession *ss, int totvert)
{
if (!ss->bm && (!ss->mdyntopo_verts || totvert != ss->mdyntopo_verts_size)) {
init_mdyntopo_layer(ss, totvert);
return true;
}
return false;
}
static void init_mdyntopo_layer(SculptSession *ss, int totvert)
{
if (ss->mdyntopo_verts) {
MEM_freeN(ss->mdyntopo_verts);
}
ss->mdyntopo_verts = MEM_calloc_arrayN(totvert, sizeof(*ss->mdyntopo_verts), "mdyntopo_verts");
ss->mdyntopo_verts_size = totvert;
MDynTopoVert *mv = ss->mdyntopo_verts;
for (int i = 0; i < totvert; i++, mv++) {
mv->flag = DYNVERT_NEED_BOUNDARY | DYNVERT_NEED_VALENCE | DYNVERT_NEED_DISK_SORT;
mv->stroke_id = -1;
}
}
PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
{
if (ob == NULL || ob->sculpt == NULL) {
return NULL;
}
Scene *scene = DEG_get_input_scene(depsgraph);
bool respect_hide = true;
if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
if (!(BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob))) {
@@ -2181,6 +2293,8 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
PBVH *pbvh = ob->sculpt->pbvh;
if (pbvh != NULL) {
SCULPT_update_flat_vcol_shading(ob, scene);
/* 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) {
@@ -2191,14 +2305,59 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg);
}
}
else if (BKE_pbvh_type(pbvh) == PBVH_BMESH) {
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
SCULPT_dynamic_topology_sync_layers(ob, BKE_object_get_original_mesh(ob));
}
return pbvh;
}
if (ob->sculpt->bm != NULL) {
/* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
pbvh = build_pbvh_for_dynamic_topology(ob);
ob->sculpt->pbvh = pbvh;
}
else {
#if 1 // def WHEN_GLOBAL_UNDO_WORKS
/*detect if we are loading from an undo memfile step*/
Mesh *mesh_orig = BKE_object_get_original_mesh(ob);
bool is_dyntopo = (mesh_orig->flag & ME_SCULPT_DYNAMIC_TOPOLOGY);
if (is_dyntopo) {
BMesh *bm = SCULPT_dyntopo_empty_bmesh();
ob->sculpt->bm = bm;
BM_mesh_bm_from_me(NULL,
bm,
mesh_orig,
(&(struct BMeshFromMeshParams){.calc_face_normal = true,
.use_shapekey = true,
.active_shapekey = ob->shapenr,
.ignore_id_layers = false,
.copy_temp_cdlayers = true,
.cd_mask_extra = CD_MASK_DYNTOPO_VERT}));
SCULPT_dyntopo_node_layers_add(ob->sculpt);
SCULPT_undo_ensure_bmlog(ob);
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, respect_hide);
}
else if (ob->type == OB_MESH) {
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform, respect_hide);
}
}
#else
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *mesh_eval = object_eval->data;
if (mesh_eval->runtime.subdiv_ccg != NULL) {
@@ -2206,11 +2365,20 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
}
else if (ob->type == OB_MESH) {
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
BKE_sculptsession_check_mdyntopo(ob->sculpt, me_eval_deform->totvert);
pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform, respect_hide);
}
#endif
}
ob->sculpt->pbvh = pbvh;
if (pbvh) {
SCULPT_update_flat_vcol_shading(ob, scene);
}
return pbvh;
}
@@ -2232,6 +2400,12 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
return false;
}
#if 0
if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
return !(v3d && (v3d->shading.type > OB_SOLID));
}
#endif
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
/* Regular mesh only draws from PBVH without modifiers and shape keys. */
const bool full_shading = (v3d && (v3d->shading.type > OB_SOLID));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
#include "MEM_guardedalloc.h"
#include "BLI_compiler_compat.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
#include "BKE_pbvh.h"
#include "DNA_customdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "bmesh.h"
#include "pbvh_intern.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// void pbvh_bmesh_do_cache_test(void);
int main(int argc, char **argv)
{
printf("argc: %d\n", argc);
// pbvh_bmesh_do_cache_test();
return 0;
}

View File

@@ -0,0 +1,266 @@
#if 0
# include "MEM_guardedalloc.h"
# include "BLI_alloca.h"
# include "BLI_array.h"
# include "BLI_compiler_attrs.h"
# include "BLI_compiler_compat.h"
# include "BLI_ghash.h"
# include "BLI_linklist.h"
# include "BLI_math.h"
# include "BLI_memarena.h"
# include "BLI_memblock.h"
# include "BLI_mempool.h"
# include "BLI_utildefines.h"
# include "BLI_hash.h"
# include "BKE_context.h"
# include "BKE_global.h"
# include "BKE_image.h"
# include "BKE_mesh.h"
# include "BKE_multires.h"
# include "BKE_object.h"
# include "BKE_pbvh.h"
# include "BKE_scene.h"
# include "BLI_bitmap.h"
# include "DNA_customdata_types.h"
# include "DNA_image_types.h"
# include "DNA_material_types.h"
# include "DNA_mesh_types.h"
# include "DNA_meshdata_types.h"
# include "DNA_object_types.h"
# include "DNA_scene_types.h"
# include "pbvh_intern.h"
# include "bmesh.h"
void *BKE_pbvh_get_tex_settings(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm)
{
return NULL; // implement me!
}
void *BKE_pbvh_get_tex_data(PBVH *pbvh, PBVHNode *node, TexPointRef vdm)
{
return NULL; // implement me!
}
typedef union TexelKey {
struct {
int idx; // index in image
int co_key; // used to differentiate same texel used in different 3d points in space
} key;
intptr_t i;
} TexelKey;
BLI_INLINE int calc_co_key(const float *co)
{
const int mul = 65535;
const int mask = 65535;
int x = (int)co[0] + (((int)co[0] * mul) & mask);
int y = (int)co[0] + (((int)co[0] * mul) & mask);
int z = (int)co[0] + (((int)co[0] * mul) & mask);
return BLI_hash_int_3d(x, y, z);
}
typedef struct TextureVDMSettings {
ImageUser ima_user;
ID *image;
bool tangent_space;
char uv_layer[64];
// used by texture_vdm_get_points
// BLI_bitmap *texel_used_map;
GSet *texel_used_map;
int width, height;
bool invalid;
} TextureVDMSettings;
typedef struct TextureNodeData {
TexPointRef *point_ids;
float (*point_cos)[3];
float (*point_uvs)[2];
float **point_cos_ptrs;
int totpoint;
} TextureNodeData;
void texture_vdm_begin(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm)
{
TextureVDMSettings *settings = BKE_pbvh_get_tex_settings(pbvh, node, vdm);
if (!settings->image) {
return;
}
Image *image = (Image *)settings->image;
int w = 0, h = 0;
BKE_image_get_size(image, &settings->ima_user, &w, &h);
// Image *image = settings->image.
settings->width = w;
settings->height = h;
// settings->texel_used_map = BLI_BITMAP_NEW(w * h, "texel_used_map");
settings->texel_used_map = BLI_gset_ptr_new("texel_used_map");
}
void texture_vdm_build_points(PBVH *pbvh, PBVHNode *node, TexLayerRef vdm)
{
TextureVDMSettings *settings = BKE_pbvh_get_tex_settings(pbvh, node, vdm);
TextureNodeData *data = BKE_pbvh_get_tex_data(pbvh, node, vdm);
int idx;
if (!settings->uv_layer[0]) {
idx = CustomData_get_layer_index(&pbvh->bm->ldata, CD_MLOOPUV);
}
else {
idx = CustomData_get_named_layer_index(&pbvh->bm->ldata, CD_MLOOPUV, settings->uv_layer);
}
if (idx < 0) {
settings->invalid = true;
return;
}
const int cd_uv = pbvh->bm->ldata.layers[idx].offset;
const int w = settings->width, h = settings->height;
float **point_cos_ptrs = NULL;
float *uvs = NULL;
float *cos = NULL;
TexPointRef *ids = NULL;
BLI_array_declare(point_cos_ptrs);
BLI_array_declare(uvs);
BLI_array_declare(cos);
BLI_array_declare(ids);
for (int i = 0; i < node->tribuf->tottri; i++) {
PBVHTri *tri = node->tribuf->tris + i;
BMLoop *ls[3] = {(BMLoop *)tri->l[0], (BMLoop *)tri->l[1], (BMLoop *)tri->l[2]};
float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {FLT_MIN, FLT_MIN};
float tricos[3][3];
copy_v3_v3(tricos[0], ls[0]->v->co);
copy_v3_v3(tricos[1], ls[1]->v->co);
copy_v3_v3(tricos[2], ls[2]->v->co);
for (int j = 0; j < 3; j++) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(ls[j], cd_uv);
minmax_v2v2_v2(min, max, luv->uv);
}
int dw = (int)((max[0] - min[0]) * (float)w + 0.000001f);
int dh = (int)((max[1] - min[1]) * (float)h + 0.000001f);
dw = MAX2(dw, 1);
dh = MAX2(dh, 1);
float du = (max[0] - min[0]) / dw;
float dv = (max[1] - min[1]) / dh;
float u = min[0], v = min[1];
for (int y = 0; y < dh; y++, v += dv) {
u = min[0];
for (int x = 0; x < dw; x++, u += du) {
int idx = y * w + x;
float co[3];
interp_barycentric_tri_v3(tricos, u, v, co);
TexelKey key;
key.key.idx = idx;
key.key.co_key = calc_co_key(co);
if (BLI_gset_haskey(settings->texel_used_map, (void *)key.i)) {
continue;
}
BLI_gset_insert(settings->texel_used_map, (void *)key.i);
BLI_array_append(uvs, u);
BLI_array_append(uvs, v);
BLI_array_append(cos, co[0]);
BLI_array_append(cos, co[1]);
BLI_array_append(cos, co[2]);
BLI_array_append(ids, (TexPointRef)key.i);
}
}
}
settings->invalid = false;
MEM_SAFE_FREE(data->point_cos);
MEM_SAFE_FREE(data->point_ids);
MEM_SAFE_FREE(data->point_uvs);
MEM_SAFE_FREE(data->point_cos_ptrs);
int totpoint = BLI_array_len(ids);
data->totpoint = totpoint;
data->point_cos_ptrs = MEM_malloc_arrayN(totpoint, sizeof(void *), "point_cos_ptrs");
// dumb casting trick
union {
float *cos;
float (*cos3)[3];
} castcos;
union {
float *uvs;
float (*uvs2)[2];
} castuvs;
castcos.cos = cos;
castuvs.uvs = uvs;
data->point_cos = castcos.cos3;
data->point_ids = ids;
data->point_uvs = castuvs.uvs2;
for (int i = 0; i < totpoint; i++) {
data->point_cos_ptrs[i] = cos + i * 3;
}
}
void texture_vdm_get_points(PBVH *pbvh,
PBVHNode *node,
TexLayerRef vdm,
TexPointRef **r_ids,
float ***r_cos,
float ***r_nos,
int *r_totpoint)
{
TextureVDMSettings *settings = BKE_pbvh_get_tex_settings(pbvh, node, vdm);
TextureNodeData *data = BKE_pbvh_get_tex_data(pbvh, node, vdm);
if (r_totpoint) {
*r_totpoint = data->totpoint;
}
if (r_cos) {
*r_cos = data->point_cos_ptrs;
}
if (r_ids) {
*r_ids = data->point_ids;
}
}
static SculptDisplacementDef texture_vdm = {
.type = SCULPT_TEXTURE_UV,
.settings_size = sizeof(TextureNodeData),
.getPointsFromNode = texture_vdm_get_points,
};
#endif

View File

@@ -16,9 +16,17 @@
#pragma once
#include "BLI_compiler_compat.h"
#include "BLI_ghash.h"
#include "DNA_customdata_types.h"
#include "DNA_material_types.h"
#include "bmesh.h"
/** \file
* \ingroup bli
*/
struct MDynTopoVert;
/* Axis-aligned bounding box */
typedef struct {
@@ -35,6 +43,10 @@ typedef struct {
struct PBVHNode {
/* Opaque handle for drawing code */
struct GPU_PBVH_Buffers *draw_buffers;
struct GPU_PBVH_Buffers **mat_draw_buffers; // currently only used by pbvh_bmesh
int tot_mat_draw_buffers;
int id;
/* Voxel bounds */
BB vb;
@@ -43,6 +55,7 @@ struct PBVHNode {
/* For internal nodes, the offset of the children in the PBVH
* 'nodes' array. */
int children_offset;
int subtree_tottri;
/* Pointer into the PBVH prim_indices array and the number of
* primitives used by this leaf node.
@@ -86,7 +99,7 @@ struct PBVHNode {
/* Indicates whether this node is a leaf or not; also used for
* marking various updates that need to be applied. */
PBVHNodeFlags flag : 16;
PBVHNodeFlags flag : 32;
/* Used for raycasting: how close bb is to the ray point. */
float tmin;
@@ -98,27 +111,39 @@ struct PBVHNode {
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;
TableGSet *bm_faces;
TableGSet *bm_unique_verts;
TableGSet *bm_other_verts;
PBVHTriBuf *tribuf; // all triangles
PBVHTriBuf *tri_buffers; // tribuffers, one per material used
int tot_tri_buffers;
int updategen;
/* Used to store the brush color during a stroke and composite it over the original color */
PBVHColorBufferNode color_buffer;
#ifdef PROXY_ADVANCED
ProxyVertArray proxyverts;
#endif
};
typedef enum {
PBVH_DYNTOPO_SMOOTH_SHADING = 1,
PBVH_FAST_DRAW = 2 // hides facesets/masks and forces smooth to save GPU bandwidth
} PBVHFlags;
typedef struct PBVHBMeshLog PBVHBMeshLog;
struct DMFlagMat;
struct PBVH {
PBVHType type;
PBVHFlags flags;
int idgen;
bool dyntopo_stop;
PBVHNode *nodes;
int node_mem_count, totnode;
@@ -127,6 +152,7 @@ struct PBVH {
int totvert;
int leaf_limit;
int depth_limit;
/* Mesh data */
const struct Mesh *mesh;
@@ -146,7 +172,7 @@ struct PBVH {
CCGKey gridkey;
CCGElem **grids;
void **gridfaces;
const DMFlagMat *grid_flag_mats;
const struct DMFlagMat *grid_flag_mats;
int totgrid;
BLI_bitmap **grid_hidden;
@@ -168,14 +194,31 @@ struct PBVH {
BMesh *bm;
float bm_max_edge_len;
float bm_min_edge_len;
float bm_detail_range;
int cd_dyn_vert;
int cd_vert_node_offset;
int cd_face_node_offset;
int cd_vert_mask_offset;
int cd_vcol_offset;
int cd_faceset_offset;
int cd_face_area;
float planes[6][4];
int num_planes;
int symmetry;
int boundary_symmetry;
struct BMLog *bm_log;
struct SubdivCCG *subdiv_ccg;
bool flat_vcol_shading;
bool need_full_render; // used by pbvh drawing for PBVH_BMESH
int balance_counter;
int stroke_id; // used to keep origdata up to date in PBVH_BMESH
struct MDynTopoVert *mdyntopo_verts;
};
/* pbvh.c */
@@ -184,6 +227,9 @@ void BB_expand(BB *bb, const float co[3]);
void BB_expand_with_bb(BB *bb, BB *bb2);
void BBC_update_centroid(BBC *bbc);
int BB_widest_axis(const BB *bb);
void BB_intersect(BB *r_out, BB *a, BB *b);
float BB_volume(const BB *bb);
void pbvh_grow_nodes(PBVH *bvh, int totnode);
bool ray_face_intersection_quad(const float ray_start[3],
struct IsectRayPrecalc *isect_precalc,
@@ -218,19 +264,85 @@ bool ray_face_nearest_tri(const float ray_start[3],
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
/* pbvh_bmesh.c */
bool pbvh_bmesh_node_raycast(PBVHNode *node,
bool pbvh_bmesh_node_raycast(PBVH *pbvh,
PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *dist,
bool use_original,
int *r_active_vertex_index,
float *r_face_normal);
bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
struct SculptVertRef *r_active_vertex_index,
struct SculptFaceRef *r_active_face_index,
float *r_face_normal,
int stroke_id);
bool pbvh_bmesh_node_nearest_to_ray(PBVH *pbvh,
PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
float *depth,
float *dist_sq,
bool use_original);
bool use_original,
int stroke_id);
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode);
void pbvh_free_all_draw_buffers(PBVHNode *node);
void pbvh_update_free_all_draw_buffers(PBVH *pbvh, PBVHNode *node);
BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *pbvh, const BMVert *key)
{
const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, pbvh->cd_vert_node_offset);
BLI_assert(node_index != DYNTOPO_NODE_NONE);
BLI_assert(node_index < pbvh->totnode);
return node_index;
}
BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *pbvh, const BMFace *key)
{
const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, pbvh->cd_face_node_offset);
BLI_assert(node_index != DYNTOPO_NODE_NONE);
BLI_assert(node_index < pbvh->totnode);
return node_index;
}
BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *pbvh, const BMVert *key)
{
int ni = pbvh_bmesh_node_index_from_vert(pbvh, key);
return ni >= 0 ? pbvh->nodes + ni : NULL;
// return &pbvh->nodes[pbvh_bmesh_node_index_from_vert(pbvh, key)];
}
BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *pbvh, const BMFace *key)
{
int ni = pbvh_bmesh_node_index_from_face(pbvh, key);
return ni >= 0 ? pbvh->nodes + ni : NULL;
// return &pbvh->nodes[pbvh_bmesh_node_index_from_face(pbvh, key)];
}
bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index);
void pbvh_bmesh_check_nodes(PBVH *pbvh);
void bke_pbvh_insert_face_finalize(PBVH *pbvh, BMFace *f, const int ni);
void bke_pbvh_insert_face(PBVH *pbvh, struct BMFace *f);
void bke_pbvh_update_vert_boundary(int cd_dyn_vert,
int cd_faceset_offset,
BMVert *v,
int bound_symmetry);
BLI_INLINE bool pbvh_check_vert_boundary(PBVH *pbvh, struct BMVert *v)
{
MDynTopoVert *mv = (MDynTopoVert *)BM_ELEM_CD_GET_VOID_P(v, pbvh->cd_dyn_vert);
if (mv->flag & DYNVERT_NEED_BOUNDARY) {
bke_pbvh_update_vert_boundary(
pbvh->cd_dyn_vert, pbvh->cd_faceset_offset, v, pbvh->boundary_symmetry);
return true;
}
return false;
}
void pbvh_bmesh_check_other_verts(PBVHNode *node);
//#define DEFRAGMENT_MEMORY

View File

@@ -69,6 +69,7 @@
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_brush_engine.h"
#include "BKE_cachefile.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
@@ -849,6 +850,11 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres
}
if (tos->sculpt) {
BLO_write_struct(writer, Sculpt, tos->sculpt);
if (tos->sculpt->channels) {
BKE_brush_channelset_write(writer, tos->sculpt->channels);
}
BKE_paint_blend_write(writer, &tos->sculpt->paint);
}
if (tos->uvsculpt) {
@@ -1050,6 +1056,11 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
sce->toolsettings->particle.object = NULL;
sce->toolsettings->gp_sculpt.paintcursor = NULL;
if (sce->toolsettings->sculpt && sce->toolsettings->sculpt->channels) {
BLO_read_data_address(reader, &sce->toolsettings->sculpt->channels);
BKE_brush_channelset_read(reader, sce->toolsettings->sculpt->channels);
}
/* relink grease pencil interpolation curves */
BLO_read_data_address(reader, &sce->toolsettings->gp_interpolate.custom_ipo);
if (sce->toolsettings->gp_interpolate.custom_ipo) {
@@ -2393,6 +2404,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, const ViewLayer *view_
if (check_rendered_viewport_visible(bmain)) {
BMesh *bm = mesh->edit_mesh->bm;
BM_mesh_bm_to_me(bmain,
NULL,
bm,
mesh,
(&(struct BMeshToMeshParams){

View File

@@ -360,6 +360,7 @@ static void eval_displacement(SubdivDisplacement *displacement,
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);
}

View File

@@ -1866,11 +1866,14 @@ static const MeshElemMap *ccgDM_getPolyMap(Object *ob, DerivedMesh *dm)
BKE_mesh_vert_poly_map_create(&ccgdm->pmap,
&ccgdm->pmap_mem,
me->mvert,
me->medge,
me->mpoly,
me->mloop,
me->totvert,
me->totpoly,
me->totloop);
me->totloop,
false);
}
return ccgdm->pmap;

View File

@@ -21,7 +21,7 @@
# define __has_feature(x) 0
#endif
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)) && !defined(_MSC_VER)
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
# include "sanitizer/asan_interface.h"
#else
/* Ensure return value is used. Just using UNUSED_VARS results in a warning. */
@@ -40,3 +40,59 @@
* Mark a region of memory as usable again.
*/
#define BLI_asan_unpoison(addr, size) ASAN_UNPOISON_MEMORY_REGION(addr, size)
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
# include "MEM_guardedalloc.h"
static void *BLI_asan_safe_malloc(size_t size, const char *tag)
{
// align size at 16 bytes
size += 15 - (size & 15);
// add safe padding
size += 32;
void *ret = MEM_mallocN(size, tag);
int *iptr = (int *)ret;
*iptr = (int)size;
char *ptr = (char *)ret;
ptr[4] = 't';
ptr[5] = 'a';
ptr[6] = 'g';
ptr[7] = '1';
BLI_asan_poison(ptr, 16);
BLI_asan_poison(ptr + size - 16, 16);
ret = (void *)(ptr + 16);
return ret;
}
static void BLI_asan_safe_free(void *mem)
{
if (!mem) {
return;
}
mem = (void *)(((char *)mem) - 16);
BLI_asan_unpoison(mem, 16);
int *iptr = (int *)mem;
volatile char *ptr = (char *)mem;
if (ptr[4] != 't' || ptr[5] != 'a' || ptr[6] != 'g' || ptr[7] != '1') {
BLI_asan_poison(mem, 16);
*ptr = 1; // deliberately trigger asan fault
}
BLI_asan_unpoison(ptr + iptr[0] - 16, 16);
MEM_freeN((void *)ptr);
}
#else
# define BLI_asan_safe_malloc(size, tag) MEM_mallocN(size, tag)
# define BLI_asan_safe_free(mem) MEM_SAFE_FREE(mem)
#endif

View File

@@ -33,6 +33,12 @@
/* hint to mark function arguments expected to be non-null
* if no arguments are given to the macro, all of pointer
* arguments would be expected to be non-null
*
* ONE-INDEXED!
*
* Example:
*
* void func(void *a, void *b, void *b) ATTR_NONNULL(1, 2, 3)
*/
#ifdef __GNUC__
# define ATTR_NONNULL(args...) __attribute__((nonnull(args)))
@@ -99,6 +105,17 @@
# define ATTR_ALIGN(x) __attribute__((aligned(x)))
#endif
/* Disable optimization for a function (for debugging use only!)*/
#ifdef __clang__
# define ATTR_NO_OPT __attribute__((optnone))
#elif defined(__MSC_VER)
# define ATTR_NO_OPT __pragma(optimize("", off))
#elif defined(__GNUC__)
# define ATTR_NO_OPT __attribute__((optimize("O0")))
#else
# define ATTR_NO_OPT
#endif
/* Alignment directive */
#ifdef _WIN64
# define ALIGN_STRUCT __declspec(align(64))

View File

@@ -188,6 +188,53 @@ BLI_INLINE bool BLI_ghashIterator_done(const GHashIterator *ghi)
typedef struct GSet GSet;
struct SmallHash;
#include "BLI_smallhash.h"
typedef struct TableGSet {
struct SmallHash ptr_to_idx;
void **elems;
int size, length;
int cur;
} TableGSet;
TableGSet *BLI_table_gset_new(const char *info);
TableGSet *BLI_table_gset_new_ex(const char *info, int size);
void BLI_table_gset_free(TableGSet *ts, GHashKeyFreeFP freefp);
void BLI_table_gset_insert(TableGSet *ts, void *elem);
bool BLI_table_gset_add(TableGSet *ts, void *elem);
void BLI_table_gset_remove(TableGSet *ts, void *elem, GHashKeyFreeFP freefp);
bool BLI_table_gset_haskey(TableGSet *ts, void *elem);
int BLI_table_gset_len(TableGSet *ts);
#define TGSET_ITER(v, ts) \
{ \
int _i1; \
for (_i1 = 0; _i1 < (ts)->cur; _i1++) { \
if (!(ts)->elems[_i1]) \
continue; \
v = (ts)->elems[_i1];
#define TGSET_ITER_END \
} \
}
#define TGSET_ITER_INDEX(v, ts, index) \
{ \
int _i1; \
index = -1; \
for (_i1 = 0; _i1 < (ts)->cur; _i1++) { \
if (!(ts)->elems[_i1]) \
continue; \
v = (ts)->elems[_i1]; \
index++;
#define TGSET_ITER_INDEX_END \
} \
}
typedef GHashHashFP GSetHashFP;
typedef GHashCmpFP GSetCmpFP;
typedef GHashKeyFreeFP GSetKeyFreeFP;

View File

@@ -52,7 +52,7 @@
#define BLI_LINKSTACK_SIZE(var) BLI_mempool_len(var##_pool_)
/* check for typeof() */
#ifdef __GNUC__
#if defined(__GNUC__) || defined(__clang__)
# define BLI_LINKSTACK_PUSH(var, ptr) \
(CHECK_TYPE_INLINE(ptr, typeof(var##_type_)), \
BLI_linklist_prepend_pool(&(var), ptr, var##_pool_))

View File

@@ -87,11 +87,35 @@ enum {
* order of allocation when no chunks have been freed.
*/
BLI_MEMPOOL_ALLOW_ITER = (1 << 0),
/* allow random access, implies BLI_MEMPOOL_ALLOW_ITER since we
need the freewords to detect free state of elements*/
BLI_MEMPOOL_RANDOM_ACCESS = (1 << 1) | (1 << 0)
};
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL();
void *BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/*
This preallocates a mempool suitable for threading. totelem elements are preallocated
in chunks of size pchunk, and returned in r_chunks.
*/
BLI_mempool *BLI_mempool_create_for_tasks(const unsigned int esize,
int totelem,
const int pchunk,
void ***r_chunks,
int *r_totchunk,
int *r_esize,
int flag);
// memory coherence stuff
int BLI_mempool_find_elems_fuzzy(
BLI_mempool *pool, int idx, int range, void **r_elems, int r_elems_size);
int BLI_mempool_get_size(BLI_mempool *pool);
int BLI_mempool_find_real_index(BLI_mempool *pool, void *ptr);
#ifdef __cplusplus
}
#endif

View File

@@ -39,11 +39,13 @@ typedef struct {
#define SMSTACKSIZE 131
typedef struct SmallHash {
unsigned int nbuckets;
unsigned int nentries;
unsigned int nentries, nfreecells;
unsigned int cursize;
SmallHashEntry *buckets;
SmallHashEntry buckets_stack[SMSTACKSIZE];
bool using_stack;
} SmallHash;
typedef struct {
@@ -57,22 +59,25 @@ void BLI_smallhash_release(SmallHash *sh) ATTR_NONNULL(1);
void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
void *BLI_smallhash_lookup(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
void **BLI_smallhash_lookup_p(SmallHash *sh, uintptr_t key)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
void **BLI_smallhash_lookup_p(const SmallHash *sh, uintptr_t key)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
bool BLI_smallhash_haskey(const SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
int BLI_smallhash_len(const SmallHash *sh) ATTR_NONNULL(1);
bool BLI_smallhash_haskey(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
int BLI_smallhash_len(SmallHash *sh) ATTR_NONNULL(1);
void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
void **BLI_smallhash_iternext_p(SmallHashIter *iter, uintptr_t *key)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
void *BLI_smallhash_iternew(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
void *BLI_smallhash_iternew(SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
void **BLI_smallhash_iternew_p(SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/* void BLI_smallhash_print(SmallHash *sh); */ /* UNUSED */
void BLI_smallhash_clear(SmallHash *sh, uintptr_t key);
bool BLI_smallhash_ensure_p(SmallHash *sh, uintptr_t key, void ***item);
bool BLI_smallhash_remove_p(SmallHash *sh, uintptr_t key, void **val);
#ifdef DEBUG
double BLI_smallhash_calc_quality(SmallHash *sh);
#endif

View File

@@ -45,10 +45,22 @@
#endif
#ifdef _MSC_VER
# pragma warning(error : 4018) /* signed/unsigned mismatch */
# pragma warning(error : 4244) /* conversion from 'type1' to 'type2', possible loss of data */
# pragma warning(error : 4245) /* conversion from 'int' to 'unsigned int' */
# pragma warning(error : 4267) /* conversion from 'size_t' to 'type', possible loss of data */
# pragma warning(error : 4305) /* truncation from 'type1' to 'type2' */
# pragma warning(error : 4389) /* signed/unsigned mismatch */
/* While regular clang defines __GNUC__ and is handled by the code above, clang-cl does not and
* needs to be handled separately. */
# ifdef __clang__
# pragma clang diagnostic error "-Wsign-conversion"
# pragma clang diagnostic error "-Wsign-compare"
# pragma clang diagnostic error "-Wimplicit-float-conversion"
# pragma clang diagnostic error "-Wimplicit-int-conversion"
# pragma clang diagnostic error "-Wimplicit-int"
# pragma clang diagnostic error "-Wshadow"
/* Normal MSVC */
# else
# pragma warning(error : 4018) /* signed/unsigned mismatch */
# pragma warning(error : 4244) /* conversion from 'type1' to 'type2', possible loss of data */
# pragma warning(error : 4245) /* conversion from 'int' to 'unsigned int' */
# pragma warning(error : 4267) /* conversion from 'size_t' to 'type', possible loss of data */
# pragma warning(error : 4305) /* truncation from 'type1' to 'type2' */
# pragma warning(error : 4389) /* signed/unsigned mismatch */
# endif
#endif

View File

@@ -153,6 +153,7 @@ set(SRC
intern/voxel.c
intern/winstuff.c
intern/winstuff_dir.c
intern/BLI_table_gset.c
# Private headers.
intern/BLI_mempool_private.h

View File

@@ -36,6 +36,7 @@
#include "BLI_utildefines.h"
#include "BLI_asan.h"
#include "BLI_mempool.h" /* own include */
#include "BLI_mempool_private.h" /* own include */
@@ -47,6 +48,12 @@
# include "valgrind/memcheck.h"
#endif
#if (defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
# define POISON_REDZONE_SIZE 32
#else
# define POISON_REDZONE_SIZE 0
#endif
/* NOTE: copied from BLO_blend_defs.h, don't use here because we're in BLI. */
#ifdef __BIG_ENDIAN__
/* Big Endian */
@@ -117,6 +124,12 @@ struct BLI_mempool {
* this is needed for iteration so we can loop over chunks in the order added. */
BLI_mempool_chunk *chunk_tail;
/* only used if BLI_MEMPOOL_RANDOM_ACCESS is true*/
BLI_mempool_chunk **chunktable;
/* only used if BLI_MEMPOOL_RANDOM_ACCESS is true*/
int totchunk;
/** Element size in bytes. */
uint esize;
/** Chunk size in bytes. */
@@ -161,6 +174,33 @@ static uint power_of_2_max_u(uint x)
}
#endif
static void mempool_update_chunktable(BLI_mempool *pool)
{
if (!(pool->flag & BLI_MEMPOOL_RANDOM_ACCESS)) {
return;
}
pool->totchunk = 0;
BLI_mempool_chunk *chunk = pool->chunks;
while (chunk) {
pool->totchunk++;
chunk = chunk->next;
}
MEM_SAFE_FREE(pool->chunktable);
pool->chunktable = (BLI_mempool_chunk **)MEM_mallocN(
sizeof(pool->chunktable) * (size_t)pool->totchunk, "mempool chunktable");
int i = 0;
chunk = pool->chunks;
while (chunk) {
pool->chunktable[i++] = chunk;
chunk = chunk->next;
}
}
BLI_INLINE BLI_mempool_chunk *mempool_chunk_find(BLI_mempool_chunk *head, uint index)
{
while (index-- && head) {
@@ -202,6 +242,26 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
BLI_freenode *curnode = CHUNK_DATA(mpchunk);
uint j;
if (pool->flag & BLI_MEMPOOL_RANDOM_ACCESS) {
if (!pool->chunktable ||
MEM_allocN_len(pool->chunktable) / sizeof(void *) <= (size_t)pool->totchunk) {
void *old = pool->chunktable;
int size = (int)pool->totchunk + 2;
size += size >> 1;
pool->chunktable = MEM_mallocN(sizeof(void *) * (size_t)size, "mempool chunktable");
if (old) {
memcpy(pool->chunktable, old, sizeof(void *) * (size_t)pool->totchunk);
}
MEM_SAFE_FREE(old);
}
pool->chunktable[pool->totchunk++] = mpchunk;
}
/* append */
if (pool->chunk_tail) {
pool->chunk_tail->next = mpchunk;
@@ -222,22 +282,42 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
j = pool->pchunk;
if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) {
while (j--) {
curnode->next = NODE_STEP_NEXT(curnode);
BLI_freenode *next;
BLI_asan_unpoison(curnode, pool->esize);
curnode->next = next = NODE_STEP_NEXT(curnode);
curnode->freeword = FREEWORD;
curnode = curnode->next;
BLI_asan_poison(curnode, pool->esize);
curnode = next;
}
}
else {
while (j--) {
curnode->next = NODE_STEP_NEXT(curnode);
curnode = curnode->next;
BLI_freenode *next;
BLI_asan_unpoison(curnode, pool->esize);
curnode->next = next = NODE_STEP_NEXT(curnode);
BLI_asan_poison(curnode, pool->esize);
curnode = next;
}
}
/* terminate the list (rewind one)
* will be overwritten if 'curnode' gets passed in again as 'last_tail' */
BLI_asan_unpoison(curnode, pool->esize);
BLI_freenode *prev = NODE_STEP_PREV(curnode);
BLI_asan_poison(curnode, pool->esize);
curnode = NODE_STEP_PREV(curnode);
BLI_asan_unpoison(curnode, pool->esize);
curnode->next = NULL;
BLI_asan_poison(curnode, pool->esize);
#ifdef USE_TOTALLOC
pool->totalloc += pool->pchunk;
@@ -245,24 +325,128 @@ static BLI_freenode *mempool_chunk_add(BLI_mempool *pool,
/* final pointer in the previously allocated chunk is wrong */
if (last_tail) {
BLI_asan_unpoison(last_tail, pool->esize);
last_tail->next = CHUNK_DATA(mpchunk);
BLI_asan_poison(last_tail, pool->esize);
}
return curnode;
}
static void mempool_chunk_free(BLI_mempool_chunk *mpchunk)
/*
This preallocates a mempool suitable for threading. totelem elements are preallocated
in chunks of size pchunk, and returned in r_chunks. The idea is to pass these
to tasks.
*/
BLI_mempool *BLI_mempool_create_for_tasks(const unsigned int esize,
int totelem,
const int pchunk,
void ***r_chunks,
int *r_totchunk,
int *r_esize,
int flag)
{
BLI_mempool *pool = BLI_mempool_create(esize, 0, (uint)pchunk, (uint)flag);
// override pchunk, may not be a power of 2
pool->pchunk = (uint)pchunk;
pool->csize = (uint)pchunk * pool->esize;
if (totelem % pchunk == 0) {
pool->maxchunks = (uint)totelem / (uint)pchunk;
}
else {
pool->maxchunks = (uint)totelem / (uint)pchunk + 1;
}
if (totelem) {
BLI_freenode *last_tail = NULL;
/* Allocate the actual chunks. */
for (uint i = 0; i < pool->maxchunks; i++) {
BLI_mempool_chunk *mpchunk = mempool_chunk_alloc(pool);
last_tail = mempool_chunk_add(pool, mpchunk, last_tail);
}
}
void **chunks = MEM_callocN(sizeof(void *) * pool->maxchunks,
"BLI_mempool_create_for_tasks r_chunks");
unsigned int totalloc = 0;
*r_totchunk = 0;
BLI_mempool_chunk *chunk = pool->chunks, *lastchunk = NULL;
while (chunk) {
lastchunk = chunk;
totalloc += pool->pchunk;
chunk = chunk->next;
}
pool->totused = totalloc;
pool->free = NULL;
int i = (int)pool->pchunk - 1;
while (lastchunk && totalloc > (uint)totelem) {
if (i < 0) {
BLI_mempool_chunk *lastchunk2 = NULL;
for (chunk = pool->chunks; chunk; chunk = chunk->next) {
if (chunk == lastchunk) {
lastchunk = lastchunk2;
}
}
if (!lastchunk) {
break;
}
i = (int)pool->pchunk - 1;
}
char *elem = CHUNK_DATA(lastchunk);
elem += pool->esize * (unsigned int)i;
BLI_mempool_free(pool, elem);
totalloc--;
i--;
}
int ci = 0;
chunk = pool->chunks;
while (chunk && chunk != lastchunk) {
chunks[ci++] = CHUNK_DATA(chunk);
chunk = chunk->next;
}
if (lastchunk && i >= 0) {
chunks[ci++] = CHUNK_DATA(lastchunk);
}
*r_totchunk = ci;
*r_chunks = (void **)chunks;
*r_esize = (int)pool->esize;
return pool;
}
static void mempool_chunk_free(BLI_mempool_chunk *mpchunk, BLI_mempool *pool)
{
BLI_asan_unpoison(mpchunk, sizeof(BLI_mempool_chunk) + pool->esize * pool->csize);
MEM_freeN(mpchunk);
}
static void mempool_chunk_free_all(BLI_mempool_chunk *mpchunk)
static void mempool_chunk_free_all(BLI_mempool_chunk *mpchunk, BLI_mempool *pool)
{
BLI_mempool_chunk *mpchunk_next;
for (; mpchunk; mpchunk = mpchunk_next) {
mpchunk_next = mpchunk->next;
mempool_chunk_free(mpchunk);
mempool_chunk_free(mpchunk, pool);
}
}
@@ -275,6 +459,9 @@ BLI_mempool *BLI_mempool_create(uint esize, uint totelem, uint pchunk, uint flag
/* allocate the pool structure */
pool = MEM_mallocN(sizeof(BLI_mempool), "memory pool");
pool->totchunk = 0;
pool->chunktable = NULL;
/* set the elem size */
if (esize < (int)MEMPOOL_ELEM_SIZE_MIN) {
esize = (int)MEMPOOL_ELEM_SIZE_MIN;
@@ -284,6 +471,8 @@ BLI_mempool *BLI_mempool_create(uint esize, uint totelem, uint pchunk, uint flag
esize = MAX2(esize, (uint)sizeof(BLI_freenode));
}
esize += POISON_REDZONE_SIZE;
maxchunks = mempool_maxchunks(totelem, pchunk);
pool->chunks = NULL;
@@ -344,6 +533,8 @@ void *BLI_mempool_alloc(BLI_mempool *pool)
free_pop = pool->free;
BLI_asan_unpoison(free_pop, pool->esize - POISON_REDZONE_SIZE);
BLI_assert(pool->chunk_tail->next == NULL);
if (pool->flag & BLI_MEMPOOL_ALLOW_ITER) {
@@ -363,10 +554,88 @@ void *BLI_mempool_alloc(BLI_mempool *pool)
void *BLI_mempool_calloc(BLI_mempool *pool)
{
void *retval = BLI_mempool_alloc(pool);
memset(retval, 0, (size_t)pool->esize);
memset(retval, 0, (size_t)pool->esize - POISON_REDZONE_SIZE);
return retval;
}
int BLI_mempool_find_real_index(BLI_mempool *pool, void *ptr)
{
BLI_mempool_chunk *chunk = pool->chunks;
uintptr_t uptr = ptr;
uintptr_t cptr;
int chunki = 0;
while (chunk) {
cptr = (uintptr_t)chunk;
if (uptr >= cptr && uptr < cptr + pool->csize) {
break;
}
chunk = chunk->next;
chunki++;
}
if (!chunk) {
return -1; // failed
}
return chunki * (int)pool->pchunk + ((int)(uptr - cptr)) / (int)pool->esize;
}
/*finds an element in pool that's roughly at idx, idx*/
int BLI_mempool_find_elems_fuzzy(
BLI_mempool *pool, int idx, int range, void **r_elems, int r_elems_size)
{
int istart = idx - range, iend = idx + range;
istart = MAX2(istart, 0);
int totelem = 0;
for (int i = istart; i < iend; i++) {
int chunki = i / (int)pool->pchunk;
if (chunki >= (int)pool->totchunk) {
break;
}
int idx2 = i % (int)pool->pchunk;
BLI_mempool_chunk *chunk = pool->chunktable[chunki];
char *data = (char *)CHUNK_DATA(chunk);
void *ptr = data + idx2 * (int)pool->esize;
BLI_asan_unpoison(ptr, pool->esize);
BLI_freenode *fnode = (BLI_freenode *)ptr;
if (fnode->freeword == FREEWORD) {
BLI_asan_poison(ptr, pool->esize);
continue;
}
r_elems[totelem++] = ptr;
if (totelem == r_elems_size) {
break;
}
}
return totelem;
}
int BLI_mempool_get_size(BLI_mempool *pool)
{
BLI_mempool_chunk *chunk = pool->chunks;
int ret = 0;
while (chunk) {
chunk = chunk->next;
ret += (int)pool->pchunk;
}
return ret;
}
/**
* Free an element from the mempool.
*
@@ -393,7 +662,7 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
/* Enable for debugging. */
if (UNLIKELY(mempool_debug_memset)) {
memset(addr, 255, pool->esize);
memset(addr, 255, pool->esize - POISON_REDZONE_SIZE);
}
#endif
@@ -408,6 +677,8 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
newhead->next = pool->free;
pool->free = newhead;
BLI_asan_poison(newhead, pool->esize);
pool->totused--;
#ifdef WITH_MEM_VALGRIND
@@ -422,10 +693,12 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
BLI_mempool_chunk *first;
first = pool->chunks;
mempool_chunk_free_all(first->next);
mempool_chunk_free_all(first->next, pool);
first->next = NULL;
pool->chunk_tail = first;
mempool_update_chunktable(pool);
#ifdef USE_TOTALLOC
pool->totalloc = pool->pchunk;
#endif
@@ -440,11 +713,21 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
j = pool->pchunk;
while (j--) {
curnode->next = NODE_STEP_NEXT(curnode);
curnode = curnode->next;
BLI_asan_unpoison(curnode, pool->esize);
BLI_freenode *next = curnode->next = NODE_STEP_NEXT(curnode);
BLI_asan_poison(curnode, pool->esize);
curnode = next;
}
curnode = NODE_STEP_PREV(curnode);
BLI_asan_unpoison(curnode, pool->esize);
BLI_freenode *prev = NODE_STEP_PREV(curnode);
BLI_asan_poison(curnode, pool->esize);
curnode = prev;
BLI_asan_unpoison(curnode, pool->esize);
curnode->next = NULL; /* terminate the list */
BLI_asan_poison(curnode, pool->esize);
#ifdef WITH_MEM_VALGRIND
VALGRIND_MEMPOOL_FREE(pool, CHUNK_DATA(first));
@@ -510,7 +793,7 @@ void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr)
*/
void BLI_mempool_as_array(BLI_mempool *pool, void *data)
{
const uint esize = pool->esize;
const uint esize = pool->esize - (uint)POISON_REDZONE_SIZE;
BLI_mempool_iter iter;
char *elem, *p = data;
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
@@ -638,12 +921,16 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
return NULL;
}
intptr_t freeword = 0;
const uint esize = iter->pool->esize;
BLI_freenode *curnode = POINTER_OFFSET(CHUNK_DATA(iter->curchunk), (esize * iter->curindex));
BLI_freenode *ret;
do {
ret = curnode;
BLI_asan_unpoison(ret, iter->pool->esize - POISON_REDZONE_SIZE);
if (++iter->curindex != iter->pool->pchunk) {
curnode = POINTER_OFFSET(curnode, esize);
}
@@ -651,7 +938,13 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
iter->curindex = 0;
iter->curchunk = iter->curchunk->next;
if (UNLIKELY(iter->curchunk == NULL)) {
return (ret->freeword == FREEWORD) ? NULL : ret;
BLI_asan_unpoison(ret, iter->pool->esize - POISON_REDZONE_SIZE);
void *ret2 = (ret->freeword == FREEWORD) ? NULL : ret;
if (ret->freeword == FREEWORD) {
BLI_asan_poison(ret, iter->pool->esize);
}
return ret2;
}
curnode = CHUNK_DATA(iter->curchunk);
}
@@ -678,6 +971,8 @@ void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
do {
ret = curnode;
BLI_asan_unpoison(ret, esize - POISON_REDZONE_SIZE);
if (++iter->curindex != iter->pool->pchunk) {
curnode = POINTER_OFFSET(curnode, esize);
}
@@ -693,17 +988,37 @@ void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
/* pass. */
}
if (UNLIKELY(iter->curchunk == NULL)) {
return (ret->freeword == FREEWORD) ? NULL : ret;
if (ret->freeword == FREEWORD) {
BLI_asan_poison(ret, esize);
return NULL;
}
else {
return ret;
}
}
/* End `threadsafe` exception. */
iter->curchunk = iter->curchunk->next;
if (UNLIKELY(iter->curchunk == NULL)) {
return (ret->freeword == FREEWORD) ? NULL : ret;
if (ret->freeword == FREEWORD) {
BLI_asan_poison(ret, iter->pool->esize);
return NULL;
}
else {
return ret;
}
}
curnode = CHUNK_DATA(iter->curchunk);
}
} while (ret->freeword == FREEWORD);
if (ret->freeword == FREEWORD) {
BLI_asan_poison(ret, iter->pool->esize);
}
else {
break;
}
} while (true);
return ret;
}
@@ -747,7 +1062,7 @@ void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve)
do {
mpchunk_next = mpchunk->next;
mempool_chunk_free(mpchunk);
mempool_chunk_free(mpchunk, pool);
} while ((mpchunk = mpchunk_next));
}
@@ -781,7 +1096,9 @@ void BLI_mempool_clear(BLI_mempool *pool)
*/
void BLI_mempool_destroy(BLI_mempool *pool)
{
mempool_chunk_free_all(pool->chunks);
mempool_chunk_free_all(pool->chunks, pool);
MEM_SAFE_FREE(pool->chunktable);
#ifdef WITH_MEM_VALGRIND
VALGRIND_DESTROY_MEMPOOL(pool);

View File

@@ -0,0 +1,153 @@
#include "MEM_guardedalloc.h"
#include "BLI_compiler_attrs.h"
#include "BLI_compiler_compat.h"
#
#include "BLI_smallhash.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
//#define PTR_TO_IDX(ts) ((GHash *)ts->ptr_to_idx.buckets)
#define PTR_TO_IDX(ts) &(ts)->ptr_to_idx
TableGSet *BLI_table_gset_new(const char *info)
{
TableGSet *ts = MEM_callocN(sizeof(TableGSet), info);
// ts->ptr_to_idx.buckets = (void *)BLI_ghash_ptr_new(info);
BLI_smallhash_init(&ts->ptr_to_idx);
return ts;
}
TableGSet *BLI_table_gset_new_ex(const char *info, int size)
{
TableGSet *ts = MEM_callocN(sizeof(TableGSet), info);
// ts->ptr_to_idx.buckets = (void *)BLI_ghash_ptr_new_ex(info, (uint)size);
BLI_smallhash_init(&ts->ptr_to_idx);
if (size) {
ts->elems = MEM_callocN(sizeof(void *) * (uint)size, info);
ts->size = size;
ts->length = 0;
ts->cur = 0;
}
return ts;
}
void BLI_table_gset_free(TableGSet *ts, GHashKeyFreeFP freefp)
{
if (!PTR_TO_IDX(ts)) {
return;
}
if (ts->elems) {
MEM_freeN(ts->elems);
}
// BLI_ghash_free(PTR_TO_IDX(ts), freefp, NULL);
BLI_smallhash_release(&ts->ptr_to_idx);
MEM_freeN(ts);
}
static void table_gset_resize(TableGSet *ts)
{
if (ts->cur >= ts->size) {
uint newsize = (uint)(ts->cur + 1);
newsize = (newsize << 1U) - (newsize >> 1U);
newsize = MAX2(newsize, 8U);
if (!ts->elems) {
ts->elems = (void *)MEM_mallocN(sizeof(void *) * newsize, "ts->elems");
}
else {
ts->elems = (void *)MEM_reallocN(ts->elems, newsize * sizeof(void *));
}
// BLI_smallhash_clear(PTR_TO_IDX(ts), 0ULL);
// compact
int i = 0, j = 0;
for (i = 0; i < ts->cur; i++) {
void *elem2 = ts->elems[i];
if (elem2) {
void **val;
BLI_smallhash_ensure_p(PTR_TO_IDX(ts), (uintptr_t)elem2, &val);
// BLI_smallhash_insert(PTR_TO_IDX(ts), elem2, (void *)j);
*val = POINTER_FROM_INT(j);
ts->elems[j++] = elem2;
}
}
ts->size = (int)newsize;
ts->cur = j;
}
}
bool BLI_table_gset_add(TableGSet *ts, void *elem)
{
void **val;
table_gset_resize(ts);
bool ret = BLI_smallhash_ensure_p(PTR_TO_IDX(ts), (uintptr_t)elem, &val);
if (!ret) {
*val = ts->cur;
ts->elems[ts->cur++] = elem;
ts->length++;
}
return ret;
}
void BLI_table_gset_insert(TableGSet *ts, void *elem)
{
table_gset_resize(ts);
BLI_smallhash_insert(PTR_TO_IDX(ts), elem, (void *)ts->cur);
ts->elems[ts->cur++] = elem;
ts->length++;
}
void BLI_table_gset_remove(TableGSet *ts, void *elem, GHashKeyFreeFP freefp)
{
if (!elem || !ts) {
return;
}
int *idx = (int *)BLI_smallhash_lookup_p(PTR_TO_IDX(ts), elem);
if (!idx) {
return;
}
int idx2 = *idx;
BLI_smallhash_remove(PTR_TO_IDX(ts), elem);
if (!ts->elems || ts->elems[idx2] != elem) {
return;
}
ts->length--;
ts->elems[idx2] = NULL;
}
bool BLI_table_gset_haskey(TableGSet *ts, void *elem)
{
return BLI_smallhash_haskey(PTR_TO_IDX(ts), elem);
}
int BLI_table_gset_len(TableGSet *ts)
{
return ts->length;
}

View File

@@ -55,20 +55,56 @@
#include "BLI_smallhash.h"
#include "BLI_asan.h"
#include "BLI_strict_flags.h"
#define SMHASH_KEY_UNUSED ((uintptr_t)(UINTPTR_MAX - 0))
#define SMHASH_CELL_FREE ((void *)(UINTPTR_MAX - 1))
#define SMHASH_CELL_UNUSED ((void *)(UINTPTR_MAX - 2))
#ifdef BLI_asan_poison
# undef BLI_asan_poison
#endif
#ifdef BLI_asan_unpoison
# undef BLI_asan_unpoison
#endif
#define BLI_asan_poison(a, b)
#define BLI_asan_unpoison(a, b)
/* NOTE: copied from BLO_blend_defs.h, don't use here because we're in BLI. */
#ifdef __BIG_ENDIAN__
/* Big Endian */
# define MAKE_ID(a, b, c, d) ((int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d))
# define MAKE_ID_8(a, b, c, d, e, f, g, h) \
((int64_t)(a) << 56 | (int64_t)(b) << 48 | (int64_t)(c) << 40 | (int64_t)(d) << 32 | \
(int64_t)(e) << 24 | (int64_t)(f) << 16 | (int64_t)(g) << 8 | (h))
#else
/* Little Endian */
# define MAKE_ID(a, b, c, d) ((int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a))
# define MAKE_ID_8(a, b, c, d, e, f, g, h) \
((int64_t)(h) << 56 | (int64_t)(g) << 48 | (int64_t)(f) << 40 | (int64_t)(e) << 32 | \
(int64_t)(d) << 24 | (int64_t)(c) << 16 | (int64_t)(b) << 8 | (a))
#endif
#define SMHASH_KEY_UNUSED (uintptr_t)(MAKE_ID_8('s', 'm', 'h', 'k', 'u', 'n', 'u', 's'))
#define SMHASH_CELL_FREE (uintptr_t)(MAKE_ID_8('s', 'm', 'h', 'c', 'f', 'r', 'e', 'e'))
#define SMHASH_CELL_UNUSED (uintptr_t)(MAKE_ID_8('s', 'm', 'h', 'c', 'u', 'n', 'u', 's'))
#define USE_REMOVE
/* typically this re-assigns 'h' */
#define SMHASH_NEXT(h, hoff) \
(CHECK_TYPE_INLINE(&(h), uint *), \
CHECK_TYPE_INLINE(&(hoff), uint *), \
(CHECK_TYPE_INLINE(&(h), uintptr_t *), \
CHECK_TYPE_INLINE(&(hoff), uintptr_t *), \
((h) + (((hoff) = ((hoff)*2) + 1), (hoff))))
/* nothing uses BLI_smallhash_remove yet */
// #define USE_REMOVE
BLI_INLINE bool check_stack_move(SmallHash *sh)
{
if (sh->using_stack && sh->buckets != sh->buckets_stack) {
sh->buckets = sh->buckets_stack;
return true;
}
return false;
}
BLI_INLINE bool smallhash_val_is_used(const void *val)
{
@@ -82,28 +118,46 @@ BLI_INLINE bool smallhash_val_is_used(const void *val)
extern const uint BLI_ghash_hash_sizes[];
#define hashsizes BLI_ghash_hash_sizes
BLI_INLINE uint smallhash_key(const uintptr_t key)
BLI_INLINE uintptr_t smallhash_key(const uintptr_t key)
{
return (uint)key;
#if 1
return key;
#else
uintptr_t y = (size_t)key;
/* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid
* excessive hash collisions for dicts and sets */
return (uintptr_t)(y >> 4) | ((uintptr_t)y << (sizeof(uintptr_t[8]) - 4));
#endif
}
/**
* Check if the number of items in the smallhash is large enough to require more buckets.
*/
BLI_INLINE bool smallhash_test_expand_buckets(const uint nentries, const uint nbuckets)
BLI_INLINE bool smallhash_test_expand_buckets(const uint nentries,
const uint nbuckets,
const uint nfreecells)
{
if (nfreecells < 3) {
return true;
}
/* (approx * 1.5) */
return (nentries + (nentries >> 1)) > nbuckets;
return (nentries + (nentries >> 1)) > nbuckets || nfreecells < 3;
}
BLI_INLINE void smallhash_init_empty(SmallHash *sh)
{
uint i;
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
for (i = 0; i < sh->nbuckets; i++) {
sh->buckets[i].key = SMHASH_KEY_UNUSED;
sh->buckets[i].val = SMHASH_CELL_FREE;
}
BLI_asan_poison(&sh->buckets, sizeof(void *));
}
/**
@@ -111,19 +165,24 @@ BLI_INLINE void smallhash_init_empty(SmallHash *sh)
*/
BLI_INLINE void smallhash_buckets_reserve(SmallHash *sh, const uint nentries_reserve)
{
while (smallhash_test_expand_buckets(nentries_reserve, sh->nbuckets)) {
while (smallhash_test_expand_buckets(nentries_reserve, sh->nbuckets, sh->nbuckets + 5)) {
sh->nbuckets = hashsizes[++sh->cursize];
sh->nfreecells = sh->nbuckets;
}
}
BLI_INLINE SmallHashEntry *smallhash_lookup(const SmallHash *sh, const uintptr_t key)
BLI_INLINE SmallHashEntry *smallhash_lookup(SmallHash *sh, const uintptr_t key)
{
check_stack_move(sh);
SmallHashEntry *e;
uint h = smallhash_key(key);
uint hoff = 1;
uintptr_t h = smallhash_key(key);
uintptr_t hoff = 1;
BLI_assert(key != SMHASH_KEY_UNUSED);
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
/* NOTE: there are always more buckets than entries,
* so we know there will always be a free bucket if the key isn't found. */
for (e = &sh->buckets[h % sh->nbuckets]; e->val != SMHASH_CELL_FREE;
@@ -135,25 +194,37 @@ BLI_INLINE SmallHashEntry *smallhash_lookup(const SmallHash *sh, const uintptr_t
}
}
BLI_asan_poison(&sh->buckets, sizeof(void *));
return NULL;
}
BLI_INLINE SmallHashEntry *smallhash_lookup_first_free(SmallHash *sh, const uintptr_t key)
{
check_stack_move(sh);
SmallHashEntry *e;
uint h = smallhash_key(key);
uint hoff = 1;
uintptr_t h = smallhash_key(key);
uintptr_t hoff = 1;
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
for (e = &sh->buckets[h % sh->nbuckets]; smallhash_val_is_used(e->val);
h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
/* pass */
}
BLI_asan_poison(&sh->buckets, sizeof(void *));
return e;
}
BLI_INLINE void smallhash_resize_buckets(SmallHash *sh, const uint nbuckets)
{
check_stack_move(sh);
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
SmallHashEntry *buckets_old = sh->buckets;
const uint nbuckets_old = sh->nbuckets;
const bool was_alloc = (buckets_old != sh->buckets_stack);
@@ -169,21 +240,29 @@ BLI_INLINE void smallhash_resize_buckets(SmallHash *sh, const uint nbuckets)
}
else {
sh->buckets = MEM_mallocN(sizeof(*sh->buckets) * nbuckets, __func__);
sh->using_stack = false;
}
sh->nbuckets = nbuckets;
sh->nfreecells = nbuckets;
sh->nentries = 0;
BLI_asan_poison(&sh->buckets, sizeof(void *));
smallhash_init_empty(sh);
for (i = 0; i < nbuckets_old; i++) {
if (smallhash_val_is_used(buckets_old[i].val)) {
SmallHashEntry *e = smallhash_lookup_first_free(sh, buckets_old[i].key);
e->key = buckets_old[i].key;
e->val = buckets_old[i].val;
sh->nfreecells--;
sh->nentries++;
}
}
if (was_alloc) {
if (was_alloc && buckets_old) {
MEM_freeN(buckets_old);
}
}
@@ -194,15 +273,23 @@ void BLI_smallhash_init_ex(SmallHash *sh, const uint nentries_reserve)
sh->nentries = 0;
sh->cursize = 2;
sh->using_stack = true;
sh->nbuckets = hashsizes[sh->cursize];
sh->nfreecells = sh->nbuckets;
sh->buckets = sh->buckets_stack;
BLI_asan_poison(&sh->buckets, sizeof(void *));
if (nentries_reserve) {
smallhash_buckets_reserve(sh, nentries_reserve);
if (sh->nbuckets > SMSTACKSIZE) {
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
sh->buckets = MEM_mallocN(sizeof(*sh->buckets) * sh->nbuckets, __func__);
BLI_asan_poison(&sh->buckets, sizeof(void *));
sh->using_stack = false;
}
}
@@ -217,24 +304,85 @@ void BLI_smallhash_init(SmallHash *sh)
/* NOTE: does *not* free *sh itself! only the direct data! */
void BLI_smallhash_release(SmallHash *sh)
{
if (sh->buckets != sh->buckets_stack) {
check_stack_move(sh);
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
if (sh->buckets && sh->buckets != sh->buckets_stack) {
MEM_freeN(sh->buckets);
}
}
bool BLI_smallhash_ensure_p(SmallHash *sh, uintptr_t key, void ***item)
{
check_stack_move(sh);
SmallHashEntry *e = NULL;
uintptr_t h = smallhash_key(key);
uintptr_t hoff = 1;
if (UNLIKELY(smallhash_test_expand_buckets(sh->nentries, sh->nbuckets, sh->nfreecells))) {
smallhash_resize_buckets(sh, hashsizes[++sh->cursize]);
}
BLI_assert(key != SMHASH_KEY_UNUSED);
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
/* NOTE: there are always more buckets than entries,
* so we know there will always be a free bucket if the key isn't found. */
for (e = &sh->buckets[h % sh->nbuckets]; e->val != SMHASH_CELL_FREE;
h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
if (e->key == key) {
/* should never happen because unused keys are zero'd */
BLI_assert(e->val != SMHASH_CELL_UNUSED);
break;
}
}
BLI_asan_poison(&sh->buckets, sizeof(void *));
bool ret;
if (e->val == SMHASH_CELL_FREE || e->val == SMHASH_CELL_UNUSED) {
sh->nentries++;
sh->nfreecells--;
ret = false;
}
else {
ret = true;
}
e->key = key;
*item = &e->val;
return ret;
}
void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item)
{
check_stack_move(sh);
SmallHashEntry *e;
BLI_assert(key != SMHASH_KEY_UNUSED);
BLI_assert(smallhash_val_is_used(item));
BLI_assert(BLI_smallhash_haskey(sh, key) == false);
if (UNLIKELY(smallhash_test_expand_buckets(++sh->nentries, sh->nbuckets))) {
if (UNLIKELY(smallhash_test_expand_buckets(sh->nentries, sh->nbuckets, sh->nfreecells))) {
smallhash_resize_buckets(sh, hashsizes[++sh->cursize]);
}
e = smallhash_lookup_first_free(sh, key);
if (e->val == SMHASH_CELL_FREE) {
sh->nentries++;
sh->nfreecells--;
}
else if (e->val == SMHASH_CELL_UNUSED) {
sh->nentries++;
}
e->key = key;
e->val = item;
}
@@ -260,10 +408,47 @@ bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item)
#ifdef USE_REMOVE
bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key)
{
check_stack_move(sh);
// SmallHashEntry *e = smallhash_lookup(sh, key);
SmallHashEntry *e;
uintptr_t h = smallhash_key(key);
uintptr_t hoff = 1;
for (e = &sh->buckets[h % sh->nbuckets]; e->val != SMHASH_CELL_FREE;
h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {
if (e->key == key) {
/* should never happen because unused keys are zero'd */
BLI_assert(e->val != SMHASH_CELL_UNUSED);
break;
}
}
if (e && e->key == key) {
h = SMHASH_NEXT(h, hoff);
SmallHashEntry *e2 = &sh->buckets[h & sh->nbuckets];
e->key = SMHASH_KEY_UNUSED;
e->val = SMHASH_CELL_UNUSED;
sh->nentries--;
return true;
}
else {
return false;
}
}
bool BLI_smallhash_remove_p(SmallHash *sh, uintptr_t key, void **val)
{
SmallHashEntry *e = smallhash_lookup(sh, key);
if (e) {
*val = e->val;
e->key = SMHASH_KEY_UNUSED;
e->val = SMHASH_CELL_UNUSED;
sh->nentries--;
@@ -276,34 +461,54 @@ bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key)
}
#endif
void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
void *BLI_smallhash_lookup(SmallHash *sh, uintptr_t key)
{
SmallHashEntry *e = smallhash_lookup(sh, key);
return e ? e->val : NULL;
}
void **BLI_smallhash_lookup_p(const SmallHash *sh, uintptr_t key)
void **BLI_smallhash_lookup_p(SmallHash *sh, uintptr_t key)
{
SmallHashEntry *e = smallhash_lookup(sh, key);
return e ? &e->val : NULL;
}
bool BLI_smallhash_haskey(const SmallHash *sh, uintptr_t key)
void BLI_smallhash_clear(SmallHash *sh, uintptr_t key)
{
check_stack_move(sh);
BLI_asan_unpoison(&sh->buckets, sizeof(void *));
SmallHashEntry *e = sh->buckets;
for (uint i = 0; i < sh->nbuckets; i++, e++) {
e->key = SMHASH_KEY_UNUSED;
e->val = SMHASH_CELL_FREE;
}
sh->nentries = 0;
BLI_asan_poison(&sh->buckets, sizeof(void *));
}
bool BLI_smallhash_haskey(SmallHash *sh, uintptr_t key)
{
SmallHashEntry *e = smallhash_lookup(sh, key);
return (e != NULL);
}
int BLI_smallhash_len(const SmallHash *sh)
int BLI_smallhash_len(SmallHash *sh)
{
return (int)sh->nentries;
}
BLI_INLINE SmallHashEntry *smallhash_iternext(SmallHashIter *iter, uintptr_t *key)
{
BLI_asan_unpoison(&iter->sh->buckets, sizeof(void *));
while (iter->i < iter->sh->nbuckets) {
if (smallhash_val_is_used(iter->sh->buckets[iter->i].val)) {
if (key) {
@@ -316,6 +521,7 @@ BLI_INLINE SmallHashEntry *smallhash_iternext(SmallHashIter *iter, uintptr_t *ke
iter->i++;
}
BLI_asan_poison(&iter->sh->buckets, sizeof(void *));
return NULL;
}
@@ -333,16 +539,20 @@ void **BLI_smallhash_iternext_p(SmallHashIter *iter, uintptr_t *key)
return e ? &e->val : NULL;
}
void *BLI_smallhash_iternew(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
void *BLI_smallhash_iternew(SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
{
check_stack_move(sh);
iter->sh = sh;
iter->i = 0;
return BLI_smallhash_iternext(iter, key);
}
void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
void **BLI_smallhash_iternew_p(SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
{
check_stack_move(sh);
iter->sh = sh;
iter->i = 0;
@@ -408,8 +618,8 @@ double BLI_smallhash_calc_quality(SmallHash *sh)
if (sh->buckets[i].key != SMHASH_KEY_UNUSED) {
uint64_t count = 0;
SmallHashEntry *e, *e_final = &sh->buckets[i];
uint h = smallhash_key(e_final->key);
uint hoff = 1;
uintptr_t h = smallhash_key(e_final->key);
uintptr_t hoff = 1;
for (e = &sh->buckets[h % sh->nbuckets]; e != e_final;
h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets]) {

View File

@@ -90,7 +90,8 @@ class Task {
other.freedata = nullptr;
}
#if defined(WITH_TBB) && TBB_INTERFACE_VERSION_MAJOR < 10
#if (defined(WITH_TBB) && TBB_INTERFACE_VERSION_MAJOR < 10) || \
(defined(__clang__) && defined(WIN32))
Task(const Task &other)
: pool(other.pool),
run(other.run),

View File

@@ -2420,7 +2420,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* this can now be turned off */
ToolSettings *ts = scene->toolsettings;
if (ts->sculpt) {
ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE;
ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_CLEANUP;
}
/* 'Increment' mode disabled for nodes, use true grid snapping instead */

View File

@@ -4424,7 +4424,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
UnifiedPaintSettings *ups = &ts->unified_paint_settings;
ups->flag &= ~(UNIFIED_PAINT_FLAG_UNUSED_0 | UNIFIED_PAINT_FLAG_UNUSED_1);
ups->flag &= ~(UNIFIED_PAINT_FLAG_UNUSED_1);
}
/* Set the default render pass in the viewport to Combined. */

View File

@@ -32,6 +32,7 @@
#include "DNA_cachefile_types.h"
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_defaults.h"
#include "DNA_fluid_types.h"
#include "DNA_genfile.h"
#include "DNA_gpencil_modifier_types.h"
@@ -55,6 +56,7 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_attribute.h"
#include "BKE_brush.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
#include "BKE_cryptomatte.h"
@@ -1940,6 +1942,13 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "diff_fac")) {
LISTBASE_FOREACH (Light *, light, &bmain->lights) {
light->diff_fac = 1.0f;
light->volume_fac = 1.0f;
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 293, 15)) {

View File

@@ -48,6 +48,7 @@
#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_asset.h"
#include "BKE_brush.h"
#include "BKE_collection.h"
#include "BKE_deform.h"
#include "BKE_fcurve.h"
@@ -1229,6 +1230,93 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 21)) {
LISTBASE_FOREACH (Brush *, br, &bmain->brushes) {
/* try to detect beta testers' files by seeing
if autosmooth_fset_slide is 0; this will
not work once it is added to DNA defaults
(right now it's being set in BKE_brush_sculpt_reset).*/
if (br->autosmooth_fset_slide == 0.0f) {
Brush defbrush = *br;
BKE_brush_sculpt_reset(&defbrush);
br->dyntopo = defbrush.dyntopo;
br->flag2 |= defbrush.flag2 & (BRUSH_SMOOTH_PRESERVE_FACE_SETS |
BRUSH_SMOOTH_USE_AREA_WEIGHT | BRUSH_CURVATURE_RAKE);
br->autosmooth_fset_slide = defbrush.autosmooth_fset_slide;
br->boundary_smooth_factor = defbrush.boundary_smooth_factor;
br->autosmooth_spacing = defbrush.autosmooth_spacing;
br->autosmooth_radius_factor = defbrush.autosmooth_radius_factor;
br->topology_rake_radius_factor = defbrush.topology_rake_radius_factor;
br->topology_rake_projection = defbrush.topology_rake_projection;
br->topology_rake_spacing = defbrush.topology_rake_spacing;
if (br->autosmooth_projection == 0.0f) {
br->autosmooth_projection = defbrush.autosmooth_projection;
}
}
if (br->sculpt_tool == SCULPT_TOOL_VCOL_BOUNDARY) {
if (br->vcol_boundary_exponent == 0.0f) {
br->vcol_boundary_exponent = 1.0f;
}
}
else if (br->sculpt_tool == SCULPT_TOOL_SIMPLIFY) {
br->dyntopo.inherit = DYNTOPO_INHERIT_BITMASK &
~(DYNTOPO_INHERIT_ALL | DYNTOPO_SUBDIVIDE | DYNTOPO_COLLAPSE);
br->dyntopo.flag |= DYNTOPO_COLLAPSE | DYNTOPO_SUBDIVIDE | DYNTOPO_CLEANUP;
}
}
Scene *scene;
for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
if (ts->sculpt) {
ts->sculpt->flags |= SCULPT_DYNTOPO_CLEANUP;
}
}
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
ToolSettings *ts = scene->toolsettings;
if (ts && ts->sculpt) {
ts->sculpt->detail_range = 0.4f;
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 22)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
ToolSettings *ts = scene->toolsettings;
if (ts) {
ts->unified_paint_settings.flag |= UNIFIED_PAINT_FLAG_HARD_EDGE_MODE;
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 22)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
ToolSettings *ts = scene->toolsettings;
if (ts) {
ts->unified_paint_settings.flag |= UNIFIED_PAINT_FLAG_HARD_EDGE_MODE;
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 23)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
ToolSettings *ts = scene->toolsettings;
if (ts && ts->sculpt) {
ts->sculpt->flags |= SCULPT_DYNTOPO_ENABLED;
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 22)) {
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
if (ntree->type == NTREE_GEOMETRY) {
@@ -1248,19 +1336,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - "versioning_userdef.c", #blo_do_versions_userdef
* - "versioning_userdef.c", #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
@@ -1275,4 +1350,17 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
/**
* Versioning code until next subversion bump goes here.
*
* \note Be sure to check when bumping the version:
* - "versioning_userdef.c", #blo_do_versions_userdef
* - "versioning_userdef.c", #do_versions_theme
*
* \note Keep this message at the bottom of the function.
*/
{
/* Keep this block, even when empty. */
}
}

View File

@@ -688,6 +688,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
brush->sculpt_tool = SCULPT_TOOL_PAINT;
}
brush_name = "Color Boundary";
brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_VCOL_BOUNDARY;
}
brush_name = "Smear";
brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
if (!brush) {

View File

@@ -99,6 +99,7 @@ set(SRC
intern/bmesh_mesh.c
intern/bmesh_mesh.h
intern/bmesh_mesh_convert.c
intern/bmesh_mesh_convert_threaded.c
intern/bmesh_mesh_convert.h
intern/bmesh_mesh_duplicate.c
intern/bmesh_mesh_duplicate.h

View File

@@ -16,6 +16,8 @@
#pragma once
#include "DNA_modifier_types.h"
/** \file
* \ingroup bmesh
*
@@ -34,6 +36,7 @@ struct BMFace;
struct BMLoop;
struct BMVert;
struct BMesh;
struct GSet;
struct MLoopNorSpaceArray;
@@ -295,6 +298,10 @@ typedef struct BMFlagLayer {
// #pragma GCC diagnostic ignored "-Wpadded"
struct RangeTreeUInt;
//#define WITH_BM_ID_FREELIST
typedef struct BMesh {
int totvert, totedge, totloop, totface;
int totvertsel, totedgesel, totfacesel;
@@ -378,8 +385,35 @@ typedef struct BMesh {
* instead of crashing on invalid memory access.
*/
void *py_handle;
MultiresModifierData multires; // copy of multires settings
bool haveMultiResSettings;
int multiresSpace;
struct {
int flag;
#ifdef WITH_BM_ID_FREELIST
uint *freelist;
int freelist_len, freelist_size;
struct GSet *free_ids;
#else
struct RangeTreeUInt *idtree;
#endif
uint maxid;
struct BMElem **map; // used if BM_NO_REUSE_IDS is false
struct GHash *ghash; // used if BM_NO_REUSE_IDS is true
int map_size;
int cd_id_off[15];
} idmap;
} BMesh;
enum {
// firsst four bits are reserved for BM_VERT/EDGE/LOOP/FACE
BM_HAS_IDS = 1 << 4,
BM_HAS_ID_MAP = 1 << 5,
BM_NO_REUSE_IDS = 1 << 6,
BM_PERMANENT_IDS = 1 << 7
};
/** #BMHeader.htype (char) */
enum {
BM_VERT = 1,
@@ -588,3 +622,7 @@ typedef bool (*BMLoopPairFilterFunc)(const BMLoop *, const BMLoop *, void *user_
#else
# define BM_OMP_LIMIT 10000
#endif
/* note does not check if ids are enabled for a given element type */
#define BM_ELEM_GET_ID(bm, elem) \
BM_ELEM_CD_GET_INT(elem, bm->idmap.cd_id_off[(int)(elem)->head.htype])

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