1
1

Compare commits

...

321 Commits

Author SHA1 Message Date
9ad96b2689 Use dupli overrides also for the selection drawing code.
Now clicking a cached dupli instance also selects the duplicator object
as expected.
2015-03-23 09:07:49 +01:00
0919a3d56d Use dupli cache in bounding box calculations involving duplis.
This feature is mostly useful for the "view selected" operator. It is
also used in the "set origin to geometry" operator, but since the
cache overrides the object geometry anyway the effect may not be what
users expect (which is acceptable).
2015-03-23 08:51:08 +01:00
8c142af0b0 Simple mesh import from Alembic files in Cycles standalone.
Note that Cycles currently only supports tessellated triangle/quad
meshes. Alembic PolyMesh generally has ngons, so external tessellation
is required until cycles gets a proper tessellation implementation of
its own.
2015-03-22 18:16:07 +01:00
4b451838ed More control over verbosity with Alembic archive info printing. 2015-03-22 14:23:33 +01:00
c27ef5692c Simple inclusion of alembic files from inside xml files for cycles
standalone.

The cycles XML files now can refer to Alembic (.abc) files. This will
call the default alembic reader to read in scene data. Currently it
simply prints the Alembic file structure.

Eventually a proper schema needs to be defined for both xml and abc.
Also care has to be taken to handle potential conflicts between settings
both within xml/abc and between them.
2015-03-22 13:26:46 +01:00
045350c3b1 Basic Alembic integration in the Cycles standalone.
This adds Alembic to the standalone application version of cycles.
Files can be specified as XML or Alembic, or use automatic detection
based on the filename extension.

Currently the Alembic reader just dumps the file structure to stdout
as a test.
2015-03-21 20:22:25 +01:00
1d2aa62366 Fix for cycles cmake missing GLEW library variable when building without
the GUI.
2015-03-21 20:03:37 +01:00
4ce017b4c8 Avoid conflicting unordered_map definition in cycles by using a general
include path instead of the boost one.

For explanation see http://stackoverflow.com/questions/3973659/c-unordered-map-compiling-issue-with-g
2015-03-21 19:06:15 +01:00
6db876bef6 Merge branch 'master' into alembic_pointcache 2015-03-21 17:58:52 +01:00
3e44712895 Fix for corruption of the item hash table in cache libraries on copy. 2015-03-20 17:50:43 +01:00
b01037b81d Take cache library items into account when baking caches.
This means we don't bluntly store all the data in a group, but use the
selection from the cache library. It also helps to avoid issues with
object visibility which is not yet stored in the cache.
2015-03-20 15:40:51 +01:00
e84b0d456f Working implementation of cache reading for dupli data during renders. 2015-03-20 14:48:51 +01:00
5950b48328 Use the temporary 'is_dupli' flag to prevent objects from freeing
overriden data that is owned by the cache.

This is not at all nice ... Hopefully it doesn't get too complicated to
work around all these drawing code and depsgraph issues, so the code
can be understood and replaced at some point in the future.
2015-03-20 10:39:40 +01:00
229befd147 Replacing boundbox temporarily during drawing is dangerous, since it
can be freed at any point.

Luckily we only need the boundbox locally for testing dupli visibility.
2015-03-20 10:18:57 +01:00
f77d75ed65 Fully reset the OB_FROM_DUPLI flag for each dupli instance, in case
later duplis can not be found in the cache.
2015-03-20 09:52:32 +01:00
481ef9704d Distinguish realtime/render setting in the Object writer.
Now the derived_render mesh version is created locally when writing
render results.
2015-03-20 09:40:46 +01:00
9ceb29d3cb Combined storage of render and realtime data in caches.
Caches now create 2 new roots below the main 'top' object of Alembic:
root and root_render for realtime and render data respectively.
This makes it easy to switch the whole archive to either of the modes
during baking and for constructing dupli caches.

Alternatively individual objects could store hires versions of their
data. This would also be more efficient if the cache contains many
simple objects which don't have 2 different variants. However, such
design decisions are difficult to make at this point and the
implementation can be modifier later.
2015-03-19 20:58:21 +01:00
65c1e00fb5 Make sure the cache baking job cancels properly when interrupted in the
first stage.
2015-03-19 20:42:02 +01:00
0a7a4d504b Allow cache libraries to store both render and realtime (viewport) data.
This is the default now. It should make workflow a lot more foolproof
and convenient, since having only one of these modes active at a time
very easily leads to broken renders and confusing situations.

The problem is mostly due to the complicated way the depsgraph layer
feature is used to handle duplicator visibility. The duplicator is
declared as a child of its group's objects (even though no real
dependency exists!), so that a visible duplicator triggers updates of
invisible group objects, making instances of hidden groups possible.

However, dupli caches have to disable this dependency in order to avoid
unnecessary costly updates in hidden layers which are overridden by
cached data anyway. At the point where these dependencies are created
the evaluation context is unknown though, which means we cannot
distinguish between render and realtime evaluation for the purpose of
cache reading ...
2015-03-19 19:19:23 +01:00
08017eef62 Removed deprecated code. 2015-03-19 19:12:20 +01:00
f3eb33c476 Make sure mesh data is really stored and reconstructed from the cache
entirely.

Also the code is much better structured now, moving toward a more
standardized sample/schema class definition.
2015-03-19 18:07:03 +01:00
20a678f240 CD_NORMAL support for mesh customdata caching. 2015-03-19 14:19:40 +01:00
29b46e4ef2 Fix for use of wrong CustomData for tessfaces. 2015-03-19 14:18:02 +01:00
bdae7f4aaa Copy rgba components of MCol explicitly to the Alembic C4f type to avoid
potentially different ordering.
2015-03-19 13:33:00 +01:00
40d3784dc3 MCol customdata caching. 2015-03-19 13:23:33 +01:00
babaf408c4 MTFACE customdata is not suitable or necessary for caching, so disable
it.
2015-03-19 12:56:13 +01:00
21fa96a72b Added customdata writers/readers for missing mesh edge, poly and loop
data.
2015-03-19 12:47:17 +01:00
97410d71b3 UI cleanup and a bit nicer workflow by treating read/write mode like
an enum toggle.
2015-03-19 10:47:03 +01:00
5d04ddea64 Disable the bake operator if cache reading is enabled.
Re-baking cache results is not technically prohibited, but not useful
and allowing only read or write selectively gives a nicer workflow.
2015-03-19 10:30:18 +01:00
279dfe6a18 Merge branch 'master' into alembic_pointcache 2015-03-19 10:09:00 +01:00
b5fb274f43 Cycles support for dupli caches.
If a cache is read-enabled cycles will now use the cached mesh data
instead of dupli results.
2015-03-18 19:22:38 +01:00
878d09e65b Skip drawing of particle systems (including hair) when using cache
duplis.

Particle systems can not be overridden from caches easily, there are too
many strings attached to the data and code to make this reliable.
Instead, a new simplified data structure for reading hair from caches
will be added, which replaces drawing and rendering of particle data.
The original particle data is not updated through duplis, so is usually
out of sync and should not be displayed.
2015-03-18 16:17:15 +01:00
238f3ac972 Main argument is no longer needed for cache reading, the cachelib is
now given explicitly.
2015-03-18 16:12:07 +01:00
a0a3c29ae4 Removed unused variable. 2015-03-18 16:09:53 +01:00
cf2c1a9062 Calculate bounding boxes for cached DMs to avoid visual popping when
using the original Object's bb.
2015-03-18 15:37:08 +01:00
2392ee9505 Test for NULL archive pointer when writing as well.
This should not usually happen because the operator asks for permission
to delete the file prior to writing, but should be checked nevertheless.
2015-03-18 14:12:16 +01:00
7c7d5645ca Safeguard against crashes from invalid Alembic file paths by returning
NULL archive pointers.

This allows writer/reader code to test against obvious archive errors
easily and is unmistakable.
2015-03-18 14:06:00 +01:00
3079019ec1 Fix for wrong ID code used in RNA->idcode mapping. 2015-03-18 13:33:10 +01:00
8a021a7d1f Removed group pointer from cache libraries and use object->cachelib
pointer instead.

This change makes it possible to have group duplicators using different
versions of a cache.
2015-03-18 12:51:26 +01:00
59ed1d0a67 Added a cache library pointer to objects as a replacement for CL->GR
pointers.

Relationship between CacheLibrary, duplicator Objects and Groups is
difficult. There are a number of somewhat conflicting goals:
- CacheLibraries write out data for objects and dupli groups. Multiple
  objects can be stored in the same cache: CL *->* GR
- Objects can override a dupli group with different caches: OB *->1 CL
- As before, each object can be the duplicator for one group: OB *->1 GR

To combine these requirements, the first relationship will be made
indirect. Only the Object -> Group/CacheLib relations are explicit
pointers in the DNA. For finding all objects contained in a cache
library the usual recursive DNA tagging system must then be used.
2015-03-18 10:24:17 +01:00
56acbcaa0e Removed the now redundant "Read" toggle from cache libraries.
At this point the reading is toggled on the side of group duplicators.
2015-03-17 17:05:07 +01:00
16258ddd03 Removed the explicit duplicache rebuild operator.
The cache is now updated on frame changes automatically, the operator
should no longer be needed.
2015-03-17 16:38:31 +01:00
aad1c616ca Removed unused deprecated functions for cache library. 2015-03-17 16:33:00 +01:00
bafa8da0ca Sanity check for dupligroup caching functions. 2015-03-17 16:28:31 +01:00
6f7b613715 Use a new flag in duplicator objects to enable cache reading and avoid
unnecessary dependencies.

This flag will replace the current "read" mode on cache libraries.

Beside enabling cache reading, it also disables the current "fake"
dependencies between duplicators and their group objects. This is
exploiting the layer visibility mechanism in depsgraph to ensure that
animated group objects get evaluated when used by a visible duplicator,
even when they are not themselves visible. These dependencies cause
group object updates even if the duplicator is using cached results.
To avoid this unnecessary overhead and make caching worthwhile we
rebuild depsgraph without these relations when using the cache instead.
2015-03-17 16:17:04 +01:00
67b7263d37 Enable frame updates of duplicache through use of an invalidation flag. 2015-03-17 09:36:43 +01:00
9772bae88e Disable additional depsgraph tagging through cache libraries.
This code is outdated due to changes in reading code and obscures some
genuine depsgraph behavior.
2015-03-16 18:48:23 +01:00
92598a6e22 Mesh overrides for duplis from cached Alembic data.
If a duplicator has cached data it will now replace the derivedFinal
mesh of objects with the cached version for drawing.

This is a compromise atm: It would be better to actually draw derived
meshes directly, so that we don't have to modify objects. Then we could
also have multiple different instances of the same orignal object
(in whatever way these might be defined). DNA Objects would then be
totally separate from duplis, but at this point the drawing and render
code makes this unfeasible.
2015-03-16 12:15:50 +01:00
e3a0736716 Mesh storage and reading in child objects for dupligroups.
The layout of the Alembic files resembles the DNA structure in Blender:
- On the top level (under the top/root node) there are Abc::Objects for
  Blender ID datablocks (currently Object and Group)
- Objects store final data (DerivedMesh) and later simulation results
  etc.
- Groups store their full duplilists for instancing. Currently there is
  no recursive nesting of groups, since this would limit duplis to
  dupligroups and exclude e.g. duplifaces.

On reading the duplilist gets reconstructed and stored in the DupliCache
for a duplicator empty (the group instance). DerivedMesh data is stored
in a hash table for each instanciated object and can later replace
finalDM in drawing and rendering.
2015-03-16 11:13:26 +01:00
be4c8e6645 Simplification of the archive init functions in writers and readers.
Now the base types for readers/writers are not nominally forming the
interface any more (they may be removed entirely later). This makes
possible a cleaner init method directly in the Abc Writer/Reader
classes.

Further work may be required in this area.
2015-03-16 09:43:27 +01:00
7677f393b4 Moved the dupli cache reading code into a AbcDupligroupReader class.
This is more in line with how readers work in the Blender Alembic
implementation elsewhere.

Generally, readers are less persistent than writers: they are created
whenever cache results need to be updated (e.g. on frame changes) and
discarded afterward. Writers OTOH stay alive during the whole baking
job, since they keep the references to Alembic Writer instances and can
only be deleted once the writing for that part is done.
2015-03-14 17:39:57 +01:00
b6b1eb5cbf Store and apply dupli object transforms in the Alembic cache.
Note that the cache stores dupli matrices without the final parent
transform, since it only knows about the group itself. The duplicator
obmat is applied to the duplis after reading the cache.
2015-03-14 15:58:02 +01:00
ae87d1f50d Handle dupli cache on object copy and freeing. 2015-03-14 15:04:47 +01:00
06ebb145ae Updated cache reading function for the new duplilist structure.
Now we store duplilists entirely inside a single alembic object for the
group. This allows using all the generated duplis, which would be
difficult if the alembic file had to define all the possible recursive
dupli relations that Blender allows, beside straightforward Group duplis.
2015-03-14 14:41:08 +01:00
ed75af586e Merge branch 'master' into alembic_pointcache 2015-03-14 13:48:44 +01:00
dfdb657427 Use a nested Object writer to store the Object ID blocks used by dupli
lists.
2015-03-13 18:04:23 +01:00
3910ff3a50 Better dupligroup Alembic writer.
Uses the duplilist generated by Blender to define instances, instead of
recreating the group layout. This omits some information about actual
structure of the DNA, which might be useful later on. The main problem
is that the duplilist itself does not encode this, so it's a tradeoff
between either including the Group structure or omitting the other
dupli types, like face, vertex, particle duplis.
2015-03-13 17:34:24 +01:00
b26ca84a82 Alternative dupli generator function for creating duplis in a group
without a specific parent.
2015-03-13 16:40:50 +01:00
2f1429a648 Some disabled code to enable automatic cache updates on every duplilist
creation call.

This is executed *a lot* (even for simple things such as viewport
panning), so the code is probably not suitable in this form. At least
it could do a frame comparison to avoid unnecessary updates.
2015-03-12 18:03:41 +01:00
d71489b095 Use a cached group only when a CacheLibrary is actually available.
Otherwise the regular duplilist generator is used.
2015-03-12 17:54:13 +01:00
7945354567 Replace usage of the procedural duplilist generation by cached duplilist. 2015-03-12 17:05:00 +01:00
d75dcf88d2 Store object pointers for the dupli objects we generate from caches.
This is necessary for the current viewport drawing and rendering code,
which expected each dupli instance to represent a copy of data in the
DNA.

The code maps base-level objects in the cache to DNA Objects inside the
dupligroup by name. Only objects that can be found in the blend data
will be allowed for DupliObjects.
2015-03-12 16:40:18 +01:00
36be233e27 Moved the DupliCache struct into DNA, it will be needed for drawing and
RNA access later.
2015-03-12 15:55:11 +01:00
91c263f492 Simple operator to force rebuilding of a dupligroup cache.
This is a placeholder for proper depsgraph integration. Eventually frame
changes and some other updates should rebuild dupligroup caches
automatically using the depsgraph. Until then this operator is a quick
way to test the IO from caches and the further drawing and rendering
(TODO).
2015-03-12 12:22:21 +01:00
2b02c0b650 Cache reading functions for constructing a nested dupligroup list based
on Alembic cache data.
2015-03-12 12:21:12 +01:00
26b788e9bd Include mesh writers in the cache writers list. 2015-03-11 16:22:27 +01:00
a45805ed2f Removed unused code. 2015-03-11 16:21:44 +01:00
a7706b3642 Removed current implementation of cache reading from various parts of
BKE (DerivedMesh, particles, cloth).

The new cache implementation will be used for constructing dupli data
instead, bypassing the complexities of the modifier stack.
2015-03-11 13:59:29 +01:00
e46dd19911 Merge branch 'master' into alembic_pointcache 2015-03-11 13:31:59 +01:00
511d8a98c5 Initial code to support dupli group instancing and overrides through
Alembic caches.

This creates representations (Abc::Object) for Blender Object and Group
datablocks in the Alembic files and uses Alembic instancing to define
the dupligroup hierarchy. This leads to a relatively flat hierarchy in
Alembic files:

Top -> Object/Group -> DerivedMesh/Particles/Hair/Cloth/Smoke/...

The dupligroup structure can not be represented by a hierarchical
structure such as the Alembic object nesting, because of the
many-to-many relationship between objects and groups (a group can
contain multiple objects, multiple objects can instance the same group).
Instead we use the instancing feature of Alembic to represent
dupligroups. This is created in 2 stages to ensure all the main ID
blocks have been serialized before creating references.
2015-03-11 12:46:33 +01:00
0a71eea5f1 Nicer info printing support for instances in Alembic files.
This now avoids repetition of internal instance structure.
2015-03-11 12:43:46 +01:00
a48d2e605c Fix for invalid ob->data access in case non-mesh objects are in the
cached group.
2015-03-11 11:42:49 +01:00
91f6635e09 Improved edge attribute caching.
Now edges should be fully restored from cache, fixing edge display.
2015-03-09 17:42:01 +01:00
b1bb3f8c82 Omit hair path lengths for anything but the first sample.
We can safely assume that paths don't change their lengths. This might
safe some cache space.
2015-03-09 17:40:50 +01:00
3e16951ec6 Fix for particle pathcache caching: have to check the psys->renderdata
pointer to figure out if we are evaluating with render settings.
2015-03-09 15:51:59 +01:00
3bd45d384b Fix for some archive checks to make sure we don't access invalid data.
This can happen if the archive file cannot be opened for some reason.
2015-03-09 12:52:51 +01:00
1a9706ceae Implementation of MDeformVert customdata layers in Alembic. 2015-03-09 12:35:27 +01:00
5f62c931d1 Fix for name collisions in compound properties when writing CustomData.
This is not clearly documented for Alembic, but apparently properties
inside compounds still need to be name uniquely for the whole object.
This is somewhat involved for Blender's CustomData, because we have
5 different customdata elements for meshes (vert, edge, face, poly,
loop) and each of these can have the same types and multiple layers of
the same type ...
2015-03-09 12:32:54 +01:00
16d259c842 Fix for Alembic info printer printing to std::cout instead of the
internal stringstream.
2015-03-09 11:35:21 +01:00
4f5f03115b Fix for potential size issue: need 64 bits for CustomDataMask types. 2015-03-09 10:38:20 +01:00
38342e444a Nicer error handling for unimplemented CustomData layer types.
Instead of failing an assert, simply print an error message and return
gracefully. We don't want Blender crashing because of this.
2015-03-09 09:57:26 +01:00
6d67e67022 Ugly hack for caching code to deal with quirky modifier stack behavior.
CustomData layers are pruned by the CDDM_copy function when they have
CD_FLAG_NOCOPY set. This is based on later modifiers in the stack, which
can specify that they require certain data layers - but the caching
modifier itself should store only what is needed by later modifiers.
It means we cannot easily keep a full copy of the DM in the cache
modifier to writing into caches later.

For now the hackish solution is to temporarily disable NOCOPY flags when
copying the DM. This is really not nice and needs a better solution.
2015-03-09 09:44:40 +01:00
5bd80e9d2c Support CD_ORIGSPACE layer caching.
This is needed by particles for distributions on meshes with changed
topology (which is of course broken).
2015-03-09 09:42:29 +01:00
752e396fcc Tessface customdata for derived mesh caching. 2015-03-07 19:04:24 +01:00
4e0b7d2f18 Support for CustomData in Alembic caches.
This is a skeleton feature that provides a general way of storing
CustomData types. Currently only ORIGINDEX layers are implemented, the
code is designed to make extension easy.

Storing CustomData layers in Alembic is a bit involved because the
complex structs often used as customdata need to be de-interleaved for
Alembic into a set of POD (plain-old-datatype) array properties.

In addition the property names should be unique, so that mapping abc
properties back to customdata layers is safe. This works by using 2
levels of compound properties: the first level stored per CD type
properties, with a number of properties for each layer of this type,
using either a name or index (for unnamed layers). The internal
properties can then in turn be compounds, if structs need to be
serialized into PODs.

Abc property readers/writers are created dynamically for the CustomData
compounds. This is necessary because we don't know in advance what kind
of data layers a DerivedMesh or other CD user will have, and this can
change each frame in theory. Alembic is easier with state data schemes,
but using it this way is possible (if somewhat cumbersome).
2015-03-07 17:56:47 +01:00
fe840e6365 Fix for cache item filtering: items can be part of the cache library
but disabled, in that case hide them as well.
2015-03-06 18:02:09 +01:00
8cc679b8d6 Fixed test for "render" eval mode for hair dynamics.
This is totally weird and convoluted, no idea if correct.
2015-03-05 17:46:17 +01:00
a4f853ed6e Removed the DM writer/reader from hair dynamics again, this is part of
the particle stuff and does not work.
2015-03-05 17:45:44 +01:00
f555bb8c61 Archive Info operator for Cache Library archives.
This creates a string with information about all the objects and
properties contained within a (Alembic) archive, used by a cache
library.

The operator has 3 modes of presenting the info string:
- stdout, ie. printing to the terminal
- popup window (not very useful usually due to size limits and lack of
  scrolling)
- clipboard copy
2015-03-05 16:31:21 +01:00
ea601a4814 Use a combined class for hair dynamics for cloth and mesh data.
Particles store a copy of the DM internally as the emitter.
2015-03-05 16:31:21 +01:00
367278e1b5 Alembic: Fixes for linux buildbot and scons 2015-03-05 17:11:51 +05:00
ca4735a485 Depsgraph tagging function for cached objects.
This is necessary to trigger object data updates for indirectly linked
objects, which would otherwise not be evaluated.
2015-03-04 19:14:48 +01:00
8cc176c14d Convenience feature: When linking a cache library, always default it to
'read' mode locally.

Linking a cache library is meant to be used for getting existing cache
data into a file.
2015-03-04 18:30:10 +01:00
9edeff8a04 Left a comment in DerivedMesh.c explaining why the caching system has
to use the cumbersome cachedm pointer instead of virtual modifiers.
2015-03-04 18:29:15 +01:00
47afa53913 Use a dedicated input_dm pointer in the cache modifier to provide a mesh
result read from the cache.

Mixing this with the output_dm used for writing leads to undefined
situations where the DM was released but should actually be passed on.
2015-03-04 18:01:32 +01:00
5a86b97991 Use correct flag enums for checking render/viewport eval mode when
writing derived mesh caches.
2015-03-04 17:59:48 +01:00
5dc9f664d0 Fix for meaningless build error (no return value, can never happen). 2015-03-04 16:13:46 +01:00
a7e2ab42df Minor fix for UI code showing cache items. 2015-03-04 13:34:29 +01:00
bb2e8ee262 Render/Viewport evaluation mode for cache libraries.
This designates a cache library to be used either for the viewport or
for renders. A "Render" cache library will evaluate modifiers with
render settings and a "Viewport" cache library will use viewport
(realtime) settings.

When reading the cache, the library will only be
used for the assigned purpose, i.e. a Render cache does not work for
viewport caching and vice-versa (although a cache can be baked for one
setting and then switched afterward).

Note that render results will never be visible in the realtime viewport
due to the way object evaluation is handled in Blender at this point
(render settings are only evaluated explicitly during renderer sync).
2015-03-04 12:50:46 +01:00
dd1cbab715 Allow the cache bake operator to overwrite existing files, using a
confirm dialog.
2015-03-03 18:45:32 +01:00
5c15fc8021 Removed now-unused util_path files from the pointcache lib.
Paths are constructed outside this module now. A valid absolute path
should always be provided through the API calls.
2015-03-03 17:41:54 +01:00
0798382397 Record and display the last result of cache reading in the cache library
items.
2015-03-03 17:30:41 +01:00
4e0c2b4e4e Free readers properly after applying cached data. 2015-03-03 16:29:57 +01:00
806a276f30 Set reader/writer archive as a separate step outside the constructors.
This allows nicer creation of readers/writers //before// actually
opening the archive. This in turns can simplify code quite a bit.
2015-03-03 16:01:09 +01:00
a597d07011 Moved functions for constructing readers/writers based on cache library
out of pointcache into blenkernel.

This is quite simple and repetitive and there is not need to have this
in the main pointcache/Alembic API. The code is mostly concerned with
logic of DNA data, so pointcache shouldn't have to deal with it.
2015-03-03 13:57:15 +01:00
56d2ad98b4 Ported archive filename constructor from pointcache library to BKE.
The pointcache library is now pretty much independent from ID blocks and
should not be responsible for handling file paths. The path construction
is also fairly straightforward now compared to the old point cache
system, with only basic conversion of relative to absolute paths for
loading archive files.
2015-03-03 12:54:27 +01:00
24c6137d46 Cache read result enum in DNA mirroring the internal pointcache results.
This can be stored in cache library items as an indicator of cache
reading state.
2015-03-03 12:30:11 +01:00
33060f829a Use a uiTemplate function for showing cache library items instead of
python code to unify symbols.

This is necessary because the operator for adding new items (as opposed
to the enable/disable button) cannot be shown with the same checkbox
button. The UI template function can display a custom button for the
operator, so the look becomes less confusing.
2015-03-03 12:01:27 +01:00
1a9c74a3a8 Nicer default filename for cache library paths.
This now appends a default extension based on the cache backend used.
At this point this is always Alembic (.abc) but would allow other
backend formats in the future.
2015-03-02 18:17:02 +01:00
800299008a Improved filtering for cache library content.
In addition to the object name filtering, items in cache library groups
can now be filtered by type as well.

Existing items in the cache are always displayed, so as to not hide
important information (what gets stored in the cache). The filtering
is primarily a utility to simplify searching inside the group for things
that should be added to the cache.
2015-03-02 14:44:56 +01:00
b3f4814a56 Use a generator in the python code to iterate over all the potential
cache library items.

This should ideally happen on the RNA side, but making the equivalent of
python generators in the RNA is really difficult.
2015-03-02 13:00:53 +01:00
489a7cb7b7 Don't show mesh cache items for non-mesh objects. 2015-03-02 12:31:24 +01:00
814624ced9 Disabled collection properties for 'virtual' cache items in RNA.
This requires a better design and is not so easy to implement properly
within the limits of RNA definition. These collections don't physically
exist in the DNA, they are mainly utilities for looping over
//potential// items in a cache library. For now the python code has to
be adapted to only show valid items, until the RNA provides a good
solution.
2015-03-02 12:28:04 +01:00
26119375cc Generic validation function to help ensure that we don't add meaningless
items to a cache library.
2015-03-02 12:10:51 +01:00
a83a61b03b Replaced use of the HDF5 Alembic backend by Ogawa.
Ogawa is replacing HDF5 as the new de-facto standard. Selecting either
should be more formalized and a user option, for now it's just hardcoded.
2015-02-28 15:52:22 +01:00
901eae21d0 Filter utility for finding objects in a cache group faster.
This is a preliminary feature and implemented purely in python, to be
replaced later.
2015-02-27 17:28:57 +01:00
91aaf8df00 New 'read' flag to toggle reading of the CacheLibrary as a whole.
This is also used during the bake process to avoid confusion: The read
flag gets disabled for the baking cachelib, so that objects don't try
to read cache data that is supposed to be generated.
2015-02-27 17:07:42 +01:00
a26eecf2a1 Delete operator for cache library datablocks.
CacheLibrary datablock has a generic unlink function now, but currently
nothing actually links to cache libs themselves, so it's empty. Still
good to keep this in mind for the future.
2015-02-27 16:22:19 +01:00
7c991a601a Reader/Writer API functions for basic particles.
Also slightly renamed pathcache functions for consistency (use plural
'particles' instead of 'particle').
2015-02-27 15:33:15 +01:00
4e5ee121af Removed deprecated and unused alembic API functions.
These are now implemented as virtual functions in the Factor class.
2015-02-27 15:32:27 +01:00
08b3ba5ecf Fixes for scons build files. 2015-02-27 11:41:54 +01:00
9e2e24a1d0 Fix for circular linker dependency with cache code library.
The `bf_pointcache_alembic` code is a separate library, to avoid
muddling up core code with alembic includes and preprocessor defines.
Alembic stuff only belongs strictly into alembic code and can be
disabled cleanly.

The `bf_pointcache` and `bf_pointcache_alembic` libraries had a circular
dependency, because the alembic implementation functions were called
directly. Now there is a "Factory" class to abstract the creation of
concrete implementations for readers and writers.
`bf_pointcache_alembic` defines this factory and is registered
//outside// of the core `bf_pointcache` lib, so there is no linker
circularity.
2015-02-27 10:53:45 +01:00
97a4905d37 Removed unused thread mutex file from pointcache lib. 2015-02-27 09:38:24 +01:00
15d3314611 Removed deprecated rna_pointcache.c file.
Scons was still compilling this, since it's source files are not
explicit.
2015-02-27 09:26:08 +01:00
cce6123911 Fix for indirectly linked object pointers in cache libraries.
These must be made "extern" to avoid losing links on loading.
2015-02-26 17:14:46 +01:00
7f442aa4b1 Removed remaining 1 frame difference in archive storage.
This was an artifact from the previous way of mapping non-0 start frame
to time 0.0. Now we start at times > 0.0 to match with the start frame.
Both ways are possible, can be changed later if needed.
2015-02-26 15:50:39 +01:00
5fa7283f86 Fixed start frame mapping in Alembic archives.
Writers were always starting at time 0.0, which means that for start
frames > 1 the readers would always be off. Now match the writer start
frame to the actual Blender start frame.
2015-02-26 15:24:29 +01:00
8a2e1b5c16 Added poll function for the cache manager panel to prevent hiding in
Cycles render engine.

The "compat_engines" thingy really gets in the way here ...
2015-02-26 14:18:48 +01:00
a7178954bf Cache reading for particle paths. 2015-02-26 14:05:49 +01:00
4b7500353a Fix for cache modifier linking and handling of the default case (no
cachd modifier).
2015-02-26 13:42:24 +01:00
58375c6f38 Changed implementation of the Cache modifier to work in tandem with the
cache library system.

The Cache modifier is now an optional "break point" of the modifier
stack:
- Without a cache modifier the stack works as before. Baking will write
  the final stack result. After baking the cache replaces the whole
  stack.
- With a cache modifier the stack result at the modifier's position is
  stored. The cache is then applied as the output of that modifier,
  skipping preceding modifiers. That way additional modifiers can be
  applied on top of the cache.
- When using multiple cache modifiers, only the last (active) one will
  be used, since all previous cache results would be discarded anyway.
2015-02-26 11:50:56 +01:00
29c0a6b435 Replaced point cache in cloth modifiers (also hair) with the new caching
system.
2015-02-26 09:43:33 +01:00
48c1a8a1d1 'expand' function for cache libraries, so link/append makes it load the
group and objects too.
2015-02-25 17:17:05 +01:00
928aab7b4e Make cache libraries a linkable data block. 2015-02-25 17:03:50 +01:00
4d8c66ddc1 Take NULL object pointers in cache items into account.
This can happen if an object gets deleted or isn't loaded for some
reason. The item should just be ignored in that case and removed at the
next opportunity (cleanup function).
2015-02-25 16:59:51 +01:00
1c20be94bc When using the "new cache library" operator, enable fake user by
default.

Nothing actually links to a cache library at this point (and probably
won't in the future), so fake user is necessary to avoid losing data.
2015-02-25 16:36:03 +01:00
240768ec7c Display cache library name and fake user button, imitating template_ID. 2015-02-25 16:33:47 +01:00
05e93c0b7f Importing of caches into Blender data.
Currently only implemented for DerivedMesh.
This replaces the `final_dm` calculation of the modifier stack with the
result from cache loading.
2015-02-25 16:24:22 +01:00
424bc7f3eb UI fixes, draw bake operator button only once at the top. 2015-02-25 12:04:28 +01:00
034b281f96 Hair path writer needs 2 different variants for parent/child hairs. 2015-02-25 11:58:19 +01:00
7a89dd778b Added writers for derived mesh result and hair paths. 2015-02-25 11:08:42 +01:00
205879263a Use explicit name strings for all readers/writers in the cache instead
of constructing names internally.

This helps prevent name collisions and guarantees a consistent naming
scheme for putting multiple items in the same cache.
2015-02-25 10:31:20 +01:00
0de4284c33 New reader/writer for DerivedMesh.
Used as a base for existing PointCacheModifier classes, but can be used
on its own.
2015-02-25 10:15:29 +01:00
79b7817af3 General support for export to/import from Alembic files based on Cache
Libraries.
2015-02-24 20:54:21 +01:00
b2a8b366eb Deleted unimplemented parts of the previous pointcache system, to make
refactoring simpler.

Since the new approach is not tied to the old set of point cache data
types there is really no need to carry their empty husks around. Once
the new caching system is defined in detail we can add back whatever
makes sense.
2015-02-24 18:39:03 +01:00
43a89c3e93 Disabled specialized Point Cache modifier handling in the modifier
stack, this will be replaced and is not correct anyway.
2015-02-24 18:37:45 +01:00
b29d9de7ad Refactoring of archive handling in readers/writers.
Now instead of each reader/writer creating its own archive, the archive
is created by the caller in advance and passed as a constructor
argument. This means that multiple items can be stored together in the
same archive.
2015-02-24 18:25:15 +01:00
517c95e723 Removed unused Scene pointer from the base Reader/Writer classes. 2015-02-24 15:43:10 +01:00
2dc88a3715 Operator skeleton for a cache bake operator, using the job system. 2015-02-24 15:10:36 +01:00
5f4bde826b Fix for undefined return value. 2015-02-24 12:47:09 +01:00
fca2eddf22 Merge branch 'master' into alembic_pointcache
Conflicts:
	source/blender/makesrna/intern/rna_main_api.c
2015-02-24 12:14:04 +01:00
a2006f37b2 Removed unused line. 2015-02-24 12:11:50 +01:00
59727c736a Unlink and cleanup functions when objects or the cached group get
unlinked or changed.
2015-02-24 12:10:27 +01:00
d0a9f20257 Make sure cache item pointers are lib-linked correctly. 2015-02-24 11:47:26 +01:00
386415509e Name string construction for cache items, to use as a unique identifier
in the cache library.
2015-02-24 11:34:44 +01:00
4f2ab75bd4 Draw some UI buttons for all the current cache item types. 2015-02-24 09:51:45 +01:00
212210b7ee Updated hash table for lookup of enabled cache items and added basic
UI support.
2015-02-23 19:24:53 +01:00
d88cd0765c Improved collections in RNA for looping over potential caching items
in the object group.
2015-02-23 18:07:21 +01:00
4716a87636 Define a collection of "object_caches" in the CacheLibrary RNA for
iterating over all objects eligible for caching in the group.

This allows for nested dupligroup instances as well. All objects that
are instantiated at least once by any group can be included in the
respective cache, but get represented only once because the cached data
is the same anyway.
2015-02-23 14:04:30 +01:00
7a462c3e35 Link main CacheLibrary pointers in readfile. 2015-02-23 14:03:46 +01:00
06338dbefd Simplified cache item path description, based on plain ID blocks with
subtype/index.

This omits possible instancing and recursion by dupli groups, but since
the data of instances is always the same in Blender at this point, there
is little need to take them into account for caching.

At some point in the future it may become desirable to store full dupli
hierarchies in the cache, but it doesn't make sense to try to design a
fully-fledged path descriptor for this hypothetical case now.
2015-02-21 13:19:41 +01:00
861e553f1d BKE functions for managing cache content based on a group.
This uses a complete hierarchy of group instances, based on a path
hierarchy (object names).

Putting
2015-02-21 12:28:51 +01:00
a7f5d1d662 Simple cache manager panel UI in the scene buttons.
This is mostly a simple and unintrusive placeholder to have some way of
making caches accessible, but needs some more thought.
2015-02-20 16:27:26 +01:00
7b16850073 Group pointer property for cache libraries to associate them with an
object group.

This is somewhat experimental, eventually we may want to link to Objects
instead, or allow multiple cache targets for the same cache, etc.
2015-02-20 16:26:24 +01:00
0e2ae9007b Missing include. 2015-02-20 16:01:25 +01:00
ba2a3efddb Removed meaningless comment. 2015-02-20 15:15:42 +01:00
1be812f426 New operator for adding cache libraries.
Conflicts:
	release/scripts/startup/bl_ui/properties_physics_common.py
	source/blender/blenkernel/BKE_pointcache.h
	source/blender/blenkernel/intern/pointcache.c
	source/blender/editors/physics/physics_ops.c
	source/blender/editors/physics/physics_pointcache.c
2015-02-20 15:08:59 +01:00
90ce1a3e8f New ID datablock 'CacheLibrary', for managing physical cache archives
and files.

At it's core this is just a file path, but many different cache users
may refer to this, so having a dedicated ID block helps. It can be
compared to Image datablocks, which also primarily are used for data
on storage, but can be packed with the blend file, and carry some
additional information that would be cumbersome to keep sync'ed
otherwise.

The name 'CacheLibrary' deliberately resembles the 'Library' datablock:
just as a Library stores ID blocks in a physical file, a CacheLibrary
stores cached data (in Alembic HDF5/Ogawa or other formats).

Conflicts:
	source/blender/blenkernel/BKE_pointcache.h
	source/blender/blenkernel/intern/pointcache.c
	source/blender/makesdna/DNA_pointcache_types.h
2015-02-20 14:36:51 +01:00
a7747a3e0c Fix for remaining PointCache references in the alembic code.
Now, for the time being, uses a simple relative "//blendcache/" folder
path again. This will be adressed later.
2015-02-20 13:56:13 +01:00
940c17af81 Big revert of all things pointcache, old code is impossible to work with.
The Alembic caching must be integrated with Blender as a new, entirely
independent feature. The old pointcache code can not be surgically
removed without major damage to vital features. Instead of wasting more
time trying to deal with an outdated complicated system, a better choice
is implementing a new caching system next to it and if possible phase
out the old one at some point ...
2015-02-19 20:40:34 +01:00
39a39a1474 Merge branch 'master' into alembic_pointcache 2015-02-19 18:54:16 +01:00
b66c1f538e Removed unused DNA field. 2015-02-19 17:16:00 +01:00
fe04d8b176 Use the cache library to construct cache file paths instead of the
relative point cache paths.
2015-02-19 17:05:15 +01:00
31d41d9b20 Use cache as a relative folder path for storing caches by default. 2015-02-19 14:12:11 +01:00
c3459108a3 Display UI for cache library inside the point cache UI. 2015-02-19 14:07:55 +01:00
b8b9788158 New operator for adding cache libraries. 2015-02-19 13:49:28 +01:00
eae8bb4c8d Use a cache library pointer in point caches to replace the per-object
path construction.
2015-02-19 13:10:54 +01:00
7d89274d14 Fix for cache panel display: the is_baked flag has been removed and
should not be used to disable cache UI any longer.
2015-02-19 13:09:33 +01:00
dc882a008c New ID datablock 'CacheLibrary', for managing physical cache archives
and files.

At it's core this is just a file path, but many different cache users
may refer to this, so having a dedicated ID block helps. It can be
compared to Image datablocks, which also primarily are used for data
on storage, but can be packed with the blend file, and carry some
additional information that would be cumbersome to keep sync'ed
otherwise.

The name 'CacheLibrary' deliberately resembles the 'Library' datablock:
just as a Library stores ID blocks in a physical file, a CacheLibrary
stores cached data (in Alembic HDF5/Ogawa or other formats).
2015-02-19 11:01:49 +01:00
2366663ebb Removed unused (and broken) functions for getting the number of written
cache samples.

This can be done more reliably using Alembic schemas.
2015-02-17 17:47:45 +01:00
617ce27ffc Merge branch 'master' into alembic_pointcache 2015-02-17 15:51:14 +01:00
3fb8d5a99a Optimization for particle path cache reading.
The pathcache data structure is really not very good. Using pointers to
small per-particle arrays leads to fragmentation and unnecessary pointer
indirection. With the new optimizations walking over this buffer is a
bit faster, but still not close to how fast Alembic could deliver the
data.
2015-02-17 14:27:12 +01:00
deeb09a5cb Sanity checks for Alembic archive validity to avoid crashes when trying
an invalid file operation (e.g. overwriting files).
2015-02-17 13:40:00 +01:00
1309ca51fa Alembic caching support for particle paths.
This hooks into the particle path update functions and reads cache data
if available instead of constructing expensive child paths every time.

Currently the cache grows quite rapidly due to lack of optimized sample
storage: constant values such as numer of segments, times, colors etc
only need to be stored in the first sample. "Velocities" (actually
position deltas) could also be calculated on-the-fly, which is
relatively cheap compared to full child calculation. In any case, disk
space it cheap ...
2015-02-17 12:44:26 +01:00
12d4db406d Fix for constructing cache reader/writer based on RNA pointer.
Because of the awkward internal cloth modifier inside the particle
system, we have to look at the psys to determine if we actually want to
use the particle system cache or the internal cloth modifier cache.
2015-02-16 19:12:34 +01:00
f464829daf Sanity NULL check when freeing caches. 2015-02-16 18:40:36 +01:00
ca94528d71 Merge branch 'master' into alembic_pointcache 2015-02-16 18:28:47 +01:00
8072c476b4 Use a default handler for printing Alembic errors in case no explicit
error handler is used, to avoid silent failure.
2015-02-13 17:55:13 +01:00
f4f7ab735b Sanity check when trying to write cloth cache, the cloth data may not
actually exist.
2015-02-13 17:18:51 +01:00
cee1ea5533 Use a realistic time scale for cloth sim. 2015-02-13 17:18:34 +01:00
e7bdd29192 Return a boolean value indicating success when getting the frame range
of a cache.

Also the default cache range is return in case no archive exists.
2015-02-13 17:16:47 +01:00
7d6779f88e Removed unused code. 2015-02-13 14:47:17 +01:00
567b10dc16 Use new point cache API in the cloth modifier.
Currently broken.
2015-02-12 19:36:15 +01:00
304e5a440a Cleanup: replaced the convoluted BKE_ptcache_id_clear function with
specific variants for clearing and truncating the cache frame range.

CLEAR_BEFORE is not used anywhere (it doesn't make much sense anyway).
CLEAR_FRAME is just a special version for deleting a single frame and
only used internally prior to replacing a cache frame.
2015-02-12 17:43:52 +01:00
40a8ef5ef0 Merge branch 'master' into alembic_pointcache
Conflicts:
	source/blender/blenkernel/intern/cloth.c
2015-02-12 16:37:28 +01:00
4edbd9586f Removed unused function. 2015-02-12 16:21:02 +01:00
5d9db8192d Read/Write implementation for cloth/hair data in alembic files.
This data is very simple, just deform positions, velocities and goal
positions. Future cloth might become more complex, but for now a plain
Abc::Point schema is sufficient.
2015-02-12 15:55:20 +01:00
d3ef995912 Store a custom context pointer "cache_user" for point cache operators,
so that all point caches can use the export feature.

This was enabled only for particles. There is a lot of weird unexplained
code with special cases all over the place - unified point cache should
be possible in the end, but currently it's still a mess.
2015-02-12 15:46:12 +01:00
743ee837b0 Separation of the main point cache API from the Alembic implementation.
Even though we probably will use only the Alembic backend in the
foreseeable future, it is still good design to have a bit of abstraction
in this place and not directly call Alembic functions.
2015-02-12 13:42:13 +01:00
036d4fc3e0 Merge branch 'master' into alembic_pointcache
Conflicts:
	source/blender/blenloader/intern/versioning_270.c
2015-02-12 10:26:43 +01:00
a4644c3605 Cleanup: Use enums where appropriate instead of #defines. 2015-02-10 17:56:56 +01:00
e89fd502d7 Merge branch 'master' into alembic_pointcache
Conflicts:
	CMakeLists.txt
	build_files/build_environment/install_deps.sh
	source/blender/blenkernel/CMakeLists.txt
	source/blender/blenkernel/SConscript
	source/blender/blenkernel/intern/particle.c
	source/blender/blenkernel/intern/pointcache.c
	source/blender/editors/physics/particle_edit.c
	source/blender/editors/space_outliner/outliner_draw.c
	source/blender/makesdna/DNA_modifier_types.h
	source/blender/makesrna/SConscript
	source/blender/makesrna/intern/CMakeLists.txt
	source/blender/makesrna/intern/SConscript
	source/blender/makesrna/intern/rna_modifier.c
	source/blender/makesrna/intern/rna_object_force.c
	source/blender/modifiers/MOD_modifiertypes.h
	source/blender/modifiers/intern/MOD_util.c
	source/blender/render/intern/source/voxeldata.c
2015-02-10 17:09:00 +01:00
6cd3ebfc9f Merge branch 'master' into alembic_pointcache
Conflicts:
	release/scripts/addons
	source/blender/blenkernel/intern/pointcache.c
	source/blender/blenloader/intern/versioning_270.c
	source/blender/editors/space_outliner/outliner_draw.c
	source/blender/makesdna/DNA_modifier_types.h
	source/blender/makesrna/intern/rna_modifier.c
	source/blender/modifiers/MOD_modifiertypes.h
	source/blender/modifiers/intern/MOD_collision.c
	source/blender/modifiers/intern/MOD_util.c
2015-01-16 12:50:11 +01:00
97a50e78ca Merge branch 'master' into alembic_pointcache
Conflicts:
	CMakeLists.txt
	source/blender/blenkernel/intern/rigidbody.c
	source/blender/makesrna/intern/rna_object_force.c
2014-11-17 14:59:25 +01:00
8f4d98283d Only poly and vertex normals are mandatory for a valid normals, loop
normals may not exist.

Note: Currently we cannot create poly normals explicitly from a modifier,
they have to be recalculated every time ...
2014-11-13 12:52:24 +01:00
a920b652f9 Basic profiling code for the mesh cache reader function. 2014-11-13 12:03:30 +01:00
e2e0a529d9 Normals storage support in Alembic mesh caches.
This is not strictly necessary, but removes another step in mesh
reconstruction that might take significant time in extreme cases.

All 3 normal attributes (loop, poly, vertex normals) need to be stored
for successful reconstruction, otherwise they have to be recalculated.
2014-11-13 11:39:45 +01:00
943691814c Fix for edge properties in Alembic files, was missing edge indices in
MLoops.
2014-11-13 09:50:39 +01:00
534760173b Keep track of the error status of readers and writers with a maximum
error level to test for validity.
2014-11-12 18:49:41 +01:00
cdfe06bf51 Store an error handler inside readers and writers.
This is a lot more convenient to use and removes the burden of setting
the desired error handlers from the point cache user. The readers/writers
already know about context (e.g. a modifier) and can define an
appropriate error handler.
2014-11-12 18:36:03 +01:00
74afc56120 Better error handling support for point cache functions.
This defines wrapper macros which catch exceptions from Alembic and
provide ways of reporting these in different ways, depending on the
context.
2014-11-12 18:00:59 +01:00
6fac43eb87 Merge branch 'master' into alembic_pointcache 2014-11-12 13:30:38 +01:00
f9b3d1c900 Merge branch 'master' into alembic_pointcache 2014-11-12 12:36:20 +01:00
f306805ba2 Split mesh reconstruction from Alembic into separate functions like with
the writer.
2014-11-12 12:35:01 +01:00
721806fa76 Nicer code structure for writing Alembic mesh samples, using smaller
functions for individual data properties.
2014-11-12 11:50:44 +01:00
8d2b7e552f Store edge topology explicitly in Alembic files as a user property.
This is not a native part of the core Alembic mesh schema, but can be
defined simply as a custom property.

Two advantages:
* Loose edges without faces are stored in the Alembic files and restored
on loading
* Building edges on the fly after loading topology from the cache was
the biggest bottleneck for cache performance.
2014-11-11 18:16:50 +01:00
501aae3aef Keep a permanent cache reader instance in the point cache modifier and
handle explicit mode switching between reading/writing.
2014-11-11 09:41:41 +01:00
66689345f0 Removed unused frame value code. 2014-11-07 12:36:02 +01:00
8c6ca4499e Added a custom mesh attribute for polygon "smooth" flags on meshes. 2014-11-07 12:07:16 +01:00
9df9ee568a Additional sanity checks needed in the cache reader because accessing
non-existent child objects when reading Alembic can cause crash.

This should be generalized somewhat later to ensure consistency between
different reader models.
2014-11-04 18:00:30 +01:00
4b2fbebc27 Support for writing derived mesh data from point cache modifier between
other modifiers.

Previously this was simply using the derivedFinal of the object. Now
the point cache has its own writer instance which is writing samples
during the regular modifier evaluation, rather than directly being
called by the bake operator.
2014-11-04 16:27:48 +01:00
e6f9f593f6 Merge branch 'master' into alembic_pointcache 2014-11-04 13:50:13 +01:00
5a48a83663 Integration of point caching into the modifier stack.
This ensures that the modifier stack is disabled up to the last valid
cache modifier. This cache modifier then provides a derived mesh as
input for the remaining modifier stack tail, or as final output if no
other modifiers follow.
2014-11-04 13:46:52 +01:00
c334b2862d Fix scons linking of Alembic and HDF5 and additiona Ilmbase/OpenEXR libraries. 2014-11-04 11:16:10 +01:00
c1343ab498 Some changes to the Alembic build script for specifying the install
prefix and build type.

Alembic build files are still horrible, have to find a reliable solution
for that.
2014-11-04 10:19:21 +01:00
8e97a13d3d Reverted changes to the Mesh Cache modifier, this functionality is now
being implemented in the new Point Cache modifier instead.
2014-11-04 09:43:09 +01:00
dd1f70ffb5 Introduced a new modifier "Point Cache" for recording cache data at
user-defined points in the modifier stack.

These will replace the preliminary test changes in the mesh cache
modifier.
2014-11-04 09:08:20 +01:00
45e4ef57dc Moved C API functions for individual data types into their respective
files to simplify the code structure.
2014-11-03 14:05:31 +01:00
21577a64f6 Partial scons build files for pointcache library and Alembic
dependencies.

This is not yet functional, the Alembic linking is quite tricky.
2014-10-21 20:31:15 +02:00
e45e593c35 Support for topology changes by making the mesh cache modifier into a
constructive modifier.

Warning! this may well break with the deform-only file types (MDD and
PC2), so it needs careful review before considering trunk merge. In any
case, this is just a test for Alembic import.
2014-10-17 17:01:52 +02:00
6ac889f2b3 Alembic reading in the Mesh Cache modifier.
Note that this only works with deformation atm.
2014-10-17 15:09:05 +02:00
c118d3d739 Implemented basic OPolyMesh Alembic writing.
Only includes vertex positions and poly loops for now. The standard
mesh schema in Alembic includes also UV layers and some other standard
data, but all the necessary Blender custom data layers can be stored in
these files as well.
2014-10-17 11:10:51 +02:00
aa8e249136 Writer/Reader classes for the mesh cache modifier. 2014-10-16 19:17:33 +02:00
a281b69bd2 Dummy point cache instance in the mesh cache modifier, as a test bed for
mesh data export/import.
2014-10-16 18:40:35 +02:00
a5b549bc63 Fix for changed function signature in freestyle code. 2014-10-16 18:39:52 +02:00
f3b9f0c619 Extra check for cache user info when running the generic point cache
export operator.
2014-10-16 18:39:05 +02:00
f065d25653 A couple of fixes for changed Blender functions and the new
EvaluationContext needed for evaluating the scene during baking.
2014-10-16 16:42:40 +02:00
0da2707387 Linux library linking is now in a cmake macro file. 2014-10-16 16:42:09 +02:00
c5dc9b60ca Include Alembic build arguments in BUILD_INFO.txt. 2014-10-16 16:41:20 +02:00
9ba99ebd95 Install Alembic in $INST path directly, use the subfolder created by
Alembic build files themselves.
2014-10-16 16:40:21 +02:00
f237f67a99 Alembic support in the install_deps.sh script.
This is a rough-and-ready way of building and installing the Alembic
library and the necessary dependencies (excluding as much as possible
for now). The Alembic cmake files are very badly constructed and require
some annoying hacks atm. Eventually we might try to supply them with
patches or write our own build scripts for Alembic.
2014-10-16 15:49:00 +02:00
ba90765050 Merge branch 'master' into pointcache
Conflicts:
	release/scripts/startup/bl_ui/properties_physics_common.py
	source/blender/blenkernel/BKE_blender.h
	source/blender/blenkernel/BKE_object.h
	source/blender/blenkernel/BKE_pointcache.h
	source/blender/blenkernel/intern/object.c
	source/blender/blenkernel/intern/particle.c
	source/blender/blenkernel/intern/particle_system.c
	source/blender/blenkernel/intern/pointcache.c
	source/blender/blenkernel/intern/rigidbody.c
	source/blender/blenkernel/intern/smoke.c
	source/blender/blenloader/intern/readfile.c
	source/blender/blenloader/intern/versioning_legacy.c
	source/blender/editors/physics/particle_edit.c
	source/blender/editors/physics/physics_pointcache.c
	source/blender/makesrna/intern/CMakeLists.txt
	source/blender/makesrna/intern/rna_fluidsim.c
	source/blender/modifiers/intern/MOD_cloth.c
	source/blender/modifiers/intern/MOD_collision.c
	source/blender/modifiers/intern/MOD_particleinstance.c
	source/blender/render/intern/source/pipeline.c
	source/blender/windowmanager/WM_api.h
	source/creator/CMakeLists.txt
2014-10-14 17:44:36 +02:00
df5cfbdc47 Let the smoke cache work on a smoke domain rather than the smoke
modifier data. This is a bit cleaner, it avoids referring to modifiers
which are a separate concern and will probably be replaced as the
container for smoke data at some point anyway.
2014-01-10 11:56:35 +01:00
cb82ec10bd Remaining RNA type mappings to pointcache readers/writers. 2014-01-10 11:55:48 +01:00
775a1287f5 Skeleton files for all remaining point cache user types, so we can start
replacing the old point cache entirely.
2013-12-08 10:32:37 +01:00
2f5ef128b9 Moved object/modifier/sim resets out of the BKE_ptcache_id_reset
function. This is a design cleanup, the point cache methods should only
write to the DNA when retrieving state data. There were already a number
of cases where such resets occured outside of this function (such as
with rigid body worlds or smoke sims).

The BKE_ptcache_object_reset function still exists and includes these
reset calls, but there the cache user data types are accessed directly.
2013-12-08 09:02:47 +01:00
44057bdffb Added XXX comment about the BAKING flag, left it in for now to not lose
track of the purpose.
2013-12-08 09:02:47 +01:00
de604e1b6e Removed the BAKED flag from point cache state. The cached now has a new
flag LOCK_SETTINGS instead, which should indicate more clearly that it
is about preventing cache modification by disabling user settings
changes.

The cache should not have to care about this setting in the first place.
It becomes increasingly difficult to control changed simulation settings
anyway (scripting!), and the cache should not even try to exert control
over sims this way. Eventually this flag should be a feature of
simulations and modifiers, using it as a 3rd option beside
enabled/disabled and using only existing cached data.
2013-12-08 09:02:47 +01:00
8aa35aa014 Removed the SIMULATION_VALID flag entirely. This was only used by the
bake operators.
2013-12-08 09:02:47 +01:00
6789e32e1d Completely removed the "bake" operators for point cache. This feature
will get a complete replacement, removing it altogether makes this much
easier.
2013-12-08 09:02:47 +01:00
bea5cec25e Marked the PTC_STATE_SIMULATION_VALID flag as deprecated. This is only
used by the bake operator, but keeping track of the sync state of cache
data vs. simulation settings needs to be radically simplified.

The API should provide a way of detecting whether a valid simulation
state can be obtained for a certain frame.

  /* check if a frame can be read from the cache (no data is modified) */
  PTCReadSampleResult PTC_test_sample(struct PTCReader *reader, float frame);
  /* try to obtain a cache sample and write to DNA data */
  PTCReadSampleResult PTC_read_sample(struct PTCReader *reader, float frame);

Beyond that the cache should be oblivious of the simulation state. When
settings or dependencies are changed which invalidate the simulation
cache state this should invalidate all cache samples (or possible a
certain frame range), but the cache itself should not need to keep track
of the simulation as a whole.
2013-12-08 09:02:47 +01:00
b69a448531 Build the archive filename inside the base Reader/Writer constructor
from info in the PointCache. This way we can replace it more flexibly
with other data streams, packed files, memory buffers etc.
2013-12-08 09:02:46 +01:00
47e2f7cf99 Make the archive file name construction based on PointCache settings
internal to the path utility function.
2013-12-08 09:02:46 +01:00
13f3b8ebdb Partial cleanup of the point cache UI panel, using a number of booleans
to store all the stupifying special cases. Not complete and will need
a general overhaul anyway ...
2013-12-08 09:02:46 +01:00
a12f3d1e86 Removed or disabled remaining BKE_pointcache calls in particle_system.
Only DNA read(!) access to PointCache is allowed (otherwise would have
to wrap all the flag checks etc., this could be done later still).

Particle edit mode uses a lot of badly designed point cache DNA writing,
so for now is disabled (or broken).
2013-12-08 09:02:46 +01:00
6ac4add2cc Moved remaining state variables of the PointCache DNA struct into the
PointCacheState struct.
2013-12-08 09:02:46 +01:00
642b27fed1 Unused function parameter. 2013-12-08 09:02:46 +01:00
af02fe2d2f Cleanup and restructuring: New 'state' struct in PointCache of type
PointCacheState, which holds all the non-user-defined state variables
for baking and validity. This has its own flags, so the state flags are
conceptually separated from the user-defined options.

The old flags are still in the DNA for backward compatibility mapping,
with an underscore prefix and _DEPRECATED suffix so they are not used
accidentally and name collision is avoided.
2013-12-08 09:02:46 +01:00
001930bda0 Moved the compression enum items for point cache into a true enum
typedef instead of using #defines.
2013-12-08 09:02:19 +01:00
2a66bf8acb 'READ_OLD' cache return value translates to READ_CACHE_EARLY now,
meaning the requested frame/time value is before the first valid sample.
2013-12-08 09:02:19 +01:00
c5d3303faf Basic point cache reading for particles.
This currently requires exporting the Alembic archive. The automatic
caching is not yet implemented and may require some changes to account
for the sequential write limitations in Alembic and do some stitching
of old/new cache files.

Error handling is also rudimentary atm, the reader ErrorHandler::Policy
is just verbose printing atm. This happens a lot during export.
2013-12-08 09:02:19 +01:00
17bbbf1843 Removed the types.h file, not used and doesn't have a clear purpose. 2013-12-08 09:02:19 +01:00
74aec79e0a Utility class for mapping Blender frames to a generic time scale.
This is used by writers and readers to convert frame numbers into time
values for the Alembic time sampling methods.
2013-12-08 09:02:18 +01:00
117f4c7d0e Store the scene pointer directly in reader/writer base class. This is
required for a variety of uses, mostly related to fps calculation atm.
2013-12-08 09:02:18 +01:00
dfc42af50b Utility function PTC::Reader for getting the stored frame range.
The way this works is currently not ideal, it takes the start/end times
used by Alembic and then multiplies by the scene fps to convert into
frames. It might be better to use the sample numbers directly, but
we cannot associate these directly to frames so far.
2013-12-08 09:02:18 +01:00
4acd9ac0a4 Removed unused PTC elements from the blenkernel BKE_pointcache header.
All new point cache stuff is in its own pointcache folder to keep it
clean.
2013-12-08 09:02:18 +01:00
9c247486aa Removed deprecated DNA data.
This will break forward compatibility, but this is broken either way,
there's no way we can smoothly convert new point cache data into the old
format without considerable effort. It's just a few settings for cache
behavior anyway, no valuable user work getting lost.
2013-12-08 09:02:18 +01:00
acb4e9fe2f Made the PTCACHE_DISK_CACHE flag deprecated and removed all uses. This
is assumed to be TRUE always, all caches are disk-based now, which
removes a lot of complexity from constant double-checking. Eventually
disk caches can be integrated into .blend files, but this will be a
secondary feature instead of an alternative format for caches, so we
don't have to implement every function in 2 different ways.
2013-12-08 09:02:18 +01:00
3497e27bb2 Removed a few unused variables. 2013-12-08 09:02:18 +01:00
67655f2a7f Removed remaining pointcache->mem_cache access in particles. Instead the
particle system should now use its own local mem_cache list for storing
cache data in memory. The actual PointCache struct does not make this
distinction any more.

Eventually the particle system should have clean methods for reading
cache data into other structures for editing and displaying cache data,
but this can not be cleaned up easily without major refactoring. For now
the important thing is to keep psys away from the PointCache internals
so we can implement a nice API for it without psys interfering.
2013-12-08 09:02:18 +01:00
f4cf45dd0b Replaced the mem_cache pointer in PointCache by a custom ListBase in
ParticleSystem PTCacheEdit for the particle edit mode. This is probably
broken like hell, but need to get rid of this for a clean point cache
API. Have to come back to particle edit mode later once we have proper
point cache in place.
2013-12-08 09:02:18 +01:00
9061ac3d99 Pass ListBase mem_cache as an explicit argument to the point cache
conversion methods. This will no longer be stored in the PointCache
DNA struct (all caches are disk based now).

ParticleSystem stores this as a separate list now, so it can keep using
it in edit mode and for trails drawing.
2013-12-08 09:02:18 +01:00
a148ec6191 Removed the disk/memory toggle for point cache. 2013-12-08 09:02:17 +01:00
9e10e191c8 Removed mem_cache access in pointcache.c, i.e. assume that the
PTCACHE_DISK_CACHE flag is always set.
2013-12-08 09:02:17 +01:00
011b6e5b18 Disabled readfile/writefile code for memory point cache. In future all
caches will be assumed to be disk caches, with the option of packing
them into .blend files.
2013-12-08 09:02:17 +01:00
8cc7969925 In preparation for removing the point cache memory frame storage, set
all point caches to 'unbaked' to enfore rebaking.
2013-12-08 09:02:17 +01:00
5852d77fe7 Removed the PTC_test_archive function, was just some initial testing
code for alembic API.
2013-12-08 09:01:15 +01:00
75c6a496e9 Removed ptcache list code in readfile.c. This was intended to provide
some forward compatibility, but it's just not feasible to support this
nicely, so better accept breaking forward compat and don't touch this
DNA any more (keep code simple).
2013-12-08 09:01:15 +01:00
aae656f9a3 Removed ListBase code for multiple point caches from blenkernel and RNA. 2013-12-08 09:01:15 +01:00
72c6fe9b8c Changed point cache writefile function to only write the point cache
struct, ptcaches lists are deprecated.
2013-12-08 09:01:15 +01:00
b2d6e736ea Removed the ptcache ListBase linking in readfile. Only the single
point_cache pointers are used now, which conveniently are already the
active point caches, so we can just ignore the lists (setting them to
the same pointer though to avoid potential problems with forward
compatibility).
2013-12-08 09:01:15 +01:00
b633ea4854 Point cache index 1 in smoke domain is not used. 2013-12-08 09:01:15 +01:00
ff0296184c Revert "Comment on smoke caches is deprecated."
Thought this was referring to the ptcaches ListBase, but actually means
the point_cache array, so i still important.

This reverts commit 8f48294bd00b61bae93f375dc0a730cac7fb594e.
2013-12-08 09:01:15 +01:00
a91f8543c7 Adapted bpath point cache traversal macro to single PointCache pointers. 2013-12-08 09:01:15 +01:00
9c05df76ad Comment on smoke caches is deprecated. 2013-12-08 09:01:14 +01:00
761248fa05 Made all point cache DNA members relating to cache lists DNA_DEPRECATED.
This includes the ListBase ptcaches members in all the users as well as
the next/prev pointers in the PointCache struct.
2013-12-08 09:01:14 +01:00
7c732da27b Moved the new point cache settings DNA data into the existing PointCache
struct. Adding new DNA data alongside the existing structs leads to
a lot of name conflicts, better try to stay within existing structs and
gradually extend/replace struct members.
2013-12-08 09:01:14 +01:00
523ff63a82 Correct time sampling for Blender frames: The cycle time is 1.0 by
default, this needs to be 1/fps. The default frame sampling can be added
by writers, Alembic will only create this sampling once internally.
2013-12-08 09:01:14 +01:00
290fe64048 Take the global G.is_break flag into account for stopping the point
cache export job.
2013-12-08 09:01:14 +01:00
42c0fdc276 Disabled UNDO for the export operator, it doesn't make sense anyway.
Cache files are external outside the undo system and can not simply be
restored.
2013-12-08 09:01:14 +01:00
039a1e76ee Set the G.is_rendering flag and lock editor drawing during export.
This is a terribly hack which is necessary to prevent draw methods
accessing the same data that is written by the export job.
2013-12-08 09:01:14 +01:00
fe303b7294 Keep a reference to the stop, do_update and progress variables from
the export job in the exporter class, so the exporter can communicate
back to the main thread. This could be done nicer, but is ok for now.
2013-12-08 09:01:14 +01:00
527e8ce74d Make sure the output directory for cache files exists before trying
to create the Alembic OArchive, otherwise HDF5 throws an exception.
2013-12-08 09:01:13 +01:00
3d01d027a0 New settings struct for poin caches (unused still). 2013-12-08 09:01:13 +01:00
2f1554c176 Added a new DNA file DNA_pointcache_types.h for all point cache related
structs and enum values. DNA_object_force.h was use previously, this is
a badly named file with a hodgepodge of different areas.
2013-12-08 09:01:13 +01:00
98b67f1d97 Added new operator for point cache 'Export'. This is basically the same as baking, naming may have to be adjusted later, for now they just exist side-by-side. 2013-12-08 09:01:13 +01:00
db237d837a Exporter class to handle baking of point cache data over a frame range. This uses a mutex and cancel flag to make it work in the job system. 2013-12-08 09:01:13 +01:00
a33c9d2a24 Added boost includes and a thread utility file for mutex and locking. 2013-12-08 09:01:13 +01:00
1ffe06d066 Incomplete dummy function for baking. 2013-12-08 09:01:13 +01:00
704ec0da44 Removed the writer_create/reader_create callbacks in PTCacheID, will focus on baking first and see about overhauling the API later. 2013-12-08 09:01:13 +01:00
1d7bd0c5b2 Removed unused Scene argument from reader/writer api functions. 2013-12-08 09:01:12 +01:00
4774c1f076 Use the path utility functions for generating the filename inside the new point cache, instead of using the blenkernel code. 2013-12-08 09:01:12 +01:00
156a5f15b2 Utility functions for setting the cache path. Same procedure as in classic pointcache, can be improved later. 2013-12-08 09:01:12 +01:00
c1411359a9 Added reader constructor function for PTCacheID, but disabled reader/writer in DNA for now, this needs consideration. 2013-12-08 09:01:12 +01:00
7859dde7fe Basic reader class. 2013-12-08 09:01:12 +01:00
7b0b538a78 More info in the persistent alembic storage. Now use Writer/Reader structs in PointCache instead of plain Archive. The writer is constructed on write calls currently, because the basic point cache creation function doesn't provide necessary parameters. This will get replaced eventually, for now just testing the alembic code. 2013-12-08 09:01:12 +01:00
684ad4f91e Some directory reorganization and a bunch of other stuff ... 2013-12-08 09:01:12 +01:00
34f8a87ca5 Use a dummy struct type PTCArchive instead of a plain void pointer. 2013-12-08 09:01:12 +01:00
f956ff1fab Create an OArchive internally for writing out point cache. 2013-12-08 09:01:12 +01:00
453eccc1c8 Pass cache and object arguments to ptcache_path directly instead of the PTCacheID. This allows using the function for the alembic archive name as well, where we don't construct the cache id struct. Also added a few sanity checks to avoid potential NULL pointer access. 2013-12-08 09:01:11 +01:00
66bfa1e35c Store an untyped archive pointer in the DNA PointCache struct. This is used to store an alembic archive which constitutes the point cache output. 2013-12-08 09:01:11 +01:00
e60715b9f1 Optional HDF5 support. This is not directly linked by Alembic, so Blender has to link hdf5 itself if desired. 2013-12-08 09:01:11 +01:00
201f43e2ff Fix for Alembic find script to link all the necessary allembic libs. 2013-12-08 09:01:11 +01:00
715a9b9ee3 Use a #define to mark old point cache code in the RNA. Even thoug it will have to be kept enabled for now, this makes it easier to identify the old stuff and remove it later. 2013-12-08 09:01:11 +01:00
5f6d8f2bc0 Moved old point cache RNA from rna_object_force to rna_pointcache. This will make it easier to replace it with the new implementation while avoiding name conflicts. 2013-12-08 09:01:11 +01:00
e223de3f37 RNA function for defining point cache API. 2013-12-08 09:01:11 +01:00
5a014df0fc Set the WITH_ALEMBIC define in subfolders that actually use it, follows the pattern in other libs. 2013-12-08 09:01:11 +01:00
f038524278 Some test code for defining a particles schema, based on I/OPointsSchema of alembic. 2013-12-08 09:01:11 +01:00
d95d8b0928 Add WITH_ALEMBIC as a cmake option and set a WITH_ALEMBIC define to use in C code. 2013-12-08 09:01:11 +01:00
1fe78b1378 Library linking for Alembic. 2013-12-08 09:01:11 +01:00
fe781f7e4d Very basic sub-folder structure for new pointcache implementation. 2013-12-08 09:01:11 +01:00
126 changed files with 10689 additions and 138 deletions

View File

@@ -275,6 +275,10 @@ option(WITH_MOD_REMESH "Enable Remesh Modifier" ON)
# mark_as_advanced(WITH_MOD_CLOTH_ELTOPO)
option(WITH_MOD_OCEANSIM "Enable Ocean Modifier" OFF)
# Alembic
option(WITH_ALEMBIC "Enable Alembic Support" OFF)
option(WITH_HDF5 "Enable HDF5 Support for Alembic" OFF)
# Image format support
option(WITH_OPENIMAGEIO "Enable OpenImageIO Support (http://www.openimageio.org)" ON)
option(WITH_IMAGE_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" ${_init_IMAGE_OPENEXR})
@@ -637,17 +641,23 @@ if(NOT WITH_BOOST)
set_and_warn(WITH_CYCLES OFF)
set_and_warn(WITH_AUDASPACE OFF)
set_and_warn(WITH_ALEMBIC OFF)
set_and_warn(WITH_INTERNATIONAL OFF)
set_and_warn(WITH_OPENAL OFF) # depends on AUDASPACE
set_and_warn(WITH_GAMEENGINE OFF) # depends on AUDASPACE
elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL)
elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_ALEMBIC OR WITH_INTERNATIONAL)
# Keep enabled
else()
# Enabled but we don't need it
set(WITH_BOOST OFF)
endif()
# disable hdf5 if Alembic is disabled
if(NOT WITH_ALEMBIC)
set(WITH_HDF5 OFF)
endif()
# auto enable openimageio for cycles
if(WITH_CYCLES)
set(WITH_OPENIMAGEIO ON)
@@ -1129,6 +1139,15 @@ if(UNIX AND NOT APPLE)
set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/source/creator/blender.map")
endif()
if(WITH_ALEMBIC)
find_package_wrapper(Alembic)
set(ALEMBIC_LIBRARIES ${ALEMBIC_LIBRARIES} ${BOOST_LIBRARIES})
endif()
if(WITH_HDF5)
find_package_wrapper(HDF5)
endif()
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
list(APPEND PLATFORM_LINKLIBS -lutil -lc -lm)
@@ -2196,6 +2215,12 @@ if(WITH_CYCLES)
endif()
endif()
if(WITH_ALEMBIC)
if(NOT WITH_BOOST)
message(FATAL_ERROR "Alembic requires WITH_BOOST, the library may not have been found. Configure BOOST or disable WITH_ALEMBIC")
endif()
endif()
if(WITH_INTERNATIONAL)
if(NOT WITH_BOOST)
message(FATAL_ERROR "Internationalization requires WITH_BOOST, the library may not have been found. Configure BOOST or disable WITH_INTERNATIONAL")

View File

@@ -95,6 +95,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--with-opencollada
Build and install the OpenCOLLADA libraries.
--with-alembic
Build and install the Alembic library.
--ver-ocio=<ver>
Force version of OCIO library.
@@ -144,6 +147,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--force-ffmpeg
Force the rebuild of FFMpeg.
--force-alembic
Force the rebuild of Alembic.
Note about the --force-foo options:
* They obviously only have an effect if those libraries are built by this script
(i.e. if there is no available and satisfactory package)!
@@ -180,6 +186,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--skip-ffmpeg
Unconditionally skip FFMpeg installation/building.
--skip-alembic
Unconditionally skip Alembic installation/building.
--required-numpy
Use this in case your distro features a valid python package, but no matching Numpy one.
It will force compilation of both python and numpy\""
@@ -264,6 +273,11 @@ MP3LAME_DEV=""
OPENJPEG_USE=false
OPENJPEG_DEV=""
ALEMBIC_VERSION="1.5.5"
ALEMBIC_VERSION_MIN="1.5.5"
ALEMBIC_FORCE_REBUILD=false
ALEMBIC_SKIP=false
# Switch to english language, else some things (like check_package_DEB()) won't work!
LANG_BACK=$LANG
LANG=""
@@ -423,6 +437,9 @@ while true; do
--force-ffmpeg)
FFMPEG_FORCE_REBUILD=true; shift; continue
;;
--force-alembic)
ALEMBIC_FORCE_REBUILD=true; shift; continue
;;
--skip-python)
PYTHON_SKIP=true; shift; continue
;;
@@ -453,6 +470,9 @@ while true; do
--skip-ffmpeg)
FFMPEG_SKIP=true; shift; continue
;;
--skip-alembic)
ALEMBIC_SKIP=true; shift; continue
;;
--required-numpy)
NUMPY_REQUIRED=true; shift; continue
;;
@@ -513,6 +533,9 @@ OPENCOLLADA_SOURCE=( "https://github.com/KhronosGroup/OpenCOLLADA.git" )
OPENCOLLADA_REPO_UID="18da7f4109a8eafaa290a33f5550501cc4c8bae8"
FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
ALEMBIC_SOURCE=( "https://code.google.com/p/alembic/" )
ALEMBIC_REPO_UID=( "1_05_05" )
##### Generic Helpers #####
@@ -839,6 +862,7 @@ compile_Boost() {
# Rebuild dependecies as well!
OIIO_FORCE_REBUILD=true
OSL_FORCE_REBUILD=true
ALEMBIC_FORCE_REBUILD=true
prepare_opt
@@ -1706,6 +1730,165 @@ compile_FFmpeg() {
fi
}
#### Build ALEMBIC ####
_init_alembic() {
_src=$SRC/Alembic-$ALEMBIC_VERSION
_hg=false
_inst=$INST/alembic-$ALEMBIC_VERSION
_inst_shortcut=$INST/alembic
}
clean_alembic() {
_init_alembic
_clean
}
compile_alembic() {
# To be changed each time we make edits that would modify the compiled result!
alembic_magic=1
_init_alembic
# Clean install if needed!
magic_compile_check alembic-$ALEMBIC_VERSION $alembic_magic
if [ $? -eq 1 -o $ALEMBIC_FORCE_REBUILD == true ]; then
clean_alembic
fi
if [ ! -d $_inst ]; then
INFO "Building Alembic-$ALEMBIC_VERSION"
prepare_opt
if [ ! -d $_src ]; then
mkdir -p $SRC
hg clone -u $ALEMBIC_REPO_UID $ALEMBIC_SOURCE $_src
fi
cd $_src
# XXX Ugly patching hack!
# Alembice cmake files are erratic, to say the least
# have to manually disable a bunch of crap here
cat << EOF | patch -p1
--- a/CMakeLists.txt Mon Jul 28 10:09:21 2014 -0700
+++ b/CMakeLists.txt Thu Oct 16 15:03:27 2014 +0200
@@ -57,9 +57,9 @@
${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} )
SET( VERSION ${PROJECT_VERSION} )
-SET( ALEMBIC_NO_TESTS FALSE )
-SET( ALEMBIC_NO_BOOTSTRAP FALSE )
-SET( ALEMBIC_NO_OPENGL FALSE )
+SET( ALEMBIC_NO_TESTS TRUE )
+SET( ALEMBIC_NO_BOOTSTRAP TRUE )
+SET( ALEMBIC_NO_OPENGL TRUE )
MESSAGE(STATUS "CMAKE SYSTEM NAME = ${CMAKE_SYSTEM_NAME}" )
@@ -306,15 +306,15 @@
ENDIF()
# Include PyAlembic stuff
-IF(DEFINED USE_PYALEMBIC AND NOT USE_PYALEMBIC)
- MESSAGE(STATUS "Skipping Alembic Python bindings")
-ELSE()
- MESSAGE(STATUS "About to include Python cmake files")
- ADD_SUBDIRECTORY( python )
-ENDIF()
+#IF(DEFINED USE_PYALEMBIC AND NOT USE_PYALEMBIC)
+# MESSAGE(STATUS "Skipping Alembic Python bindings")
+#ELSE()
+# MESSAGE(STATUS "About to include Python cmake files")
+# ADD_SUBDIRECTORY( python )
+#ENDIF()
# Example code not supported
-ADD_SUBDIRECTORY( examples )
+#ADD_SUBDIRECTORY( examples )
# Uncomment to build python docs Makefile (requires Sphinx)
# Run `make docs` from build root
EOF
cat << EOF | patch -p1
--- a/lib/Alembic/Util/CMakeLists.txt Mon Jul 28 10:09:21 2014 -0700
+++ b/lib/Alembic/Util/CMakeLists.txt Thu Oct 16 15:03:27 2014 +0200
@@ -65,7 +65,7 @@
DESTINATION include/Alembic/Util
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ )
-IF( NOT ALEMBIC_NO_TESTS )
- ADD_SUBDIRECTORY( Tests )
-ENDIF()
+#IF( NOT ALEMBIC_NO_TESTS )
+# ADD_SUBDIRECTORY( Tests )
+#ENDIF()
EOF
cat << EOF | patch -p1
--- a/python/CMakeLists.txt Mon Jul 28 10:09:21 2014 -0700
+++ b/python/CMakeLists.txt Thu Oct 16 14:20:25 2014 +0200
@@ -35,4 +35,4 @@
ADD_SUBDIRECTORY( PyAlembic )
ADD_SUBDIRECTORY( PyAbcOpenGL )
-ADD_SUBDIRECTORY( examples )
+#ADD_SUBDIRECTORY( examples )
EOF
# Always refresh the whole build!
# XXX 'build' directory is included in Alembic sources, don't touch that
if [ -d blender_build ]; then
rm -rf blender_build
fi
mkdir blender_build
cd blender_build
# XXX Alembic cmake doesn't take these as options
# XXX Alembic creates a subfolder itself ... rather than fix their
# stupid build files, just expect this here by using $INST as prefix
export ALEMBIC_INSTALL_PREFIX=$INST
cmake_d="-D CMAKE_BUILD_TYPE=Release"
cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$INST"
cmake_d="$cmake_d -D BUILD_SHARED_LIBS=ON"
cmake_d="$cmake_d -D BUILD_STATIC_LIBS=ON"
cmake_d="$cmake_d -D USE_PYTHON=OFF"
cmake_d="$cmake_d -D USE_PYALEMBIC=OFF"
cmake_d="$cmakd_d -D ALEMBIC_PYTHON_INCLUDE_DIR=/use/include/python2.7" # XXX BAD
cmake_d="$cmakd_d -D ALEMBIC_PYTHON_LIBRARY=/use/lib/python2.7" # XXX BAD
cmake_d="$cmake_d -D USE_PYILMBASE=OFF"
cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr"
cmake_d="$cmake_d -D ALEMBIC_ILMBASE_HALF_LIB=$INST/openexr/lib/libHalf.la"
cmake_d="$cmake_d -D ALEMBIC_ILMBASE_IEX_LIB=$INST/openexr/lib/libIex-2_1.la"
cmake_d="$cmake_d -D ALEMBIC_ILMBASE_ILMTHREAD_LIB=$INST/openexr/lib/libIlmThread-2_1.la"
cmake_d="$cmake_d -D ALEMBIC_ILMBASE_IMATH_LIB=$INST/openexr/lib/libImath-2_1.la"
cmake $cmake_d ../
make -j$THREADS && make install
make clean
if [ -d $_inst ]; then
_create_inst_shortcut
else
ERROR "Alembic-$ALEMBIC_VERSION failed to compile, exiting"
exit 1
fi
magic_compile_set alembic-$ALEMBIC_VERSION $alembic_magic
cd $CWD
INFO "Done compiling Alembic-$ALEMBIC_VERSION!"
else
INFO "Own Alembic-$ALEMBIC_VERSION is up to date, nothing to do!"
INFO "If you want to force rebuild of this lib, use the --force-alembic option."
fi
}
#### Install on DEB-like ####
get_package_version_DEB() {
@@ -1992,7 +2175,8 @@ install_DEB() {
if [ $? -eq 0 ]; then
install_packages_DEB libboost-locale$boost_version-dev libboost-filesystem$boost_version-dev \
libboost-regex$boost_version-dev libboost-system$boost_version-dev \
libboost-thread$boost_version-dev libboost-wave$boost_version-dev
libboost-thread$boost_version-dev libboost-python$boost_version-dev \
libboost-program-options$boost_version-dev libboost-wave$boost_version-dev
clean_Boost
else
compile_Boost
@@ -2125,6 +2309,14 @@ install_DEB() {
# fi
compile_FFmpeg
fi
if $ALEMBIC_SKIP; then
WARNING "Skipping Alembic installation, as requested..."
else
install_packages_DEB libhdf5-dev
install_packages_DEB libpython2.7-dev # XXX nasty hack, should be done better ...
compile_alembic
fi
}
@@ -3030,6 +3222,12 @@ print_info() {
fi
fi
if [ -d $INST/alembic ]; then
_1="-D ALEMBIC_ROOT_DIR=$INST/alembic"
PRINT " $_1"
_buildargs="$_buildargs $_1"
fi
PRINT ""
PRINT "Or even simpler, just run (in your blender-source dir):"
PRINT " make -j$THREADS BUILD_CMAKE_ARGS=\"$_buildargs\""
@@ -3099,6 +3297,13 @@ print_info() {
PRINT "BF_FFMPEG_LIB = 'avformat avcodec swscale avutil avdevice `print_info_ffmpeglink`'"
fi
if [ "$ALEMBIC_SKIP" = false ]; then
PRINT "WITH_BF_ALEMBIC = True"
if [ -d $INST/alembic ]; then
PRINT "BF_ALEMBIC = '$INST/alembic'"
fi
fi
if [ "$WITH_ALL" = false ]; then
PRINT "WITH_BF_3DMOUSE = False"
# No libspacenav in official arch repos...

View File

@@ -166,6 +166,19 @@ BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
# Ocean Simulation
WITH_BF_OCEANSIM = True
# Alembic
WITH_BF_HDF5 = False
WITH_BF_ALEMBIC = True
WITH_BF_STATICALEMBIC = True
BF_ALEMBIC = '/opt/lib/alembic'
BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
BF_ALEMBIC_LIBPATH = '${BF_ALEMBIC}/lib/static'
BF_ALEMBIC_LIB_STATIC = '${BF_ALEMBIC_LIBPATH}/libAlembicAbcGeom.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbc.a ' + \
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCollection.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreFactory.a ' + \
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcMaterial.a ' + \
'${BF_ALEMBIC_LIBPATH}/libAlembicOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreAbstract.a ' + \
'${BF_ALEMBIC_LIBPATH}/libAlembicUtil.a'
# Compilation and optimization
BF_DEBUG = False
REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++

View File

@@ -166,6 +166,19 @@ BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
# Ocean Simulation
WITH_BF_OCEANSIM = True
# Alembic
WITH_BF_HDF5 = False
WITH_BF_ALEMBIC = True
WITH_BF_STATICALEMBIC = True
BF_ALEMBIC = '/opt/lib/alembic'
BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
BF_ALEMBIC_LIBPATH = '${BF_ALEMBIC}/lib/static'
BF_ALEMBIC_LIB_STATIC = '${BF_ALEMBIC_LIBPATH}/libAlembicAbcGeom.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbc.a ' + \
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCollection.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreFactory.a ' + \
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcMaterial.a ' + \
'${BF_ALEMBIC_LIBPATH}/libAlembicOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreAbstract.a ' + \
'${BF_ALEMBIC_LIBPATH}/libAlembicUtil.a'
# Compilation and optimization
BF_DEBUG = False
REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++

View File

@@ -0,0 +1,84 @@
# - Find Alembic library
# Find the native Alembic includes and library
# This module defines
# ALEMBIC_INCLUDE_DIRS, where to find Alembic headers.
# ALEMBIC_LIBRARIES, libraries to link against to use Alembic.
# ALEMBIC_ROOT_DIR, The base directory to search for Alembic.
# This can also be an environment variable.
# ALEMBIC_FOUND, If false, do not try to use Alembic.
#=============================================================================
# Copyright 2013 Blender Foundation.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# If ALEMBIC_ROOT_DIR was defined in the environment, use it.
IF(NOT ALEMBIC_ROOT_DIR AND NOT $ENV{ALEMBIC_ROOT_DIR} STREQUAL "")
SET(ALEMBIC_ROOT_DIR $ENV{ALEMBIC_ROOT_DIR})
ENDIF()
SET(_alembic_SEARCH_DIRS
${ALEMBIC_ROOT_DIR}
/usr/local
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt/lib/alembic
)
SET(_alembic_FIND_COMPONENTS
AlembicAbc
AlembicAbcCoreAbstract
AlembicAbcGeom
AlembicAbcCoreHDF5
AlembicAbcCoreOgawa
AlembicOgawa
AlembicUtil
)
FIND_PATH(_alembic_INCLUDE_DIRS
NAMES
Alembic/Abc/All.h
HINTS
${_alembic_SEARCH_DIRS}
PATH_SUFFIXES
include
)
SET(_alembic_LIBRARIES)
FOREACH(COMPONENT ${_alembic_FIND_COMPONENTS})
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
FIND_LIBRARY(ALEMBIC_${UPPERCOMPONENT}_LIBRARY
NAMES
${COMPONENT}
HINTS
${_alembic_SEARCH_DIRS}
PATH_SUFFIXES
lib/static
)
MARK_AS_ADVANCED(ALEMBIC_${UPPERCOMPONENT}_LIBRARY)
LIST(APPEND _alembic_LIBRARIES "${ALEMBIC_${UPPERCOMPONENT}_LIBRARY}")
ENDFOREACH()
# handle the QUIETLY and REQUIRED arguments and set ALEMBIC_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Alembic DEFAULT_MSG
_alembic_LIBRARIES _alembic_INCLUDE_DIRS)
IF(ALEMBIC_FOUND)
SET(ALEMBIC_LIBRARIES ${_alembic_LIBRARIES})
SET(ALEMBIC_INCLUDE_DIRS ${_alembic_INCLUDE_DIRS})
ENDIF(ALEMBIC_FOUND)
MARK_AS_ADVANCED(
ALEMBIC_INCLUDE_DIRS
ALEMBIC_LIBRARIES
)

View File

@@ -0,0 +1,75 @@
# - Find HDF5 library
# Find the native hdf5 includes and library
# This module defines
# HDF5_INCLUDE_DIRS, where to find hdf5 headers.
# HDF5_LIBRARIES, libraries to link against to use hdf5.
# HDF5_ROOT_DIR, The base directory to search for hdf5.
# This can also be an environment variable.
# HDF5_FOUND, If false, do not try to use hdf5.
#=============================================================================
# Copyright 2013 Blender Foundation.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# If HDF5_ROOT_DIR was defined in the environment, use it.
IF(NOT HDF5_ROOT_DIR AND NOT $ENV{HDF5_ROOT_DIR} STREQUAL "")
SET(HDF5_ROOT_DIR $ENV{HDF5_ROOT_DIR})
ENDIF()
SET(_hdf5_SEARCH_DIRS
${HDF5_ROOT_DIR}
/usr/local
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt/lib/hdf5
)
SET(_hdf5_FIND_COMPONENTS
hdf5
hdf5_hl
)
FIND_PATH(_hdf5_INCLUDE_DIRS
NAMES
hdf5.h
HINTS
${_hdf5_SEARCH_DIRS}
)
SET(_hdf5_LIBRARIES)
FOREACH(COMPONENT ${_hdf5_FIND_COMPONENTS})
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
FIND_LIBRARY(HDF5_${UPPERCOMPONENT}_LIBRARY
NAMES
${COMPONENT}
HINTS
${_hdf5_SEARCH_DIRS}
)
MARK_AS_ADVANCED(HDF5_${UPPERCOMPONENT}_LIBRARY)
LIST(APPEND _hdf5_LIBRARIES "${HDF5_${UPPERCOMPONENT}_LIBRARY}")
ENDFOREACH()
# handle the QUIETLY and REQUIRED arguments and set HDF5_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(hdf5 DEFAULT_MSG
_hdf5_LIBRARIES _hdf5_INCLUDE_DIRS)
IF(HDF5_FOUND)
SET(HDF5_LIBRARIES ${_hdf5_LIBRARIES})
SET(HDF5_INCLUDE_DIRS ${_hdf5_INCLUDE_DIRS})
ENDIF(HDF5_FOUND)
MARK_AS_ADVANCED(
HDF5_INCLUDE_DIRS
HDF5_LIBRARIES
)

View File

@@ -421,6 +421,12 @@ macro(setup_liblinks
if(WITH_LLVM)
target_link_libraries(${target} ${LLVM_LIBRARY})
endif()
if(WITH_ALEMBIC)
target_link_libraries(${target} ${ALEMBIC_LIBRARIES})
endif()
if(WITH_HDF5)
target_link_libraries(${target} ${HDF5_LIBRARIES})
endif()
if(WIN32 AND NOT UNIX)
target_link_libraries(${target} ${PTHREADS_LIBRARIES})
endif()
@@ -560,6 +566,8 @@ macro(SETUP_BLENDER_SORTED_LIBS)
ge_videotex
bf_dna
bf_blenfont
bf_pointcache_alembic
bf_pointcache
bf_intern_audaspace
bf_intern_mikktspace
bf_intern_dualcon

View File

@@ -52,9 +52,9 @@ BF_OPENEXR = '/usr'
# BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include'
BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR'
BF_OPENEXR_LIB = 'Half IlmImf Iex Imath '
BF_OPENEXR_LIB = 'Half IlmImf-2_1 Iex-2_1 Imath-2_1 '
BF_OPENEXR_LIB_STATIC = '${BF_OPENEXR}/lib/libHalf.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_OPENEXR}/lib/libIex.a ${BF_OPENEXR}/lib/libImath.a ${BF_OPENEXR}/lib/libIlmThread.a'
# BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
WITH_BF_DDS = True
@@ -226,6 +226,19 @@ BF_3DMOUSE_LIB_STATIC = '${BF_3DMOUSE_LIBPATH}/libspnav.a'
#Freestyle
WITH_BF_FREESTYLE = True
# HDF5
WITH_BF_HDF5 = True
BF_HDF5 = '/usr'
BF_HDF5_LIB = 'hdf5 hdf5_hl'
BF_HDF5_LIBPATH='${BF_HDF5}/lib'
# Alembic
WITH_BF_ALEMBIC = True
BF_ALEMBIC = '/opt/lib/alembic'
BF_ALEMBIC_LIB = 'AlembicAbcGeom AlembicAbc AlembicAbcCollection AlembicAbcCoreFactory AlembicAbcCoreHDF5 AlembicAbcCoreAbstract AlembicAbcCoreOgawa AlembicAbcMaterial AlembicOgawa AlembicUtil'
BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
BF_ALEMBIC_LIBPATH='${BF_ALEMBIC}/lib/static'
##
CC = 'gcc'
CXX = 'g++'

View File

@@ -204,10 +204,20 @@ def setup_staticlibs(lenv):
libincs += Split(lenv['BF_OIIO_LIBPATH'])
if lenv['WITH_BF_STATICOIIO']:
statlibs += Split(lenv['BF_OIIO_LIB_STATIC'])
if lenv['WITH_BF_HDF5']:
libincs += Split(lenv['BF_HDF5_LIBPATH'])
if lenv['WITH_BF_ALEMBIC']:
libincs += Split(lenv['BF_ALEMBIC_LIBPATH'])
if lenv['WITH_BF_STATICALEMBIC']:
statlibs += Split(lenv['BF_ALEMBIC_LIB_STATIC'])
if lenv['WITH_BF_OPENEXR']:
libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
if lenv['WITH_BF_STATICOPENEXR']:
statlibs += Split(lenv['BF_OPENEXR_LIB_STATIC'])
if lenv['WITH_BF_ZLIB'] and lenv['WITH_BF_STATICZLIB']:
statlibs += Split(lenv['BF_ZLIB_LIB_STATIC'])
@@ -283,8 +293,16 @@ def setup_syslibs(lenv):
if not lenv['WITH_BF_STATICOCIO']:
syslibs += Split(lenv['BF_OCIO_LIB'])
if lenv['WITH_BF_HDF5']:
syslibs += Split(lenv['BF_HDF5_LIB'])
if lenv['WITH_BF_ALEMBIC']:
if not lenv['WITH_BF_STATICALEMBIC']:
syslibs += Split(lenv['BF_ALEMBIC_LIB'])
if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
syslibs += Split(lenv['BF_OPENEXR_LIB'])
if lenv['WITH_BF_ZLIB'] and not lenv['WITH_BF_STATICZLIB']:
syslibs += Split(lenv['BF_ZLIB_LIB'])
if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
@@ -372,7 +390,22 @@ def propose_priorities():
def creator(env):
sources = ['creator.c']# + Blender.buildinfo(env, "dynamic") + Blender.resources
incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', env['BF_OPENGL_INC']]
incs = ['#/intern/guardedalloc',
'#/source/blender/blenlib',
'#/source/blender/blenkernel',
'#/source/blender/editors/include',
'#/source/blender/blenloader',
'#/source/blender/imbuf',
'#/source/blender/renderconverter',
'#/source/blender/render/extern/include',
'#/source/blender/windowmanager',
'#/source/blender/makesdna',
'#/source/blender/makesrna',
'#/source/blender/pointcache',
'#/source/gameengine/BlenderRoutines',
'#/extern/glew/include',
'#/source/blender/gpu',
env['BF_OPENGL_INC']]
defs = []

View File

@@ -182,7 +182,8 @@ def validate_arguments(args, bc):
'WITH_BF_BOOST', 'WITH_BF_STATICBOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIB_INTERNATIONAL', 'BF_BOOST_LIB_STATIC', 'BF_BOOST_LIBPATH',
'WITH_BF_LIBMV', 'WITH_BF_LIBMV_SCHUR_SPECIALIZATIONS',
'WITH_BF_CYCLES_OSL', 'WITH_BF_STATICOSL', 'BF_OSL', 'BF_OSL_INC', 'BF_OSL_LIB', 'BF_OSL_LIBPATH', 'BF_OSL_LIB_STATIC', 'BF_OSL_COMPILER',
'WITH_BF_LLVM', 'WITH_BF_STATICLLVM', 'BF_LLVM', 'BF_LLVM_LIB', 'BF_LLVM_LIBPATH', 'BF_LLVM_LIB_STATIC', 'BF_PROGRAM_LINKFLAGS'
'WITH_BF_LLVM', 'WITH_BF_STATICLLVM', 'BF_LLVM', 'BF_LLVM_LIB', 'BF_LLVM_LIBPATH', 'BF_LLVM_LIB_STATIC', 'BF_PROGRAM_LINKFLAGS',
'WITH_BF_ALEMBIC', 'BF_ALEMBIC', 'BF_ALEMBIC_INC', 'BF_ALEMBIC_LIB', 'BF_ALEMBIC_LIBPATH',
]
# Have options here that scons expects to be lists
@@ -581,6 +582,19 @@ def read_opts(env, cfg, args):
(BoolVariable('WITH_BF_LIBMV_SCHUR_SPECIALIZATIONS', 'Enable fixed-size schur specializations', True)),
(BoolVariable('WITH_BF_COMPOSITOR', 'Enable the tile based nodal compositor', True)),
(BoolVariable('WITH_BF_HDF5', 'Use HDF5 if true', False)),
('BF_HDF5', 'HDF5 base path', ''),
('BF_HDF5_LIB', 'HDF5 library', ''),
('BF_HDF5_LIBPATH', 'HDF5 library path', ''),
(BoolVariable('WITH_BF_ALEMBIC', 'Use Alembic if true', False)),
(BoolVariable('WITH_BF_STATICALEMBIC', 'Staticly link to Alembic', False)),
('BF_ALEMBIC', 'Alembic base path', ''),
('BF_ALEMBIC_INC', 'Alembic include path', ''),
('BF_ALEMBIC_LIB', 'Alembic library', ''),
('BF_ALEMBIC_LIB_STATIC', 'Alembic static libraries', ''),
('BF_ALEMBIC_LIBPATH', 'Alembic library path', ''),
) # end of opts.AddOptions()
localopts.AddVariables(

View File

@@ -96,6 +96,12 @@ macro(cycles_target_link_libraries target)
${CMAKE_DL_LIBS}
${PLATFORM_LINKLIBS}
)
if(WITH_ALEMBIC)
target_link_libraries(
${target}
${ALEMBIC_LIBRARIES}
)
endif()
endmacro()
# Application build targets
@@ -106,6 +112,23 @@ if(WITH_CYCLES_STANDALONE)
cycles_xml.cpp
cycles_xml.h
)
if(WITH_ALEMBIC)
list(APPEND SRC
cycles_alembic.cpp
cycles_alembic.h
)
add_definitions(-DWITH_ALEMBIC)
include_directories(
SYSTEM
${ALEMBIC_INCLUDE_DIRS}
)
endif()
if(WITH_HDF5)
add_definitions(-DWITH_HDF5)
endif()
add_executable(cycles ${SRC})
cycles_target_link_libraries(cycles)

View File

@@ -0,0 +1,426 @@
/*
* Copyright 2015 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <Alembic/AbcCoreOgawa/ReadWrite.h>
#ifdef WITH_HDF5
#include <Alembic/AbcCoreHDF5/ReadWrite.h>
#endif
#include <Alembic/Abc/IArchive.h>
#include <Alembic/Abc/IObject.h>
#include <Alembic/Abc/ISampleSelector.h>
#include <Alembic/Abc/ICompoundProperty.h>
#include <Alembic/Abc/IScalarProperty.h>
#include <Alembic/Abc/IArrayProperty.h>
#include <Alembic/Abc/ArchiveInfo.h>
#include <Alembic/AbcGeom/IPolyMesh.h>
#include "camera.h"
#include "film.h"
#include "graph.h"
#include "integrator.h"
#include "light.h"
#include "mesh.h"
#include "nodes.h"
#include "object.h"
#include "shader.h"
#include "scene.h"
#include "subd_mesh.h"
#include "subd_patch.h"
#include "subd_split.h"
#include "util_debug.h"
#include "util_foreach.h"
#include "util_path.h"
#include "util_transform.h"
#include "util_xml.h"
#include "cycles_alembic.h"
CCL_NAMESPACE_BEGIN
using namespace Alembic;
using namespace Abc;
using namespace AbcGeom;
#define ABC_SAFE_CALL_BEGIN \
try {
#define ABC_SAFE_CALL_END \
} \
catch (Alembic::Util::Exception e) { \
printf("%s", e.what()); \
}
/* File */
static const std::string g_sep(";");
static void visitProperties(std::stringstream &ss, ICompoundProperty, std::string &);
template <class PROP>
static void visitSimpleArrayProperty(std::stringstream &ss, PROP iProp, const std::string &iIndent)
{
std::string ptype = "ArrayProperty ";
size_t asize = 0;
AbcA::ArraySamplePtr samp;
index_t maxSamples = iProp.getNumSamples();
for (index_t i = 0 ; i < maxSamples; ++i) {
iProp.get(samp, ISampleSelector( i ));
asize = samp->size();
};
std::string mdstring = "interpretation=";
mdstring += iProp.getMetaData().get("interpretation");
std::stringstream dtype;
dtype << "datatype=";
dtype << iProp.getDataType();
std::stringstream asizestr;
asizestr << ";arraysize=";
asizestr << asize;
mdstring += g_sep;
mdstring += dtype.str();
mdstring += asizestr.str();
ss << iIndent << " " << ptype << "name=" << iProp.getName()
<< g_sep << mdstring << g_sep << "numsamps="
<< iProp.getNumSamples() << std::endl;
}
template <class PROP>
static void visitSimpleScalarProperty(std::stringstream &ss, PROP iProp, const std::string &iIndent)
{
std::string ptype = "ScalarProperty ";
size_t asize = 0;
const AbcA::DataType &dt = iProp.getDataType();
const Alembic::Util ::uint8_t extent = dt.getExtent();
Alembic::Util::Dimensions dims(extent);
AbcA::ArraySamplePtr samp = AbcA::AllocateArraySample( dt, dims );
index_t maxSamples = iProp.getNumSamples();
for (index_t i = 0 ; i < maxSamples; ++i) {
iProp.get(const_cast<void*>(samp->getData()), ISampleSelector( i ));
asize = samp->size();
};
std::string mdstring = "interpretation=";
mdstring += iProp.getMetaData().get("interpretation");
std::stringstream dtype;
dtype << "datatype=";
dtype << dt;
std::stringstream asizestr;
asizestr << ";arraysize=";
asizestr << asize;
mdstring += g_sep;
mdstring += dtype.str();
mdstring += asizestr.str();
ss << iIndent << " " << ptype << "name=" << iProp.getName()
<< g_sep << mdstring << g_sep << "numsamps="
<< iProp.getNumSamples() << std::endl;
}
static void visitCompoundProperty(std::stringstream &ss, ICompoundProperty iProp, std::string &ioIndent)
{
std::string oldIndent = ioIndent;
ioIndent += " ";
std::string interp = "schema=";
interp += iProp.getMetaData().get("schema");
ss << ioIndent << "CompoundProperty " << "name=" << iProp.getName()
<< g_sep << interp << std::endl;
visitProperties(ss, iProp, ioIndent);
ioIndent = oldIndent;
}
static void visitProperties(std::stringstream &ss, ICompoundProperty iParent, std::string &ioIndent )
{
std::string oldIndent = ioIndent;
for (size_t i = 0 ; i < iParent.getNumProperties() ; i++) {
PropertyHeader header = iParent.getPropertyHeader(i);
if (header.isCompound()) {
visitCompoundProperty(ss, ICompoundProperty(iParent, header.getName()), ioIndent);
}
else if (header.isScalar()) {
visitSimpleScalarProperty(ss, IScalarProperty(iParent, header.getName()), ioIndent);
}
else {
assert(header.isArray());
visitSimpleArrayProperty(ss, IArrayProperty(iParent, header.getName()), ioIndent);
}
}
ioIndent = oldIndent;
}
static void visitObject(std::stringstream &ss, IObject iObj, std::string iIndent, AbcArchiveInfoLevel info_level)
{
// Object has a name, a full name, some meta data,
// and then it has a compound property full of properties.
std::string path = iObj.getFullName();
if (iObj.isInstanceRoot()) {
if (path != "/") {
ss << "Object " << "name=" << path
<< " [Instance " << iObj.instanceSourcePath() << "]"
<< std::endl;
}
}
else if (iObj.isInstanceDescendant()) {
/* skip non-root instances to avoid repetition */
return;
}
else {
if (path != "/") {
ss << "Object " << "name=" << path << std::endl;
}
if (info_level >= ABC_INFO_PROPERTIES) {
// Get the properties.
ICompoundProperty props = iObj.getProperties();
visitProperties(ss, props, iIndent);
}
// now the child objects
for (size_t i = 0 ; i < iObj.getNumChildren() ; i++) {
visitObject(ss, IObject(iObj, iObj.getChildHeader(i).getName()), iIndent, info_level);
}
}
}
static std::string abc_archive_info(IArchive &archive, AbcArchiveInfoLevel info_level)
{
std::stringstream ss;
ss << "Alembic Archive Info for "
<< Alembic::AbcCoreAbstract::GetLibraryVersion()
<< std::endl;;
std::string appName;
std::string libraryVersionString;
Alembic::Util::uint32_t libraryVersion;
std::string whenWritten;
std::string userDescription;
GetArchiveInfo(archive,
appName,
libraryVersionString,
libraryVersion,
whenWritten,
userDescription);
if (appName != "") {
ss << " file written by: " << appName << std::endl;
ss << " using Alembic : " << libraryVersionString << std::endl;
ss << " written on : " << whenWritten << std::endl;
ss << " user description : " << userDescription << std::endl;
ss << std::endl;
}
else {
// ss << argv[1] << std::endl;
ss << " (file doesn't have any ArchiveInfo)"
<< std::endl;
ss << std::endl;
}
if (info_level >= ABC_INFO_OBJECTS)
visitObject(ss, archive.getTop(), "", info_level);
return ss.str();
}
/* ========================================================================= */
struct AbcReadState {
Scene *scene; /* scene pointer */
float time;
Transform tfm; /* current transform state */
bool smooth; /* smooth normal state */
int shader; /* current shader */
string base; /* base path to current file*/
float dicing_rate; /* current dicing rate */
Mesh::DisplacementMethod displacement_method;
};
static ISampleSelector get_sample_selector(const AbcReadState &state)
{
return ISampleSelector(state.time, ISampleSelector::kFloorIndex);
}
static Mesh *add_mesh(Scene *scene, const Transform& tfm)
{
/* create mesh */
Mesh *mesh = new Mesh();
scene->meshes.push_back(mesh);
/* create object*/
Object *object = new Object();
object->mesh = mesh;
object->tfm = tfm;
scene->objects.push_back(object);
return mesh;
}
static void read_mesh(const AbcReadState &state, IPolyMesh object)
{
/* add mesh */
Mesh *mesh = add_mesh(state.scene, state.tfm);
mesh->used_shaders.push_back(state.shader);
/* read state */
int shader = state.shader;
bool smooth = state.smooth;
mesh->displacement_method = state.displacement_method;
ISampleSelector ss = get_sample_selector(state);
IPolyMeshSchema schema = object.getSchema();
IPolyMeshSchema::Sample sample;
schema.get(sample, ss);
int totverts = sample.getPositions()->size();
int totfaces = sample.getFaceCounts()->size();
const V3f *P = sample.getPositions()->get();
const int32_t *verts = sample.getFaceIndices()->get();
const int32_t *nverts = sample.getFaceCounts()->get();
/* create vertices */
mesh->verts.reserve(totverts);
for(int i = 0; i < totverts; i++) {
mesh->verts.push_back(make_float3(P[i].x, P[i].y, P[i].z));
}
/* create triangles */
int index_offset = 0;
for(int i = 0; i < totfaces; i++) {
int n = nverts[i];
/* XXX TODO only supports tris and quads atm,
* need a proper tessellation algorithm in cycles.
*/
if (n > 4) {
printf("%d-sided face found, only triangles and quads are supported currently", n);
n = 4;
}
for(int j = 0; j < n-2; j++) {
int v0 = verts[index_offset];
int v1 = verts[index_offset + j + 1];
int v2 = verts[index_offset + j + 2];
assert(v0 < (int)totverts);
assert(v1 < (int)totverts);
assert(v2 < (int)totverts);
mesh->add_triangle(v0, v1, v2, shader, smooth);
}
index_offset += n;
}
/* temporary for test compatibility */
mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
}
static void read_object(const AbcReadState &state, IObject object)
{
for (int i = 0; i < object.getNumChildren(); ++i) {
IObject child = object.getChild(i);
const MetaData &metadata = child.getMetaData();
if (IPolyMeshSchema::matches(metadata)) {
read_mesh(state, IPolyMesh(child, kWrapExisting));
}
else {
read_object(state, child);
}
}
}
static void read_archive(Scene *scene, IArchive archive, const char *filepath)
{
AbcReadState state;
state.scene = scene;
state.time = 0.0f; // TODO
state.tfm = transform_identity();
state.shader = scene->default_surface;
state.smooth = false;
state.dicing_rate = 0.1f;
state.base = path_dirname(filepath);
read_object(state, archive.getTop());
scene->params.bvh_type = SceneParams::BVH_STATIC;
}
void abc_read_ogawa_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level)
{
IArchive archive;
ABC_SAFE_CALL_BEGIN
archive = IArchive(AbcCoreOgawa::ReadArchive(), filepath, ErrorHandler::kThrowPolicy);
ABC_SAFE_CALL_END
if (archive) {
if (info_level >= ABC_INFO_BASIC)
printf("%s", abc_archive_info(archive, info_level).c_str());
read_archive(scene, archive, filepath);
}
}
void abc_read_hdf5_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level)
{
#ifdef WITH_HDF5
IArchive archive;
ABC_SAFE_CALL_BEGIN
archive = IArchive(AbcCoreHDF5::ReadArchive(), filepath, ErrorHandler::kThrowPolicy);
ABC_SAFE_CALL_END
if (archive) {
if (info_level >= ABC_INFO_BASIC)
printf("%s", abc_archive_info(archive, info_level).c_str());
read_archive(scene, archive, filepath);
}
#endif
}
CCL_NAMESPACE_END

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2015 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CYCLES_ALEMBIC_H__
#define __CYCLES_ALEMBIC_H__
CCL_NAMESPACE_BEGIN
class Scene;
enum AbcArchiveInfoLevel {
ABC_INFO_NONE = 0,
ABC_INFO_BASIC,
ABC_INFO_OBJECTS,
ABC_INFO_PROPERTIES,
};
void abc_read_ogawa_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level = ABC_INFO_NONE);
void abc_read_hdf5_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level = ABC_INFO_NONE);
CCL_NAMESPACE_END
#endif /* __CYCLES_XML_H__ */

View File

@@ -37,13 +37,23 @@
#endif
#include "cycles_xml.h"
#ifdef WITH_ALEMBIC
#include "cycles_alembic.h"
#endif
CCL_NAMESPACE_BEGIN
enum FileType {
FILETYPE_XML = 0,
FILETYPE_ABC_HDF5,
FILETYPE_ABC_OGAWA,
};
struct Options {
Session *session;
Scene *scene;
string filepath;
FileType filetype;
int width, height;
SceneParams scene_params;
SessionParams session_params;
@@ -120,8 +130,22 @@ static void scene_init()
{
options.scene = new Scene(options.scene_params, options.session_params.device);
/* Read XML */
xml_read_file(options.scene, options.filepath.c_str());
/* Read file */
switch (options.filetype) {
case FILETYPE_XML:
xml_read_file(options.scene, options.filepath.c_str());
break;
#ifdef WITH_ALEMBIC
case FILETYPE_ABC_OGAWA:
abc_read_ogawa_file(options.scene, options.filepath.c_str());
break;
case FILETYPE_ABC_HDF5:
abc_read_hdf5_file(options.scene, options.filepath.c_str());
break;
#endif
default:
return;
}
/* Camera width/height override? */
if (!(options.width == 0 || options.height == 0)) {
@@ -335,6 +359,16 @@ static void options_parse(int argc, const char **argv)
/* shading system */
string ssname = "svm";
/* input file type */
string filetypes = "auto, xml";
#ifdef WITH_ALEMBIC
filetypes += ", alembic_ogawa";
#ifdef WITH_HDF5
filetypes += ", alembic_hdf5";
#endif
#endif
string filetype = "auto";
/* parse options */
ArgParse ap;
bool help = false, debug = false;
@@ -350,6 +384,7 @@ static void options_parse(int argc, const char **argv)
"--quiet", &options.quiet, "In background mode, don't print progress messages",
"--samples %d", &options.session_params.samples, "Number of samples to render",
"--output %s", &options.session_params.output_path, "File path to write output image",
"--filetype %s", &filetype, ("File type: " + filetypes).c_str(),
"--threads %d", &options.session_params.threads, "CPU Rendering Threads",
"--width %d", &options.width, "Window width in pixel",
"--height %d", &options.height, "Window height in pixel",
@@ -394,6 +429,21 @@ static void options_parse(int argc, const char **argv)
else if(ssname == "svm")
options.scene_params.shadingsystem = SHADINGSYSTEM_SVM;
if(filetype == "auto") {
string extension = options.filepath.substr(options.filepath.find_last_of(".") + 1);
if (extension == "xml")
options.filetype = FILETYPE_XML;
else if (extension == "abc")
options.filetype = FILETYPE_ABC_OGAWA;
}
else if(filetype == "xml")
options.filetype = FILETYPE_XML;
else if(filetype == "alembic_ogawa")
options.filetype = FILETYPE_ABC_OGAWA;
else if(filetype == "alembic_hdf5")
options.filetype = FILETYPE_ABC_HDF5;
#ifndef WITH_CYCLES_STANDALONE_GUI
options.session_params.background = true;
#endif

View File

@@ -42,6 +42,9 @@
#include "util_xml.h"
#include "cycles_xml.h"
#ifdef WITH_ALEMBIC
#include "cycles_alembic.h"
#endif
CCL_NAMESPACE_BEGIN
@@ -1109,6 +1112,25 @@ static void xml_read_state(XMLReadState& state, pugi::xml_node node)
state.displacement_method = Mesh::DISPLACE_BOTH;
}
/* Alembic */
static void xml_read_alembic(const XMLReadState& state, pugi::xml_node node)
{
#ifdef WITH_ALEMBIC
string filepath;
if(xml_read_string(&filepath, node, "file")) {
filepath = path_join(state.base, filepath);
if(xml_equal_string(node, "type", "hdf5"))
abc_read_hdf5_file(state.scene, filepath.c_str(), ABC_INFO_BASIC);
else if(xml_equal_string(node, "type", "ogawa"))
abc_read_ogawa_file(state.scene, filepath.c_str(), ABC_INFO_BASIC);
else
abc_read_ogawa_file(state.scene, filepath.c_str(), ABC_INFO_BASIC); /* default */
}
#endif
}
/* Scene */
static void xml_read_include(const XMLReadState& state, const string& src);
@@ -1158,6 +1180,9 @@ static void xml_read_scene(const XMLReadState& state, pugi::xml_node scene_node)
if(xml_read_string(&src, node, "src"))
xml_read_include(state, src);
}
else if(string_iequals(node.name(), "alembic")) {
xml_read_alembic(state, node);
}
else
fprintf(stderr, "Unknown node \"%s\".\n", node.name());
}

View File

@@ -587,8 +587,10 @@ static void create_subd_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, PointerR
/* Sync */
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris)
Mesh *BlenderSync::sync_mesh(BL::Object b_parent, bool object_updated, bool hide_tris, BL::DupliObject b_dupli_ob)
{
BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
/* When viewport display is not needed during render we can force some
* caches to be releases from blender side in order to reduce peak memory
* footprint during synchronization process.
@@ -599,7 +601,6 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
/* test if we can instance or if the object is modified */
BL::ID b_ob_data = b_ob.data();
BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
BL::Material material_override = render_layer.material_override;
/* find shader indices */
@@ -624,7 +625,21 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
bool use_mesh_geometry = render_layer.use_surfaces || render_layer.use_hair;
Mesh *mesh;
if(!mesh_map.sync(&mesh, key)) {
bool need_update;
bool use_dupli_override = b_dupli_ob && b_parent.cache_library() && b_parent.use_dupli_cache_read();
if (use_dupli_override) {
/* if a dupli override (cached data) is used, identify the mesh by object and parent together,
* so that individual per-dupli overrides are possible.
*/
MeshKey key = MeshKey(b_parent, b_ob);
need_update = mesh_map.sync(&mesh, b_parent, PointerRNA_NULL, key);
}
else {
BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
need_update = mesh_map.sync(&mesh, key);
}
if(!need_update) {
/* if transform was applied to mesh, need full update */
if(object_updated && mesh->transform_applied);
/* test if shaders changed, these can be object level so mesh
@@ -675,7 +690,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
b_ob.update_from_editmode();
bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
BL::Mesh b_mesh = (b_dupli_ob && b_parent)?
dupli_to_mesh(b_data, b_scene, b_parent, b_dupli_ob, !preview, need_undeformed):
object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
if(b_mesh) {
if(render_layer.use_surfaces && !hide_tris) {

View File

@@ -280,7 +280,10 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0;
/* mesh sync */
object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
if (b_dupli_ob)
object->mesh = sync_mesh(b_parent, object_updated, hide_tris, b_dupli_ob);
else
object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
/* special case not tracked by object update flags */

View File

@@ -83,7 +83,7 @@ private:
void sync_curve_settings();
void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
Mesh *sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris);
Mesh *sync_mesh(BL::Object b_parent, bool object_updated, bool hide_tris, BL::DupliObject b_dupli_ob = PointerRNA_NULL);
void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool motion, int time_index = 0);
Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob,
Transform& tfm, uint layer_flag, float motion_time, bool hide_tris);
@@ -108,7 +108,7 @@ private:
id_map<void*, Shader> shader_map;
id_map<ObjectKey, Object> object_map;
id_map<void*, Mesh> mesh_map;
id_map<MeshKey, Mesh> mesh_map;
id_map<ObjectKey, Light> light_map;
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
set<Mesh*> mesh_synced;

View File

@@ -52,6 +52,18 @@ static inline BL::Mesh object_to_mesh(BL::BlendData data, BL::Object object, BL:
return me;
}
static inline BL::Mesh dupli_to_mesh(BL::BlendData data, BL::Scene scene, BL::Object parent, BL::DupliObject dob, bool render, bool calc_undeformed)
{
BL::Mesh me = data.meshes.new_from_dupli(scene, parent, dob, (render)? 2: 1, false, calc_undeformed);
if ((bool)me) {
if (me.use_auto_smooth()) {
me.calc_normals_split();
}
me.calc_tessface(true);
}
return me;
}
static inline void colorramp_to_array(BL::ColorRamp ramp, float4 *data, int size)
{
for(int i = 0; i < size; i++) {
@@ -568,6 +580,36 @@ struct ObjectKey {
}
};
/* Mesh Key */
struct MeshKey {
void *parent;
void *mesh;
MeshKey(void *mesh_)
: parent(NULL), mesh(mesh_)
{
}
MeshKey(void *parent_, void *mesh_)
: parent(parent_), mesh(mesh_)
{
}
bool operator<(const MeshKey& k) const
{
if(mesh < k.mesh) {
return true;
}
else if(mesh == k.mesh) {
return parent < k.parent;
return true;
}
return false;
}
};
/* Particle System Key */
struct ParticleSystemKey {

View File

@@ -30,7 +30,7 @@ if(NOT CYCLES_STANDALONE_REPOSITORY)
set(GLEW_INCLUDE_DIR "${GLEW_INCLUDE_PATH}")
endif()
if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
if(WITH_CYCLES_STANDALONE)
set(CYCLES_APP_GLEW_LIBRARY ${BLENDER_GLEW_LIBRARIES})
endif()

View File

@@ -18,7 +18,7 @@
#define __UTIL_MAP_H__
#include <map>
#include <boost/tr1/unordered_map.hpp>
#include <tr1/unordered_map>
CCL_NAMESPACE_BEGIN

View File

@@ -169,6 +169,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
sub.active = md.use_random_order
sub.prop(md, "seed")
def CACHE(self, layout, ob, md):
pass
def MESH_CACHE(self, layout, ob, md):
layout.prop(md, "cache_format")
layout.prop(md, "filepath")

View File

@@ -259,9 +259,109 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
col.prop(obj, "color", text="")
# XXX temporary solution
bpy.types.CacheLibrary.filter_string = \
bpy.props.StringProperty(
name="Filter Object Name",
description="Filter cache library objects by name",
)
bpy.types.CacheLibrary.filter_types = \
bpy.props.EnumProperty(
name="Filter Item Type",
description="Filter cache library items by type",
options={'ENUM_FLAG'},
items=[ (e.identifier, e.name, e.description, e.icon, 2**i) for i, e in enumerate(bpy.types.CacheItem.bl_rna.properties['type'].enum_items) ],
default=set( e.identifier for e in bpy.types.CacheItem.bl_rna.properties['type'].enum_items ),
)
def cachelib_objects(cachelib, group):
if not cachelib or not group:
return []
filter_string = cachelib.filter_string.lower()
if filter_string:
return filter(lambda ob: filter_string in ob.name.lower(), group.objects)
else:
return group.objects
# Yields (item, type, index, enabled)
# Note that item can be None when not included in the cache yet
def cachelib_object_items(cachelib, ob):
filter_types = cachelib.filter_types
def items_desc():
yield 'OBJECT', -1
if (ob.type == 'MESH'):
yield 'DERIVED_MESH', -1
for index, psys in enumerate(ob.particle_systems):
if psys.settings.type == 'EMITTER':
yield 'PARTICLES', index
if psys.settings.type == 'HAIR':
yield 'HAIR', index
yield 'HAIR_PATHS', index
for item_type, item_index in items_desc():
item = cachelib.cache_item_find(ob, item_type, item_index)
show = False
enable = False
# always show existing items
if item and item.enabled:
show = True
enable = True
# always show selected types
elif item_type in filter_types:
show = True
enable = True
# special case: OBJECT type used as top level, show but disable
elif item_type == 'OBJECT':
show = True
enable = False
if show:
yield item, item_type, item_index, enable
class OBJECT_PT_duplication(ObjectButtonsPanel, Panel):
bl_label = "Duplication"
def draw_cachelib(self, context, layout, ob, cachelib, objects):
col = layout.column(align=True)
colrow = col.row(align=True)
colrow.label("Archive:")
props = colrow.operator("cachelibrary.archive_info", text="", icon='QUESTION')
props.use_stdout = True
props.use_popup = True
props.use_clipboard = True
col.prop(cachelib, "filepath", text="")
row = col.row(align=True)
row.prop(ob, "use_dupli_cache_read", text="Read", toggle=True)
row.prop(ob, "use_dupli_cache_write", text="Write", toggle=True)
col.operator("cachelibrary.bake")
row = col.row(align=True)
row.prop(cachelib, "eval_mode", toggle=True, expand=True)
row = layout.row(align=True)
row.label("Filter:")
row.prop(cachelib, "filter_types", icon_only=True, toggle=True)
row.prop(cachelib, "filter_string", icon='VIEWZOOM', text="")
first = True
for ob in objects:
if not any(cachelib_object_items(cachelib, ob)):
continue
if first:
layout.separator()
first = False
for item, item_type, item_index, enable in cachelib_object_items(cachelib, ob):
row = layout.row(align=True)
row.alignment = 'LEFT'
row.template_cache_library_item(cachelib, ob, item_type, item_index, enable)
def draw(self, context):
layout = self.layout
@@ -294,6 +394,12 @@ class OBJECT_PT_duplication(ObjectButtonsPanel, Panel):
elif ob.dupli_type == 'GROUP':
layout.prop(ob, "dupli_group", text="Group")
row = layout.row(align=True)
row.template_ID(ob, "cache_library", new="cachelibrary.new")
if ob.cache_library:
cache_objects = cachelib_objects(ob.cache_library, ob.dupli_group)
self.draw_cachelib(context, layout, ob, ob.cache_library, cache_objects)
class OBJECT_PT_relations_extras(ObjectButtonsPanel, Panel):

View File

@@ -31,6 +31,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_boid_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cache_library_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cloth_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_color_types.h
@@ -108,6 +109,7 @@ add_subdirectory(gpu)
add_subdirectory(imbuf)
add_subdirectory(nodes)
add_subdirectory(modifiers)
add_subdirectory(pointcache)
add_subdirectory(makesdna)
add_subdirectory(makesrna)

View File

@@ -43,7 +43,8 @@ SConscript(['avi/SConscript',
'ikplugin/SConscript',
'physics/SConscript',
'windowmanager/SConscript',
'blenfont/SConscript'])
'blenfont/SConscript',
'pointcache/SConscript'])
makesrna = SConscript('makesrna/SConscript')

View File

@@ -146,6 +146,7 @@ const char *BLF_translate_do_new_dataname(const char *msgctxt, const char *msgid
#define BLF_I18NCONTEXT_ID_ACTION "Action"
#define BLF_I18NCONTEXT_ID_ARMATURE "Armature"
#define BLF_I18NCONTEXT_ID_BRUSH "Brush"
#define BLF_I18NCONTEXT_ID_CACHELIBRARY "CacheLibrary"
#define BLF_I18NCONTEXT_ID_CAMERA "Camera"
#define BLF_I18NCONTEXT_ID_CURVE "Curve"
#define BLF_I18NCONTEXT_ID_FREESTYLELINESTYLE "FreestyleLineStyle"

View File

@@ -42,6 +42,11 @@ struct bAnimVizSettings;
struct bMotionPath;
struct bPoseChannel;
struct ReportList;
struct GHash;
struct DupliCache;
struct DupliObject;
struct DupliObjectData;
struct DerivedMesh;
/* ---------------------------------------------------- */
/* Animation Visualization */
@@ -66,11 +71,26 @@ int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], fl
/* ---------------------------------------------------- */
/* Dupli-Geometry */
struct ListBase *object_duplilist_ex(struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob, bool update);
struct ListBase *object_duplilist(struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob);
struct ListBase *object_duplilist_ex(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, bool update);
struct ListBase *object_duplilist(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
struct ListBase *group_duplilist_ex(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Group *group, bool update);
struct ListBase *group_duplilist(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Group *group);
void free_object_duplilist(struct ListBase *lb);
int count_duplilist(struct Object *ob);
void BKE_object_dupli_cache_update(struct Scene *scene, struct Object *ob, struct EvaluationContext *eval_ctx, float frame);
void BKE_object_dupli_cache_clear(struct Object *ob);
void BKE_object_dupli_cache_free(struct Object *ob);
bool BKE_object_dupli_cache_contains(struct Object *ob, struct Object *other);
struct DupliObjectData *BKE_dupli_cache_find_data(struct DupliCache *dupcache, struct Object *ob);
void BKE_dupli_object_data_init(struct DupliObjectData *data, struct Object *ob, struct DerivedMesh *dm);
/* does not free data itself */
void BKE_dupli_object_data_clear(struct DupliObjectData *data);
struct DupliObjectData *BKE_dupli_cache_add_mesh(struct DupliCache *dupcache, struct Object *ob, struct DerivedMesh *dm);
void BKE_dupli_cache_add_instance(struct DupliCache *dupcache, float obmat[4][4], struct DupliObjectData *data);
typedef struct DupliExtraData {
float obmat[4][4];
unsigned int lay;

View File

@@ -0,0 +1,109 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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) 2015 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BKE_CACHE_LIBRARY_H__
#define __BKE_CACHE_LIBRARY_H__
/** \file BKE_cache_library.h
* \ingroup bke
*/
#include "DNA_cache_library_types.h"
struct ListBase;
struct Main;
struct Object;
struct Scene;
struct EvaluationContext;
struct ParticleSystem;
struct DupliCache;
struct DupliObjectData;
struct ClothModifierData;
struct CacheLibrary *BKE_cache_library_add(struct Main *bmain, const char *name);
struct CacheLibrary *BKE_cache_library_copy(struct CacheLibrary *cachelib);
void BKE_cache_library_free(struct CacheLibrary *cachelib);
void BKE_cache_library_unlink(struct CacheLibrary *cachelib);
void BKE_cache_library_make_object_list(struct Main *bmain, struct CacheLibrary *cachelib, struct ListBase *lb);
typedef struct CacheLibraryObjectsIterator {
ListBase objects;
LinkData *cur;
} CacheLibraryObjectsIterator;
void BKE_object_cache_iter_init(CacheLibraryObjectsIterator *iter, struct CacheLibrary *cachelib);
bool BKE_object_cache_iter_valid(CacheLibraryObjectsIterator *iter);
void BKE_object_cache_iter_next(CacheLibraryObjectsIterator *iter);
void BKE_object_cache_iter_end(CacheLibraryObjectsIterator *iter);
struct Object *BKE_object_cache_iter_get(CacheLibraryObjectsIterator *iter);
typedef struct CacheLibraryItemsIterator {
struct Object *ob;
struct CacheItem *items;
int totitems;
struct CacheItem *cur;
} CacheLibraryItemsIterator;
void BKE_cache_item_iter_init(CacheLibraryItemsIterator *iter, struct Object *ob);
bool BKE_cache_item_iter_valid(CacheLibraryItemsIterator *iter);
void BKE_cache_item_iter_next(CacheLibraryItemsIterator *iter);
void BKE_cache_item_iter_end(CacheLibraryItemsIterator *iter);
#if 0
typedef void (*CacheGroupWalkFunc)(void *userdata, struct CacheLibrary *cachelib, const struct CacheItemPath *path);
void BKE_cache_library_walk(struct CacheLibrary *cachelib, CacheGroupWalkFunc walk, void *userdata);
#endif
const char *BKE_cache_item_name_prefix(int type);
void BKE_cache_item_name(struct Object *ob, int type, int index, char *name);
int BKE_cache_item_name_length(struct Object *ob, int type, int index);
eCacheReadSampleResult BKE_cache_read_result(int ptc_result);
struct CacheItem *BKE_cache_library_find_item(struct CacheLibrary *cachelib, struct Object *ob, int type, int index);
struct CacheItem *BKE_cache_library_add_item(struct CacheLibrary *cachelib, struct Object *ob, int type, int index);
void BKE_cache_library_remove_item(struct CacheLibrary *cachelib, struct CacheItem *item);
void BKE_cache_library_clear(struct CacheLibrary *cachelib);
bool BKE_cache_library_validate_item(struct CacheLibrary *cachelib, struct Object *ob, int type, int index);
void BKE_cache_library_group_update(struct Main *bmain, struct CacheLibrary *cachelib);
/* ========================================================================= */
bool BKE_cache_archive_path_test(const char *path, ID *id, Library *lib);
void BKE_cache_archive_path(const char *path, ID *id, Library *lib, char *result, int max);
void BKE_cache_library_dag_recalc_tag(struct EvaluationContext *eval_ctx, struct Main *bmain);
bool BKE_cache_read_dupli_cache(struct Scene *scene, float frame, eCacheLibrary_EvalMode eval_mode,
struct Group *dupgroup, struct DupliCache *dupcache, struct CacheLibrary *cachelib);
bool BKE_cache_read_dupli_object(struct Scene *scene, float frame, eCacheLibrary_EvalMode eval_mode,
struct Object *ob, struct DupliObjectData *data, struct CacheLibrary *cachelib);
#endif

View File

@@ -71,7 +71,7 @@ void id_clear_lib_data(struct Main *bmain, struct ID *id);
struct ListBase *which_libbase(struct Main *mainlib, short type);
#define MAX_LIBARRAY 35
#define MAX_LIBARRAY 36
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
void BKE_libblock_free(struct Main *bmain, void *idv);

View File

@@ -94,6 +94,7 @@ typedef struct Main {
ListBase movieclip;
ListBase mask;
ListBase linestyle;
ListBase cache_library;
char id_tag_update[256];

View File

@@ -41,6 +41,7 @@ struct BLI_Stack;
struct MemArena;
struct BMEditMesh;
struct BMesh;
struct DupliObjectData;
struct Main;
struct Mesh;
struct MPoly;
@@ -135,6 +136,7 @@ void BKE_mesh_split_faces(struct Mesh *mesh);
struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Scene *sce, struct Object *ob,
int apply_modifiers, int settings, int calc_tessface, int calc_undeformed);
struct Mesh *BKE_mesh_new_from_dupli_data(struct Main *bmain, struct DupliObjectData *data, bool calc_tessface, bool calc_undeformed);
/* vertex level transformations & checks (no derived mesh) */

View File

@@ -37,6 +37,7 @@ set(INC
../modifiers
../nodes
../physics
../pointcache
../render/extern/include
../../../intern/ghost
../../../intern/guardedalloc
@@ -75,6 +76,7 @@ set(SRC
intern/brush.c
intern/bullet.c
intern/bvhutils.c
intern/cache_library.c
intern/camera.c
intern/cdderivedmesh.c
intern/cloth.c
@@ -193,6 +195,7 @@ set(SRC
BKE_brush.h
BKE_bullet.h
BKE_bvhutils.h
BKE_cache_library.h
BKE_camera.h
BKE_ccg.h
BKE_cdderivedmesh.h

View File

@@ -66,6 +66,7 @@ incs = [
'../modifiers',
'../nodes',
'../physics',
'../pointcache',
'../render/extern/include',
'../windowmanager',
env['BF_ZLIB_INC'],

View File

@@ -482,10 +482,6 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
BPATH_TRAVERSE_POINTCACHE(smd->domain->ptcaches[0]);
}
}
else if (md->type == eModifierType_Cloth) {
ClothModifierData *clmd = (ClothModifierData *) md;
BPATH_TRAVERSE_POINTCACHE(clmd->ptcaches);
}
else if (md->type == eModifierType_Ocean) {
OceanModifierData *omd = (OceanModifierData *) md;
rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data);

View File

@@ -0,0 +1,746 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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) 2015 by NaN Holding BV.
* All rights reserved.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/cache_library.c
* \ingroup bke
*/
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_fileops.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_cache_library_types.h"
#include "DNA_group_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
#include "BKE_anim.h"
#include "BKE_cache_library.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "PTC_api.h"
CacheLibrary *BKE_cache_library_add(Main *bmain, const char *name)
{
CacheLibrary *cachelib;
char basename[MAX_NAME];
cachelib = BKE_libblock_alloc(bmain, ID_CL, name);
BLI_strncpy(basename, cachelib->id.name+2, sizeof(basename));
BLI_filename_make_safe(basename);
BLI_snprintf(cachelib->filepath, sizeof(cachelib->filepath), "//cache/%s.%s", basename, PTC_get_default_archive_extension());
cachelib->eval_mode = CACHE_LIBRARY_EVAL_REALTIME | CACHE_LIBRARY_EVAL_RENDER;
return cachelib;
}
CacheLibrary *BKE_cache_library_copy(CacheLibrary *cachelib)
{
CacheLibrary *cachelibn;
cachelibn = BKE_libblock_copy(&cachelib->id);
BLI_duplicatelist(&cachelibn->items, &cachelib->items);
/* hash table will be rebuilt when needed */
cachelibn->items_hash = NULL;
if (cachelib->id.lib) {
BKE_id_lib_local_paths(G.main, cachelib->id.lib, &cachelibn->id);
}
return cachelibn;
}
void BKE_cache_library_free(CacheLibrary *cachelib)
{
BLI_freelistN(&cachelib->items);
if (cachelib->items_hash)
BLI_ghash_free(cachelib->items_hash, NULL, NULL);
}
void BKE_cache_library_unlink(CacheLibrary *UNUSED(cachelib))
{
}
/* ========================================================================= */
static void cache_library_tag_recursive(int level, Object *ob)
{
if (level > MAX_CACHE_GROUP_LEVEL)
return;
/* dupli group recursion */
if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
GroupObject *gob;
for (gob = ob->dup_group->gobject.first; gob; gob = gob->next) {
if (!(ob->id.flag & LIB_DOIT)) {
ob->id.flag |= LIB_DOIT;
cache_library_tag_recursive(level + 1, gob->ob);
}
}
}
}
/* tag IDs contained in the cache library group */
void BKE_cache_library_make_object_list(Main *bmain, CacheLibrary *cachelib, ListBase *lb)
{
if (cachelib) {
Object *ob;
LinkData *link;
/* clear tags */
BKE_main_id_tag_idcode(bmain, ID_OB, false);
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->cache_library == cachelib) {
cache_library_tag_recursive(0, ob);
}
}
/* store object pointers in the list */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->id.flag & LIB_DOIT) {
link = MEM_callocN(sizeof(LinkData), "cache library ID link");
link->data = ob;
BLI_addtail(lb, link);
}
}
}
}
void BKE_object_cache_iter_init(CacheLibraryObjectsIterator *iter, CacheLibrary *cachelib)
{
BLI_listbase_clear(&iter->objects);
BKE_cache_library_make_object_list(G.main, cachelib, &iter->objects);
iter->cur = iter->objects.first;
}
bool BKE_object_cache_iter_valid(CacheLibraryObjectsIterator *iter)
{
return iter->cur != NULL;
}
void BKE_object_cache_iter_next(CacheLibraryObjectsIterator *iter)
{
iter->cur = iter->cur->next;
}
Object *BKE_object_cache_iter_get(CacheLibraryObjectsIterator *iter)
{
return iter->cur->data;
}
void BKE_object_cache_iter_end(CacheLibraryObjectsIterator *iter)
{
BLI_freelistN(&iter->objects);
}
/* ========================================================================= */
static int cache_count_items(Object *ob) {
ParticleSystem *psys;
int totitem = 1; /* base object */
if (ob->type == OB_MESH)
totitem += 1; /* derived mesh */
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
if (psys->part->type == PART_HAIR) {
totitem += 2; /* hair and hair paths */
}
else {
totitem += 1; /* particles */
}
}
return totitem;
}
static void cache_make_items(Object *ob, CacheItem *item) {
ParticleSystem *psys;
int i;
/* base object */
item->ob = ob;
item->type = CACHE_TYPE_OBJECT;
item->index = -1;
++item;
if (ob->type == OB_MESH) {
/* derived mesh */
item->ob = ob;
item->type = CACHE_TYPE_DERIVED_MESH;
item->index = -1;
++item;
}
for (psys = ob->particlesystem.first, i = 0; psys; psys = psys->next, ++i) {
if (psys->part->type == PART_HAIR) {
/* hair */
item->ob = ob;
item->type = CACHE_TYPE_HAIR;
item->index = i;
++item;
/* hair paths */
item->ob = ob;
item->type = CACHE_TYPE_HAIR_PATHS;
item->index = i;
++item;
}
else {
/* hair paths */
item->ob = ob;
item->type = CACHE_TYPE_PARTICLES;
item->index = i;
++item;
}
}
}
void BKE_cache_item_iter_init(CacheLibraryItemsIterator *iter, Object *ob)
{
iter->ob = ob;
iter->totitems = cache_count_items(ob);
iter->items = MEM_mallocN(sizeof(CacheItem) * iter->totitems, "object cache items");
cache_make_items(ob, iter->items);
iter->cur = iter->items;
}
bool BKE_cache_item_iter_valid(CacheLibraryItemsIterator *iter)
{
return (int)(iter->cur - iter->items) < iter->totitems;
}
void BKE_cache_item_iter_next(CacheLibraryItemsIterator *iter)
{
++iter->cur;
}
void BKE_cache_item_iter_end(CacheLibraryItemsIterator *iter)
{
if (iter->items)
MEM_freeN(iter->items);
}
#if 0
static void cache_library_walk_recursive(CacheLibrary *cachelib, CacheGroupWalkFunc walk, void *userdata, int level, Object *ob)
{
CacheItemPath path;
if (level > MAX_CACHE_GROUP_LEVEL)
return;
/* object dm */
cache_path_object(&path, ob);
walk(userdata, cachelib, &path);
/* dupli group recursion */
if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
GroupObject *gob;
for (gob = ob->dup_group->gobject.first; gob; gob = gob->next) {
cache_library_walk_recursive(cachelib, walk, userdata, level + 1, gob->ob);
}
}
}
void BKE_cache_library_walk(CacheLibrary *cachelib, CacheGroupWalkFunc walk, void *userdata)
{
if (cachelib && cachelib->group) {
GroupObject *gob;
for (gob = cachelib->group->gobject.first; gob; gob = gob->next) {
cache_library_walk_recursive(cachelib, walk, userdata, 0, gob->ob);
}
}
}
#endif
/* ========================================================================= */
BLI_INLINE unsigned int hash_int_2d(unsigned int kx, unsigned int ky)
{
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
uint a, b, c;
a = b = c = 0xdeadbeef + (2 << 2) + 13;
a += kx;
b += ky;
c ^= b; c -= rot(b,14);
a ^= c; a -= rot(c,11);
b ^= a; b -= rot(a,25);
c ^= b; c -= rot(b,16);
a ^= c; a -= rot(c,4);
b ^= a; b -= rot(a,14);
c ^= b; c -= rot(b,24);
return c;
#undef rot
}
static unsigned int cache_item_hash(const void *key)
{
const CacheItem *item = key;
unsigned int hash;
hash = BLI_ghashutil_inthash(item->type);
if (item->ob)
hash = hash_int_2d(hash, BLI_ghashutil_ptrhash(item->ob));
if (item->index >= 0)
hash = hash_int_2d(hash, BLI_ghashutil_inthash(item->index));
return hash;
}
static bool cache_item_cmp(const void *key_a, const void *key_b)
{
const CacheItem *item_a = key_a, *item_b = key_b;
if (item_a->type != item_b->type)
return true;
if (item_a->ob != item_b->ob)
return true;
if (item_a->index >= 0 || item_b->index >= 0) {
if (item_a->index != item_b->index)
return true;
}
return false;
}
BLI_INLINE void print_cachelib_items(CacheLibrary *cachelib)
{
CacheItem *item;
int i;
printf("Cache Library %s:\n", cachelib->id.name+2);
for (item = cachelib->items.first, i = 0; item; item = item->next, ++i) {
printf(" Item %d: ob=%s, type=%d, index=%d, hash=%d\n", i, item->ob ? item->ob->id.name+2 : "!!!", item->type, item->index, cache_item_hash(item));
}
}
const char *BKE_cache_item_name_prefix(int type)
{
/* note: avoid underscores and the like here,
* the prefixes must be unique and safe when combined with arbitrary strings!
*/
switch (type) {
case CACHE_TYPE_OBJECT: return "OBJECT";
case CACHE_TYPE_DERIVED_MESH: return "MESH";
case CACHE_TYPE_HAIR: return "HAIR";
case CACHE_TYPE_HAIR_PATHS: return "HAIRPATHS";
case CACHE_TYPE_PARTICLES: return "PARTICLES";
default: BLI_assert(false); return NULL; break;
}
}
void BKE_cache_item_name(Object *ob, int type, int index, char *name)
{
if (index >= 0)
sprintf(name, "%s_%s_%d", BKE_cache_item_name_prefix(type), ob->id.name+2, index);
else
sprintf(name, "%s_%s", BKE_cache_item_name_prefix(type), ob->id.name+2);
}
int BKE_cache_item_name_length(Object *ob, int type, int index)
{
if (index >= 0)
return snprintf(NULL, 0, "%s_%s_%d", BKE_cache_item_name_prefix(type), ob->id.name+2, index);
else
return snprintf(NULL, 0, "%s_%s", BKE_cache_item_name_prefix(type), ob->id.name+2);
}
eCacheReadSampleResult BKE_cache_read_result(int ptc_result)
{
switch (ptc_result) {
case PTC_READ_SAMPLE_INVALID: return CACHE_READ_SAMPLE_INVALID;
case PTC_READ_SAMPLE_EARLY: return CACHE_READ_SAMPLE_EARLY;
case PTC_READ_SAMPLE_LATE: return CACHE_READ_SAMPLE_LATE;
case PTC_READ_SAMPLE_EXACT: return CACHE_READ_SAMPLE_EXACT;
case PTC_READ_SAMPLE_INTERPOLATED: return CACHE_READ_SAMPLE_INTERPOLATED;
default: BLI_assert(false); break; /* should never happen, enums out of sync? */
}
return CACHE_READ_SAMPLE_INVALID;
}
static void cache_library_insert_item_hash(CacheLibrary *cachelib, CacheItem *item, bool replace)
{
CacheItem *exist = BLI_ghash_lookup(cachelib->items_hash, item);
if (exist && replace) {
BLI_remlink(&cachelib->items, exist);
BLI_ghash_remove(cachelib->items_hash, item, NULL, NULL);
MEM_freeN(exist);
}
if (!exist || replace)
BLI_ghash_insert(cachelib->items_hash, item, item);
}
/* make sure the items hash exists (lazy init after loading files) */
static void cache_library_ensure_items_hash(CacheLibrary *cachelib)
{
CacheItem *item;
if (!cachelib->items_hash) {
cachelib->items_hash = BLI_ghash_new(cache_item_hash, cache_item_cmp, "cache item hash");
for (item = cachelib->items.first; item; item = item->next) {
cache_library_insert_item_hash(cachelib, item, true);
}
}
}
CacheItem *BKE_cache_library_find_item(CacheLibrary *cachelib, Object *ob, int type, int index)
{
CacheItem item;
item.next = item.prev = NULL;
item.ob = ob;
item.type = type;
item.index = index;
cache_library_ensure_items_hash(cachelib);
return BLI_ghash_lookup(cachelib->items_hash, &item);
}
CacheItem *BKE_cache_library_add_item(CacheLibrary *cachelib, struct Object *ob, int type, int index)
{
CacheItem *item;
/* assert validity */
BLI_assert(BKE_cache_library_validate_item(cachelib, ob, type, index));
cache_library_ensure_items_hash(cachelib);
item = BKE_cache_library_find_item(cachelib, ob, type, index);
if (!item) {
item = MEM_callocN(sizeof(CacheItem), "cache library item");
item->ob = ob;
item->type = type;
item->index = index;
BLI_addtail(&cachelib->items, item);
cache_library_insert_item_hash(cachelib, item, false);
id_lib_extern((ID *)item->ob);
}
return item;
}
void BKE_cache_library_remove_item(CacheLibrary *cachelib, CacheItem *item)
{
if (item) {
if (cachelib->items_hash)
BLI_ghash_remove(cachelib->items_hash, item, NULL, NULL);
BLI_remlink(&cachelib->items, item);
MEM_freeN(item);
}
}
void BKE_cache_library_clear(CacheLibrary *cachelib)
{
CacheItem *item, *item_next;
if (cachelib->items_hash)
BLI_ghash_clear(cachelib->items_hash, NULL, NULL);
for (item = cachelib->items.first; item; item = item_next) {
item_next = item->next;
MEM_freeN(item);
}
BLI_listbase_clear(&cachelib->items);
}
bool BKE_cache_library_validate_item(CacheLibrary *cachelib, Object *ob, int type, int index)
{
if (!cachelib)
return false;
if (ELEM(type, CACHE_TYPE_DERIVED_MESH)) {
if (ob->type != OB_MESH)
return false;
}
else if (ELEM(type, CACHE_TYPE_PARTICLES, CACHE_TYPE_HAIR, CACHE_TYPE_HAIR_PATHS)) {
ParticleSystem *psys = BLI_findlink(&ob->particlesystem, index);
if (!psys)
return false;
if (ELEM(type, CACHE_TYPE_PARTICLES)) {
if (psys->part->type != PART_EMITTER)
return false;
}
if (ELEM(type, CACHE_TYPE_HAIR, CACHE_TYPE_HAIR_PATHS)) {
if (psys->part->type != PART_HAIR)
return false;
}
}
return true;
}
void BKE_cache_library_group_update(Main *bmain, CacheLibrary *cachelib)
{
if (cachelib) {
Object *ob;
CacheItem *item, *item_next;
/* clear tags */
BKE_main_id_tag_idcode(bmain, ID_OB, false);
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->cache_library == cachelib) {
cache_library_tag_recursive(0, ob);
}
}
/* remove unused items */
for (item = cachelib->items.first; item; item = item_next) {
item_next = item->next;
if (!item->ob || !(item->ob->id.flag & LIB_DOIT)) {
BKE_cache_library_remove_item(cachelib, item);
}
}
}
}
/* ========================================================================= */
#if 0
typedef struct UpdateItemsData {
CacheItem *cur;
} UpdateItemsData;
static void cache_library_update_items_walk(void *userdata, CacheLibrary *cachelib)
{
UpdateItemsData *data = userdata;
CacheItem *item;
if (data->cur) {
item = data->cur;
data->cur = data->cur->next;
}
else {
item = MEM_callocN(sizeof(CacheItem), "cache library item");
BLI_addtail(&cachelib->items, item);
}
}
void BKE_cache_library_update_items(CacheLibrary *cachelib)
{
UpdateItemsData data;
data.cur = cachelib->items.first;
BKE_cache_library_walk(cachelib, cache_library_update_items_walk, &data);
/* truncate items list */
if (data.cur) {
cachelib->items.last = data.cur->prev;
while (data.cur) {
CacheItem *item = data.cur;
data.cur = data.cur->next;
BLI_remlink(&cachelib->items, item);
MEM_freeN(item);
}
}
}
#endif
/* ========================================================================= */
static const char *default_filename = "blendcache";
BLI_INLINE bool path_is_dirpath(const char *path)
{
/* last char is a slash? */
return *(BLI_last_slash(path) + 1) == '\0';
}
bool BKE_cache_archive_path_test(const char *path, ID *UNUSED(id), Library *lib)
{
if (BLI_path_is_rel(path)) {
if (!(G.relbase_valid || lib))
return false;
}
return true;
}
void BKE_cache_archive_path(const char *path, ID *id, Library *lib, char *result, int max)
{
char abspath[FILE_MAX];
result[0] = '\0';
if (BLI_path_is_rel(path)) {
if (G.relbase_valid || lib) {
const char *relbase = lib ? lib->filepath : G.main->name;
BLI_strncpy(abspath, path, sizeof(abspath));
BLI_path_abs(abspath, relbase);
}
else {
/* can't construct a valid path */
return;
}
}
else {
BLI_strncpy(abspath, path, sizeof(abspath));
}
if (path_is_dirpath(abspath) || BLI_is_dir(abspath)) {
BLI_join_dirfile(result, max, abspath, id ? id->name+2 : default_filename);
}
else {
BLI_strncpy(result, abspath, max);
}
}
bool BKE_cache_read_dupli_cache(Scene *scene, float frame, eCacheLibrary_EvalMode eval_mode,
struct Group *dupgroup, struct DupliCache *dupcache, CacheLibrary *cachelib)
{
char filename[FILE_MAX];
struct PTCReaderArchive *archive;
struct PTCReader *reader;
eCacheReadSampleResult result;
if (!dupcache || !dupgroup || !cachelib)
return false;
if (!(cachelib->eval_mode & eval_mode))
return false;
BKE_cache_archive_path(cachelib->filepath, (ID *)cachelib, cachelib->id.lib, filename, sizeof(filename));
archive = PTC_open_reader_archive(scene, filename);
if (!archive)
return false;
reader = PTC_reader_duplicache(dupgroup->id.name, dupgroup, dupcache);
PTC_reader_init(reader, archive);
result = BKE_cache_read_result(PTC_read_sample(reader, frame));
PTC_reader_free(reader);
PTC_close_reader_archive(archive);
return true;
}
bool BKE_cache_read_dupli_object(Scene *scene, float frame, eCacheLibrary_EvalMode eval_mode,
struct Object *ob, struct DupliObjectData *data, CacheLibrary *cachelib)
{
char filename[FILE_MAX];
struct PTCReaderArchive *archive;
struct PTCReader *reader;
eCacheReadSampleResult result;
if (!data || !ob || !cachelib)
return false;
if (!(cachelib->eval_mode & eval_mode))
return false;
BKE_cache_archive_path(cachelib->filepath, (ID *)cachelib, cachelib->id.lib, filename, sizeof(filename));
archive = PTC_open_reader_archive(scene, filename);
if (!archive)
return false;
PTC_reader_archive_use_render(archive, eval_mode == CACHE_LIBRARY_EVAL_RENDER);
reader = PTC_reader_duplicache_object(ob->id.name, ob, data);
PTC_reader_init(reader, archive);
result = BKE_cache_read_result(PTC_read_sample(reader, frame));
PTC_reader_free(reader);
PTC_close_reader_archive(archive);
return true;
}
void BKE_cache_library_dag_recalc_tag(EvaluationContext *eval_ctx, Main *bmain)
{
#if 0
eCacheLibrary_EvalMode eval_mode = (eval_ctx->mode == DAG_EVAL_RENDER) ? CACHE_LIBRARY_EVAL_RENDER : CACHE_LIBRARY_EVAL_REALTIME;
CacheLibrary *cachelib;
FOREACH_CACHELIB_READ(bmain, cachelib, eval_mode) {
if (cachelib->flag & CACHE_LIBRARY_READ) {
CacheItem *item;
// TODO tag group instance objects or so?
for (item = cachelib->items.first; item; item = item->next) {
if (item->ob && (item->flag & CACHE_ITEM_ENABLED)) {
switch (item->type) {
case CACHE_TYPE_OBJECT:
DAG_id_tag_update(&item->ob->id, OB_RECALC_OB | OB_RECALC_TIME);
break;
case CACHE_TYPE_DERIVED_MESH:
case CACHE_TYPE_PARTICLES:
case CACHE_TYPE_HAIR:
case CACHE_TYPE_HAIR_PATHS:
DAG_id_tag_update(&item->ob->id, OB_RECALC_DATA | OB_RECALC_TIME);
break;
}
}
}
}
}
#endif
}

View File

@@ -620,7 +620,12 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
/* inverted relation, so addtoroot shouldn't be set to zero */
}
if (ob->transflag & OB_DUPLI) {
/* XXX Fake dependency: duplicator object becomes a child of group objects.
* This exploits the layer visibility mechanism, making the group objects update
* when the duplicator is visible (even if group objects are not visible themselves).
* It is not a true dependency, the duplicator does not in any way depend on group objects or data!
*/
if (ob->transflag & OB_DUPLI && !(ob->transflag & OB_DUPLI_READ_CACHE)) {
if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
GroupObject *go;
for (go = ob->dup_group->gobject.first; go; go = go->next) {
@@ -2137,6 +2142,10 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
}
}
/* invalidate dupli cache */
if (ob->dup_cache)
ob->dup_cache->flag |= DUPCACHE_FLAG_DIRTY;
if (ob->recalc & OB_RECALC_OB)
lib_id_recalc_tag(bmain, &ob->id);
if (ob->recalc & OB_RECALC_DATA)

View File

@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_cache_library_types.h"
#include "DNA_group_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
@@ -45,7 +46,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BKE_cache_library.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_group.h"
@@ -318,7 +319,7 @@ bool BKE_group_is_animated(Group *group, Object *UNUSED(parent))
GroupObject *go;
#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
if (parent->nlastrips.first)
if (parent && parent->nlastrips.first)
return 1;
#endif
@@ -385,7 +386,7 @@ void BKE_group_handle_recalc_and_update(EvaluationContext *eval_ctx, Scene *scen
* but when its enabled at some point it will need to be changed so as not to update so much - campbell */
/* if animated group... */
if (parent->nlastrips.first) {
if (parent && parent->nlastrips.first) {
int cfrao;
/* switch to local time */

View File

@@ -53,6 +53,7 @@ static IDType idtypes[] = {
{ ID_AC, "Action", "actions", IDTYPE_FLAGS_ISLINKABLE },
{ ID_AR, "Armature", "armatures", IDTYPE_FLAGS_ISLINKABLE },
{ ID_BR, "Brush", "brushes", IDTYPE_FLAGS_ISLINKABLE },
{ ID_CL, "CacheLibrary", "cache_libraries", IDTYPE_FLAGS_ISLINKABLE },
{ ID_CA, "Camera", "cameras", IDTYPE_FLAGS_ISLINKABLE },
{ ID_CU, "Curve", "curves", IDTYPE_FLAGS_ISLINKABLE },
{ ID_GD, "GPencil", "grease_pencil", IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */

View File

@@ -45,6 +45,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
@@ -79,6 +80,7 @@
#include "BKE_armature.h"
#include "BKE_bpath.h"
#include "BKE_brush.h"
#include "BKE_cache_library.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -107,6 +109,7 @@
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
#include "BKE_pointcache.h"
#include "BKE_speaker.h"
#include "BKE_sound.h"
#include "BKE_screen.h"
@@ -409,6 +412,10 @@ bool id_unlink(ID *id, int test)
if (test) return true;
BKE_object_unlink((Object *)id);
break;
case ID_CL:
if (test) return true;
BKE_cache_library_unlink((CacheLibrary *)id);
break;
}
if (id->us == 0) {
@@ -521,6 +528,8 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->palettes);
case ID_PC:
return &(mainlib->paintcurves);
case ID_CL:
return &(mainlib->cache_library);
}
return NULL;
}
@@ -616,6 +625,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[a++] = &(main->linestyle); /* referenced by scenes */
lb[a++] = &(main->scene);
lb[a++] = &(main->library);
lb[a++] = &(main->cache_library);
lb[a++] = &(main->wm);
lb[a++] = &(main->mask);
@@ -747,6 +757,9 @@ static ID *alloc_libblock_notest(short type)
case ID_PC:
id = MEM_callocN(sizeof(PaintCurve), "Paint Curve");
break;
case ID_CL:
id = MEM_callocN(sizeof(CacheLibrary), "Cache Library");
break;
}
return id;
}
@@ -1029,6 +1042,9 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
case ID_PC:
BKE_paint_curve_free((PaintCurve *)id);
break;
case ID_CL:
BKE_cache_library_free((CacheLibrary *)id);
break;
}
/* avoid notifying on removed data */

View File

@@ -2479,3 +2479,63 @@ Mesh *BKE_mesh_new_from_object(
return tmpmesh;
}
/* settings: 1 - preview, 2 - render */
Mesh *BKE_mesh_new_from_dupli_data(
Main *bmain, DupliObjectData *data,
bool calc_tessface, bool calc_undeformed)
{
Object *ob = data->ob;
DerivedMesh *dm = data->cache_dm;
CustomDataMask mask;
Mesh *tmpmesh;
if (!ob || !dm)
return NULL;
mask = CD_MASK_MESH; /* this seems more suitable, exporter,
* for example, needs CD_MASK_MDEFORMVERT */
if (calc_undeformed)
mask |= CD_MASK_ORCO;
tmpmesh = BKE_mesh_add(bmain, "Mesh");
DM_to_mesh(dm, tmpmesh, ob, mask, true);
/* BKE_mesh_add/copy gives us a user count we don't need */
tmpmesh->id.us--;
/* Copy materials to new mesh */
switch (ob->type) {
case OB_MESH: {
Mesh *origmesh = ob->data;
int i;
tmpmesh->flag = origmesh->flag;
tmpmesh->mat = MEM_dupallocN(origmesh->mat);
tmpmesh->totcol = origmesh->totcol;
tmpmesh->smoothresh = origmesh->smoothresh;
if (origmesh->mat) {
for (i = origmesh->totcol; i-- > 0; ) {
/* are we an object material or data based? */
tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : origmesh->mat[i];
if (tmpmesh->mat[i]) {
tmpmesh->mat[i]->id.us++;
}
}
}
break;
}
} /* end copy materials */
if (calc_tessface) {
/* cycles and exporters rely on this still */
BKE_mesh_tessface_ensure(tmpmesh);
}
/* make sure materials get updated in objects */
test_object_materials(bmain, &tmpmesh->id);
return tmpmesh;
}

View File

@@ -38,6 +38,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_group_types.h"
@@ -76,6 +77,7 @@
#include "BKE_armature.h"
#include "BKE_action.h"
#include "BKE_bullet.h"
#include "BKE_cache_library.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
@@ -316,9 +318,12 @@ void BKE_object_free_derived_caches(Object *ob)
}
if (ob->derivedFinal) {
ob->derivedFinal->needsFree = 1;
ob->derivedFinal->release(ob->derivedFinal);
ob->derivedFinal = NULL;
/* dupli cache owns the derivedFinal, is freed by duplicator object */
if (!(ob->transflag & OB_IS_DUPLI_CACHE)) {
ob->derivedFinal->needsFree = 1;
ob->derivedFinal->release(ob->derivedFinal);
ob->derivedFinal = NULL;
}
}
if (ob->derivedDeform) {
ob->derivedDeform->needsFree = 1;
@@ -327,6 +332,8 @@ void BKE_object_free_derived_caches(Object *ob)
}
BKE_object_free_curve_cache(ob);
BKE_object_dupli_cache_clear(ob);
}
void BKE_object_free_caches(Object *object)
@@ -447,6 +454,8 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
free_path(ob->curve_cache->path);
MEM_freeN(ob->curve_cache);
}
BKE_object_dupli_cache_free(ob);
}
void BKE_object_free(Object *ob)
@@ -486,6 +495,7 @@ void BKE_object_unlink(Object *ob)
ARegion *ar;
RegionView3D *rv3d;
LodLevel *lod;
CacheLibrary *cachelib;
int a, found;
unlink_controllers(&ob->controllers);
@@ -673,6 +683,10 @@ void BKE_object_unlink(Object *ob)
lod->source = NULL;
}
/* dupli cache is cleared entirely if the object in question is duplified to keep it simple */
if (BKE_object_dupli_cache_contains(obt, ob))
BKE_object_dupli_cache_clear(ob);
obt = obt->id.next;
}
@@ -858,6 +872,17 @@ void BKE_object_unlink(Object *ob)
}
camera = camera->id.next;
}
/* cache libraries */
for (cachelib = bmain->cache_library.first; cachelib; cachelib = cachelib->id.next) {
CacheItem *item, *item_next;
for (item = cachelib->items.first; item; item = item_next) {
item_next = item->next;
if (item->ob == ob) {
BKE_cache_library_remove_item(cachelib, item);
}
}
}
}
/* actual check for internal data, not context or flags */
@@ -1330,12 +1355,6 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, false);
/* XXX - from reading existing code this seems correct but intended usage of
* pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
if (psysn->clmd) {
psysn->clmd->point_cache = psysn->pointcache;
}
id_us_plus((ID *)psysn->part);
return psysn;
@@ -1527,6 +1546,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
id_us_plus((ID *)obn->data);
id_us_plus((ID *)obn->gpd);
id_lib_extern((ID *)obn->dup_group);
id_lib_extern((ID *)obn->cache_library);
for (a = 0; a < obn->totcol; a++) id_us_plus((ID *)obn->mat[a]);
@@ -1558,6 +1578,8 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
/* Copy runtime surve data. */
obn->curve_cache = NULL;
obn->dup_cache = NULL;
if (ob->id.lib) {
BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id);
}
@@ -1589,6 +1611,7 @@ static void extern_local_object(Object *ob)
id_lib_extern((ID *)ob->data);
id_lib_extern((ID *)ob->dup_group);
id_lib_extern((ID *)ob->cache_library);
id_lib_extern((ID *)ob->poselib);
id_lib_extern((ID *)ob->gpd);
@@ -2846,7 +2869,15 @@ bool BKE_object_minmax_dupli(Scene *scene, Object *ob, float r_min[3], float r_m
/* pass */
}
else {
BoundBox *bb = BKE_object_boundbox_get(dob->ob);
BoundBox *bb = NULL;
if (ob->dup_cache) {
DupliObjectData *dob_data = BKE_dupli_cache_find_data(ob->dup_cache, dob->ob);
if (dob_data->cache_dm) {
bb = &dob_data->bb;
}
}
if (!bb)
bb = BKE_object_boundbox_get(dob->ob);
if (bb) {
int i;

View File

@@ -35,6 +35,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_string_utf8.h"
@@ -48,6 +50,7 @@
#include "DNA_vfont_types.h"
#include "BKE_animsys.h"
#include "BKE_cache_library.h"
#include "BKE_DerivedMesh.h"
#include "BKE_depsgraph.h"
#include "BKE_font.h"
@@ -96,7 +99,7 @@ typedef struct DupliGenerator {
static const DupliGenerator *get_dupli_generator(const DupliContext *ctx);
/* create initial context for root object */
static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene *scene, Object *ob, float space_mat[4][4], bool update)
static void init_context_ex(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene *scene, Object *ob, float space_mat[4][4], const DupliGenerator *gen, bool update)
{
r_ctx->eval_ctx = eval_ctx;
r_ctx->scene = scene;
@@ -110,14 +113,19 @@ static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene
copy_m4_m4(r_ctx->space_mat, space_mat);
else
unit_m4(r_ctx->space_mat);
r_ctx->lay = ob->lay;
r_ctx->lay = ob ? ob->lay : 0;
r_ctx->level = 0;
r_ctx->gen = get_dupli_generator(r_ctx);
r_ctx->gen = gen ? gen : get_dupli_generator(r_ctx);
r_ctx->duplilist = NULL;
}
static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene *scene, Object *ob, bool update)
{
init_context_ex(r_ctx, eval_ctx, scene, ob, NULL, NULL, update);
}
/* create sub-context for recursive duplis */
static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated)
{
@@ -126,7 +134,7 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj
r_ctx->animated |= animated; /* object animation makes all children animated */
/* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */
if (ctx->gen->type == OB_DUPLIGROUP)
if (ctx->gen->type == OB_DUPLIGROUP && ctx->object)
r_ctx->group = ctx->object->dup_group;
r_ctx->object = ob;
@@ -219,7 +227,10 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
{
Object *parent = ctx->object;
Object *obedit = ctx->scene->obedit;
if (!parent)
return;
if (ctx->group) {
unsigned int lay = ctx->group->layer;
GroupObject *go;
@@ -255,69 +266,84 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
/*---- Implementations ----*/
/* OB_DUPLIGROUP */
static void make_duplis_group(const DupliContext *ctx)
/* Intern function for creating instances of group content
* with or without a parent (parent == NULL is allowed!)
* Note: some of the group animation update functions use the parent object,
* but this is old NLA code that is currently disabled and might be removed entirely.
*/
static void make_duplis_group_intern(const DupliContext *ctx, Group *group, Object *parent)
{
bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER);
Object *ob = ctx->object;
Group *group;
const bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER);
GroupObject *go;
float group_mat[4][4];
int id;
bool animated, hide;
if (ob->dup_group == NULL) return;
group = ob->dup_group;
/* combine group offset and obmat */
bool animated;
unit_m4(group_mat);
sub_v3_v3(group_mat[3], group->dupli_ofs);
mul_m4_m4m4(group_mat, ob->obmat, group_mat);
/* don't access 'ob->obmat' from now on. */
if (parent) {
/* combine group offset and obmat */
mul_m4_m4m4(group_mat, parent->obmat, group_mat);
/* don't access 'parent->obmat' from now on. */
}
/* handles animated groups */
/* we need to check update for objects that are not in scene... */
if (ctx->do_update) {
/* note: update is optional because we don't always need object
* transformations to be correct. Also fixes bug [#29616]. */
BKE_group_handle_recalc_and_update(ctx->eval_ctx, ctx->scene, ob, group);
BKE_group_handle_recalc_and_update(ctx->eval_ctx, ctx->scene, parent, group);
}
animated = BKE_group_is_animated(group, ob);
animated = BKE_group_is_animated(group, parent);
for (go = group->gobject.first, id = 0; go; go = go->next, id++) {
float mat[4][4];
bool hide;
/* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */
if (go->ob != ob) {
float mat[4][4];
/* Special case for instancing dupli-groups, see: T40051
* this object may be instanced via dupli-verts/faces, in this case we don't want to render
* (blender convention), but _do_ show in the viewport.
*
* Regular objects work fine but not if we're instancing dupli-groups,
* because the rules for rendering aren't applied to objects they instance.
* We could recursively pass down the 'hide' flag instead, but that seems unnecessary.
*/
if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) {
continue;
}
/* group dupli offset, should apply after everything else */
mul_m4_m4m4(mat, group_mat, go->ob->obmat);
/* check the group instance and object layers match, also that the object visible flags are ok. */
hide = (go->ob->lay & group->layer) == 0 ||
(for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW);
make_dupli(ctx, go->ob, mat, id, animated, hide);
/* recursion */
make_recursive_duplis(ctx, go->ob, group_mat, id, animated);
if (go->ob == parent)
continue;
/* Special case for instancing dupli-groups, see: T40051
* this object may be instanced via dupli-verts/faces, in this case we don't want to render
* (blender convention), but _do_ show in the viewport.
*
* Regular objects work fine but not if we're instancing dupli-groups,
* because the rules for rendering aren't applied to objects they instance.
* We could recursively pass down the 'hide' flag instead, but that seems unnecessary.
*/
if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) {
continue;
}
/* group dupli offset, should apply after everything else */
mul_m4_m4m4(mat, group_mat, go->ob->obmat);
/* check the group instance and object layers match, also that the object visible flags are ok. */
hide = (go->ob->lay & group->layer) == 0 ||
(for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW);
make_dupli(ctx, go->ob, mat, id, animated, hide);
/* recursion */
make_recursive_duplis(ctx, go->ob, group_mat, id, animated);
}
}
/* OB_DUPLIGROUP */
static void make_duplis_group(const DupliContext *ctx)
{
Object *ob = ctx->object;
if (!ob || !ob->dup_group)
return;
make_duplis_group_intern(ctx, ob->dup_group, ob);
}
const DupliGenerator gen_dupli_group = {
OB_DUPLIGROUP, /* type */
make_duplis_group /* make_duplis */
@@ -331,8 +357,9 @@ static void make_duplis_frames(const DupliContext *ctx)
extern int enable_cu_speed; /* object.c */
Object copyob;
int cfrao = scene->r.cfra;
int dupend = ob->dupend;
if (!ob)
return;
/* dupliframes not supported inside groups */
if (ctx->group)
return;
@@ -341,7 +368,7 @@ static void make_duplis_frames(const DupliContext *ctx)
*/
if (ob->parent == NULL && BLI_listbase_is_empty(&ob->constraints) && ob->adt == NULL)
return;
/* make a copy of the object's original data (before any dupli-data overwrites it)
* as we'll need this to keep track of unkeyed data
* - this doesn't take into account other data that can be reached from the object,
@@ -356,7 +383,7 @@ static void make_duplis_frames(const DupliContext *ctx)
* updates, as this is not a permanent change to the object */
ob->id.flag |= LIB_ANIM_NO_RECALC;
for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) {
for (scene->r.cfra = ob->dupsta; scene->r.cfra <= ob->dupend; scene->r.cfra++) {
int ok = 1;
/* - dupoff = how often a frames within the range shouldn't be made into duplis
@@ -512,6 +539,9 @@ static void make_duplis_verts(const DupliContext *ctx)
Object *parent = ctx->object;
bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
VertexDupliData vdd;
if (!parent)
return;
vdd.ctx = ctx;
vdd.use_rotation = parent->transflag & OB_DUPLIROT;
@@ -592,6 +622,8 @@ static void make_duplis_font(const DupliContext *ctx)
const wchar_t *text = NULL;
bool text_free = false;
if (!par)
return;
/* font dupliverts not supported inside groups */
if (ctx->group)
return;
@@ -779,6 +811,9 @@ static void make_duplis_faces(const DupliContext *ctx)
bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
FaceDupliData fdd;
if (!parent)
return;
fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0);
/* gather mesh info */
@@ -842,7 +877,8 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
int no_draw_flag = PARS_UNEXIST;
if (psys == NULL) return;
if (!psys)
return;
part = psys->part;
@@ -1123,6 +1159,9 @@ static void make_duplis_particles(const DupliContext *ctx)
ParticleSystem *psys;
int psysid;
if (!ctx->object)
return;
/* particle system take up one level in id, the particles another */
for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) {
/* particles create one more level for persistent psys index */
@@ -1142,8 +1181,13 @@ const DupliGenerator gen_dupli_particles = {
/* select dupli generator from given context */
static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
{
int transflag = ctx->object->transflag;
int restrictflag = ctx->object->restrictflag;
int transflag, restrictflag;
if (!ctx->object)
return NULL;
transflag = ctx->object->transflag;
restrictflag = ctx->object->restrictflag;
if ((transflag & OB_DUPLI) == 0)
return NULL;
@@ -1183,15 +1227,36 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
/* Returns a list of DupliObject */
ListBase *object_duplilist_ex(EvaluationContext *eval_ctx, Scene *scene, Object *ob, bool update)
{
ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
DupliContext ctx;
init_context(&ctx, eval_ctx, scene, ob, NULL, update);
if (ctx.gen) {
ctx.duplilist = duplilist;
ctx.gen->make_duplis(&ctx);
if (update) {
BKE_object_dupli_cache_update(scene, ob, eval_ctx, (float)scene->r.cfra);
}
if (ob->dup_cache) {
/* Note: duplis in the cache don't have the main duplicator obmat applied.
* duplilist also should return a full copy of duplis, so we copy
* the cached list and apply the obmat to each.
*/
ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
DupliObject *dob;
BLI_duplicatelist(duplilist, &ob->dup_cache->duplilist);
for (dob = duplilist->first; dob; dob = dob->next) {
mul_m4_m4m4(dob->mat, ob->obmat, dob->mat);
}
return duplilist;
}
else {
ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
DupliContext ctx;
init_context(&ctx, eval_ctx, scene, ob, update);
if (ctx.gen) {
ctx.duplilist = duplilist;
ctx.gen->make_duplis(&ctx);
}
return duplilist;
}
return duplilist;
}
/* note: previously updating was always done, this is why it defaults to be on
@@ -1201,6 +1266,24 @@ ListBase *object_duplilist(EvaluationContext *eval_ctx, Scene *sce, Object *ob)
return object_duplilist_ex(eval_ctx, sce, ob, true);
}
ListBase *group_duplilist_ex(EvaluationContext *eval_ctx, Scene *scene, Group *group, bool update)
{
ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
DupliContext ctx;
init_context_ex(&ctx, eval_ctx, scene, NULL, NULL, &gen_dupli_group, update);
ctx.duplilist = duplilist;
make_duplis_group_intern(&ctx, group, NULL);
return duplilist;
}
ListBase *group_duplilist(EvaluationContext *eval_ctx, Scene *scene, Group *group)
{
return group_duplilist_ex(eval_ctx, scene, group, true);
}
void free_object_duplilist(ListBase *lb)
{
BLI_freelistN(lb);
@@ -1237,6 +1320,209 @@ int count_duplilist(Object *ob)
return 1;
}
/* ------------------------------------------------------------------------- */
static void dupli_cache_calc_boundbox(DupliObjectData *data)
{
float min[3], max[3];
if (data->cache_dm) {
INIT_MINMAX(min, max);
data->cache_dm->getMinMax(data->cache_dm, min, max);
}
else {
zero_v3(min);
zero_v3(max);
}
BKE_boundbox_init_from_minmax(&data->bb, min, max);
}
void BKE_dupli_object_data_init(DupliObjectData *data, Object *ob, DerivedMesh *dm)
{
data->ob = ob;
data->cache_dm = dm;
dm->needsFree = false; /* take ownership */
memset(&data->bb, 0, sizeof(data->bb));
dupli_cache_calc_boundbox(data);
}
void BKE_dupli_object_data_clear(DupliObjectData *data)
{
if (data->cache_dm) {
/* we lock DMs in the cache to prevent freeing outside,
* now allow releasing again
*/
data->cache_dm->needsFree = true;
data->cache_dm->release(data->cache_dm);
}
}
static void dupli_object_data_free(DupliObjectData *data)
{
BKE_dupli_object_data_clear(data);
MEM_freeN(data);
}
static void dupli_object_free(DupliObject *dob)
{
MEM_freeN(dob);
}
static void dupli_cache_clear(DupliCache *dupcache)
{
DupliObject *dob, *dob_next;
for (dob = dupcache->duplilist.first; dob; dob = dob_next) {
dob_next = dob->next;
dupli_object_free(dob);
}
BLI_listbase_clear(&dupcache->duplilist);
BLI_ghash_clear(dupcache->ghash, NULL, (GHashValFreeFP)dupli_object_data_free);
}
static void dupli_cache_free(DupliCache *dupcache)
{
dupli_cache_clear(dupcache);
BLI_ghash_free(dupcache->ghash, NULL, (GHashValFreeFP)dupli_object_data_free);
MEM_freeN(dupcache);
}
static DupliCache *dupli_cache_new(void)
{
DupliCache *dupcache = MEM_callocN(sizeof(DupliCache), "dupli object cache");
dupcache->ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "dupli object data hash");
return dupcache;
}
static DupliObjectData *dupli_cache_add_object_data(DupliCache *dupcache, Object *ob)
{
DupliObjectData *data = MEM_callocN(sizeof(DupliObjectData), "dupli object data");
data->ob = ob;
BLI_ghash_insert(dupcache->ghash, data->ob, data);
return data;
}
static DupliObject *dupli_cache_add_object(DupliCache *dupcache)
{
DupliObject *dob = MEM_callocN(sizeof(DupliObject), "dupli object");
unit_m4(dob->mat);
BLI_addtail(&dupcache->duplilist, dob);
return dob;
}
/* ------------------------------------------------------------------------- */
void BKE_object_dupli_cache_update(Scene *scene, Object *ob, EvaluationContext *eval_ctx, float frame)
{
const eCacheLibrary_EvalMode eval_mode = eval_ctx->mode == DAG_EVAL_RENDER ? CACHE_LIBRARY_EVAL_RENDER : CACHE_LIBRARY_EVAL_REALTIME;
bool is_dupligroup = (ob->transflag & OB_DUPLIGROUP) && ob->dup_group;
bool is_cached = (ob->transflag & OB_DUPLI_READ_CACHE) && ob->cache_library;
/* cache is a group duplicator feature only */
if (is_dupligroup && is_cached) {
if (ob->dup_cache && !(ob->dup_cache->flag & DUPCACHE_FLAG_DIRTY)) {
/* skip if cache is valid */
}
else {
if (G.debug & G_DEBUG)
printf("Update dupli cache for object '%s'\n", ob->id.name+2);
if (ob->dup_cache) {
dupli_cache_clear(ob->dup_cache);
}
else {
ob->dup_cache = dupli_cache_new();
}
/* TODO at this point we could apply animation offset */
BKE_cache_read_dupli_cache(scene, frame, eval_mode, ob->dup_group, ob->dup_cache, ob->cache_library);
ob->dup_cache->flag &= ~DUPCACHE_FLAG_DIRTY;
ob->dup_cache->cfra = frame;
}
}
else {
if (ob->dup_cache) {
dupli_cache_free(ob->dup_cache);
ob->dup_cache = NULL;
}
}
}
void BKE_object_dupli_cache_clear(Object *ob)
{
if (ob->dup_cache) {
dupli_cache_clear(ob->dup_cache);
}
}
void BKE_object_dupli_cache_free(Object *ob)
{
if (ob->dup_cache) {
dupli_cache_free(ob->dup_cache);
ob->dup_cache = NULL;
}
}
bool BKE_object_dupli_cache_contains(Object *ob, Object *other)
{
if (ob->dup_cache) {
DupliObject *dob;
for (dob = ob->dup_cache->duplilist.first; dob; dob = dob->next) {
if (dob->ob == other)
return true;
}
}
return false;
}
DupliObjectData *BKE_dupli_cache_find_data(DupliCache *dupcache, Object *ob)
{
DupliObjectData *data = BLI_ghash_lookup(dupcache->ghash, ob);
return data;
}
DupliObjectData *BKE_dupli_cache_add_mesh(DupliCache *dupcache, Object *ob, DerivedMesh *dm)
{
DupliObjectData *data = dupli_cache_add_object_data(dupcache, ob);
data->cache_dm = dm;
dupli_cache_calc_boundbox(data);
/* we own this dm now and need to protect it until we free it ourselves */
dm->needsFree = false;
return data;
}
void BKE_dupli_cache_add_instance(DupliCache *dupcache, float obmat[4][4], DupliObjectData *data)
{
DupliObject *dob = dupli_cache_add_object(dupcache);
/* data must have been created correctly */
BLI_assert(BLI_ghash_lookup(dupcache->ghash, data->ob) != NULL);
dob->ob = data->ob;
copy_m4_m4(dob->mat, obmat);
dob->data = data;
}
/* ------------------------------------------------------------------------- */
DupliApplyData *duplilist_apply(Object *ob, ListBase *duplilist)
{
DupliApplyData *apply_data = NULL;

View File

@@ -64,6 +64,7 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_cache_library.h"
#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
#include "BKE_editmesh.h"
@@ -1771,6 +1772,9 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
/* clear animation overrides */
/* XXX TODO... */
/* tag cached objects */
BKE_cache_library_dag_recalc_tag(eval_ctx, bmain);
for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set)
DAG_scene_relations_update(bmain, sce_iter);

View File

@@ -58,6 +58,7 @@
#include "DNA_armature_types.h"
#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
#include "DNA_controller_types.h"
@@ -113,6 +114,7 @@
#include "BKE_armature.h"
#include "BKE_brush.h"
#include "BKE_cache_library.h"
#include "BKE_cloth.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
@@ -1969,7 +1971,6 @@ static void direct_link_paint_curve(FileData *fd, PaintCurve *pc)
pc->points = newdataadr(fd, pc->points);
}
static void direct_link_script(FileData *UNUSED(fd), Script *script)
{
script->id.us = 1;
@@ -1977,6 +1978,36 @@ static void direct_link_script(FileData *UNUSED(fd), Script *script)
}
/* ************ READ CacheLibrary *************** */
static void lib_link_cache_library(FileData *fd, Main *main)
{
CacheLibrary *cachelib;
CacheItem *item, *item_next;
for (cachelib = main->cache_library.first; cachelib; cachelib = cachelib->id.next) {
if (cachelib->id.flag & LIB_NEED_LINK) {
cachelib->id.flag -= LIB_NEED_LINK;
for (item = cachelib->items.first; item; item = item_next) {
item_next = item->next;
item->ob = newlibadr(fd, cachelib->id.lib, item->ob);
if (!item->ob)
BKE_cache_library_remove_item(cachelib, item);
}
}
}
}
static void direct_link_cache_library(FileData *fd, CacheLibrary *cachelib)
{
link_list(fd, &cachelib->items);
cachelib->items_hash = NULL;
}
/* ************ READ PACKEDFILE *************** */
static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
@@ -4406,6 +4437,7 @@ static void lib_link_object(FileData *fd, Main *main)
ob->track = newlibadr(fd, ob->id.lib, ob->track);
ob->poselib = newlibadr_us(fd, ob->id.lib, ob->poselib);
ob->dup_group = newlibadr_us(fd, ob->id.lib, ob->dup_group);
ob->cache_library = newlibadr_us(fd, ob->id.lib, ob->cache_library);
ob->proxy = newlibadr_us(fd, ob->id.lib, ob->proxy);
if (ob->proxy) {
@@ -4949,6 +4981,13 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
}
lmd->cache_system = NULL;
}
else if (md->type == eModifierType_Cache) {
CacheModifierData *cmd = (CacheModifierData *)md;
cmd->output_dm = NULL;
cmd->input_dm = NULL;
cmd->flag &= ~(MOD_CACHE_USE_OUTPUT_REALTIME | MOD_CACHE_USE_OUTPUT_RENDER);
}
}
}
@@ -5004,6 +5043,8 @@ static void direct_link_object(FileData *fd, Object *ob)
/* do it here, below old data gets converted */
direct_link_modifiers(fd, &ob->modifiers);
ob->dup_cache = NULL;
link_list(fd, &ob->effect);
paf= ob->effect.first;
while (paf) {
@@ -7450,6 +7491,7 @@ static const char *dataname(short id_code)
case ID_MC: return "Data from MC";
case ID_MSK: return "Data from MSK";
case ID_LS: return "Data from LS";
case ID_CL: return "Data from CL";
}
return "Data from Lib Block";
@@ -7636,6 +7678,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
case ID_PC:
direct_link_paint_curve(fd, (PaintCurve *)id);
break;
case ID_CL:
direct_link_cache_library(fd, (CacheLibrary *)id);
break;
}
oldnewmap_free_unused(fd->datamap);
@@ -7830,6 +7875,7 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_mask(fd, main);
lib_link_linestyle(fd, main);
lib_link_gpencil(fd, main);
lib_link_cache_library(fd, main);
lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
@@ -8706,6 +8752,8 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
if (ob->dup_group)
expand_doit(fd, mainvar, ob->dup_group);
if (ob->cache_library)
expand_doit(fd, mainvar, ob->cache_library);
if (ob->proxy)
expand_doit(fd, mainvar, ob->proxy);
@@ -8980,6 +9028,15 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
expand_animdata(fd, mainvar, gpd->adt);
}
static void expand_cache_library(FileData *fd, Main *mainvar, CacheLibrary *cachelib)
{
CacheItem *item;
for (item = cachelib->items.first; item; item = item->next) {
expand_doit(fd, mainvar, item->ob);
}
}
void BLO_main_expander(void (*expand_doit_func)(void *, Main *, void *))
{
expand_doit = expand_doit_func;
@@ -9077,6 +9134,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_GD:
expand_gpencil(fd, mainvar, (bGPdata *)id);
break;
case ID_CL:
expand_cache_library(fd, mainvar, (CacheLibrary *)id);
break;
}
do_it = true;

View File

@@ -97,6 +97,7 @@
#include "DNA_armature_types.h"
#include "DNA_actuator_types.h"
#include "DNA_brush_types.h"
#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
#include "DNA_constraint_types.h"
@@ -147,6 +148,7 @@
#include "BKE_action.h"
#include "BKE_blender.h"
#include "BKE_bpath.h"
#include "BKE_cache_library.h"
#include "BKE_curve.h"
#include "BKE_constraint.h"
#include "BKE_global.h" // for G
@@ -3473,6 +3475,24 @@ static void write_linestyles(WriteData *wd, ListBase *idbase)
}
}
static void write_cachelibraries(WriteData *wd, ListBase *idbase)
{
CacheLibrary *cachelib;
CacheItem *item;
for (cachelib = idbase->first; cachelib; cachelib = cachelib->id.next) {
if (cachelib->id.us > 0 || wd->current) {
writestruct(wd, ID_CL, "CacheLibrary", 1, cachelib);
if (cachelib->id.properties)
IDP_WriteProperty(cachelib->id.properties, wd);
for (item = cachelib->items.first; item; item = item->next) {
writestruct(wd, DATA, "CacheItem", 1, item);
}
}
}
}
/* context is usually defined by WM, two cases where no WM is available:
* - for forward compatibility, curscreen has to be saved
* - for undofile, curscene needs to be saved */
@@ -3601,6 +3621,7 @@ static int write_file_handle(
write_scripts (wd, &mainvar->script);
write_gpencils (wd, &mainvar->gpencil);
write_linestyles(wd, &mainvar->linestyle);
write_cachelibraries(wd, &mainvar->cache_library);
write_libraries(wd, mainvar->next);
if (write_user_block) {

View File

@@ -75,6 +75,7 @@ struct ImBuf;
struct bNodeTree;
struct bNode;
struct bNodeSocket;
struct CacheLibrary;
struct wmDropBox;
struct wmDrag;
struct wmEvent;
@@ -907,6 +908,8 @@ void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
void uiTemplateComponentMenu(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name);
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color);
uiLayout *uiTemplateCacheLibraryItem(uiLayout *layout, struct bContext *C, struct CacheLibrary *cachelib,
struct Object *ob, int type, int index, int enabled);
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"

View File

@@ -31,6 +31,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_cache_library_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -49,6 +50,7 @@
#include "BLF_api.h"
#include "BLF_translation.h"
#include "BKE_cache_library.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
@@ -73,6 +75,7 @@
#include "ED_util.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -354,6 +357,7 @@ static const char *template_id_browse_tip(StructRNA *type)
case ID_MSK: return N_("Browse Mask to be linked");
case ID_PAL: return N_("Browse Palette Data to be linked");
case ID_PC: return N_("Browse Paint Curve Data to be linked");
case ID_CL: return N_("Browse Cache Library Data to be linked");
}
}
return N_("Browse ID data to be linked");
@@ -394,6 +398,7 @@ static const char *template_id_context(StructRNA *type)
case ID_MSK: return BLF_I18NCONTEXT_ID_MASK;
case ID_PAL: return BLF_I18NCONTEXT_ID_PALETTE;
case ID_PC: return BLF_I18NCONTEXT_ID_PAINTCURVE;
case ID_CL: return BLF_I18NCONTEXT_ID_CACHELIBRARY;
}
}
return BLF_I18NCONTEXT_DEFAULT;
@@ -3693,3 +3698,81 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
UI_block_align_end(block);
}
/************************* Cache Library Item **************************/
static void cache_item_button(uiLayout *layout, bContext *UNUSED(C), CacheLibrary *cachelib, CacheItem *item, Object *ob, int type, int index)
{
if (item) {
PointerRNA itemptr;
RNA_pointer_create((ID *)cachelib, &RNA_CacheItem, item, &itemptr);
uiItemR(layout, &itemptr, "enabled", 0, "", ICON_NONE);
}
else {
uiLayout *row = uiLayoutRow(layout, false);
uiBlock *block = uiLayoutGetBlock(row);
uiBut *but;
PointerRNA obptr;
PointerRNA *opptr;
RNA_id_pointer_create((ID *)ob, &obptr);
uiLayoutSetContextPointer(row, "cache_object", &obptr);
but = uiDefButO(block, UI_BTYPE_CHECKBOX, "CACHELIBRARY_OT_item_enable", WM_OP_EXEC_DEFAULT, "",
0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
opptr = UI_but_operator_ptr_get(but);
RNA_enum_set(opptr, "type", type);
RNA_int_set(opptr, "index", index);
}
}
static int cache_item_indent(int type)
{
switch (type) {
case CACHE_TYPE_OBJECT:
return 0;
default:
return 1;
}
}
uiLayout *uiTemplateCacheLibraryItem(uiLayout *layout, bContext *C, CacheLibrary *cachelib,
Object *ob, int type, int index, int enabled)
{
CacheItem *item = BKE_cache_library_find_item(cachelib, ob, type, index);
uiLayout *split, *row, *sub;
int i;
char name[2*MAX_NAME];
int icon = ICON_NONE;
row = uiLayoutRow(layout, false);
uiLayoutSetEnabled(row, enabled);
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
split = uiLayoutSplit(row, 0.0f, false);
for (i = 0; i < cache_item_indent(type); ++i)
uiItemL(split, "", ICON_NONE);
cache_item_button(split, C, cachelib, item, ob, type, index);
split = uiLayoutSplit(row, 0.1f, false);
uiLayoutSetEnabled(split, item && (item->flag & CACHE_ITEM_ENABLED));
sub = uiLayoutColumn(split, false);
BKE_cache_item_name(ob, type, index, name);
RNA_enum_icon_from_value(cache_library_item_type_items, type, &icon);
uiItemL(split, name, icon);
/* display read result */
split = uiLayoutSplit(row, 0.9f, false);
if (item && (item->flag & CACHE_ITEM_ENABLED))
RNA_enum_icon_from_value(cache_library_read_result_items, item->read_result, &icon);
else
icon = ICON_NONE;
uiItemL(split, NULL, icon);
return sub;
}

View File

@@ -26,8 +26,10 @@ set(INC
../../bmesh
../../makesdna
../../makesrna
../../pointcache
../../windowmanager
../../collada
../../../../intern/guardedalloc
)
set(INC_SYS
@@ -35,9 +37,11 @@ set(INC_SYS
)
set(SRC
io_cache_library.c
io_collada.c
io_ops.c
io_cache_library.h
io_collada.h
io_ops.h
)

View File

@@ -36,10 +36,13 @@ incs = [
'../../blenfont',
'../../blenkernel',
'../../blenlib',
'../../bmesh',
'../../collada',
'../../makesdna',
'../../makesrna',
'../../pointcache',
'../../windowmanager',
'../../bmesh../../makesdna',
'../../../../intern/guardedalloc',
]
if env['WITH_BF_COLLADA']:

View File

@@ -0,0 +1,576 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/io/io_cache_library.c
* \ingroup editor/io
*/
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLF_translation.h"
#include "BLI_blenlib.h"
#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_utildefines.h"
#include "DNA_cache_library_types.h"
#include "DNA_group_types.h"
#include "DNA_listBase.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BKE_anim.h"
#include "BKE_depsgraph.h"
#include "BKE_cache_library.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "ED_screen.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
#include "io_cache_library.h"
#include "PTC_api.h"
static int ED_cache_library_active_object_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
if (!ob || !ob->cache_library)
return false;
return true;
}
/********************** new cache library operator *********************/
static int new_cachelib_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
CacheLibrary *cachelib = ob->cache_library;
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
/* add or copy material */
if (cachelib) {
cachelib = BKE_cache_library_copy(cachelib);
}
else {
cachelib = BKE_cache_library_add(bmain, DATA_("CacheLibrary"));
}
/* enable fake user by default */
cachelib->id.flag |= LIB_FAKEUSER;
/* hook into UI */
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer se also increases user, so this compensates it */
cachelib->id.us--;
RNA_id_pointer_create(&cachelib->id, &idptr);
RNA_property_pointer_set(&ptr, prop, idptr);
RNA_property_update(C, &ptr, prop);
}
WM_event_add_notifier(C, NC_SCENE, cachelib);
return OPERATOR_FINISHED;
}
void CACHELIBRARY_OT_new(wmOperatorType *ot)
{
/* identifiers */
ot->name = "New Cache Library";
ot->idname = "CACHELIBRARY_OT_new";
ot->description = "Add a new cache library";
/* api callbacks */
ot->poll = ED_operator_object_active;
ot->exec = new_cachelib_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
/********************** delete cache library operator *********************/
static int cache_library_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_active_object(C);
CacheLibrary *cachelib = ob->cache_library;
BKE_cache_library_unlink(cachelib);
BKE_libblock_free(bmain, cachelib);
WM_event_add_notifier(C, NC_SCENE, cachelib);
return OPERATOR_FINISHED;
}
void CACHELIBRARY_OT_delete(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Delete Cache Library";
ot->idname = "CACHELIBRARY_OT_delete";
ot->description = "Delete a cache library data block";
/* api callbacks */
ot->exec = cache_library_delete_exec;
ot->invoke = WM_operator_confirm;
ot->poll = ED_cache_library_active_object_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
}
/********************** enable cache item operator *********************/
static int cache_item_enable_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
CacheLibrary *cachelib = ob->cache_library;
Object *obcache = CTX_data_pointer_get_type(C, "cache_object", &RNA_Object).data;
if (!cachelib || !obcache)
return false;
return true;
}
static int cache_item_enable_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
CacheLibrary *cachelib = ob->cache_library;
Object *obcache = CTX_data_pointer_get_type(C, "cache_object", &RNA_Object).data;
int type = RNA_enum_get(op->ptr, "type");
int index = RNA_int_get(op->ptr, "index");
CacheItem *item = BKE_cache_library_add_item(cachelib, obcache, type, index);
item->flag |= CACHE_ITEM_ENABLED;
WM_event_add_notifier(C, NC_OBJECT, cachelib);
return OPERATOR_FINISHED;
}
void CACHELIBRARY_OT_item_enable(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Enable Cache Item";
ot->idname = "CACHELIBRARY_OT_item_enable";
ot->description = "Enable a cache item";
/* api callbacks */
ot->poll = cache_item_enable_poll;
ot->exec = cache_item_enable_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
prop = RNA_def_enum(ot->srna, "type", cache_library_item_type_items, CACHE_TYPE_OBJECT, "Type", "Type of cache item to add");
RNA_def_property_flag(prop, PROP_REQUIRED);
RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "Index", "Index of data in the object", -1, INT_MAX);
}
/********************** bake cache operator *********************/
static int cache_library_bake_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
if (!ob || !(ob->transflag & OB_DUPLIGROUP) || !ob->dup_group || !ob->cache_library)
return false;
/* re-baking cached results doesn't make much sense,
* clarify workflow by enabling either reading or writing, but not both
*/
if (ob->transflag & OB_DUPLI_READ_CACHE)
return false;
return true;
}
typedef struct CacheLibraryBakeJob {
short *stop, *do_update;
float *progress;
struct Main *bmain;
struct Scene *scene;
EvaluationContext eval_ctx;
struct CacheLibrary *cachelib;
struct Group *group;
struct PTCWriterArchive *archive;
struct PTCWriter *writer;
int origfra; /* original frame to reset scene after export */
float origframelen; /* original frame length to reset scene after export */
} CacheLibraryBakeJob;
static void cache_library_bake_freejob(void *customdata)
{
CacheLibraryBakeJob *data= (CacheLibraryBakeJob *)customdata;
MEM_freeN(data);
}
static void cache_library_bake_do(CacheLibraryBakeJob *data, short *stop, short *do_update, float *progress)
{
Scene *scene = data->scene;
int start_frame, end_frame;
if ((*stop) || (G.is_break))
return;
data->writer = PTC_writer_dupligroup(data->group->id.name, &data->eval_ctx, scene, data->group, data->cachelib);
PTC_writer_init(data->writer, data->archive);
/* XXX where to get this from? */
start_frame = scene->r.sfra;
end_frame = scene->r.efra;
PTC_bake(data->bmain, scene, &data->eval_ctx, data->writer, start_frame, end_frame, stop, do_update, progress);
if (data->writer) {
PTC_writer_free(data->writer);
data->writer = NULL;
}
}
static void cache_library_bake_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
CacheLibraryBakeJob *data = (CacheLibraryBakeJob *)customdata;
Scene *scene = data->scene;
char filename[FILE_MAX];
data->stop = stop;
data->do_update = do_update;
data->progress = progress;
data->origfra = scene->r.cfra;
data->origframelen = scene->r.framelen;
scene->r.framelen = 1.0f;
BKE_cache_archive_path(data->cachelib->filepath, (ID *)data->cachelib, data->cachelib->id.lib, filename, sizeof(filename));
data->archive = PTC_open_writer_archive(scene, filename);
if (data->archive) {
G.is_break = false;
if (data->cachelib->eval_mode & CACHE_LIBRARY_EVAL_REALTIME) {
data->eval_ctx.mode = DAG_EVAL_VIEWPORT;
PTC_writer_archive_use_render(data->archive, false);
cache_library_bake_do(data, stop, do_update, progress);
}
if (data->cachelib->eval_mode & CACHE_LIBRARY_EVAL_RENDER) {
data->eval_ctx.mode = DAG_EVAL_RENDER;
PTC_writer_archive_use_render(data->archive, true);
cache_library_bake_do(data, stop, do_update, progress);
}
}
*do_update = true;
*stop = 0;
}
static void cache_library_bake_endjob(void *customdata)
{
CacheLibraryBakeJob *data = (CacheLibraryBakeJob *)customdata;
Scene *scene = data->scene;
G.is_rendering = false;
BKE_spacedata_draw_locks(false);
if (data->writer)
PTC_writer_free(data->writer);
if (data->archive)
PTC_close_writer_archive(data->archive);
/* reset scene frame */
scene->r.cfra = data->origfra;
scene->r.framelen = data->origframelen;
BKE_scene_update_for_newframe(&data->eval_ctx, data->bmain, scene, scene->lay);
}
/* Warning! Deletes existing files if possible, operator should show confirm dialog! */
static bool cache_library_bake_ensure_file_target(CacheLibrary *cachelib)
{
char filename[FILE_MAX];
BKE_cache_archive_path(cachelib->filepath, (ID *)cachelib, cachelib->id.lib, filename, sizeof(filename));
if (BLI_exists(filename)) {
if (BLI_is_dir(filename)) {
return false;
}
else if (BLI_is_file(filename)) {
if (BLI_file_is_writable(filename)) {
/* returns 0 on success */
return (BLI_delete(filename, false, false) == 0);
}
else {
return false;
}
}
else {
return false;
}
}
return true;
}
static int cache_library_bake_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
CacheLibraryBakeJob *data;
wmJob *wm_job;
/* make sure we can write */
cache_library_bake_ensure_file_target(ob->cache_library);
/* XXX annoying hack: needed to prevent data corruption when changing
* scene frame in separate threads
*/
G.is_rendering = true;
BKE_spacedata_draw_locks(true);
/* XXX set WM_JOB_EXCL_RENDER to prevent conflicts with render jobs,
* since we need to set G.is_rendering
*/
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Cache Library Bake",
WM_JOB_PROGRESS | WM_JOB_EXCL_RENDER, WM_JOB_TYPE_CACHELIBRARY_BAKE);
/* setup job */
data = MEM_callocN(sizeof(CacheLibraryBakeJob), "Cache Library Bake Job");
data->bmain = bmain;
data->scene = scene;
data->cachelib = ob->cache_library;
data->group = ob->dup_group;
WM_jobs_customdata_set(wm_job, data, cache_library_bake_freejob);
WM_jobs_timer(wm_job, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME);
WM_jobs_callbacks(wm_job, cache_library_bake_startjob, NULL, NULL, cache_library_bake_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
return OPERATOR_FINISHED;
}
static int cache_library_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = CTX_data_active_object(C);
CacheLibrary *cachelib = ob->cache_library;
char filename[FILE_MAX];
if (!cachelib)
return OPERATOR_CANCELLED;
if (!BKE_cache_archive_path_test(cachelib->filepath, (ID *)cachelib, cachelib->id.lib)) {
BKE_reportf(op->reports, RPT_ERROR, "Cannot create file path for cache library %200s", cachelib->id.name+2);
return OPERATOR_CANCELLED;
}
BKE_cache_archive_path(cachelib->filepath, (ID *)cachelib, cachelib->id.lib, filename, sizeof(filename));
if (BLI_exists(filename)) {
if (BLI_is_dir(filename)) {
BKE_reportf(op->reports, RPT_ERROR, "Cache Library target is a directory: %200s", filename);
return OPERATOR_CANCELLED;
}
else if (BLI_is_file(filename)) {
if (BLI_file_is_writable(filename)) {
return WM_operator_confirm_message(C, op, "Overwrite?");
}
else {
BKE_reportf(op->reports, RPT_ERROR, "Cannot overwrite Cache Library target: %200s", filename);
return OPERATOR_CANCELLED;
}
}
else {
BKE_reportf(op->reports, RPT_ERROR, "Invalid Cache Library target: %200s", filename);
return OPERATOR_CANCELLED;
}
}
else
return cache_library_bake_exec(C, op);
}
void CACHELIBRARY_OT_bake(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Bake";
ot->description = "Bake cache library";
ot->idname = "CACHELIBRARY_OT_bake";
/* api callbacks */
ot->invoke = cache_library_bake_invoke;
ot->exec = cache_library_bake_exec;
ot->poll = cache_library_bake_poll;
/* flags */
/* no undo for this operator, cannot restore old cache files anyway */
ot->flag = OPTYPE_REGISTER;
}
/* ========================================================================= */
static void ui_item_nlabel(uiLayout *layout, const char *s, size_t len)
{
char buf[256];
BLI_strncpy(buf, s, sizeof(buf)-1);
buf[min_ii(len, sizeof(buf)-1)] = '\0';
uiItemL(layout, buf, ICON_NONE);
}
static void archive_info_labels(uiLayout *layout, const char *info)
{
const char delim[] = {'\n', '\0'};
const char *cur = info;
size_t linelen;
char *sep, *suf;
linelen = BLI_str_partition(cur, delim, &sep, &suf);
while (sep) {
ui_item_nlabel(layout, cur, linelen);
cur = suf;
linelen = BLI_str_partition(cur, delim, &sep, &suf);
}
ui_item_nlabel(layout, cur, linelen);
}
static uiBlock *archive_info_popup_create(bContext *C, ARegion *ar, void *arg)
{
const char *info = arg;
uiBlock *block;
uiLayout *layout;
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
UI_block_flag_disable(block, UI_BLOCK_LOOP);
UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT);
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, UI_UNIT_X * 20, UI_UNIT_Y, 0, UI_style_get());
archive_info_labels(layout, info);
UI_block_bounds_set_centered(block, 0);
UI_block_direction_set(block, UI_DIR_DOWN);
return block;
}
static int cache_library_archive_info_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
CacheLibrary *cachelib = ob->cache_library;
Scene *scene = CTX_data_scene(C);
const bool use_stdout = RNA_boolean_get(op->ptr, "use_stdout");
const bool use_popup = RNA_boolean_get(op->ptr, "use_popup");
const bool use_clipboard = RNA_boolean_get(op->ptr, "use_clipboard");
char filename[FILE_MAX];
struct PTCReaderArchive *archive;
char *info;
BKE_cache_archive_path(cachelib->filepath, (ID *)cachelib, cachelib->id.lib, filename, sizeof(filename));
archive = PTC_open_reader_archive(scene, filename);
if (!archive) {
BKE_reportf(op->reports, RPT_ERROR, "Cannot open cache file at '%s'", cachelib->filepath);
return OPERATOR_CANCELLED;
}
info = PTC_get_archive_info(archive);
PTC_close_reader_archive(archive);
if (info) {
if (use_stdout) {
printf("%s", info);
}
if (use_popup) {
UI_popup_block_invoke(C, archive_info_popup_create, info);
}
if (use_clipboard) {
WM_clipboard_text_set(info, false);
}
MEM_freeN(info);
}
return OPERATOR_FINISHED;
}
void CACHELIBRARY_OT_archive_info(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Archive Info";
ot->description = "Get archive details from a cache library archive";
ot->idname = "CACHELIBRARY_OT_archive_info";
/* api callbacks */
ot->exec = cache_library_archive_info_exec;
ot->poll = ED_cache_library_active_object_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "use_stdout", false, "Use stdout", "Print info in standard output");
RNA_def_boolean(ot->srna, "use_popup", false, "Show Popup", "Display archive info in a popup");
RNA_def_boolean(ot->srna, "use_clipboard", false, "Copy to Clipboard", "Copy archive info to the clipboard");
}

View File

@@ -0,0 +1,44 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/io/io_cache_library.h
* \ingroup editor/io
*/
#ifndef __IO_CACHE_LIBRARY_H__
#define __IO_CACHE_LIBRARY_H__
struct wmOperatorType;
void CACHELIBRARY_OT_new(struct wmOperatorType *ot);
void CACHELIBRARY_OT_delete(struct wmOperatorType *ot);
void CACHELIBRARY_OT_item_enable(struct wmOperatorType *ot);
void CACHELIBRARY_OT_bake(struct wmOperatorType *ot);
void CACHELIBRARY_OT_archive_info(struct wmOperatorType *ot);
#endif

View File

@@ -30,13 +30,21 @@
#include "io_ops.h" /* own include */
#include "io_cache_library.h"
#ifdef WITH_COLLADA
# include "io_collada.h"
# include "WM_api.h"
#endif
#include "WM_api.h"
void ED_operatortypes_io(void)
{
WM_operatortype_append(CACHELIBRARY_OT_new);
WM_operatortype_append(CACHELIBRARY_OT_delete);
WM_operatortype_append(CACHELIBRARY_OT_item_enable);
WM_operatortype_append(CACHELIBRARY_OT_bake);
WM_operatortype_append(CACHELIBRARY_OT_archive_info);
#ifdef WITH_COLLADA
/* Collada operators: */
WM_operatortype_append(WM_OT_collada_export);

View File

@@ -1190,29 +1190,30 @@ static void filelist_from_main(struct FileList *filelist)
filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT);
filelist->filelist[1].relname = BLI_strdup("Scene");
filelist->filelist[2].relname = BLI_strdup("Object");
filelist->filelist[3].relname = BLI_strdup("Mesh");
filelist->filelist[4].relname = BLI_strdup("Curve");
filelist->filelist[5].relname = BLI_strdup("Metaball");
filelist->filelist[6].relname = BLI_strdup("Material");
filelist->filelist[7].relname = BLI_strdup("Texture");
filelist->filelist[8].relname = BLI_strdup("Image");
filelist->filelist[9].relname = BLI_strdup("Ika");
filelist->filelist[10].relname = BLI_strdup("Wave");
filelist->filelist[11].relname = BLI_strdup("Lattice");
filelist->filelist[12].relname = BLI_strdup("Lamp");
filelist->filelist[13].relname = BLI_strdup("Camera");
filelist->filelist[14].relname = BLI_strdup("Ipo");
filelist->filelist[15].relname = BLI_strdup("World");
filelist->filelist[16].relname = BLI_strdup("Screen");
filelist->filelist[17].relname = BLI_strdup("VFont");
filelist->filelist[18].relname = BLI_strdup("Text");
filelist->filelist[19].relname = BLI_strdup("Armature");
filelist->filelist[20].relname = BLI_strdup("Action");
filelist->filelist[21].relname = BLI_strdup("NodeTree");
filelist->filelist[22].relname = BLI_strdup("Speaker");
filelist->filelist[2].relname = BLI_strdup("CacheLibrary");
filelist->filelist[3].relname = BLI_strdup("Object");
filelist->filelist[4].relname = BLI_strdup("Mesh");
filelist->filelist[5].relname = BLI_strdup("Curve");
filelist->filelist[6].relname = BLI_strdup("Metaball");
filelist->filelist[7].relname = BLI_strdup("Material");
filelist->filelist[8].relname = BLI_strdup("Texture");
filelist->filelist[9].relname = BLI_strdup("Image");
filelist->filelist[10].relname = BLI_strdup("Ika");
filelist->filelist[11].relname = BLI_strdup("Wave");
filelist->filelist[12].relname = BLI_strdup("Lattice");
filelist->filelist[13].relname = BLI_strdup("Lamp");
filelist->filelist[14].relname = BLI_strdup("Camera");
filelist->filelist[15].relname = BLI_strdup("Ipo");
filelist->filelist[16].relname = BLI_strdup("World");
filelist->filelist[17].relname = BLI_strdup("Screen");
filelist->filelist[18].relname = BLI_strdup("VFont");
filelist->filelist[19].relname = BLI_strdup("Text");
filelist->filelist[20].relname = BLI_strdup("Armature");
filelist->filelist[21].relname = BLI_strdup("Action");
filelist->filelist[22].relname = BLI_strdup("NodeTree");
filelist->filelist[23].relname = BLI_strdup("Speaker");
#ifdef WITH_FREESTYLE
filelist->filelist[23].relname = BLI_strdup("FreestyleLineStyle");
filelist->filelist[24].relname = BLI_strdup("FreestyleLineStyle");
#endif
}
else {

View File

@@ -1170,6 +1170,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_DATA_TRANSFER); break;
case eModifierType_NormalEdit:
UI_icon_draw(x, y, ICON_MOD_NORMALEDIT); break;
case eModifierType_Cache:
UI_icon_draw(x, y, ICON_PHYSICS); break;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:

View File

@@ -7611,7 +7611,8 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* code for new particle system */
if ((ob->particlesystem.first) &&
(ob != scene->obedit))
(ob != scene->obedit) &&
!(ob->transflag & OB_IS_DUPLI_CACHE))
{
ParticleSystem *psys;

View File

@@ -55,6 +55,7 @@
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_DerivedMesh.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_main.h"
@@ -2044,7 +2045,7 @@ static void draw_dupli_objects_color(
UI_GetThemeColorBlend3ubv(color, TH_BACK, 0.5f, color_rgb);
}
tbase.flag = OB_FROMDUPLI | base->flag;
tbase.flag |= OB_FROMDUPLI;
lb = object_duplilist(G.main->eval_ctx, scene, base->object);
// BLI_listbase_sort(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */
@@ -2054,7 +2055,11 @@ static void draw_dupli_objects_color(
if (dob) dob_next = dupli_step(dob->next);
for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) {
/* for restoring after override */
DerivedMesh *store_final_dm;
tbase.object = dob->ob;
store_final_dm = dob->ob->derivedFinal;
/* Make sure lod is updated from dupli's position */
@@ -2091,6 +2096,21 @@ static void draw_dupli_objects_color(
glColor3ubv(color_rgb);
}
/* override final DM */
bb_tmp = NULL;
tbase.object->transflag &= ~OB_IS_DUPLI_CACHE;
if (base->object->dup_cache) {
DupliObjectData *dob_data = BKE_dupli_cache_find_data(base->object->dup_cache, tbase.object);
if (dob_data->cache_dm) {
tbase.object->transflag |= OB_IS_DUPLI_CACHE;
tbase.object->derivedFinal = dob_data->cache_dm;
bb_tmp = &dob_data->bb;
}
}
if (!bb_tmp)
bb_tmp = BKE_object_boundbox_get(dob->ob);
/* generate displist, test for new object */
if (dob_prev && dob_prev->ob != dob->ob) {
if (use_displist == true)
@@ -2099,7 +2119,7 @@ static void draw_dupli_objects_color(
use_displist = false;
}
if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) {
if (bb_tmp) {
bb = *bb_tmp; /* must make a copy */
testbb = true;
}
@@ -2160,6 +2180,10 @@ static void draw_dupli_objects_color(
tbase.object->dtx = dtx;
tbase.object->transflag = transflag;
tbase.object->currentlod = savedlod;
/* restore final DM */
tbase.object->transflag &= ~OB_IS_DUPLI_CACHE;
tbase.object->derivedFinal = store_final_dm;
}
if (apply_data) {

View File

@@ -1030,23 +1030,40 @@ static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegi
lb = object_duplilist(G.main->eval_ctx, scene, base->object);
for (dob = lb->first; dob; dob = dob->next) {
float omat[4][4];
/* for restoring after override */
struct DerivedMesh *store_final_dm;
float store_obmat[4][4];
tbase.object = dob->ob;
copy_m4_m4(omat, dob->ob->obmat);
copy_m4_m4(store_obmat, dob->ob->obmat);
copy_m4_m4(dob->ob->obmat, dob->mat);
store_final_dm = dob->ob->derivedFinal;
/* extra service: draw the duplicator in drawtype of parent */
/* MIN2 for the drawtype to allow bounding box objects in groups for lods */
dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
/* override final DM */
tbase.object->transflag &= ~OB_IS_DUPLI_CACHE;
if (base->object->dup_cache) {
DupliObjectData *dob_data = BKE_dupli_cache_find_data(base->object->dup_cache, tbase.object);
if (dob_data->cache_dm) {
tbase.object->transflag |= OB_IS_DUPLI_CACHE;
tbase.object->derivedFinal = dob_data->cache_dm;
}
}
draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR);
tbase.object->dt = dt;
tbase.object->dtx = dtx;
copy_m4_m4(dob->ob->obmat, omat);
/* restore obmat and final DM */
tbase.object->transflag &= ~OB_IS_DUPLI_CACHE;
copy_m4_m4(dob->ob->obmat, store_obmat);
tbase.object->derivedFinal = store_final_dm;
}
free_object_duplilist(lb);
}

View File

@@ -222,6 +222,7 @@ typedef struct PreviewImage {
#define ID_LS MAKE_ID2('L', 'S') /* FreestyleLineStyle */
#define ID_PAL MAKE_ID2('P', 'L') /* Palette */
#define ID_PC MAKE_ID2('P', 'C') /* PaintCurve */
#define ID_CL MAKE_ID2('C', 'L') /* CacheLibrary */
/* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */
#define ID_SEQ MAKE_ID2('S', 'Q')

View File

@@ -0,0 +1,94 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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) 2015 by Blender Foundation
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file DNA_cache_library_types.h
* \ingroup DNA
*/
#ifndef __DNA_CACHE_LIBRARY_TYPES_H__
#define __DNA_CACHE_LIBRARY_TYPES_H__
#include "DNA_defs.h"
#include "DNA_ID.h"
#include "DNA_listBase.h"
#define MAX_CACHE_GROUP_LEVEL 8
typedef enum eCacheItemType {
CACHE_TYPE_OBJECT = 0,
CACHE_TYPE_DERIVED_MESH = 1,
CACHE_TYPE_HAIR = 2,
CACHE_TYPE_HAIR_PATHS = 3,
CACHE_TYPE_PARTICLES = 4,
} eCacheItemType;
typedef enum eCacheReadSampleResult {
CACHE_READ_SAMPLE_INVALID = 0, /* no valid result can be retrieved */
CACHE_READ_SAMPLE_EARLY = 1, /* request time before first sample */
CACHE_READ_SAMPLE_LATE = 2, /* request time after last sample */
CACHE_READ_SAMPLE_EXACT = 3, /* found sample for requested frame */
CACHE_READ_SAMPLE_INTERPOLATED = 4, /* no exact sample, but found enclosing samples for interpolation */
} eCacheReadSampleResult;
typedef struct CacheItem {
struct CacheItem *next, *prev;
struct Object *ob;
int type;
int index;
int flag;
short read_result;
short pad;
} CacheItem;
typedef enum eCacheItem_Flag {
CACHE_ITEM_ENABLED = 1,
} eCacheItem_Flag;
typedef struct CacheLibrary {
ID id;
int flag;
short eval_mode;
short pad;
char filepath[1024]; /* 1024 = FILE_MAX */
ListBase items; /* cached items */
struct GHash *items_hash; /* runtime: cached items hash for fast lookup */
} CacheLibrary;
//typedef enum eCacheLibrary_Flag {
//} eCacheLibrary_Flag;
typedef enum eCacheLibrary_EvalMode {
CACHE_LIBRARY_EVAL_REALTIME = (1 << 0), /* evaluate data with realtime settings */
CACHE_LIBRARY_EVAL_RENDER = (1 << 1), /* evaluate data with render settings */
} eCacheLibrary_EvalMode;
#endif

View File

@@ -84,6 +84,7 @@ typedef enum ModifierType {
eModifierType_Wireframe = 48,
eModifierType_DataTransfer = 49,
eModifierType_NormalEdit = 50,
eModifierType_Cache = 51,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -1444,6 +1445,25 @@ enum {
MOD_DATATRANSFER_USE_POLY = 1 << 31,
};
/* point cache modifier */
typedef struct CacheModifierData {
ModifierData modifier;
int flag;
int pad;
/* DM data for writing into the cache */
struct DerivedMesh *output_dm;
/* DM data read from the cache for modifier input */
struct DerivedMesh *input_dm;
} CacheModifierData;
typedef enum eCacheModifier_Flag {
MOD_CACHE_USE_OUTPUT_REALTIME = 1,
MOD_CACHE_USE_OUTPUT_RENDER = 2,
} eCacheModifier_Flag;
/* Set Split Normals modifier */
typedef struct NormalEditModifierData {
ModifierData modifier;

View File

@@ -180,7 +180,8 @@ typedef struct Object {
short flag; /* copy of Base */
short colbits DNA_DEPRECATED; /* deprecated, use 'matbits' */
short transflag, protectflag; /* transformation settings and transform locks */
int transflag; /* transformation settings */
short protectflag, pad; /* transform locks */
short trackflag, upflag;
short nlaflag; /* used for DopeSheet filtering settings (expanded/collapsed) */
short ipoflag; // xxx deprecated... old animation system
@@ -191,8 +192,6 @@ typedef struct Object {
/* dupli-frame settings */
int dupon, dupoff, dupsta, dupend;
int pad;
/* during realtime */
/* note that inertia is only called inertia for historical reasons
@@ -263,6 +262,8 @@ typedef struct Object {
struct PartDeflect *pd; /* particle deflector/attractor/collision data */
struct SoftBody *soft; /* if exists, saved in file */
struct Group *dup_group; /* object duplicator for group */
struct DupliCache *dup_cache; /* cached dupli overrides */
struct CacheLibrary *cache_library; /* cache library to use */
char body_type; /* for now used to temporarily holds the type of collision object */
char shapeflag; /* flag for pinning */
@@ -328,8 +329,33 @@ typedef struct DupliObject {
/* particle this dupli was generated from */
struct ParticleSystem *particle_system;
struct DupliObjectData *data;
} DupliObject;
/* data that can be shared by multiple DupliObject instances */
typedef struct DupliObjectData {
/* XXX eventually it should be possible to construct dupli instances
* entirely without Objects in the DNA, but current drawing code and
* others make this too difficult
*/
struct Object *ob;
struct BoundBox bb;
struct DerivedMesh *cache_dm;
} DupliObjectData;
typedef struct DupliCache {
int flag;
float cfra; /* frame for which the cache was constructed */
struct GHash *ghash;
ListBase duplilist;
} DupliCache;
typedef enum eDupliCache_Flag {
DUPCACHE_FLAG_DIRTY = (1 << 0), /* cache requires update */
} eDupliCache_Flag;
/* **************** OBJECT ********************* */
/* used many places... should be specialized */
@@ -405,6 +431,9 @@ enum {
OB_RENDER_DUPLI = 1 << 12,
OB_NO_CONSTRAINTS = 1 << 13, /* runtime constraints disable */
OB_NO_PSYS_UPDATE = 1 << 14, /* hack to work around particle issue */
OB_DUPLI_READ_CACHE = 1 << 15, /* use cache instead of object data */
OB_IS_DUPLI_CACHE = 1 << 31, /* temporary flag: object data overridden from cache */
OB_DUPLI = OB_DUPLIFRAMES | OB_DUPLIVERTS | OB_DUPLIGROUP | OB_DUPLIFACES | OB_DUPLIPARTS,
};

View File

@@ -136,6 +136,7 @@ static const char *includefiles[] = {
"DNA_rigidbody_types.h",
"DNA_freestyle_types.h",
"DNA_linestyle_types.h",
"DNA_cache_library_types.h",
/* empty string to indicate end of includefiles */
""
@@ -1287,4 +1288,5 @@ int main(int argc, char **argv)
#include "DNA_rigidbody_types.h"
#include "DNA_freestyle_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_cache_library_types.h"
/* end of list */

View File

@@ -95,6 +95,8 @@ extern StructRNA RNA_Brush;
extern StructRNA RNA_BrushTextureSlot;
extern StructRNA RNA_BuildModifier;
extern StructRNA RNA_MeshCacheModifier;
extern StructRNA RNA_CacheItem;
extern StructRNA RNA_CacheLibrary;
extern StructRNA RNA_Camera;
extern StructRNA RNA_CastModifier;
extern StructRNA RNA_ChildOfConstraint;
@@ -451,6 +453,7 @@ extern StructRNA RNA_ParticleSystemModifier;
extern StructRNA RNA_ParticleTarget;
extern StructRNA RNA_PivotConstraint;
extern StructRNA RNA_PointCache;
extern StructRNA RNA_PointCacheModifier;
extern StructRNA RNA_PointDensity;
extern StructRNA RNA_PointDensityTexture;
extern StructRNA RNA_PointLamp;

View File

@@ -174,6 +174,9 @@ extern EnumPropertyItem prop_dynamicpaint_type_items[];
extern EnumPropertyItem clip_editor_mode_items[];
extern EnumPropertyItem cache_library_item_type_items[];
extern EnumPropertyItem cache_library_read_result_items[];
extern EnumPropertyItem icon_items[];
extern EnumPropertyItem uilist_layout_type_items[];
@@ -213,5 +216,7 @@ EnumPropertyItem *RNA_movieclip_itemf(struct bContext *C, struct PointerRNA *ptr
EnumPropertyItem *RNA_movieclip_local_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
EnumPropertyItem *RNA_mask_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
EnumPropertyItem *RNA_mask_local_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
EnumPropertyItem *RNA_cachelibrary_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
EnumPropertyItem *RNA_cachelibrary_local_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
#endif /* __RNA_ENUM_TYPES_H__ */

View File

@@ -38,6 +38,7 @@ set(DEFSRC
rna_armature.c
rna_boid.c
rna_brush.c
rna_cache_library.c
rna_camera.c
rna_cloth.c
rna_color.c

View File

@@ -3283,6 +3283,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_boid.c", NULL, RNA_def_boid},
{"rna_brush.c", NULL, RNA_def_brush},
{"rna_camera.c", "rna_camera_api.c", RNA_def_camera},
{"rna_cache_library.c", NULL, RNA_def_cache_library},
{"rna_cloth.c", NULL, RNA_def_cloth},
{"rna_color.c", NULL, RNA_def_color},
{"rna_constraint.c", NULL, RNA_def_constraint},

View File

@@ -50,6 +50,7 @@ EnumPropertyItem id_type_items[] = {
{ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armature", ""},
{ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brush", ""},
{ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""},
{ID_CL, "CACHELIBRARY", ICON_PHYSICS, "Cache Library", ""},
{ID_CU, "CURVE", ICON_CURVE_DATA, "Curve", ""},
{ID_VF, "FONT", ICON_FONT_DATA, "Font", ""},
{ID_GD, "GREASEPENCIL", ICON_GREASEPENCIL, "Grease Pencil", ""},
@@ -130,6 +131,7 @@ short RNA_type_to_ID_code(StructRNA *type)
if (RNA_struct_is_a(type, &RNA_Action)) return ID_AC;
if (RNA_struct_is_a(type, &RNA_Armature)) return ID_AR;
if (RNA_struct_is_a(type, &RNA_Brush)) return ID_BR;
if (RNA_struct_is_a(type, &RNA_CacheLibrary)) return ID_CL;
if (RNA_struct_is_a(type, &RNA_Camera)) return ID_CA;
if (RNA_struct_is_a(type, &RNA_Curve)) return ID_CU;
if (RNA_struct_is_a(type, &RNA_GreasePencil)) return ID_GD;
@@ -170,6 +172,7 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_AR: return &RNA_Armature;
case ID_BR: return &RNA_Brush;
case ID_CA: return &RNA_Camera;
case ID_CL: return &RNA_CacheLibrary;
case ID_CU: return &RNA_Curve;
case ID_GD: return &RNA_GreasePencil;
case ID_GR: return &RNA_Group;

View File

@@ -0,0 +1,339 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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.
*
* Contributor(s): Blender Foundation (2015).
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/makesrna/intern/rna_cache_library.c
* \ingroup RNA
*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "DNA_cache_library_types.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "rna_internal.h"
#include "WM_types.h"
EnumPropertyItem cache_library_item_type_items[] = {
{CACHE_TYPE_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object base properties"},
{CACHE_TYPE_DERIVED_MESH, "DERIVED_MESH", ICON_OUTLINER_OB_MESH, "Derived Mesh", "Mesh result from modifiers"},
{CACHE_TYPE_HAIR, "HAIR", ICON_PARTICLE_POINT, "Hair", "Hair parent strands"},
{CACHE_TYPE_HAIR_PATHS, "HAIR_PATHS", ICON_PARTICLE_PATH, "Hair Paths", "Full hair paths"},
{CACHE_TYPE_PARTICLES, "PARTICLES", ICON_PARTICLES, "Particles", "Emitter particles"},
{0, NULL, 0, NULL, NULL}
};
EnumPropertyItem cache_library_read_result_items[] = {
{CACHE_READ_SAMPLE_INVALID, "INVALID", ICON_ERROR, "Invalid", "No valid sample found"},
{CACHE_READ_SAMPLE_EXACT, "EXACT", ICON_SPACE3, "Exact", "Found sample for requested frame"},
{CACHE_READ_SAMPLE_INTERPOLATED, "INTERPOLATED", ICON_TRIA_DOWN_BAR, "Interpolated", "Enclosing samples found for interpolation"},
{CACHE_READ_SAMPLE_EARLY, "EARLY", ICON_TRIA_RIGHT_BAR, "Early", "Requested frame before the first sample"},
{CACHE_READ_SAMPLE_LATE, "LATE", ICON_TRIA_LEFT_BAR, "Late", "Requested frame after the last sample"},
{0, NULL, 0, NULL, NULL}
};
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "DNA_object_types.h"
#include "BKE_cache_library.h"
#include "BKE_main.h"
#include "RNA_access.h"
#include "WM_api.h"
static void rna_CacheItem_name_get(PointerRNA *ptr, char *value)
{
CacheItem *item = ptr->data;
BKE_cache_item_name(item->ob, item->type, item->index, value);
}
static int rna_CacheItem_name_length(PointerRNA *ptr)
{
CacheItem *item = ptr->data;
return BKE_cache_item_name_length(item->ob, item->type, item->index);
}
static void rna_CacheItem_get_name(struct Object *ob, int type, int index, char *name)
{
BKE_cache_item_name(ob, type, index, name);
}
/* ========================================================================= */
static void rna_CacheLibrary_update(Main *UNUSED(main), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
}
/* ========================================================================= */
#if 0 /* UNUSED */
static PointerRNA rna_ObjectCache_object_get(PointerRNA *ptr)
{
Object *ob = ptr->data;
PointerRNA rptr;
RNA_id_pointer_create((ID *)ob, &rptr);
return rptr;
}
static void rna_CacheLibrary_object_caches_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
CacheLibraryObjectsIterator *internal = (CacheLibraryObjectsIterator *)(&iter->internal.listbase);
CacheLibrary *cachelib = ptr->data;
/* XXX this is not particularly elegant, but works:
* abuse the internal union for storing our own iterator
*/
BLI_STATIC_ASSERT(sizeof(iter->internal) >= sizeof(CacheLibraryObjectsIterator), "CollectionPropertyIterator internal not large enough");
BKE_object_cache_iter_init(internal, cachelib);
iter->valid = BKE_object_cache_iter_valid(internal);
}
void rna_CacheLibrary_object_caches_next(CollectionPropertyIterator *iter)
{
CacheLibraryObjectsIterator *internal = (CacheLibraryObjectsIterator *)(&iter->internal.listbase);
BKE_object_cache_iter_next(internal);
iter->valid = BKE_object_cache_iter_valid(internal);
}
void rna_CacheLibrary_object_caches_end(CollectionPropertyIterator *iter)
{
CacheLibraryObjectsIterator *internal = (CacheLibraryObjectsIterator *)(&iter->internal.listbase);
BKE_object_cache_iter_end(internal);
}
PointerRNA rna_CacheLibrary_object_caches_get(CollectionPropertyIterator *iter)
{
CacheLibraryObjectsIterator *internal = (CacheLibraryObjectsIterator *)(&iter->internal.listbase);
PointerRNA rptr;
RNA_pointer_create((ID *)iter->parent.id.data, &RNA_ObjectCache, BKE_object_cache_iter_get(internal), &rptr);
return rptr;
}
#endif
static PointerRNA rna_CacheLibrary_cache_item_find(CacheLibrary *cachelib, Object *ob, int type, int index)
{
CacheItem *item = BKE_cache_library_find_item(cachelib, ob, type, index);
PointerRNA rptr;
RNA_pointer_create((ID *)cachelib, &RNA_CacheItem, item, &rptr);
return rptr;
}
/* ========================================================================= */
#if 0 /* UNUSED */
static void rna_ObjectCache_caches_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
CacheLibraryItemsIterator *internal = (CacheLibraryItemsIterator *)(&iter->internal.listbase);
Object *ob = ptr->data;
/* XXX this is not particularly elegant, but works:
* abuse the internal union for storing our own iterator
*/
BLI_STATIC_ASSERT(sizeof(iter->internal) >= sizeof(CacheLibraryItemsIterator), "CollectionPropertyIterator internal not large enough");
BKE_cache_item_iter_init(internal, ob);
iter->valid = BKE_cache_item_iter_valid(internal);
}
void rna_ObjectCache_caches_next(CollectionPropertyIterator *iter)
{
CacheLibraryItemsIterator *internal = (CacheLibraryItemsIterator *)(&iter->internal.listbase);
BKE_cache_item_iter_next(internal);
iter->valid = BKE_cache_item_iter_valid(internal);
}
void rna_ObjectCache_caches_end(CollectionPropertyIterator *iter)
{
CacheLibraryItemsIterator *internal = (CacheLibraryItemsIterator *)(&iter->internal.listbase);
BKE_cache_item_iter_end(internal);
}
PointerRNA rna_ObjectCache_caches_get(CollectionPropertyIterator *iter)
{
CacheLibraryItemsIterator *internal = (CacheLibraryItemsIterator *)(&iter->internal.listbase);
PointerRNA rptr;
/* XXX this returns a temporary pointer that becomes invalid after iteration, potentially dangerous! */
RNA_pointer_create((ID *)iter->parent.id.data, &RNA_CacheItem, internal->cur, &rptr);
return rptr;
}
#endif
#else
static void rna_def_cache_item(BlenderRNA *brna)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *prop, *parm;
srna = RNA_def_struct(brna, "CacheItem", NULL);
RNA_def_struct_ui_text(srna, "Cache Item", "Description of a cacheable item in an object");
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "ob");
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Object", "");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, cache_library_item_type_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Type", "Type of cached data");
prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "index");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Index", "Index of the cached data");
prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CACHE_ITEM_ENABLED);
RNA_def_property_ui_text(prop, "Enabled", "Enable caching for this item");
prop = RNA_def_property(srna, "read_result", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "read_result");
RNA_def_property_enum_items(prop, cache_library_read_result_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Read Result", "Result of cache read");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, 2*MAX_NAME);
RNA_def_property_string_funcs(prop, "rna_CacheItem_name_get", "rna_CacheItem_name_length", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Name", "");
RNA_def_struct_name_property(srna, prop);
func = RNA_def_function(srna, "get_name", "rna_CacheItem_get_name");
RNA_def_function_flag(func, FUNC_NO_SELF);
RNA_def_function_ui_description(func, "Get name of items from properties without an instance");
parm = RNA_def_pointer(func, "object", "Object", "Object", "");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
parm = RNA_def_enum(func, "type", cache_library_item_type_items, CACHE_TYPE_OBJECT, "Type", "Type of cache item");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_int(func, "index", -1, -1, INT_MAX, "Index", "Index of the data in it's' collection", -1, INT_MAX);
parm = RNA_def_string(func, "name", NULL, 2*MAX_NAME, "Name", "");
RNA_def_property_flag(parm, PROP_THICK_WRAP);
RNA_def_function_output(func, parm);
}
#if 0 /* UNUSED */
static void rna_def_object_cache(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "ObjectCache", NULL);
RNA_def_struct_ui_text(srna, "Object Cache", "Cacheable data in an Object");
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_funcs(prop, "rna_ObjectCache_object_get", NULL, NULL, NULL);
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Object", "");
prop = RNA_def_property(srna, "caches", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "CacheItem");
RNA_def_property_collection_funcs(prop, "rna_ObjectCache_caches_begin", "rna_ObjectCache_caches_next", "rna_ObjectCache_caches_end",
"rna_ObjectCache_caches_get", NULL, NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Caches", "Cacheable items for in an object cache");
}
#endif
static void rna_def_cache_library(BlenderRNA *brna)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *prop, *parm;
static EnumPropertyItem eval_mode_items[] = {
{CACHE_LIBRARY_EVAL_REALTIME, "REALTIME", ICON_RESTRICT_VIEW_OFF, "Realtime", "Evaluate data with realtime settings"},
{CACHE_LIBRARY_EVAL_RENDER, "RENDER", ICON_RESTRICT_RENDER_OFF, "Render", "Evaluate data with render settings"},
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "CacheLibrary", "ID");
RNA_def_struct_ui_text(srna, "Cache Library", "Cache Library datablock for constructing an archive of caches");
RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_sdna(prop, NULL, "filepath");
RNA_def_property_ui_text(prop, "File Path", "Path to cache library storage");
RNA_def_property_update(prop, 0, "rna_CacheLibrary_update");
prop = RNA_def_property(srna, "eval_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "eval_mode");
RNA_def_property_enum_items(prop, eval_mode_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Evaluation Mode", "Mode to use when evaluating data");
RNA_def_property_update(prop, 0, "rna_CacheLibrary_update");
#if 0 /* UNUSED */
prop = RNA_def_property(srna, "object_caches", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "ObjectCache");
RNA_def_property_collection_funcs(prop, "rna_CacheLibrary_object_caches_begin", "rna_CacheLibrary_object_caches_next", "rna_CacheLibrary_object_caches_end",
"rna_CacheLibrary_object_caches_get", NULL, NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Object Caches", "Cacheable objects inside the cache library group");
#endif
func = RNA_def_function(srna, "cache_item_find", "rna_CacheLibrary_cache_item_find");
RNA_def_function_ui_description(func, "Find item for an object cache item");
parm = RNA_def_pointer(func, "object", "Object", "Object", "");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
parm = RNA_def_enum(func, "type", cache_library_item_type_items, CACHE_TYPE_OBJECT, "Type", "Type of cache item");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_int(func, "index", -1, -1, INT_MAX, "Index", "Index of the data in it's' collection", -1, INT_MAX);
parm = RNA_def_pointer(func, "item", "CacheItem", "Item", "Item in the cache");
RNA_def_property_flag(parm, PROP_RNAPTR);
RNA_def_function_return(func, parm);
}
void RNA_def_cache_library(BlenderRNA *brna)
{
rna_def_cache_item(brna);
#if 0 /* UNUSED */
rna_def_object_cache(brna);
#endif
rna_def_cache_library(brna);
}
#endif

View File

@@ -136,6 +136,7 @@ void RNA_def_armature(struct BlenderRNA *brna);
void RNA_def_actuator(struct BlenderRNA *brna);
void RNA_def_boid(struct BlenderRNA *brna);
void RNA_def_brush(struct BlenderRNA *brna);
void RNA_def_cache_library(struct BlenderRNA *brna);
void RNA_def_camera(struct BlenderRNA *brna);
void RNA_def_cloth(struct BlenderRNA *brna);
void RNA_def_color(struct BlenderRNA *brna);
@@ -332,6 +333,7 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_cache_libraries(BlenderRNA *brna, PropertyRNA *cprop);
/* ID Properties */

View File

@@ -287,6 +287,12 @@ static void rna_Main_linestyle_begin(CollectionPropertyIterator *iter, PointerRN
rna_iterator_listbase_begin(iter, &bmain->linestyle, NULL);
}
static void rna_Main_cachelibraries_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Main *bmain = (Main *)ptr->data;
rna_iterator_listbase_begin(iter, &bmain->cache_library, NULL);
}
static void rna_Main_version_get(PointerRNA *ptr, int *value)
{
Main *bmain = (Main *)ptr->data;
@@ -361,6 +367,7 @@ void RNA_def_main(BlenderRNA *brna)
{"movieclips", "MovieClip", "rna_Main_movieclips_begin", "Movie Clips", "Movie Clip datablocks", RNA_def_main_movieclips},
{"masks", "Mask", "rna_Main_masks_begin", "Masks", "Masks datablocks", RNA_def_main_masks},
{"linestyles", "FreestyleLineStyle", "rna_Main_linestyle_begin", "Line Styles", "Line Style datablocks", RNA_def_main_linestyles},
{"cache_libraries", "CacheLibrary", "rna_Main_cachelibraries_begin", "Cache Libraries", "Cache Library datablocks", RNA_def_main_cache_libraries},
{NULL, NULL, NULL, NULL, NULL, NULL}
};

View File

@@ -48,6 +48,8 @@
#ifdef RNA_RUNTIME
#include "BKE_main.h"
#include "BKE_anim.h"
#include "BKE_cache_library.h"
#include "BKE_camera.h"
#include "BKE_curve.h"
#include "BKE_DerivedMesh.h"
@@ -80,6 +82,7 @@
#include "BKE_linestyle.h"
#include "DNA_armature_types.h"
#include "DNA_cache_library_types.h"
#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
#include "DNA_lamp_types.h"
@@ -308,6 +311,62 @@ Mesh *rna_Main_meshes_new_from_object(
return BKE_mesh_new_from_object(bmain, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed);
}
/* copied from Mesh_getFromObject and adapted to RNA interface */
/* settings: 1 - preview, 2 - render */
Mesh *rna_Main_meshes_new_from_dupli(
Main *bmain, ReportList *reports, Scene *scene, Object *parent, DupliObject *dob,
int settings, int calc_tessface, int calc_undeformed)
{
Mesh *mesh = NULL;
switch (dob->ob->type) {
case OB_FONT:
case OB_CURVE:
case OB_SURF:
case OB_MBALL:
case OB_MESH:
break;
default:
BKE_report(reports, RPT_ERROR, "Object does not have geometry data");
return NULL;
}
if ((parent->transflag & OB_DUPLI_READ_CACHE) && parent->cache_library) {
float frame = (float)scene->r.cfra;
eCacheLibrary_EvalMode eval_mode;
if (settings == 1)
eval_mode = CACHE_LIBRARY_EVAL_REALTIME;
else if (settings == 2)
eval_mode = CACHE_LIBRARY_EVAL_RENDER;
else
return NULL;
if (settings == 1 && parent->dup_cache) {
DupliObjectData *data;
/* use dupli cache for realtime dupli data if possible */
data = BKE_dupli_cache_find_data(parent->dup_cache, dob->ob);
if (data)
mesh = BKE_mesh_new_from_dupli_data(bmain, data, calc_tessface, calc_undeformed);
}
else {
DupliObjectData data;
memset(&data, 0, sizeof(data));
if (BKE_cache_read_dupli_object(scene, frame, eval_mode, dob->ob, &data, parent->cache_library))
mesh = BKE_mesh_new_from_dupli_data(bmain, &data, calc_tessface, calc_undeformed);
BKE_dupli_object_data_clear(&data);
}
}
else {
mesh = BKE_mesh_new_from_object(bmain, scene, dob->ob, true, settings, calc_tessface, calc_undeformed);
}
return mesh;
}
static void rna_Main_meshes_remove(Main *bmain, ReportList *reports, PointerRNA *mesh_ptr)
{
Mesh *mesh = mesh_ptr->data;
@@ -721,6 +780,22 @@ static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, Freesty
/* XXX python now has invalid pointer? */
}
static CacheLibrary *rna_Main_cachelibraries_new(Main *bmain, const char *name)
{
CacheLibrary *cachelib = BKE_cache_library_add(bmain, name);
id_us_min(&cachelib->id);
return cachelib;
}
static void rna_Main_cachelibraries_remove(Main *bmain, ReportList *reports, CacheLibrary *cachelib)
{
if (ID_REAL_USERS(cachelib) <= 0)
BKE_libblock_free(bmain, cachelib);
else
BKE_reportf(reports, RPT_ERROR, "Cache library '%s' must have zero users to be removed, found %d",
cachelib->id.name + 2, ID_REAL_USERS(cachelib));
}
/* tag functions, all the same */
static void rna_Main_cameras_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->camera, value); }
static void rna_Main_scenes_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->scene, value); }
@@ -754,6 +829,7 @@ static void rna_Main_gpencil_tag(Main *bmain, int value) { BKE_main_id_tag_listb
static void rna_Main_movieclips_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->movieclip, value); }
static void rna_Main_masks_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->mask, value); }
static void rna_Main_linestyle_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->linestyle, value); }
static void rna_Main_cachelibraries_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->cache_library, value); }
static int rna_Main_cameras_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_CA) != 0; }
static int rna_Main_scenes_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_SCE) != 0; }
@@ -783,6 +859,7 @@ static int rna_Main_particles_is_updated_get(PointerRNA *ptr) { return DAG_id_ty
static int rna_Main_palettes_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_PAL) != 0; }
static int rna_Main_gpencil_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_GD) != 0; }
static int rna_Main_linestyle_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_LS) != 0; }
static int rna_Main_cachelibraries_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_CL) != 0; }
#else
@@ -1037,6 +1114,23 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
"Mesh created from object, remove it if it is only used for export");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "new_from_dupli", "rna_Main_meshes_new_from_dupli");
RNA_def_function_ui_description(func, "Add a new mesh created from dupli cache data");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
parm = RNA_def_pointer(func, "parent", "Object", "", "Duplicator parent of the object");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
parm = RNA_def_pointer(func, "dupli_object", "DupliObject", "", "Dupli Object to create mesh from");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_boolean(func, "calc_tessface", true, "Calculate Tessellation", "Calculate tessellation faces");
RNA_def_boolean(func, "calc_undeformed", false, "Calculate Undeformed", "Calculate undeformed vertex coordinates");
parm = RNA_def_pointer(func, "mesh", "Mesh", "",
"Mesh created from object, remove it if it is only used for export");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_meshes_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a mesh from the current blendfile");
@@ -1869,4 +1963,39 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_boolean_funcs(prop, "rna_Main_linestyle_is_updated_get", NULL);
}
void RNA_def_main_cache_libraries(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataCacheLibraries");
srna = RNA_def_struct(brna, "BlendDataCacheLibraries", NULL);
RNA_def_struct_sdna(srna, "Main");
RNA_def_struct_ui_text(srna, "Main Cache Libraries", "Collection of cache libraries");
func = RNA_def_function(srna, "tag", "rna_Main_cachelibraries_tag");
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
func = RNA_def_function(srna, "new", "rna_Main_cachelibraries_new");
RNA_def_function_ui_description(func, "Add a new cache library to the main database");
parm = RNA_def_string(func, "name", "CacheLibrary", 0, "", "New name for the datablock");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "cachelib", "CacheLibrary", "", "New cache library datablock");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_cachelibraries_remove");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Remove a cache library from the current blendfile");
parm = RNA_def_pointer(func, "cachelib", "CacheLibrary", "", "Cache Library to remove");
RNA_def_property_flag(parm, PROP_REQUIRED);
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Main_cachelibraries_is_updated_get", NULL);
}
#endif

View File

@@ -65,6 +65,7 @@ EnumPropertyItem modifier_type_items[] = {
{0, "", 0, N_("Modify"), ""},
{eModifierType_DataTransfer, "DATA_TRANSFER", ICON_MOD_DATA_TRANSFER, "Data Transfer", ""},
{eModifierType_MeshCache, "MESH_CACHE", ICON_MOD_MESHDEFORM, "Mesh Cache", ""},
{eModifierType_Cache, "CACHE", ICON_MOD_MESHDEFORM, "Cache", ""},
{eModifierType_NormalEdit, "NORMAL_EDIT", ICON_MOD_NORMALEDIT, "Normal Edit", ""},
{eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""},
{eModifierType_UVWarp, "UV_WARP", ICON_MOD_UVPROJECT, "UV Warp", ""},
@@ -377,6 +378,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_DataTransferModifier;
case eModifierType_NormalEdit:
return &RNA_NormalEditModifier;
case eModifierType_Cache:
return &RNA_CacheModifier;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -2498,7 +2501,7 @@ static void rna_def_modifier_cloth(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ClothSolverResult");
RNA_def_property_pointer_sdna(prop, NULL, "solver_result");
RNA_def_property_ui_text(prop, "Solver Result", "");
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "Point Cache", "");
@@ -4438,6 +4441,16 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_cache(BlenderRNA *brna)
{
StructRNA *srna;
srna = RNA_def_struct(brna, "CacheModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Cache Modifier", "Write and Read mesh results to/from cache libraries");
RNA_def_struct_sdna(srna, "CacheModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
}
void RNA_def_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4553,6 +4566,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_wireframe(brna);
rna_def_modifier_datatransfer(brna);
rna_def_modifier_normaledit(brna);
rna_def_modifier_cache(brna);
}
#endif

View File

@@ -2634,6 +2634,17 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Dupli Faces Scale", "Scale the DupliFace objects");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
prop = RNA_def_property(srna, "use_dupli_cache_read", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "transflag", OB_DUPLI_READ_CACHE);
RNA_def_property_ui_text(prop, "Read Dupli Cache", "Use cached data instead of object data");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
/* note: inversion of use_dupli_cache_read, for enum-like mode switch */
prop = RNA_def_property(srna, "use_dupli_cache_write", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "transflag", OB_DUPLI_READ_CACHE);
RNA_def_property_ui_text(prop, "Write Dupli Cache", "Enabling writing of dupli cache data");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
prop = RNA_def_property(srna, "dupli_group", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "dup_group");
RNA_def_property_flag(prop, PROP_EDITABLE);
@@ -2641,6 +2652,12 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Dupli Group", "Instance an existing group");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
prop = RNA_def_property(srna, "cache_library", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "cache_library");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Cache Library", "Cache Library to use");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
prop = RNA_def_property(srna, "dupli_frames_start", PROP_INT, PROP_NONE | PROP_UNIT_TIME);
RNA_def_property_int_sdna(prop, NULL, "dupsta");
RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
@@ -2847,6 +2864,16 @@ static void rna_def_dupli_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Dupli Type", "Duplicator type that generated this dupli object");
}
static void rna_def_dupli_object_data(BlenderRNA *brna)
{
StructRNA *srna;
/*PropertyRNA *prop;*/
srna = RNA_def_struct(brna, "DupliObjectData", NULL);
RNA_def_struct_sdna(srna, "DupliObjectData");
RNA_def_struct_ui_text(srna, "Object Duplicate Data", "Override of object data for duplis");
}
static void rna_def_object_base(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2893,6 +2920,7 @@ void RNA_def_object(BlenderRNA *brna)
rna_def_vertex_group(brna);
rna_def_material_slot(brna);
rna_def_dupli_object(brna);
rna_def_dupli_object_data(brna);
RNA_define_animate_sdna(true);
rna_def_object_lodlevel(brna);
}

View File

@@ -222,6 +222,18 @@ static void rna_Object_free_duplilist(Object *ob)
}
}
static PointerRNA rna_Object_find_dupli_cache(Object *ob, Object *dupob)
{
DupliObjectData *data = NULL;
PointerRNA ptr;
if (ob->dup_cache)
data = BKE_dupli_cache_find_data(ob->dup_cache, dupob);
RNA_pointer_create((ID *)ob, &RNA_DupliObjectData, data, &ptr);
return ptr;
}
static PointerRNA rna_Object_shape_key_add(Object *ob, bContext *C, ReportList *reports,
const char *name, int from_mix)
{
@@ -547,6 +559,14 @@ void RNA_api_object(StructRNA *srna)
func = RNA_def_function(srna, "dupli_list_clear", "rna_Object_free_duplilist");
RNA_def_function_ui_description(func, "Free the list of dupli objects");
func = RNA_def_function(srna, "find_dupli_cache", "rna_Object_find_dupli_cache");
RNA_def_function_ui_description(func, "Find cached data for a dupli object");
parm = RNA_def_pointer(func, "object", "Object", "", "Object data to look up");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
parm = RNA_def_pointer(func, "data", "DupliObjectData", "", "Cached object data");
RNA_def_property_flag(parm, PROP_RNAPTR);
RNA_def_function_return(func, parm);
/* Armature */
func = RNA_def_function(srna, "find_armature", "modifiers_isDeformedByArmature");
RNA_def_function_ui_description(func, "Find armature influencing this object as a parent or via a modifier");

View File

@@ -899,6 +899,19 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func, "Node Socket Icon");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_float_array(func, "color", 4, node_socket_color_default, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
/* cache library item */
func = RNA_def_function(srna, "template_cache_library_item", "uiTemplateCacheLibraryItem");
RNA_def_function_ui_description(func, "Cache Library Item");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_pointer(func, "cachelib", "CacheLibrary", "Cache Library", "Cache library containing the item");
RNA_def_pointer(func, "object", "Object", "Object", "Object to cache");
parm = RNA_def_enum(func, "type", cache_library_item_type_items, 0, "Type", "Type of cached data");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_int(func, "index", -1, -1, INT_MAX, "Index", "Index of cached data", -1, INT_MAX);
RNA_def_boolean(func, "enabled", true, "Enabled", "Enable the item");
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
RNA_def_function_return(func, parm);
}
#endif

View File

@@ -33,6 +33,7 @@ set(INC
../makesdna
../makesrna
../bmesh
../pointcache
../render/extern/include
../../../intern/elbeem/extern
../../../intern/guardedalloc
@@ -77,6 +78,7 @@ set(SRC
intern/MOD_ocean.c
intern/MOD_particleinstance.c
intern/MOD_particlesystem.c
intern/MOD_cache.c
intern/MOD_remesh.c
intern/MOD_screw.c
intern/MOD_shapekey.c

View File

@@ -83,6 +83,7 @@ extern ModifierTypeInfo modifierType_LaplacianDeform;
extern ModifierTypeInfo modifierType_Wireframe;
extern ModifierTypeInfo modifierType_DataTransfer;
extern ModifierTypeInfo modifierType_NormalEdit;
extern ModifierTypeInfo modifierType_Cache;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);

View File

@@ -44,6 +44,7 @@ incs = [
'../makesrna',
'../blenkernel',
'../gpu',
'../pointcache',
env['BF_ZLIB_INC'],
]

View File

@@ -0,0 +1,231 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/modifiers/intern/MOD_cache.c
* \ingroup modifiers
*/
#include <stdio.h>
#include <stdlib.h>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "DNA_customdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_customdata.h"
#include "BKE_DerivedMesh.h"
#include "BKE_scene.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_main.h"
#include "MEM_guardedalloc.h"
#include "MOD_modifiertypes.h"
#include "MOD_util.h"
struct BMEditMesh;
static void initData(ModifierData *UNUSED(md))
{
/*CacheModifierData *pcmd = (CacheModifierData *)md;*/
}
static void copyData(ModifierData *md, ModifierData *target)
{
/*CacheModifierData *pcmd = (CacheModifierData *)md;*/
CacheModifierData *tpcmd = (CacheModifierData *)target;
modifier_copyData_generic(md, target);
tpcmd->output_dm = NULL;
tpcmd->input_dm = NULL;
tpcmd->flag &= ~(MOD_CACHE_USE_OUTPUT_REALTIME | MOD_CACHE_USE_OUTPUT_RENDER);
}
static void freeData(ModifierData *md)
{
CacheModifierData *pcmd = (CacheModifierData *)md;
if (pcmd->output_dm) {
pcmd->output_dm->release(pcmd->output_dm);
pcmd->output_dm = NULL;
}
if (pcmd->input_dm) {
pcmd->input_dm->release(pcmd->input_dm);
pcmd->input_dm = NULL;
}
}
static bool *store_nocopy_flags(CustomData *cdata)
{
if (cdata) {
int totlayer = cdata->totlayer;
bool *nocopy = MEM_mallocN(sizeof(bool) * totlayer, "customdata nocopy flags");
CustomDataLayer *layer;
int i;
for (i = 0, layer = cdata->layers; i < totlayer; ++i, ++layer) {
nocopy[i] = layer->flag & CD_FLAG_NOCOPY;
layer->flag &= ~CD_FLAG_NOCOPY;
}
return nocopy;
}
else
return NULL;
}
static void restore_nocopy_flags(CustomData *cdata, bool *nocopy)
{
if (cdata && nocopy) {
int totlayer = cdata->totlayer;
CustomDataLayer *layer;
int i;
for (i = 0, layer = cdata->layers; i < totlayer; ++i, ++layer) {
if (nocopy[i])
layer->flag |= CD_FLAG_NOCOPY;
else
layer->flag &= ~CD_FLAG_NOCOPY;
}
}
if (nocopy)
MEM_freeN(nocopy);
}
static DerivedMesh *pointcache_do(CacheModifierData *pcmd, Object *UNUSED(ob), DerivedMesh *dm, ModifierApplyFlag flag)
{
bool use_output;
if (!(flag & MOD_APPLY_USECACHE))
return dm;
use_output = (flag & MOD_APPLY_RENDER) ? (pcmd->flag & MOD_CACHE_USE_OUTPUT_RENDER) : (pcmd->flag & MOD_CACHE_USE_OUTPUT_REALTIME);
if (use_output) {
if (pcmd->output_dm) {
pcmd->output_dm->release(pcmd->output_dm);
}
/* XXX HACK!
* DM copy will ignore all layers with CD_FLAG_NOCOPY set.
* This include layers that are needed by subsequent modifiers,
* which works for the modifier stack eval because DMs are passed
* down the chain directly. Making a copy for keeping the DM for the
* writer will discard those layers, so we have to temporarily disable
* the NOCOPY flags ...
*
* Probably a better way of writing out temporary data could help
*/
{
CustomData *vdata = dm->getVertDataLayout(dm);
CustomData *edata = dm->getEdgeDataLayout(dm);
CustomData *fdata = dm->getTessFaceDataLayout(dm);
CustomData *pdata = dm->getPolyDataLayout(dm);
CustomData *ldata = dm->getLoopDataLayout(dm);
bool *vdata_nocopy = store_nocopy_flags(vdata);
bool *edata_nocopy = store_nocopy_flags(edata);
bool *fdata_nocopy = store_nocopy_flags(fdata);
bool *pdata_nocopy = store_nocopy_flags(pdata);
bool *ldata_nocopy = store_nocopy_flags(ldata);
pcmd->output_dm = CDDM_copy(dm);
restore_nocopy_flags(vdata, vdata_nocopy);
restore_nocopy_flags(edata, edata_nocopy);
restore_nocopy_flags(fdata, fdata_nocopy);
restore_nocopy_flags(pdata, pdata_nocopy);
restore_nocopy_flags(ldata, ldata_nocopy);
}
}
else {
/* unused cache output? clean up! */
if (pcmd->output_dm) {
pcmd->output_dm->release(pcmd->output_dm);
pcmd->output_dm = NULL;
}
}
if (pcmd->input_dm) {
/* pass on the input DM from the cache */
dm = pcmd->input_dm;
pcmd->input_dm = NULL;
}
return dm;
}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm,
ModifierApplyFlag flag)
{
CacheModifierData *pcmd = (CacheModifierData *)md;
return pointcache_do(pcmd, ob, dm, flag);
}
static DerivedMesh *applyModifierEM(ModifierData *md, Object *ob,
struct BMEditMesh *UNUSED(editData),
DerivedMesh *dm,
ModifierApplyFlag flag)
{
CacheModifierData *pcmd = (CacheModifierData *)md;
return pointcache_do(pcmd, ob, dm, flag);
}
ModifierTypeInfo modifierType_Cache = {
/* name */ "Cache",
/* structName */ "CacheModifierData",
/* structSize */ sizeof(CacheModifierData),
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_AcceptsCVs |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
/* applyModifierEM */ applyModifierEM,
/* initData */ initData,
/* requiredDataMask */ NULL,
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
};

View File

@@ -306,5 +306,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(Wireframe);
INIT_TYPE(DataTransfer);
INIT_TYPE(NormalEdit);
INIT_TYPE(Cache);
#undef INIT_TYPE
}

View File

@@ -0,0 +1,61 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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) 2013, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
intern
util
../blenkernel
../blenlib
../makesdna
../makesrna
../../../intern/guardedalloc
)
set(INC_SYS
)
set(SRC
intern/export.h
intern/export.cpp
intern/ptc_types.h
intern/ptc_types.cpp
intern/reader.h
intern/reader.cpp
intern/writer.h
intern/writer.cpp
util/util_error_handler.h
util/util_error_handler.cpp
util/util_types.h
PTC_api.h
PTC_api.cpp
)
if(WITH_ALEMBIC)
add_definitions(-DWITH_PTC_ALEMBIC)
add_subdirectory(alembic)
endif()
blender_add_lib(bf_pointcache "${SRC}" "${INC}" "${INC_SYS}")

View File

@@ -0,0 +1,408 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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.
*/
#include "MEM_guardedalloc.h"
#include "PTC_api.h"
#include "util/util_error_handler.h"
#include "reader.h"
#include "writer.h"
#include "export.h"
#include "ptc_types.h"
extern "C" {
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "DNA_listBase.h"
#include "DNA_modifier_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_modifier.h"
#include "BKE_report.h"
#include "RNA_access.h"
}
using namespace PTC;
void PTC_error_handler_std(void)
{
ErrorHandler::clear_default_handler();
}
void PTC_error_handler_callback(PTCErrorCallback cb, void *userdata)
{
ErrorHandler::set_default_handler(new CallbackErrorHandler(cb, userdata));
}
static ReportType report_type_from_error_level(PTCErrorLevel level)
{
switch (level) {
case PTC_ERROR_NONE: return RPT_DEBUG;
case PTC_ERROR_INFO: return RPT_INFO;
case PTC_ERROR_WARNING: return RPT_WARNING;
case PTC_ERROR_CRITICAL: return RPT_ERROR;
}
return RPT_ERROR;
}
static void error_handler_reports_cb(void *vreports, PTCErrorLevel level, const char *message)
{
ReportList *reports = (ReportList *)vreports;
BKE_report(reports, report_type_from_error_level(level), message);
}
void PTC_error_handler_reports(struct ReportList *reports)
{
ErrorHandler::set_default_handler(new CallbackErrorHandler(error_handler_reports_cb, reports));
}
static void error_handler_modifier_cb(void *vmd, PTCErrorLevel UNUSED(level), const char *message)
{
ModifierData *md = (ModifierData *)vmd;
modifier_setError(md, "%s", message);
}
void PTC_error_handler_modifier(struct ModifierData *md)
{
ErrorHandler::set_default_handler(new CallbackErrorHandler(error_handler_modifier_cb, md));
}
const char *PTC_get_default_archive_extension(void)
{
return PTC::Factory::alembic->get_default_extension().c_str();
}
PTCWriterArchive *PTC_open_writer_archive(Scene *scene, const char *path)
{
return (PTCWriterArchive *)PTC::Factory::alembic->open_writer_archive(scene, path, NULL);
}
void PTC_close_writer_archive(PTCWriterArchive *_archive)
{
PTC::WriterArchive *archive = (PTC::WriterArchive *)_archive;
delete archive;
}
void PTC_writer_archive_use_render(PTCWriterArchive *_archive, bool enable)
{
PTC::WriterArchive *archive = (PTC::WriterArchive *)_archive;
archive->use_render(enable);
}
PTCReaderArchive *PTC_open_reader_archive(Scene *scene, const char *path)
{
return (PTCReaderArchive *)PTC::Factory::alembic->open_reader_archive(scene, path, NULL);
}
void PTC_close_reader_archive(PTCReaderArchive *_archive)
{
PTC::ReaderArchive *archive = (PTC::ReaderArchive *)_archive;
delete archive;
}
void PTC_reader_archive_use_render(PTCReaderArchive *_archive, bool enable)
{
PTC::ReaderArchive *archive = (PTC::ReaderArchive *)_archive;
archive->use_render(enable);
}
void PTC_writer_init(PTCWriter *_writer, PTCWriterArchive *_archive)
{
PTC::Writer *writer = (PTC::Writer *)_writer;
PTC::WriterArchive *archive = (PTC::WriterArchive *)_archive;
writer->init(archive);
}
void PTC_writer_create_refs(PTCWriter *_writer)
{
PTC::Writer *writer = (PTC::Writer *)_writer;
writer->create_refs();
}
void PTC_reader_init(PTCReader *_reader, PTCReaderArchive *_archive)
{
PTC::Reader *reader = (PTC::Reader *)_reader;
PTC::ReaderArchive *archive = (PTC::ReaderArchive *)_archive;
reader->init(archive);
}
/* ========================================================================= */
void PTC_writer_free(PTCWriter *_writer)
{
PTC::Writer *writer = (PTC::Writer *)_writer;
delete writer;
}
void PTC_write_sample(struct PTCWriter *_writer)
{
PTC::Writer *writer = (PTC::Writer *)_writer;
writer->write_sample();
}
void PTC_bake(struct Main *bmain, struct Scene *scene, struct EvaluationContext *evalctx,
PTCWriter *writer, int start_frame, int end_frame,
short *stop, short *do_update, float *progress)
{
PTC::Exporter exporter(bmain, scene, evalctx, stop, do_update, progress);
exporter.bake(writer, start_frame, end_frame);
}
void PTC_reader_free(PTCReader *_reader)
{
PTC::Reader *reader = (PTC::Reader *)_reader;
delete reader;
}
bool PTC_reader_get_frame_range(PTCReader *_reader, int *start_frame, int *end_frame)
{
PTC::Reader *reader = (PTC::Reader *)_reader;
int sfra, efra;
if (reader->get_frame_range(sfra, efra)) {
if (start_frame) *start_frame = sfra;
if (end_frame) *end_frame = efra;
return true;
}
else {
return false;
}
}
PTCReadSampleResult PTC_read_sample(PTCReader *_reader, float frame)
{
PTC::Reader *reader = (PTC::Reader *)_reader;
return reader->read_sample(frame);
}
PTCReadSampleResult PTC_test_sample(PTCReader *_reader, float frame)
{
PTC::Reader *reader = (PTC::Reader *)_reader;
return reader->test_sample(frame);
}
char *PTC_get_archive_info(PTCReaderArchive *_archive)
{
PTC::ReaderArchive *archive = (PTC::ReaderArchive *)_archive;
std::string info = archive->get_info();
return BLI_sprintfN("%s", info.c_str());
}
PTCWriter *PTC_writer_dupligroup(const char *name, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Group *group, struct CacheLibrary *cachelib)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_dupligroup(name, eval_ctx, scene, group, cachelib);
}
PTCReader *PTC_reader_duplicache(const char *name, struct Group *group, struct DupliCache *dupcache)
{
return (PTCReader *)PTC::Factory::alembic->create_reader_duplicache(name, group, dupcache);
}
PTCReader *PTC_reader_duplicache_object(const char *name, struct Object *ob, struct DupliObjectData *data)
{
return (PTCReader *)PTC::Factory::alembic->create_reader_duplicache_object(name, ob, data);
}
/* get writer/reader from RNA type */
PTCWriter *PTC_writer_from_rna(Scene *scene, PointerRNA *ptr)
{
#if 0
#if 0
if (RNA_struct_is_a(ptr->type, &RNA_ParticleSystem)) {
Object *ob = (Object *)ptr->id.data;
ParticleSystem *psys = (ParticleSystem *)ptr->data;
return PTC_writer_particles_combined(scene, ob, psys);
}
#endif
if (RNA_struct_is_a(ptr->type, &RNA_ClothModifier)) {
Object *ob = (Object *)ptr->id.data;
ClothModifierData *clmd = (ClothModifierData *)ptr->data;
return PTC_writer_cloth(scene, ob, clmd);
}
#endif
return NULL;
}
PTCReader *PTC_reader_from_rna(Scene *scene, PointerRNA *ptr)
{
#if 0
if (RNA_struct_is_a(ptr->type, &RNA_ParticleSystem)) {
Object *ob = (Object *)ptr->id.data;
ParticleSystem *psys = (ParticleSystem *)ptr->data;
/* XXX particles are bad ...
* this can be either the actual particle cache or the hair dynamics cache,
* which is actually the cache of the internal cloth modifier
*/
bool use_cloth_cache = psys->part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DYNAMICS);
if (use_cloth_cache && psys->clmd)
return PTC_reader_cloth(scene, ob, psys->clmd);
else
return PTC_reader_particles(scene, ob, psys);
}
if (RNA_struct_is_a(ptr->type, &RNA_ClothModifier)) {
Object *ob = (Object *)ptr->id.data;
ClothModifierData *clmd = (ClothModifierData *)ptr->data;
return PTC_reader_cloth(scene, ob, clmd);
}
#endif
return NULL;
}
/* ==== CLOTH ==== */
PTCWriter *PTC_writer_cloth(const char *name, Object *ob, ClothModifierData *clmd)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_cloth(name, ob, clmd);
}
PTCReader *PTC_reader_cloth(const char *name, Object *ob, ClothModifierData *clmd)
{
return (PTCReader *)PTC::Factory::alembic->create_reader_cloth(name, ob, clmd);
}
/* ==== MESH ==== */
PTCWriter *PTC_writer_derived_mesh(const char *name, Object *ob, DerivedMesh **dm_ptr)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_derived_mesh(name, ob, dm_ptr);
}
PTCReader *PTC_reader_derived_mesh(const char *name, Object *ob)
{
return (PTCReader *)PTC::Factory::alembic->create_reader_derived_mesh(name, ob);
}
struct DerivedMesh *PTC_reader_derived_mesh_acquire_result(PTCReader *_reader)
{
DerivedMeshReader *reader = (DerivedMeshReader *)_reader;
return reader->acquire_result();
}
void PTC_reader_derived_mesh_discard_result(PTCReader *_reader)
{
DerivedMeshReader *reader = (DerivedMeshReader *)_reader;
reader->discard_result();
}
PTCWriter *PTC_writer_derived_final_realtime(const char *name, Object *ob)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_derived_final_realtime(name, ob);
}
PTCWriter *PTC_writer_cache_modifier_realtime(const char *name, Object *ob, CacheModifierData *cmd)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_cache_modifier_realtime(name, ob, cmd);
}
PTCWriter *PTC_writer_derived_final_render(const char *name, Scene *scene, Object *ob, DerivedMesh **render_dm_ptr)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_derived_final_render(name, scene, ob, render_dm_ptr);
}
PTCWriter *PTC_writer_cache_modifier_render(const char *name, Scene *scene, Object *ob, CacheModifierData *cmd)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_cache_modifier_render(name, scene, ob, cmd);
}
/* ==== OBJECT ==== */
PTCWriter *PTC_writer_object(const char *name, Scene *scene, Object *ob)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_object(name, scene, ob);
}
PTCReader *PTC_reader_object(const char *name, Object *ob)
{
return (PTCReader *)PTC::Factory::alembic->create_reader_object(name, ob);
}
/* ==== GROUP ==== */
PTCWriter *PTC_writer_group(const char *name, Group *group)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_group(name, group);
}
PTCReader *PTC_reader_group(const char *name, Group *group)
{
return (PTCReader *)PTC::Factory::alembic->create_writer_group(name, group);
}
/* ==== PARTICLES ==== */
PTCWriter *PTC_writer_particles(const char *name, Object *ob, ParticleSystem *psys)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_particles(name, ob, psys);
}
PTCReader *PTC_reader_particles(const char *name, Object *ob, ParticleSystem *psys)
{
return (PTCReader *)PTC::Factory::alembic->create_reader_particles(name, ob, psys);
}
int PTC_reader_particles_totpoint(PTCReader *_reader)
{
return ((PTC::ParticlesReader *)_reader)->totpoint();
}
PTCWriter *PTC_writer_hair_dynamics(const char *name, Object *ob, ParticleSystem *psys)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_hair_dynamics(name, ob, psys);
}
PTCReader *PTC_reader_hair_dynamics(const char *name, Object *ob, ParticleSystem *psys)
{
return (PTCReader *)PTC::Factory::alembic->create_reader_hair_dynamics(name, ob, psys);
}
PTCWriter *PTC_writer_particles_pathcache_parents(const char *name, Object *ob, ParticleSystem *psys)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_particles_pathcache_parents(name, ob, psys);
}
PTCReader *PTC_reader_particles_pathcache_parents(const char *name, Object *ob, ParticleSystem *psys)
{
return (PTCReader *)PTC::Factory::alembic->create_reader_particles_pathcache_parents(name, ob, psys);
}
PTCWriter *PTC_writer_particles_pathcache_children(const char *name, Object *ob, ParticleSystem *psys)
{
return (PTCWriter *)PTC::Factory::alembic->create_writer_particles_pathcache_children(name, ob, psys);
}
PTCReader *PTC_reader_particles_pathcache_children(const char *name, Object *ob, ParticleSystem *psys)
{
return (PTCReader *)PTC::Factory::alembic->create_reader_particles_pathcache_children(name, ob, psys);
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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.
*/
#ifndef PTC_API_H
#define PTC_API_H
#include "util/util_types.h"
#ifdef __cplusplus
extern "C" {
#endif
struct Main;
struct Scene;
struct EvaluationContext;
struct ListBase;
struct PointerRNA;
struct ReportList;
struct DupliCache;
struct ClothModifierData;
struct DerivedMesh;
struct Group;
struct ModifierData;
struct Object;
struct ParticleSystem;
struct CacheModifierData;
struct SoftBody;
struct PTCWriterArchive;
struct PTCReaderArchive;
struct PTCWriter;
struct PTCReader;
void PTC_alembic_init(void);
/*** Error Handling ***/
void PTC_error_handler_std(void);
void PTC_error_handler_callback(PTCErrorCallback cb, void *userdata);
void PTC_error_handler_reports(struct ReportList *reports);
void PTC_error_handler_modifier(struct ModifierData *md);
void PTC_bake(struct Main *bmain, struct Scene *scene, struct EvaluationContext *evalctx,
struct PTCWriter *writer, int start_frame, int end_frame,
short *stop, short *do_update, float *progress);
/*** Archive ***/
const char *PTC_get_default_archive_extension(void);
struct PTCWriterArchive *PTC_open_writer_archive(struct Scene *scene, const char *path);
void PTC_close_writer_archive(struct PTCWriterArchive *archive);
void PTC_writer_archive_use_render(struct PTCWriterArchive *archive, bool enable);
struct PTCReaderArchive *PTC_open_reader_archive(struct Scene *scene, const char *path);
void PTC_close_reader_archive(struct PTCReaderArchive *archive);
void PTC_reader_archive_use_render(struct PTCReaderArchive *archive, bool enable);
void PTC_writer_init(struct PTCWriter *writer, struct PTCWriterArchive *archive);
void PTC_writer_create_refs(struct PTCWriter *writer);
void PTC_reader_init(struct PTCReader *reader, struct PTCReaderArchive *archive);
/*** Reader/Writer Interface ***/
void PTC_writer_free(struct PTCWriter *writer);
void PTC_write_sample(struct PTCWriter *writer);
void PTC_reader_free(struct PTCReader *reader);
bool PTC_reader_get_frame_range(struct PTCReader *reader, int *start_frame, int *end_frame);
PTCReadSampleResult PTC_read_sample(struct PTCReader *reader, float frame);
PTCReadSampleResult PTC_test_sample(struct PTCReader *reader, float frame);
char *PTC_get_archive_info(struct PTCReaderArchive *archive);
struct PTCWriter *PTC_writer_dupligroup(const char *name, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Group *group, struct CacheLibrary *cachelib);
struct PTCReader *PTC_reader_duplicache(const char *name, struct Group *group, struct DupliCache *dupcache);
struct PTCReader *PTC_reader_duplicache_object(const char *name, struct Object *ob, struct DupliObjectData *data);
/* get writer/reader from RNA type */
struct PTCWriter *PTC_writer_from_rna(struct Scene *scene, struct PointerRNA *ptr);
struct PTCReader *PTC_reader_from_rna(struct Scene *scene, struct PointerRNA *ptr);
/* Object */
struct PTCWriter *PTC_writer_object(const char *name, struct Scene *scene, struct Object *ob);
struct PTCReader *PTC_reader_object(const char *name, struct Object *ob);
/* Group */
struct PTCWriter *PTC_writer_group(const char *name, struct Group *group);
struct PTCReader *PTC_reader_group(const char *name, struct Group *group);
/* Particles */
struct PTCWriter *PTC_writer_particles(const char *name, struct Object *ob, struct ParticleSystem *psys);
struct PTCReader *PTC_reader_particles(const char *name, struct Object *ob, struct ParticleSystem *psys);
int PTC_reader_particles_totpoint(struct PTCReader *reader);
struct PTCWriter *PTC_writer_hair_dynamics(const char *name, struct Object *ob, struct ParticleSystem *psys);
struct PTCReader *PTC_reader_hair_dynamics(const char *name, struct Object *ob, struct ParticleSystem *psys);
struct PTCWriter *PTC_writer_particles_pathcache_parents(const char *name, struct Object *ob, struct ParticleSystem *psys);
struct PTCReader *PTC_reader_particles_pathcache_parents(const char *name, struct Object *ob, struct ParticleSystem *psys);
struct PTCWriter *PTC_writer_particles_pathcache_children(const char *name, struct Object *ob, struct ParticleSystem *psys);
struct PTCReader *PTC_reader_particles_pathcache_children(const char *name, struct Object *ob, struct ParticleSystem *psys);
/* Cloth */
struct PTCWriter *PTC_writer_cloth(const char *name, struct Object *ob, struct ClothModifierData *clmd);
struct PTCReader *PTC_reader_cloth(const char *name, struct Object *ob, struct ClothModifierData *clmd);
struct PTCWriter *PTC_writer_derived_mesh(const char *name, struct Object *ob, struct DerivedMesh **dm_ptr);
struct PTCReader *PTC_reader_derived_mesh(const char *name, struct Object *ob);
struct DerivedMesh *PTC_reader_derived_mesh_acquire_result(struct PTCReader *reader);
void PTC_reader_derived_mesh_discard_result(struct PTCReader *reader);
struct PTCWriter *PTC_writer_derived_final_realtime(const char *name, struct Object *ob);
struct PTCWriter *PTC_writer_cache_modifier_realtime(const char *name, struct Object *ob, struct CacheModifierData *cmd);
struct PTCWriter *PTC_writer_derived_final_render(const char *name, struct Scene *scene, struct Object *ob, struct DerivedMesh **render_dm_ptr);
struct PTCWriter *PTC_writer_cache_modifier_render(const char *name, struct Scene *scene, struct Object *ob, struct CacheModifierData *cmd);
#ifdef __cplusplus
} /* extern C */
#endif
#endif /* PTC_API_H */

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env python
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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) 2014, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Lukas Toenne.
#
# ***** END GPL LICENSE BLOCK *****
Import ('env')
sources = env.Glob('intern/*.cpp') + env.Glob('util/*.cpp') + env.Glob('*.cpp')
incs = [
'.',
'intern',
'util',
'../blenkernel',
'../blenlib',
'../makesdna',
'../makesrna',
'../../../intern/guardedalloc',
]
defs = []
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs.append(env['BF_PTHREADS_INC'])
if env['WITH_BF_ALEMBIC']:
defs.append('WITH_PTC_ALEMBIC')
SConscript(['alembic/SConscript'])
env.BlenderLib('bf_pointcache', sources, incs, defines=defs, libtype=['core'], priority=[900])

View File

@@ -0,0 +1,71 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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) 2013, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
../
../intern
../util
../../blenkernel
../../blenlib
../../makesdna
../../makesrna
../../../../intern/guardedalloc
)
set(INC_SYS
${BOOST_INCLUDE_DIR}
${ALEMBIC_INCLUDE_DIRS}
${OPENEXR_INCLUDE_DIR}/OpenEXR
)
set(SRC
alembic.cpp
alembic.h
abc_frame_mapper.cpp
abc_frame_mapper.h
abc_info.cpp
abc_reader.cpp
abc_reader.h
abc_schema.h
abc_writer.cpp
abc_writer.h
abc_cloth.cpp
abc_cloth.h
abc_customdata.cpp
abc_customdata.h
abc_group.cpp
abc_group.h
abc_mesh.cpp
abc_mesh.h
abc_object.cpp
abc_object.h
abc_particles.cpp
abc_particles.h
)
add_definitions(-DWITH_ALEMBIC)
blender_add_lib(bf_pointcache_alembic "${SRC}" "${INC}" "${INC_SYS}")

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env python
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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) 2014, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Lukas Toenne.
#
# ***** END GPL LICENSE BLOCK *****
Import ('env')
sources = env.Glob('*.cpp')
incs = [
'.',
'../',
'../intern',
'../util',
'../../blenkernel',
'../../blenlib',
'../../makesdna',
'../../makesrna',
'../../../../intern/guardedalloc',
]
incs += Split(env['BF_OPENEXR_INC'])
defs = []
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs.append(env['BF_PTHREADS_INC'])
if env['WITH_BF_ALEMBIC']:
incs.append(env['BF_OPENEXR_INC'])
incs.append(env['BF_ALEMBIC_INC'])
defs.append('WITH_ALEMBIC')
env.BlenderLib('bf_pointcache_alembic', sources, incs, defines=defs, libtype=['core'], priority=[901])

View File

@@ -0,0 +1,244 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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.
*/
#include "abc_cloth.h"
extern "C" {
#include "BLI_math.h"
#include "DNA_cloth_types.h"
#include "DNA_object_types.h"
#include "DNA_modifier_types.h"
#include "BKE_cloth.h"
}
#include "PTC_api.h"
namespace PTC {
using namespace Abc;
using namespace AbcGeom;
AbcClothWriter::AbcClothWriter(const std::string &name, Object *ob, ClothModifierData *clmd) :
ClothWriter(ob, clmd, name)
{
set_error_handler(new ModifierErrorHandler(&clmd->modifier));
}
AbcClothWriter::~AbcClothWriter()
{
}
void AbcClothWriter::init_abc(OObject parent)
{
if (m_points)
return;
m_points = OPoints(parent, m_name, abc_archive()->frame_sampling_index());
OPointsSchema &schema = m_points.getSchema();
OCompoundProperty geom_params = schema.getArbGeomParams();
m_param_velocities = OV3fGeomParam(geom_params, "velocities", false, kVaryingScope, 1, 0);
m_param_goal_positions = OP3fGeomParam(geom_params, "goal_positions", false, kVaryingScope, 1, 0);
}
static V3fArraySample create_sample_velocities(Cloth *cloth, std::vector<V3f> &data)
{
ClothVertex *vert;
int i, totvert = cloth->numverts;
data.reserve(totvert);
for (i = 0, vert = cloth->verts; i < totvert; ++i, ++vert) {
float *co = vert->v;
data.push_back(V3f(co[0], co[1], co[2]));
}
return V3fArraySample(data);
}
static P3fArraySample create_sample_goal_positions(Cloth *cloth, std::vector<V3f> &data)
{
ClothVertex *vert;
int i, totvert = cloth->numverts;
data.reserve(totvert);
for (i = 0, vert = cloth->verts; i < totvert; ++i, ++vert) {
float *co = vert->xconst;
data.push_back(V3f(co[0], co[1], co[2]));
}
return P3fArraySample(data);
}
void AbcClothWriter::write_sample()
{
if (!m_points)
return;
Cloth *cloth = m_clmd->clothObject;
if (!cloth)
return;
OPointsSchema &schema = m_points.getSchema();
int totpoint = cloth->numverts;
ClothVertex *vert;
int i;
/* XXX TODO only needed for the first frame/sample */
std::vector<Util::uint64_t> ids;
ids.reserve(totpoint);
for (i = 0, vert = cloth->verts; i < totpoint; ++i, ++vert)
ids.push_back(i);
std::vector<V3f> positions;
positions.reserve(totpoint);
for (i = 0, vert = cloth->verts; i < totpoint; ++i, ++vert) {
float *co = vert->x;
positions.push_back(V3f(co[0], co[1], co[2]));
}
std::vector<V3f> velocities_buffer;
std::vector<V3f> goal_positions_buffer;
V3fArraySample velocities = create_sample_velocities(cloth, velocities_buffer);
P3fArraySample goal_positions = create_sample_goal_positions(cloth, goal_positions_buffer);
OPointsSchema::Sample sample = OPointsSchema::Sample(V3fArraySample(positions), UInt64ArraySample(ids));
schema.set(sample);
m_param_velocities.set(OV3fGeomParam::Sample(velocities, kVaryingScope));
m_param_goal_positions.set(OP3fGeomParam::Sample(goal_positions, kVaryingScope));
}
AbcClothReader::AbcClothReader(const std::string &name, Object *ob, ClothModifierData *clmd) :
ClothReader(ob, clmd, name)
{
set_error_handler(new ModifierErrorHandler(&clmd->modifier));
}
AbcClothReader::~AbcClothReader()
{
}
void AbcClothReader::init_abc(IObject parent)
{
if (m_points)
return;
if (parent.getChild(m_name)) {
m_points = IPoints(parent, m_name);
IPointsSchema &schema = m_points.getSchema();
ICompoundProperty geom_params = schema.getArbGeomParams();
m_param_velocities = IV3fGeomParam(geom_params, "velocities", 0);
m_param_goal_positions= IP3fGeomParam(geom_params, "goal_positions", 0);
}
}
static void apply_sample_positions(Cloth *cloth, P3fArraySamplePtr sample)
{
ClothVertex *vert;
int i, totvert = cloth->numverts;
BLI_assert(sample->size() == totvert);
const V3f *data = sample->get();
for (i = 0, vert = cloth->verts; i < totvert; ++i, ++vert) {
const V3f &co = data[i];
copy_v3_v3(vert->x, co.getValue());
}
}
static void apply_sample_velocities(Cloth *cloth, V3fArraySamplePtr sample)
{
ClothVertex *vert;
int i, totvert = cloth->numverts;
BLI_assert(sample->size() == totvert);
const V3f *data = sample->get();
for (i = 0, vert = cloth->verts; i < totvert; ++i, ++vert) {
const V3f &vel = data[i];
copy_v3_v3(vert->v, vel.getValue());
}
}
static void apply_sample_goal_positions(Cloth *cloth, P3fArraySamplePtr sample)
{
ClothVertex *vert;
int i, totvert = cloth->numverts;
BLI_assert(sample->size() == totvert);
const V3f *data = sample->get();
for (i = 0, vert = cloth->verts; i < totvert; ++i, ++vert) {
const V3f &co = data[i];
copy_v3_v3(vert->xconst, co.getValue());
}
}
PTCReadSampleResult AbcClothReader::read_sample(float frame)
{
Cloth *cloth = m_clmd->clothObject;
if (!m_points)
return PTC_READ_SAMPLE_INVALID;
IPointsSchema &schema = m_points.getSchema();
TimeSamplingPtr ts = schema.getTimeSampling();
ISampleSelector ss = abc_archive()->get_frame_sample_selector(frame);
// chrono_t time = ss.getRequestedTime();
// std::pair<index_t, chrono_t> sres = ts->getFloorIndex(time, schema.getNumSamples());
// chrono_t stime = sres.second;
// float sframe = archive()->time_to_frame(stime);
IPointsSchema::Sample sample;
schema.get(sample, ss);
P3fArraySamplePtr positions = sample.getPositions();
V3fArraySamplePtr velocities;
if (m_param_velocities && m_param_velocities.getNumSamples() > 0) {
IV3fGeomParam::Sample sample_velocities;
m_param_velocities.getExpanded(sample_velocities, ss);
velocities = sample_velocities.getVals();
}
P3fArraySamplePtr goal_positions;
if (m_param_goal_positions && m_param_goal_positions.getNumSamples() > 0) {
IP3fGeomParam::Sample sample_goal_positions;
m_param_goal_positions.getExpanded(sample_goal_positions, ss);
goal_positions = sample_goal_positions.getVals();
}
apply_sample_positions(cloth, positions);
if (velocities)
apply_sample_velocities(cloth, velocities);
if (goal_positions)
apply_sample_goal_positions(cloth, goal_positions);
return PTC_READ_SAMPLE_EXACT;
}
} /* namespace PTC */

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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.
*/
#ifndef PTC_ABC_CLOTH_H
#define PTC_ABC_CLOTH_H
#include <Alembic/AbcGeom/IPoints.h>
#include <Alembic/AbcGeom/OPoints.h>
#include "ptc_types.h"
#include "abc_reader.h"
#include "abc_schema.h"
#include "abc_writer.h"
struct Object;
struct ClothModifierData;
namespace PTC {
class AbcClothWriter : public ClothWriter, public AbcWriter {
public:
AbcClothWriter(const std::string &name, Object *ob, ClothModifierData *clmd);
~AbcClothWriter();
void init_abc(Abc::OObject parent);
void write_sample();
private:
AbcGeom::OPoints m_points;
AbcGeom::OV3fGeomParam m_param_velocities;
AbcGeom::OP3fGeomParam m_param_goal_positions;
};
class AbcClothReader : public ClothReader, public AbcReader {
public:
AbcClothReader(const std::string &name, Object *ob, ClothModifierData *clmd);
~AbcClothReader();
void init_abc(Abc::IObject parent);
PTCReadSampleResult read_sample(float frame);
private:
AbcGeom::IPoints m_points;
AbcGeom::IV3fGeomParam m_param_velocities;
AbcGeom::IP3fGeomParam m_param_goal_positions;
};
} /* namespace PTC */
#endif /* PTC_CLOTH_H */

View File

@@ -0,0 +1,512 @@
/*
* Copyright 2015, Blender Foundation.
*
* 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.
*/
#include <sstream>
#include <Alembic/AbcGeom/IGeomParam.h>
#include <Alembic/AbcGeom/OGeomParam.h>
#include "abc_customdata.h"
extern "C" {
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_customdata.h"
}
namespace PTC {
using namespace Abc;
using namespace AbcGeom;
/* DEBUG */
BLI_INLINE void print_writer_compound(OCompoundProperty &prop)
{
CompoundPropertyWriterPtr ptr = prop.getPtr()->asCompoundPtr();
printf("compound %s: [%p] (%d)\n", ptr->getName().c_str(), ptr.get(), (int)ptr->getNumProperties());
for (int i = 0; i < ptr->getNumProperties(); ++i) {
printf(" %d: [%p]\n", i, prop.getProperty(i).getPtr().get());
printf(" %s\n", prop.getProperty(i).getName().c_str());
}
}
/* ========================================================================= */
template <CustomDataType CDTYPE>
static void write_sample(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
{
/* no implementation available, should not happen */
printf("ERROR: CustomData type %s has no write_sample implementation\n", CustomData_layertype_name((int)CDTYPE));
}
template <>
void write_sample<CD_MDEFORMVERT>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
{
OCompoundProperty prop = writer->add_compound_property<OCompoundProperty>(name, parent);
OInt32ArrayProperty totweight_prop = writer->add_array_property<OInt32ArrayProperty>(name+":totweight", prop);
OInt32ArrayProperty flag_prop = writer->add_array_property<OInt32ArrayProperty>(name+":flag", prop);
OInt32ArrayProperty def_nr_prop = writer->add_array_property<OInt32ArrayProperty>(name+":def_nr", prop);
OFloatArrayProperty weight_prop = writer->add_array_property<OFloatArrayProperty>(name+":weight", prop);
MDeformVert *mdef = (MDeformVert *)data;
/* sum all totweight for the sample size */
int num_mdefweight = 0;
for (int i = 0; i < num_data; ++i)
num_mdefweight += mdef[i].totweight;
std::vector<int32_t> totweight_data;
std::vector<int32_t> flag_data;
std::vector<int32_t> def_nr_data;
std::vector<float> weight_data;
totweight_data.reserve(num_data);
flag_data.reserve(num_data);
def_nr_data.reserve(num_mdefweight);
weight_data.reserve(num_mdefweight);
for (int i = 0; i < num_data; ++i) {
totweight_data.push_back(mdef->totweight);
flag_data.push_back(mdef->flag);
MDeformWeight *mw = mdef->dw;
for (int j = 0; j < mdef->totweight; ++j) {
def_nr_data.push_back(mw->def_nr);
weight_data.push_back(mw->weight);
++mw;
}
++mdef;
}
totweight_prop.set(Int32ArraySample(totweight_data));
flag_prop.set(Int32ArraySample(flag_data));
def_nr_prop.set(Int32ArraySample(def_nr_data));
weight_prop.set(FloatArraySample(weight_data));
}
template <>
void write_sample<CD_MCOL>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
{
OC4fArrayProperty prop = writer->add_array_property<OC4fArrayProperty>(name, parent);
MCol *mcol = (MCol *)data;
std::vector<C4f> mcol_data;
mcol_data.reserve(num_data);
for (int i = 0; i < num_data; ++i) {
mcol_data.push_back(C4f(mcol->r, mcol->g, mcol->b, mcol->a));
++mcol;
}
prop.set(OC4fArrayProperty::sample_type(mcol_data));
}
template <>
void write_sample<CD_ORIGINDEX>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
{
OInt32ArrayProperty prop = writer->add_array_property<OInt32ArrayProperty>(name, parent);
prop.set(OInt32ArrayProperty::sample_type((int *)data, num_data));
}
template <>
void write_sample<CD_NORMAL>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
{
ON3fArrayProperty prop = writer->add_array_property<ON3fArrayProperty>(name, parent);
prop.set(ON3fArrayProperty::sample_type((N3f *)data, num_data));
}
template <>
void write_sample<CD_ORIGSPACE>(CustomDataWriter *writer, OCompoundProperty &parent, const std::string &name, void *data, int num_data)
{
OCompoundProperty prop = writer->add_compound_property<OCompoundProperty>(name, parent);
OV2fArrayProperty uv_prop[4];
uv_prop[0] = writer->add_array_property<OV2fArrayProperty>(name+":uv0", prop);
uv_prop[1] = writer->add_array_property<OV2fArrayProperty>(name+":uv1", prop);
uv_prop[2] = writer->add_array_property<OV2fArrayProperty>(name+":uv2", prop);
uv_prop[3] = writer->add_array_property<OV2fArrayProperty>(name+":uv3", prop);
OrigSpaceFace *ospace = (OrigSpaceFace *)data;
std::vector<V2f> uv_data[4];
uv_data[0].reserve(num_data);
uv_data[1].reserve(num_data);
uv_data[2].reserve(num_data);
uv_data[3].reserve(num_data);
for (int i = 0; i < num_data; ++i) {
uv_data[0].push_back(V2f(ospace[i].uv[0][0], ospace[i].uv[0][1]));
uv_data[1].push_back(V2f(ospace[i].uv[1][0], ospace[i].uv[1][1]));
uv_data[2].push_back(V2f(ospace[i].uv[2][0], ospace[i].uv[2][1]));
uv_data[3].push_back(V2f(ospace[i].uv[3][0], ospace[i].uv[3][1]));
}
uv_prop[0].set(V2fArraySample(uv_data[0]));
uv_prop[1].set(V2fArraySample(uv_data[1]));
uv_prop[2].set(V2fArraySample(uv_data[2]));
uv_prop[3].set(V2fArraySample(uv_data[3]));
}
/* ------------------------------------------------------------------------- */
template <CustomDataType CDTYPE>
static PTCReadSampleResult read_sample(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
{
/* no implementation available, should not happen */
printf("ERROR: CustomData type %s has no read_sample implementation\n", CustomData_layertype_name((int)CDTYPE));
return PTC_READ_SAMPLE_INVALID;
}
template <>
PTCReadSampleResult read_sample<CD_MDEFORMVERT>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
{
ICompoundProperty prop = reader->add_compound_property<ICompoundProperty>(name, parent);
IInt32ArrayProperty totweight_prop = reader->add_array_property<IInt32ArrayProperty>(name+":totweight", prop);
IInt32ArrayProperty flag_prop = reader->add_array_property<IInt32ArrayProperty>(name+":flag", prop);
IInt32ArrayProperty def_nr_prop = reader->add_array_property<IInt32ArrayProperty>(name+":def_nr", prop);
IFloatArrayProperty weight_prop = reader->add_array_property<IFloatArrayProperty>(name+":weight", prop);
Int32ArraySamplePtr sample_totweight = totweight_prop.getValue(ss);
Int32ArraySamplePtr sample_flag = flag_prop.getValue(ss);
Int32ArraySamplePtr sample_def_nr = def_nr_prop.getValue(ss);
FloatArraySamplePtr sample_weight = weight_prop.getValue(ss);
if (sample_totweight->size() != num_data ||
sample_flag->size() != num_data)
return PTC_READ_SAMPLE_INVALID;
const int32_t *data_totweight = (const int32_t *)sample_totweight->getData();
const int32_t *data_flag = (const int32_t *)sample_flag->getData();
const int32_t *data_def_nr = (const int32_t *)sample_def_nr->getData();
const float *data_weight = (const float *)sample_weight->getData();
MDeformVert *mdef = (MDeformVert *)data;
for (int i = 0; i < num_data; ++i) {
mdef->totweight = *data_totweight;
mdef->flag = *data_flag;
MDeformWeight *mw = mdef->dw = (MDeformWeight *)MEM_mallocN(sizeof(MDeformWeight) * mdef->totweight, "deformWeight");
for (int j = 0; j < mdef->totweight; ++j) {
mw->def_nr = *data_def_nr;
mw->weight = *data_weight;
++data_def_nr;
++data_weight;
++mw;
}
++data_totweight;
++data_flag;
++mdef;
}
return PTC_READ_SAMPLE_EXACT;
}
template <>
PTCReadSampleResult read_sample<CD_MCOL>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
{
IC4fArrayProperty prop = reader->add_array_property<IC4fArrayProperty>(name, parent);
C4fArraySamplePtr sample = prop.getValue(ss);
if (sample->size() != num_data)
return PTC_READ_SAMPLE_INVALID;
MCol *mcol = (MCol *)data;
C4f *data_mcol = (C4f *)sample->getData();
for (int i = 0; i < num_data; ++i) {
mcol->r = data_mcol->r;
mcol->g = data_mcol->g;
mcol->b = data_mcol->b;
mcol->a = data_mcol->a;
++data_mcol;
++mcol;
}
return PTC_READ_SAMPLE_EXACT;
}
template <>
PTCReadSampleResult read_sample<CD_ORIGINDEX>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
{
IInt32ArrayProperty prop = reader->add_array_property<IInt32ArrayProperty>(name, parent);
Int32ArraySamplePtr sample = prop.getValue(ss);
if (sample->size() != num_data)
return PTC_READ_SAMPLE_INVALID;
memcpy(data, sample->getData(), sizeof(int32_t) * num_data);
return PTC_READ_SAMPLE_EXACT;
}
template <>
PTCReadSampleResult read_sample<CD_NORMAL>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
{
IN3fArrayProperty prop = reader->add_array_property<IN3fArrayProperty>(name, parent);
N3fArraySamplePtr sample = prop.getValue(ss);
if (sample->size() != num_data)
return PTC_READ_SAMPLE_INVALID;
memcpy(data, sample->getData(), sizeof(N3f) * num_data);
return PTC_READ_SAMPLE_EXACT;
}
template <>
PTCReadSampleResult read_sample<CD_ORIGSPACE>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, const std::string &name, void *data, int num_data)
{
ICompoundProperty prop = reader->add_compound_property<ICompoundProperty>(name, parent);
IV2fArrayProperty uv_prop[4];
uv_prop[0] = reader->add_array_property<IV2fArrayProperty>(name+":uv0", prop);
uv_prop[1] = reader->add_array_property<IV2fArrayProperty>(name+":uv1", prop);
uv_prop[2] = reader->add_array_property<IV2fArrayProperty>(name+":uv2", prop);
uv_prop[3] = reader->add_array_property<IV2fArrayProperty>(name+":uv3", prop);
V2fArraySamplePtr sample0 = uv_prop[0].getValue(ss);
V2fArraySamplePtr sample1 = uv_prop[1].getValue(ss);
V2fArraySamplePtr sample2 = uv_prop[2].getValue(ss);
V2fArraySamplePtr sample3 = uv_prop[3].getValue(ss);
if (sample0->size() != num_data ||
sample1->size() != num_data ||
sample2->size() != num_data ||
sample3->size() != num_data)
return PTC_READ_SAMPLE_INVALID;
OrigSpaceFace *ospace = (OrigSpaceFace *)data;
const V2f *data0 = (const V2f *)sample0->getData();
const V2f *data1 = (const V2f *)sample1->getData();
const V2f *data2 = (const V2f *)sample2->getData();
const V2f *data3 = (const V2f *)sample3->getData();
for (int i = 0; i < num_data; ++i) {
copy_v2_v2(ospace->uv[0], data0->getValue());
copy_v2_v2(ospace->uv[1], data1->getValue());
copy_v2_v2(ospace->uv[2], data2->getValue());
copy_v2_v2(ospace->uv[3], data3->getValue());
++data0;
++data1;
++data2;
++data3;
++ospace;
}
return PTC_READ_SAMPLE_EXACT;
}
/* ========================================================================= */
/* recursive template that handles dispatch by CD layer type */
template <int CDTYPE>
BLI_INLINE void write_sample_call(CustomDataWriter *writer, OCompoundProperty &parent, CustomDataType type, const std::string &name, void *data, int num_data)
{
if (type == CDTYPE)
write_sample<(CustomDataType)CDTYPE>(writer, parent, name, data, num_data);
else
write_sample_call<CDTYPE+1>(writer, parent, type, name, data, num_data);
}
/* terminator specialization */
template <>
void write_sample_call<CD_NUMTYPES>(CustomDataWriter *writer, OCompoundProperty &parent, CustomDataType type, const std::string &name, void *data, int num_data)
{
}
/* ------------------------------------------------------------------------- */
/* recursive template that handles dispatch by CD layer type */
template <int CDTYPE>
BLI_INLINE PTCReadSampleResult read_sample_call(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, CustomDataType type, const std::string &name, void *data, int num_data)
{
if (type == CDTYPE)
return read_sample<(CustomDataType)CDTYPE>(reader, parent, ss, name, data, num_data);
else
return read_sample_call<CDTYPE+1>(reader, parent, ss, type, name, data, num_data);
}
/* terminator specialization */
template <>
PTCReadSampleResult read_sample_call<CD_NUMTYPES>(CustomDataReader *reader, ICompoundProperty &parent, const ISampleSelector &ss, CustomDataType type, const std::string &name, void *data, int num_data)
{
return PTC_READ_SAMPLE_INVALID;
}
/* ========================================================================= */
CustomDataWriter::CustomDataWriter(const std::string &name, CustomDataMask cdmask) :
m_name(name),
m_cdmask(cdmask)
{
}
CustomDataWriter::~CustomDataWriter()
{
for (LayerPropsMap::iterator it = m_layer_props.begin(); it != m_layer_props.end(); ++it) {
BasePropertyWriterPtr prop = it->second;
if (prop)
prop.reset();
}
}
/* unique property name based on either layer name or index */
std::string CustomDataWriter::cdtype_to_name(CustomData *cdata, CustomDataType type, int n)
{
const char *layertype_name = CustomData_layertype_name(type);
const char *layer_name = CustomData_get_layer_name(cdata, type, n);
std::string name;
if (layer_name && layer_name[0] != '\0') {
name = m_name + ":" + std::string(layertype_name) + ":S" + std::string(layer_name);
}
else {
std::stringstream ss; ss << n;
name = m_name + ":" + std::string(layertype_name) + ":N" + ss.str();
}
return name;
}
/* parse property name to CD layer name based on S or N prefix for named/unnamed layers */
void CustomDataReader::cdtype_from_name(CustomData *cdata, const std::string &name, int type, int *n, char *layer_name, int max_layer_name)
{
const char *layertype_name = CustomData_layertype_name(type);
/* We can safely assume all properties in the compound share the correct prefix
* <m_name>:<layertype_name>:
* The layertype_name is only prepended to avoid name collisions
*/
const size_t start = m_name.size() + 1 + strlen(layertype_name) + 1;
if (name.size() <= start) {
printf("ERROR: invalid CustomData layer property name '%s'\n", name.c_str());
*n = -1;
layer_name[0] = '\0';
}
else if (name[start] == 'S') {
/* named layer */
*n = -1;
BLI_strncpy(layer_name, name.c_str() + start + 1, max_layer_name);
}
else if (name[start] == 'N') {
/* unnamed layer */
std::istringstream ss(name.c_str() + start + 1);
ss >> (*n);
layer_name[0] = '\0';
}
else {
*n = -1;
layer_name[0] = '\0';
}
}
void CustomDataWriter::write_sample(CustomData *cdata, int num_data, OCompoundProperty &parent)
{
/* compound property for all CD layers in the CustomData instance */
m_props = add_compound_property<OCompoundProperty>(m_name, parent);
for (int type = 0; type < CD_NUMTYPES; ++type) {
CustomDataMask mask = (1 << type);
/* only use specified types */
if (!(mask & m_cdmask))
continue;
const char *layertype_name = CustomData_layertype_name(type);
int num = CustomData_number_of_layers(cdata, type);
bool has_props = false;
OCompoundProperty layertype_props;
for (int n = 0; n < num; ++n) {
/* compound for all CD layers of the same type */
if (!has_props) {
has_props = true;
layertype_props = add_compound_property<OCompoundProperty>(m_name+":"+layertype_name, m_props);
}
std::string name = cdtype_to_name(cdata, (CustomDataType)type, n);
void *data = CustomData_get_layer_n(cdata, type, n);
write_sample_call<0>(this, layertype_props, (CustomDataType)type, name, data, num_data);
}
}
}
/* ------------------------------------------------------------------------- */
CustomDataReader::CustomDataReader(const std::string &name, CustomDataMask cdmask) :
m_name(name),
m_cdmask(cdmask)
{
}
CustomDataReader::~CustomDataReader()
{
for (LayerPropsMap::iterator it = m_layer_props.begin(); it != m_layer_props.end(); ++it) {
BasePropertyReaderPtr prop = it->second;
if (prop)
prop.reset();
}
}
PTCReadSampleResult CustomDataReader::read_sample(const ISampleSelector &ss, CustomData *cdata, int num_data, ICompoundProperty &parent)
{
m_props = add_compound_property<ICompoundProperty>(m_name, parent);
for (int type = 0; type < CD_NUMTYPES; ++type) {
CustomDataMask mask = (1 << type);
/* only use specified types */
if (!(mask & m_cdmask))
continue;
const char *layertype_name = CustomData_layertype_name(type);
BasePropertyReaderPtr ptr = m_props.getPtr()->asCompoundPtr()->getProperty(m_name+":"+layertype_name);
if (!ptr) {
/* no layer of this type stored */
continue;
}
ICompoundProperty layertype_props(ptr->asCompoundPtr(), kWrapExisting);
for (int i = 0; i < layertype_props.getNumProperties(); ++i) {
const std::string &name = layertype_props.getPropertyHeader(i).getName();
char layer_name[MAX_CUSTOMDATA_LAYER_NAME];
int n;
void *data;
cdtype_from_name(cdata, name, type, &n, layer_name, sizeof(layer_name));
if (layer_name[0] == '\0')
data = CustomData_add_layer(cdata, type, CD_DEFAULT, NULL, num_data);
else
data = CustomData_add_layer_named(cdata, type, CD_DEFAULT, NULL, num_data, layer_name);
read_sample_call<0>(this, layertype_props, ss, (CustomDataType)type, name, data, num_data);
}
}
return PTC_READ_SAMPLE_EXACT;
}
} /* namespace PTC */

View File

@@ -0,0 +1,144 @@
/*
* Copyright 2015, Blender Foundation.
*
* 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.
*/
#ifndef PTC_ABC_CUSTOMDATA_H
#define PTC_ABC_CUSTOMDATA_H
#include <map>
#include <Alembic/AbcGeom/IGeomParam.h>
#include <Alembic/AbcGeom/OGeomParam.h>
#include <Alembic/Abc/IBaseProperty.h>
#include <Alembic/Abc/TypedPropertyTraits.h>
#include "abc_reader.h"
#include "abc_writer.h"
extern "C" {
#include "BKE_customdata.h"
#include "DNA_customdata_types.h"
}
namespace PTC {
using namespace Alembic;
std::string abc_customdata_layer_name(CustomData *cdata, CustomDataType type, int n);
struct CustomDataWriter {
typedef std::map<std::string, Abc::BasePropertyWriterPtr> LayerPropsMap;
typedef std::pair<std::string, Abc::BasePropertyWriterPtr> LayerPropsPair;
CustomDataWriter(const std::string &name, CustomDataMask cdmask);
~CustomDataWriter();
void write_sample(CustomData *cdata, int num_data, Abc::OCompoundProperty &parent);
Abc::OCompoundProperty &props() { return m_props; }
template <typename PropertyT, typename ParentT>
PropertyT add_array_property(const std::string &name, ParentT &parent)
{
LayerPropsMap::iterator it = m_layer_props.find(name);
if (it == m_layer_props.end()) {
PropertyT prop = PropertyT(parent, name, 0);
m_layer_props.insert(LayerPropsPair(name, prop.getPtr()));
return prop;
}
else {
return PropertyT(it->second->asArrayPtr(), Abc::kWrapExisting);
}
}
template <typename PropertyT, typename ParentT>
PropertyT add_compound_property(const std::string &name, ParentT &parent)
{
LayerPropsMap::iterator it = m_layer_props.find(name);
if (it == m_layer_props.end()) {
PropertyT prop = PropertyT(parent, name, 0);
m_layer_props.insert(LayerPropsPair(name, prop.getPtr()));
return prop;
}
else {
return PropertyT(it->second->asCompoundPtr(), Abc::kWrapExisting);
}
}
std::string cdtype_to_name(CustomData *cdata, CustomDataType type, int n);
private:
std::string m_name;
CustomDataMask m_cdmask;
Abc::OCompoundProperty m_props;
LayerPropsMap m_layer_props;
};
struct CustomDataReader {
typedef std::map<std::string, Abc::BasePropertyReaderPtr> LayerPropsMap;
typedef std::pair<std::string, Abc::BasePropertyReaderPtr> LayerPropsPair;
CustomDataReader(const std::string &name, CustomDataMask cdmask);
~CustomDataReader();
PTCReadSampleResult read_sample(const Abc::ISampleSelector &ss, CustomData *cdata, int num_data, Abc::ICompoundProperty &parent);
Abc::ICompoundProperty &props() { return m_props; }
template <typename PropertyT, typename ParentT>
PropertyT add_array_property(const std::string &name, ParentT &parent)
{
LayerPropsMap::iterator it = m_layer_props.find(name);
if (it == m_layer_props.end()) {
PropertyT prop = PropertyT(parent, name, 0);
m_layer_props.insert(LayerPropsPair(name, prop.getPtr()));
return prop;
}
else {
return PropertyT(it->second->asArrayPtr(), Abc::kWrapExisting);
}
}
template <typename PropertyT, typename ParentT>
PropertyT add_compound_property(const std::string &name, ParentT &parent)
{
LayerPropsMap::iterator it = m_layer_props.find(name);
if (it == m_layer_props.end()) {
PropertyT prop = PropertyT(parent, name, 0);
m_layer_props.insert(LayerPropsPair(name, prop.getPtr()));
return prop;
}
else {
return PropertyT(it->second->asCompoundPtr(), Abc::kWrapExisting);
}
}
void cdtype_from_name(CustomData *cdata, const std::string &name, int type, int *n, char *layer_name, int max_layer_name);
private:
std::string m_name;
CustomDataMask m_cdmask;
Abc::ICompoundProperty m_props;
LayerPropsMap m_layer_props;
};
} /* namespace PTC */
#endif /* PTC_CLOTH_H */

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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.
*/
#include "abc_frame_mapper.h"
extern "C" {
#include "DNA_scene_types.h"
}
namespace PTC {
#ifdef WITH_ALEMBIC
using namespace Abc;
using namespace AbcCoreAbstract;
FrameMapper::FrameMapper(double fps, double start_time)
{
m_frames_per_sec = fps;
m_sec_per_frame = (fps == 0.0 ? 0.0 : 1.0/fps);
m_start_frame = start_time * fps;
m_start_time = start_time;
}
FrameMapper::FrameMapper(Scene *scene)
{
m_frames_per_sec = (scene->r.frs_sec_base == 0.0f ? 0.0 : (double)scene->r.frs_sec / (double)scene->r.frs_sec_base);
m_sec_per_frame = (scene->r.frs_sec == 0.0f ? 0.0 : (double)scene->r.frs_sec_base / (double)scene->r.frs_sec);
m_start_frame = ((double)scene->r.sfra);
m_start_time = m_start_frame * m_sec_per_frame;
}
chrono_t FrameMapper::frame_to_time(float frame) const
{
return (double)frame * m_sec_per_frame;
}
float FrameMapper::time_to_frame(chrono_t time) const
{
return (float)(time * m_frames_per_sec);
}
#endif /* WITH_ALEMBIC */
} /* namespace PTC */

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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.
*/
#ifndef PTC_ABC_FRAME_MAPPER_H
#define PTC_ABC_FRAME_MAPPER_H
#ifdef WITH_ALEMBIC
#include <Alembic/AbcCoreAbstract/Foundation.h>
#include <Alembic/Abc/ISampleSelector.h>
#endif
struct Scene;
namespace PTC {
#ifdef WITH_ALEMBIC
using namespace Alembic;
using Alembic::AbcCoreAbstract::chrono_t;
class FrameMapper {
public:
FrameMapper(double fps, double start_time);
FrameMapper(Scene *scene);
double frames_per_second() const { return m_frames_per_sec; }
double seconds_per_frame() const { return m_sec_per_frame; }
double start_frame() const { return m_start_frame; }
double start_time() const { return m_start_time; }
chrono_t frame_to_time(float frame) const;
float time_to_frame(chrono_t time) const;
private:
double m_frames_per_sec, m_sec_per_frame;
double m_start_frame, m_start_time;
};
#endif /* WITH_ALEMBIC */
} /* namespace PTC */
#endif /* PTC_UTIL_FRAME_MAPPER_H */

View File

@@ -0,0 +1,424 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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.
*/
#include <map>
#include <sstream>
#include <string>
#include <Alembic/Abc/IObject.h>
#include <Alembic/Abc/OObject.h>
#include "abc_mesh.h"
#include "abc_group.h"
#include "abc_object.h"
extern "C" {
#include "BLI_math.h"
#include "DNA_group_types.h"
#include "DNA_object_types.h"
#include "BKE_anim.h"
#include "BKE_cache_library.h"
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_library.h"
}
namespace PTC {
using namespace Abc;
using namespace AbcGeom;
AbcGroupWriter::AbcGroupWriter(const std::string &name, Group *group) :
GroupWriter(group, name)
{
}
void AbcGroupWriter::init_abc()
{
if (m_abc_object)
return;
m_abc_object = abc_archive()->add_id_object<OObject>((ID *)m_group);
}
void AbcGroupWriter::create_refs()
{
GroupObject *gob = (GroupObject *)m_group->gobject.first;
int i = 0;
for (; gob; gob = gob->next, ++i) {
OObject abc_object = abc_archive()->get_id_object((ID *)gob->ob);
if (abc_object) {
std::stringstream ss;
ss << i;
m_abc_object.addChildInstance(abc_object, std::string("group_object")+ss.str());
}
}
}
void AbcGroupWriter::write_sample()
{
if (!m_abc_object)
return;
}
AbcGroupReader::AbcGroupReader(const std::string &name, Group *group) :
GroupReader(group, name)
{
}
void AbcGroupReader::init_abc()
{
if (m_abc_object)
return;
m_abc_object = abc_archive()->get_id_object((ID *)m_group);
}
PTCReadSampleResult AbcGroupReader::read_sample(float frame)
{
if (!m_abc_object)
return PTC_READ_SAMPLE_INVALID;
return PTC_READ_SAMPLE_EXACT;
}
/* ========================================================================= */
AbcDupligroupWriter::AbcDupligroupWriter(const std::string &name, EvaluationContext *eval_ctx, Scene *scene, Group *group, CacheLibrary *cachelib) :
GroupWriter(group, name),
m_eval_ctx(eval_ctx),
m_scene(scene),
m_cachelib(cachelib)
{
}
AbcDupligroupWriter::~AbcDupligroupWriter()
{
for (IDWriterMap::iterator it = m_id_writers.begin(); it != m_id_writers.end(); ++it) {
if (it->second)
delete it->second;
}
}
void AbcDupligroupWriter::init_abc()
{
if (m_abc_group)
return;
m_abc_group = abc_archive()->add_id_object<OObject>((ID *)m_group);
}
static bool do_cache_type(CacheLibrary *cachelib, Object *ob, int type, int index=-1)
{
CacheItem *item = BKE_cache_library_find_item(cachelib, ob, type, index);
return item && (item->flag & CACHE_ITEM_ENABLED);
}
void AbcDupligroupWriter::write_sample_object(Object *ob)
{
AbcWriter *ob_writer = find_id_writer((ID *)ob);
if (!ob_writer) {
bool do_mesh = do_cache_type(m_cachelib, ob, CACHE_TYPE_DERIVED_MESH);
// bool do_hair = do_cache_type(m_cachelib, ob, CACHE_TYPE_HAIR, ); // TODO
bool do_hair = false;
ob_writer = new AbcObjectWriter(ob->id.name, m_scene, ob, do_mesh, do_hair);
ob_writer->init(abc_archive());
m_id_writers.insert(IDWriterPair((ID *)ob, ob_writer));
}
ob_writer->write_sample();
}
void AbcDupligroupWriter::write_sample_dupli(DupliObject *dob, int index)
{
OObject abc_object = abc_archive()->get_id_object((ID *)dob->ob);
if (!abc_object)
return;
std::stringstream ss;
ss << "DupliObject" << index;
std::string name = ss.str();
OObject abc_dupli = m_abc_group.getChild(name);
OCompoundProperty props;
OM44fProperty prop_matrix;
if (!abc_dupli) {
abc_dupli = OObject(m_abc_group, name, 0);
m_object_writers.push_back(abc_dupli.getPtr());
props = abc_dupli.getProperties();
abc_dupli.addChildInstance(abc_object, "object");
prop_matrix = OM44fProperty(props, "matrix", 0);
m_property_writers.push_back(prop_matrix.getPtr());
}
else {
props = abc_dupli.getProperties();
prop_matrix = OM44fProperty(props.getProperty("matrix").getPtr()->asScalarPtr(), kWrapExisting);
}
prop_matrix.set(M44f(dob->mat));
}
void AbcDupligroupWriter::write_sample()
{
if (!m_abc_group)
return;
ListBase *duplilist = group_duplilist_ex(m_eval_ctx, m_scene, m_group, true);
DupliObject *dob;
int i;
/* LIB_DOIT is used to mark handled objects, clear first */
for (dob = (DupliObject *)duplilist->first; dob; dob = dob->next) {
if (dob->ob)
dob->ob->id.flag &= ~LIB_DOIT;
}
/* write actual object data: duplicator itself + all instanced objects */
for (dob = (DupliObject *)duplilist->first; dob; dob = dob->next) {
if (dob->ob->id.flag & LIB_DOIT)
continue;
dob->ob->id.flag |= LIB_DOIT;
write_sample_object(dob->ob);
}
/* write dupli instances */
for (dob = (DupliObject *)duplilist->first, i = 0; dob; dob = dob->next, ++i) {
write_sample_dupli(dob, i);
}
free_object_duplilist(duplilist);
}
AbcWriter *AbcDupligroupWriter::find_id_writer(ID *id) const
{
IDWriterMap::const_iterator it = m_id_writers.find(id);
if (it == m_id_writers.end())
return NULL;
else
return it->second;
}
/* ------------------------------------------------------------------------- */
AbcDupliCacheReader::AbcDupliCacheReader(const std::string &name, Group *group, DupliCache *dupli_cache) :
GroupReader(group, name),
dupli_cache(dupli_cache)
{
/* XXX this mapping allows fast lookup of existing objects in Blender data
* to associate with duplis. Later i may be possible to create instances of
* non-DNA data, but for the time being this is a requirement due to other code parts (drawing, rendering)
*/
build_object_map(G.main, group);
}
AbcDupliCacheReader::~AbcDupliCacheReader()
{
}
void AbcDupliCacheReader::init_abc()
{
}
void AbcDupliCacheReader::read_dupligroup_object(IObject object, float frame)
{
if (GS(object.getName().c_str()) == ID_OB) {
/* instances are handled later, we create true object data here */
if (object.isInstanceDescendant())
return;
Object *b_ob = find_object(object.getName());
if (!b_ob)
return;
AbcDerivedMeshReader dm_reader("mesh", b_ob);
dm_reader.init(abc_archive());
dm_reader.init_abc(object);
if (dm_reader.read_sample(frame) != PTC_READ_SAMPLE_INVALID) {
DerivedMesh *dm = dm_reader.acquire_result();
DupliObjectData *data = BKE_dupli_cache_add_mesh(dupli_cache, b_ob, dm);
insert_dupli_data(object.getPtr(), data);
}
else
dm_reader.discard_result();
}
}
void AbcDupliCacheReader::read_dupligroup_group(IObject abc_group, const ISampleSelector &ss)
{
if (GS(abc_group.getName().c_str()) == ID_GR) {
size_t num_child = abc_group.getNumChildren();
for (size_t i = 0; i < num_child; ++i) {
IObject abc_dupli = abc_group.getChild(i);
ICompoundProperty props = abc_dupli.getProperties();
IM44fProperty prop_matrix(props, "matrix", 0);
M44f abc_matrix = prop_matrix.getValue(ss);
float matrix[4][4];
memcpy(matrix, abc_matrix.getValue(), sizeof(float)*4*4);
IObject abc_dupli_object = abc_dupli.getChild("object");
if (abc_dupli_object.isInstanceRoot()) {
DupliObjectData *dupli_data = find_dupli_data(abc_dupli_object.getPtr());
if (dupli_data) {
BKE_dupli_cache_add_instance(dupli_cache, matrix, dupli_data);
}
}
}
}
}
PTCReadSampleResult AbcDupliCacheReader::read_sample(float frame)
{
ISampleSelector ss = abc_archive()->get_frame_sample_selector(frame);
IObject abc_top = abc_archive()->root();
IObject abc_group = abc_archive()->get_id_object((ID *)m_group);
if (!abc_group)
return PTC_READ_SAMPLE_INVALID;
/* first create shared object data */
for (size_t i = 0; i < abc_top.getNumChildren(); ++i) {
read_dupligroup_object(abc_top.getChild(i), frame);
}
/* now generate dupli instances for the group */
read_dupligroup_group(abc_group, ss);
return PTC_READ_SAMPLE_EXACT;
}
DupliObjectData *AbcDupliCacheReader::find_dupli_data(ObjectReaderPtr ptr) const
{
DupliMap::const_iterator it = dupli_map.find(ptr);
if (it == dupli_map.end())
return NULL;
else
return it->second;
}
void AbcDupliCacheReader::insert_dupli_data(ObjectReaderPtr ptr, DupliObjectData *data)
{
dupli_map.insert(DupliPair(ptr, data));
}
void AbcDupliCacheReader::build_object_map(Main *bmain, Group *group)
{
BKE_main_id_tag_idcode(bmain, ID_OB, false);
BKE_main_id_tag_idcode(bmain, ID_GR, false);
object_map.clear();
build_object_map_add_group(group);
}
Object *AbcDupliCacheReader::find_object(const std::string &name) const
{
ObjectMap::const_iterator it = object_map.find(name);
if (it == object_map.end())
return NULL;
else
return it->second;
}
void AbcDupliCacheReader::build_object_map_add_group(Group *group)
{
if (group->id.flag & LIB_DOIT)
return;
group->id.flag |= LIB_DOIT;
for (GroupObject *gob = (GroupObject *)group->gobject.first; gob; gob = gob->next) {
Object *ob = gob->ob;
if (ob->id.flag & LIB_DOIT)
continue;
ob->id.flag |= LIB_DOIT;
object_map.insert(ObjectPair(ob->id.name, ob));
if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
build_object_map_add_group(ob->dup_group);
}
}
}
/* ------------------------------------------------------------------------- */
AbcDupliObjectReader::AbcDupliObjectReader(const std::string &name, Object *ob, DupliObjectData *dupli_data) :
ObjectReader(ob, name),
dupli_data(dupli_data)
{
}
AbcDupliObjectReader::~AbcDupliObjectReader()
{
}
void AbcDupliObjectReader::init_abc()
{
}
void AbcDupliObjectReader::read_dupligroup_object(IObject object, float frame)
{
if (GS(object.getName().c_str()) == ID_OB) {
/* instances are handled later, we create true object data here */
if (object.isInstanceDescendant())
return;
AbcDerivedMeshReader dm_reader("mesh", m_ob);
dm_reader.init(abc_archive());
dm_reader.init_abc(object);
if (dm_reader.read_sample(frame) != PTC_READ_SAMPLE_INVALID) {
DerivedMesh *dm = dm_reader.acquire_result();
BKE_dupli_object_data_init(dupli_data, m_ob, dm);
}
else
dm_reader.discard_result();
}
}
PTCReadSampleResult AbcDupliObjectReader::read_sample(float frame)
{
IObject abc_object = abc_archive()->get_id_object((ID *)m_ob);
if (!abc_object)
return PTC_READ_SAMPLE_INVALID;
read_dupligroup_object(abc_object, frame);
return PTC_READ_SAMPLE_EXACT;
}
DupliObjectData *AbcDupliObjectReader::find_dupli_data(ObjectReaderPtr ptr) const
{
DupliMap::const_iterator it = dupli_map.find(ptr);
if (it == dupli_map.end())
return NULL;
else
return it->second;
}
void AbcDupliObjectReader::insert_dupli_data(ObjectReaderPtr ptr, DupliObjectData *data)
{
dupli_map.insert(DupliPair(ptr, data));
}
} /* namespace PTC */

View File

@@ -0,0 +1,155 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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.
*/
#ifndef PTC_ABC_GROUP_H
#define PTC_ABC_GROUP_H
#include "ptc_types.h"
#include "abc_reader.h"
#include "abc_schema.h"
#include "abc_writer.h"
struct CacheLibrary;
struct DupliCache;
struct DupliObject;
struct DupliObjectData;
struct Group;
struct Object;
struct Scene;
namespace PTC {
class AbcGroupWriter : public GroupWriter, public AbcWriter {
public:
AbcGroupWriter(const std::string &name, Group *group);
void init_abc();
void create_refs();
void write_sample();
private:
Abc::OObject m_abc_object;
};
class AbcGroupReader : public GroupReader, public AbcReader {
public:
AbcGroupReader(const std::string &name, Group *group);
void init_abc();
PTCReadSampleResult read_sample(float frame);
private:
Abc::IObject m_abc_object;
};
/* ========================================================================= */
class AbcDupligroupWriter : public GroupWriter, public AbcWriter {
public:
typedef std::vector<Abc::ObjectWriterPtr> ObjectWriterList;
typedef std::vector<Abc::BasePropertyWriterPtr> PropertyWriterList;
typedef std::map<ID*, AbcWriter*> IDWriterMap;
typedef std::pair<ID*, AbcWriter*> IDWriterPair;
AbcDupligroupWriter(const std::string &name, EvaluationContext *eval_ctx, Scene *scene, Group *group, CacheLibrary *cachelib);
~AbcDupligroupWriter();
void init_abc();
void write_sample();
void write_sample_object(Object *ob);
void write_sample_dupli(DupliObject *dob, int index);
AbcWriter *find_id_writer(ID *id) const;
private:
EvaluationContext *m_eval_ctx;
Scene *m_scene;
CacheLibrary *m_cachelib;
Abc::OObject m_abc_group;
ObjectWriterList m_object_writers;
PropertyWriterList m_property_writers;
IDWriterMap m_id_writers;
};
class AbcDupliCacheReader : public GroupReader, public AbcReader {
public:
typedef std::map<Abc::ObjectReaderPtr, DupliObjectData*> DupliMap;
typedef std::pair<Abc::ObjectReaderPtr, DupliObjectData*> DupliPair;
typedef std::map<std::string, Object*> ObjectMap;
typedef std::pair<std::string, Object*> ObjectPair;
public:
AbcDupliCacheReader(const std::string &name, Group *group, DupliCache *dupcache);
~AbcDupliCacheReader();
void init_abc();
PTCReadSampleResult read_sample(float frame);
protected:
void read_dupligroup_object(Abc::IObject object, float frame);
void read_dupligroup_group(Abc::IObject abc_group, const Abc::ISampleSelector &ss);
DupliObjectData *find_dupli_data(Abc::ObjectReaderPtr ptr) const;
void insert_dupli_data(Abc::ObjectReaderPtr ptr, DupliObjectData *data);
void build_object_map(Main *bmain, Group *group);
void build_object_map_add_group(Group *group);
Object *find_object(const std::string &name) const;
private:
DupliMap dupli_map;
DupliCache *dupli_cache;
ObjectMap object_map;
};
class AbcDupliObjectReader : public ObjectReader, public AbcReader {
public:
typedef std::map<Abc::ObjectReaderPtr, DupliObjectData*> DupliMap;
typedef std::pair<Abc::ObjectReaderPtr, DupliObjectData*> DupliPair;
public:
AbcDupliObjectReader(const std::string &name, Object *ob, DupliObjectData *dupli_data);
~AbcDupliObjectReader();
void init_abc();
PTCReadSampleResult read_sample(float frame);
protected:
void read_dupligroup_object(Abc::IObject object, float frame);
DupliObjectData *find_dupli_data(Abc::ObjectReaderPtr ptr) const;
void insert_dupli_data(Abc::ObjectReaderPtr ptr, DupliObjectData *data);
private:
DupliMap dupli_map;
DupliObjectData *dupli_data;
};
} /* namespace PTC */
#endif /* PTC_OBJECT_H */

View File

@@ -0,0 +1,259 @@
//-*****************************************************************************
//
// Copyright (c) 2009-2013,
// Sony Pictures Imageworks, Inc. and
// Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Sony Pictures Imageworks, nor
// Industrial Light & Magic nor the names of their contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//-*****************************************************************************
/*
* Copyright 2015, Blender Foundation.
*
* 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.
*/
#include <Alembic/AbcGeom/All.h>
#include <Alembic/AbcCoreAbstract/All.h>
#include <Alembic/AbcCoreFactory/All.h>
#include <Alembic/Util/All.h>
#include <Alembic/Abc/TypedPropertyTraits.h>
#include <sstream>
#include "alembic.h"
extern "C" {
#include "BLI_utildefines.h"
}
using namespace ::Alembic::AbcGeom;
namespace PTC {
static const std::string g_sep(";");
static void visitProperties(std::stringstream &ss, ICompoundProperty, std::string &);
template <class PROP>
static void visitSimpleArrayProperty(std::stringstream &ss, PROP iProp, const std::string &iIndent)
{
std::string ptype = "ArrayProperty ";
size_t asize = 0;
AbcA::ArraySamplePtr samp;
index_t maxSamples = iProp.getNumSamples();
for (index_t i = 0 ; i < maxSamples; ++i) {
iProp.get(samp, ISampleSelector( i ));
asize = samp->size();
};
std::string mdstring = "interpretation=";
mdstring += iProp.getMetaData().get("interpretation");
std::stringstream dtype;
dtype << "datatype=";
dtype << iProp.getDataType();
std::stringstream asizestr;
asizestr << ";arraysize=";
asizestr << asize;
mdstring += g_sep;
mdstring += dtype.str();
mdstring += asizestr.str();
ss << iIndent << " " << ptype << "name=" << iProp.getName()
<< g_sep << mdstring << g_sep << "numsamps="
<< iProp.getNumSamples() << std::endl;
}
template <class PROP>
static void visitSimpleScalarProperty(std::stringstream &ss, PROP iProp, const std::string &iIndent)
{
std::string ptype = "ScalarProperty ";
size_t asize = 0;
const AbcA::DataType &dt = iProp.getDataType();
const Alembic::Util ::uint8_t extent = dt.getExtent();
Alembic::Util::Dimensions dims(extent);
AbcA::ArraySamplePtr samp = AbcA::AllocateArraySample( dt, dims );
index_t maxSamples = iProp.getNumSamples();
for (index_t i = 0 ; i < maxSamples; ++i) {
iProp.get(const_cast<void*>(samp->getData()), ISampleSelector( i ));
asize = samp->size();
};
std::string mdstring = "interpretation=";
mdstring += iProp.getMetaData().get("interpretation");
std::stringstream dtype;
dtype << "datatype=";
dtype << dt;
std::stringstream asizestr;
asizestr << ";arraysize=";
asizestr << asize;
mdstring += g_sep;
mdstring += dtype.str();
mdstring += asizestr.str();
ss << iIndent << " " << ptype << "name=" << iProp.getName()
<< g_sep << mdstring << g_sep << "numsamps="
<< iProp.getNumSamples() << std::endl;
}
static void visitCompoundProperty(std::stringstream &ss, ICompoundProperty iProp, std::string &ioIndent)
{
std::string oldIndent = ioIndent;
ioIndent += " ";
std::string interp = "schema=";
interp += iProp.getMetaData().get("schema");
ss << ioIndent << "CompoundProperty " << "name=" << iProp.getName()
<< g_sep << interp << std::endl;
visitProperties(ss, iProp, ioIndent);
ioIndent = oldIndent;
}
static void visitProperties(std::stringstream &ss, ICompoundProperty iParent, std::string &ioIndent )
{
std::string oldIndent = ioIndent;
for (size_t i = 0 ; i < iParent.getNumProperties() ; i++) {
PropertyHeader header = iParent.getPropertyHeader(i);
if (header.isCompound()) {
visitCompoundProperty(ss, ICompoundProperty(iParent, header.getName()), ioIndent);
}
else if (header.isScalar()) {
visitSimpleScalarProperty(ss, IScalarProperty(iParent, header.getName()), ioIndent);
}
else {
BLI_assert(header.isArray());
visitSimpleArrayProperty(ss, IArrayProperty(iParent, header.getName()), ioIndent);
}
}
ioIndent = oldIndent;
}
static void visitObject(std::stringstream &ss, IObject iObj, std::string iIndent)
{
// Object has a name, a full name, some meta data,
// and then it has a compound property full of properties.
std::string path = iObj.getFullName();
if (iObj.isInstanceRoot()) {
if (path != "/") {
ss << "Object " << "name=" << path
<< " [Instance " << iObj.instanceSourcePath() << "]"
<< std::endl;
}
}
else if (iObj.isInstanceDescendant()) {
/* skip non-root instances to avoid repetition */
return;
}
else {
if (path != "/") {
ss << "Object " << "name=" << path << std::endl;
}
// Get the properties.
ICompoundProperty props = iObj.getProperties();
visitProperties(ss, props, iIndent);
// now the child objects
for (size_t i = 0 ; i < iObj.getNumChildren() ; i++) {
visitObject(ss, IObject(iObj, iObj.getChildHeader(i).getName()), iIndent);
}
}
}
std::string abc_archive_info(IArchive &archive)
{
std::stringstream ss;
ss << "Alembic Archive Info for "
<< Alembic::AbcCoreAbstract::GetLibraryVersion()
<< std::endl;;
std::string appName;
std::string libraryVersionString;
Alembic::Util::uint32_t libraryVersion;
std::string whenWritten;
std::string userDescription;
GetArchiveInfo(archive,
appName,
libraryVersionString,
libraryVersion,
whenWritten,
userDescription);
if (appName != "") {
ss << " file written by: " << appName << std::endl;
ss << " using Alembic : " << libraryVersionString << std::endl;
ss << " written on : " << whenWritten << std::endl;
ss << " user description : " << userDescription << std::endl;
ss << std::endl;
}
else {
// ss << argv[1] << std::endl;
ss << " (file doesn't have any ArchiveInfo)"
<< std::endl;
ss << std::endl;
}
visitObject(ss, archive.getTop(), "");
return ss.str();
}
} /* namespace PTC */

View File

@@ -0,0 +1,638 @@
/*
* Copyright 2014, Blender Foundation.
*
* 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.
*/
#include "abc_mesh.h"
extern "C" {
#include "BLI_math.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_mesh.h"
#include "PIL_time.h"
}
#include "PTC_api.h"
//#define USE_TIMING
namespace PTC {
using namespace Abc;
using namespace AbcGeom;
/* CD layers that are stored in generic customdata arrays created with CD_ALLOC */
static CustomDataMask CD_MASK_CACHE = ~(CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MPOLY | CD_MASK_MLOOP | CD_MASK_BMESH | CD_MASK_MTFACE);
struct MVertSample {
std::vector<V3f> co;
std::vector<N3f> no;
std::vector<int8_t> flag;
std::vector<int8_t> bweight;
};
struct MEdgeSample {
std::vector<uint32_t> verts;
std::vector<int16_t> flag;
std::vector<int8_t> crease;
std::vector<int8_t> bweight;
};
struct MPolySample {
/*std::vector<int32_t> loopstart;*/ /* loopstart is not stored explicitly */
std::vector<int32_t> totloop;
std::vector<int16_t> mat_nr;
std::vector<int8_t> flag;
};
struct MLoopSample {
/* XXX these are unsigned int in DNA, but Alembic expects signed int */
std::vector<int32_t> verts;
std::vector<int32_t> edges;
};
AbcDerivedMeshWriter::AbcDerivedMeshWriter(const std::string &name, Object *ob, DerivedMesh **dm_ptr) :
DerivedMeshWriter(ob, dm_ptr, name),
m_vert_data_writer("vertex_data", CD_MASK_CACHE),
m_edge_data_writer("edge_data", CD_MASK_CACHE),
m_face_data_writer("face_data", CD_MASK_CACHE),
m_poly_data_writer("poly_data", CD_MASK_CACHE),
m_loop_data_writer("loop_data", CD_MASK_CACHE)
{
}
AbcDerivedMeshWriter::~AbcDerivedMeshWriter()
{
}
void AbcDerivedMeshWriter::init_abc(OObject parent)
{
if (m_mesh)
return;
m_mesh = OPolyMesh(parent, m_name, abc_archive()->frame_sampling_index());
OPolyMeshSchema &schema = m_mesh.getSchema();
// OCompoundProperty geom_props = schema.getArbGeomParams();
OCompoundProperty user_props = schema.getUserProperties();
m_prop_vert_normals = ON3fArrayProperty(user_props, "vertex_normals", 0);
m_prop_vert_flag = OCharArrayProperty(user_props, "vertex_flag", 0);
m_prop_vert_bweight = OCharArrayProperty(user_props, "vertex_bweight", 0);
m_prop_edge_verts = OUInt32ArrayProperty(user_props, "edge_verts", 0);
m_prop_edge_flag = OInt16ArrayProperty(user_props, "edge_flag", 0);
m_prop_edge_crease = OCharArrayProperty(user_props, "edge_crease", 0);
m_prop_edge_bweight = OCharArrayProperty(user_props, "edge_bweight", 0);
m_prop_poly_mat_nr = OInt16ArrayProperty(user_props, "poly_mat_nr", 0);
m_prop_poly_flag = OCharArrayProperty(user_props, "poly_flag", 0);
m_prop_loop_verts = OInt32ArrayProperty(user_props, "loop_verts", 0);
m_prop_loop_edges = OInt32ArrayProperty(user_props, "loop_edges", 0);
}
/* XXX modifiers are not allowed to generate poly normals on their own!
* see assert in DerivedMesh.c : dm_ensure_display_normals
*/
#if 0
static void ensure_normal_data(DerivedMesh *dm)
{
MVert *mverts = dm->getVertArray(dm);
MLoop *mloops = dm->getLoopArray(dm);
MPoly *mpolys = dm->getPolyArray(dm);
CustomData *cdata = dm->getPolyDataLayout(dm);
float (*polynors)[3];
int totvert = dm->getNumVerts(dm);
int totloop = dm->getNumLoops(dm);
int totpoly = dm->getNumPolys(dm);
if (CustomData_has_layer(cdata, CD_NORMAL))
polynors = (float (*)[3])CustomData_get_layer(cdata, CD_NORMAL);
else
polynors = (float (*)[3])CustomData_add_layer(cdata, CD_NORMAL, CD_CALLOC, NULL, totpoly);
BKE_mesh_calc_normals_poly(mverts, totvert, mloops, mpolys, totloop, totpoly, polynors, false);
}
#endif
static void create_sample_verts(DerivedMesh *dm, MVertSample &sample)
{
MVert *mv, *mverts = dm->getVertArray(dm);
int i, totvert = dm->getNumVerts(dm);
sample.co.reserve(totvert);
sample.no.reserve(totvert);
sample.flag.reserve(totvert);
sample.bweight.reserve(totvert);
for (i = 0, mv = mverts; i < totvert; ++i, ++mv) {
float nor[3];
sample.co.push_back(V3f(mv->co[0], mv->co[1], mv->co[2]));
normal_short_to_float_v3(nor, mv->no);
sample.no.push_back(N3f(nor[0], nor[1], nor[2]));
sample.flag.push_back(mv->flag);
sample.bweight.push_back(mv->bweight);
}
}
static void create_sample_edges(DerivedMesh *dm, MEdgeSample &sample)
{
MEdge *me, *medges = dm->getEdgeArray(dm);
int i, totedge = dm->getNumEdges(dm);
sample.verts.reserve(totedge * 2);
sample.flag.reserve(totedge);
sample.crease.reserve(totedge);
sample.bweight.reserve(totedge);
for (i = 0, me = medges; i < totedge; ++i, ++me) {
sample.verts.push_back(me->v1);
sample.verts.push_back(me->v2);
sample.flag.push_back(me->flag);
sample.crease.push_back(me->crease);
sample.bweight.push_back(me->bweight);
}
}
static void create_sample_polys(DerivedMesh *dm, MPolySample &sample)
{
MPoly *mp, *mpolys = dm->getPolyArray(dm);
int i, totpoly = dm->getNumPolys(dm);
sample.totloop.reserve(totpoly);
sample.mat_nr.reserve(totpoly);
sample.flag.reserve(totpoly);
for (i = 0, mp = mpolys; i < totpoly; ++i, ++mp) {
sample.totloop.push_back(mp->totloop);
sample.mat_nr.push_back(mp->mat_nr);
sample.flag.push_back(mp->flag);
}
}
static void create_sample_loops(DerivedMesh *dm, MLoopSample &sample)
{
MLoop *ml, *mloops = dm->getLoopArray(dm);
int i, totloop = dm->getNumLoops(dm);
sample.verts.reserve(totloop);
sample.edges.reserve(totloop);
for (i = 0, ml = mloops; i < totloop; ++i, ++ml) {
sample.verts.push_back(ml->v);
sample.edges.push_back(ml->e);
}
}
static N3fArraySample create_sample_loop_normals(DerivedMesh *dm, std::vector<N3f> &data)
{
CustomData *cdata = dm->getLoopDataLayout(dm);
float (*nor)[3], (*loopnors)[3];
int i, totloop = dm->getNumLoops(dm);
if (!CustomData_has_layer(cdata, CD_NORMAL))
return N3fArraySample();
loopnors = (float (*)[3])CustomData_get_layer(cdata, CD_NORMAL);
data.reserve(totloop);
for (i = 0, nor = loopnors; i < totloop; ++i, ++nor) {
float *vec = *nor;
data.push_back(N3f(vec[0], vec[1], vec[2]));
}
return N3fArraySample(data);
}
void AbcDerivedMeshWriter::write_sample()
{
if (!m_mesh)
return;
DerivedMesh *output_dm = *m_dm_ptr;
if (!output_dm)
return;
/* TODO make this optional by a flag? */
/* XXX does not work atm, see comment above */
/*ensure_normal_data(output_dm);*/
OPolyMeshSchema &schema = m_mesh.getSchema();
OCompoundProperty user_props = schema.getUserProperties();
MVertSample vert_sample;
MEdgeSample edge_sample;
MPolySample poly_sample;
MLoopSample loop_sample;
std::vector<N3f> loop_normals_buffer;
// TODO decide how to handle vertex/face normals, in caching vs. export ...
create_sample_verts(output_dm, vert_sample);
create_sample_edges(output_dm, edge_sample);
create_sample_polys(output_dm, poly_sample);
create_sample_loops(output_dm, loop_sample);
N3fArraySample lnormals = create_sample_loop_normals(output_dm, loop_normals_buffer);
OPolyMeshSchema::Sample sample = OPolyMeshSchema::Sample(
P3fArraySample(vert_sample.co),
Int32ArraySample(loop_sample.verts),
Int32ArraySample(poly_sample.totloop),
OV2fGeomParam::Sample(), /* XXX define how/which UV map should be considered primary for the alembic schema */
ON3fGeomParam::Sample(lnormals, kFacevaryingScope)
);
schema.set(sample);
m_prop_vert_normals.set(N3fArraySample(vert_sample.no));
m_prop_vert_flag.set(CharArraySample(vert_sample.flag));
m_prop_vert_bweight.set(CharArraySample(vert_sample.bweight));
m_prop_edge_verts.set(UInt32ArraySample(edge_sample.verts));
m_prop_edge_flag.set(Int16ArraySample(edge_sample.flag));
m_prop_edge_crease.set(CharArraySample(edge_sample.crease));
m_prop_edge_bweight.set(CharArraySample(edge_sample.bweight));
m_prop_poly_mat_nr.set(Int16ArraySample(poly_sample.mat_nr));
m_prop_poly_flag.set(CharArraySample(poly_sample.flag));
m_prop_loop_verts.set(Int32ArraySample(loop_sample.verts));
m_prop_loop_edges.set(Int32ArraySample(loop_sample.edges));
CustomData *vdata = output_dm->getVertDataLayout(output_dm);
int num_vdata = output_dm->getNumVerts(output_dm);
m_vert_data_writer.write_sample(vdata, num_vdata, user_props);
CustomData *edata = output_dm->getEdgeDataLayout(output_dm);
int num_edata = output_dm->getNumEdges(output_dm);
m_edge_data_writer.write_sample(edata, num_edata, user_props);
DM_ensure_tessface(output_dm);
CustomData *fdata = output_dm->getTessFaceDataLayout(output_dm);
int num_fdata = output_dm->getNumTessFaces(output_dm);
m_face_data_writer.write_sample(fdata, num_fdata, user_props);
CustomData *pdata = output_dm->getPolyDataLayout(output_dm);
int num_pdata = output_dm->getNumPolys(output_dm);
m_poly_data_writer.write_sample(pdata, num_pdata, user_props);
CustomData *ldata = output_dm->getLoopDataLayout(output_dm);
int num_ldata = output_dm->getNumLoops(output_dm);
m_loop_data_writer.write_sample(ldata, num_ldata, user_props);
}
/* ========================================================================= */
AbcDerivedMeshReader::AbcDerivedMeshReader(const std::string &name, Object *ob) :
DerivedMeshReader(ob, name),
m_vert_data_reader("vertex_data", CD_MASK_CACHE),
m_edge_data_reader("edge_data", CD_MASK_CACHE),
m_face_data_reader("face_data", CD_MASK_CACHE),
m_poly_data_reader("poly_data", CD_MASK_CACHE),
m_loop_data_reader("loop_data", CD_MASK_CACHE)
{
}
AbcDerivedMeshReader::~AbcDerivedMeshReader()
{
}
void AbcDerivedMeshReader::init_abc(IObject parent)
{
if (m_mesh)
return;
if (parent.getChild(m_name)) {
m_mesh = IPolyMesh(parent, m_name);
IPolyMeshSchema &schema = m_mesh.getSchema();
ICompoundProperty geom_props = schema.getArbGeomParams();
ICompoundProperty user_props = schema.getUserProperties();
m_prop_vert_normals = IN3fArrayProperty(user_props, "vertex_normals", 0);
m_prop_vert_flag = ICharArrayProperty(user_props, "vertex_flag", 0);
m_prop_vert_bweight = ICharArrayProperty(user_props, "vertex_bweight", 0);
m_prop_edge_verts = IUInt32ArrayProperty(user_props, "edge_verts", 0);
m_prop_edge_flag = IInt16ArrayProperty(user_props, "edge_flag", 0);
m_prop_edge_crease = ICharArrayProperty(user_props, "edge_crease", 0);
m_prop_edge_bweight = ICharArrayProperty(user_props, "edge_bweight", 0);
m_prop_poly_mat_nr = IInt16ArrayProperty(user_props, "poly_mat_nr", 0);
m_prop_poly_flag = ICharArrayProperty(user_props, "poly_flag", 0);
m_prop_loop_verts = IInt32ArrayProperty(user_props, "loop_verts", 0);
m_prop_loop_edges = IInt32ArrayProperty(user_props, "loop_edges", 0);
}
}
static PTCReadSampleResult apply_sample_verts(DerivedMesh *dm, P3fArraySamplePtr sample_co, N3fArraySamplePtr sample_no,
CharArraySamplePtr sample_flag, CharArraySamplePtr sample_bweight)
{
int totvert = dm->getNumVerts(dm);
if (sample_co->size() != totvert ||
sample_no->size() != totvert ||
sample_flag->size() != totvert ||
sample_bweight->size() != totvert)
return PTC_READ_SAMPLE_INVALID;
MVert *mv = dm->getVertArray(dm);
for (int i = 0; i < totvert; ++i) {
copy_v3_v3(mv->co, (*sample_co)[i].getValue());
normal_float_to_short_v3(mv->no, (*sample_no)[i].getValue());
mv->flag = (*sample_flag)[i];
mv->bweight = (*sample_bweight)[i];
++mv;
}
return PTC_READ_SAMPLE_EXACT;
}
static PTCReadSampleResult apply_sample_edges(DerivedMesh *dm, UInt32ArraySamplePtr sample_verts, Int16ArraySamplePtr sample_flag,
CharArraySamplePtr sample_crease, CharArraySamplePtr sample_bweight, bool &has_edges)
{
int totedge = dm->getNumEdges(dm);
if (sample_verts->size() != totedge * 2 ||
sample_flag->size() != totedge ||
sample_crease->size() != totedge ||
sample_bweight->size() != totedge)
{
has_edges = false;
return PTC_READ_SAMPLE_INVALID;
}
const uint32_t *data_verts = sample_verts->get();
const int16_t *data_flag = sample_flag->get();
const int8_t *data_crease = sample_crease->get();
const int8_t *data_bweight = sample_bweight->get();
MEdge *me = dm->getEdgeArray(dm);
for (int i = 0; i < totedge; ++i) {
me->v1 = data_verts[0];
me->v2 = data_verts[1];
me->flag = *data_flag;
me->crease = *data_crease;
me->bweight = *data_bweight;
++me;
data_verts += 2;
++data_flag;
++data_crease;
++data_bweight;
}
return PTC_READ_SAMPLE_EXACT;
}
static PTCReadSampleResult apply_sample_polys(DerivedMesh *dm, Int32ArraySamplePtr sample_totloop, Int16ArraySamplePtr sample_mat_nr, CharArraySamplePtr sample_flag)
{
int totpoly = dm->getNumPolys(dm);
if (sample_totloop->size() != totpoly ||
sample_mat_nr->size() != totpoly ||
sample_flag->size() != totpoly)
return PTC_READ_SAMPLE_INVALID;
const int32_t *data_totloop = sample_totloop->get();
const int16_t *data_mat_nr = sample_mat_nr->get();
const int8_t *data_flag = sample_flag->get();
int loopstart = 0;
MPoly *mp = dm->getPolyArray(dm);
for (int i = 0; i < totpoly; ++i) {
mp->totloop = *data_totloop;
mp->loopstart = loopstart;
mp->mat_nr = *data_mat_nr;
mp->flag = *data_flag;
loopstart += mp->totloop;
++mp;
++data_totloop;
++data_mat_nr;
++data_flag;
}
return PTC_READ_SAMPLE_EXACT;
}
static PTCReadSampleResult apply_sample_loops(DerivedMesh *dm, Int32ArraySamplePtr sample_verts, Int32ArraySamplePtr sample_edges, bool &has_edges)
{
int totloop = dm->getNumLoops(dm);
if (sample_verts->size() != totloop)
return PTC_READ_SAMPLE_INVALID;
const int32_t *data_verts = sample_verts->get();
MLoop *ml = dm->getLoopArray(dm);
for (int i = 0; i < totloop; ++i) {
ml->v = *data_verts;
++ml;
++data_verts;
}
/* edge data is optional, if not available the edges must be recalculated */
if (sample_edges->size() == totloop) {
const int32_t *data_edges = sample_edges->get();
MLoop *ml = dm->getLoopArray(dm);
for (int i = 0; i < totloop; ++i) {
ml->e = *data_edges;
++ml;
++data_edges;
}
}
else {
has_edges = false;
}
return PTC_READ_SAMPLE_EXACT;
}
PTCReadSampleResult AbcDerivedMeshReader::read_sample(float frame)
{
#ifdef USE_TIMING
double start_time;
double time_get_sample, time_build_mesh, time_calc_edges, time_calc_normals;
#define PROFILE_START \
start_time = PIL_check_seconds_timer();
#define PROFILE_END(var) \
var = PIL_check_seconds_timer() - start_time;
#else
#define PROFILE_START ;
#define PROFILE_END(var) ;
#endif
/* discard existing result data */
discard_result();
if (!m_mesh)
return PTC_READ_SAMPLE_INVALID;
IPolyMeshSchema &schema = m_mesh.getSchema();
if (!schema.valid() || schema.getPositionsProperty().getNumSamples() == 0)
return PTC_READ_SAMPLE_INVALID;
ICompoundProperty user_props = schema.getUserProperties();
ISampleSelector ss = abc_archive()->get_frame_sample_selector(frame);
PROFILE_START;
IPolyMeshSchema::Sample sample;
schema.get(sample, ss);
P3fArraySamplePtr vert_co = sample.getPositions();
Int32ArraySamplePtr loop_verts = sample.getFaceIndices();
Int32ArraySamplePtr poly_totloop = sample.getFaceCounts();
N3fArraySamplePtr vnormals;
bool has_normals = false;
if (m_prop_vert_normals && m_prop_vert_normals.getNumSamples() > 0) {
vnormals = m_prop_vert_normals.getValue(ss);
has_normals = vnormals->valid();
}
UInt32ArraySamplePtr edge_verts = m_prop_edge_verts.getValue(ss);
Int32ArraySamplePtr loop_edges = m_prop_loop_edges.getValue(ss);
PROFILE_END(time_get_sample);
PROFILE_START;
bool has_edges = true; // XXX do we have to check for existing sample in advance?
int totverts = vert_co->size();
int totloops = loop_verts->size();
int totpolys = poly_totloop->size();
int totedges = has_edges ? edge_verts->size() >> 1 : 0;
m_result = CDDM_new(totverts, totedges, 0, totloops, totpolys);
apply_sample_verts(m_result, vert_co, vnormals, m_prop_vert_flag.getValue(ss), m_prop_vert_bweight.getValue(ss));
apply_sample_edges(m_result, edge_verts, m_prop_edge_flag.getValue(ss), m_prop_edge_crease.getValue(ss), m_prop_edge_bweight.getValue(ss), has_edges);
apply_sample_polys(m_result, poly_totloop, m_prop_poly_mat_nr.getValue(ss), m_prop_poly_flag.getValue(ss));
apply_sample_loops(m_result, loop_verts, loop_edges, has_edges);
PROFILE_END(time_build_mesh);
CustomData *vdata = m_result->getVertDataLayout(m_result);
int num_vdata = totverts;
m_vert_data_reader.read_sample(ss, vdata, num_vdata, user_props);
CustomData *edata = m_result->getEdgeDataLayout(m_result);
int num_edata = totedges;
m_edge_data_reader.read_sample(ss, edata, num_edata, user_props);
DM_ensure_tessface(m_result);
CustomData *fdata = m_result->getTessFaceDataLayout(m_result);
int num_fdata = m_result->getNumTessFaces(m_result);
m_face_data_reader.read_sample(ss, fdata, num_fdata, user_props);
CustomData *pdata = m_result->getPolyDataLayout(m_result);
int num_pdata = totpolys;
m_poly_data_reader.read_sample(ss, pdata, num_pdata, user_props);
CustomData *ldata = m_result->getLoopDataLayout(m_result);
int num_ldata = totloops;
m_loop_data_reader.read_sample(ss, ldata, num_ldata, user_props);
PROFILE_START;
if (!has_edges)
CDDM_calc_edges(m_result);
PROFILE_END(time_calc_edges);
PROFILE_START;
/* we need all normal properties defined, otherwise have to recalculate */
has_normals &= CustomData_has_layer(pdata, CD_NORMAL);
if (!has_normals) {
/* make sure normals are recalculated if there is no sample data */
m_result->dirty = (DMDirtyFlag)((int)m_result->dirty | DM_DIRTY_NORMALS);
}
DM_ensure_normals(m_result); /* only recalculates normals if no valid samples were found (has_normals == false) */
PROFILE_END(time_calc_normals);
// BLI_assert(DM_is_valid(m_result));
#ifdef USE_TIMING
printf("-------- Point Cache Timing --------\n");
printf("read sample: %f seconds\n", time_get_sample);
printf("build mesh: %f seconds\n", time_build_mesh);
printf("calculate edges: %f seconds\n", time_calc_edges);
printf("calculate normals: %f seconds\n", time_calc_normals);
printf("------------------------------------\n");
#endif
return PTC_READ_SAMPLE_EXACT;
}
/* ========================================================================= */
AbcDerivedFinalRealtimeWriter::AbcDerivedFinalRealtimeWriter(const std::string &name, Object *ob) :
AbcDerivedMeshWriter(name, ob, &ob->derivedFinal)
{
}
AbcCacheModifierRealtimeWriter::AbcCacheModifierRealtimeWriter(const std::string &name, Object *ob, CacheModifierData *cmd) :
AbcDerivedMeshWriter(name, ob, &cmd->output_dm),
m_cmd(cmd)
{
m_cmd->flag |= MOD_CACHE_USE_OUTPUT_REALTIME;
}
AbcCacheModifierRealtimeWriter::~AbcCacheModifierRealtimeWriter()
{
m_cmd->flag &= ~MOD_CACHE_USE_OUTPUT_REALTIME;
if (m_cmd->output_dm) {
m_cmd->output_dm->release(m_cmd->output_dm);
m_cmd->output_dm = NULL;
}
}
AbcDerivedFinalRenderWriter::AbcDerivedFinalRenderWriter(const std::string &name, Scene *scene, Object *ob, DerivedMesh **render_dm_ptr) :
AbcDerivedMeshWriter(name, ob, render_dm_ptr),
m_scene(scene)
{
}
AbcCacheModifierRenderWriter::AbcCacheModifierRenderWriter(const std::string &name, Scene *scene, Object *ob, CacheModifierData *cmd) :
AbcDerivedMeshWriter(name, ob, &cmd->output_dm),
m_scene(scene),
m_cmd(cmd)
{
}
AbcCacheModifierRenderWriter::~AbcCacheModifierRenderWriter()
{
m_cmd->flag &= ~MOD_CACHE_USE_OUTPUT_RENDER;
if (m_cmd->output_dm) {
m_cmd->output_dm->release(m_cmd->output_dm);
m_cmd->output_dm = NULL;
}
}
} /* namespace PTC */

View File

@@ -0,0 +1,175 @@
/*
* Copyright 2014, Blender Foundation.
*
* 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.
*/
#ifndef PTC_ABC_MESH_H
#define PTC_ABC_MESH_H
#include <Alembic/AbcGeom/IPolyMesh.h>
#include <Alembic/AbcGeom/OPolyMesh.h>
#include "ptc_types.h"
#include "abc_customdata.h"
#include "abc_reader.h"
#include "abc_schema.h"
#include "abc_writer.h"
extern "C" {
#include "DNA_modifier_types.h"
#include "BKE_DerivedMesh.h"
}
struct Object;
struct CacheModifierData;
struct DerivedMesh;
namespace PTC {
class AbcDerivedMeshWriter : public DerivedMeshWriter, public AbcWriter {
public:
AbcDerivedMeshWriter(const std::string &name, Object *ob, DerivedMesh **dm_ptr);
~AbcDerivedMeshWriter();
void init_abc(Abc::OObject parent);
void write_sample();
private:
AbcGeom::OPolyMesh m_mesh;
/* MVert attributes */
AbcGeom::ON3fArrayProperty m_prop_vert_normals;
AbcGeom::OCharArrayProperty m_prop_vert_flag;
AbcGeom::OCharArrayProperty m_prop_vert_bweight;
/* MEdge attributes */
AbcGeom::OUInt32ArrayProperty m_prop_edge_verts;
AbcGeom::OInt16ArrayProperty m_prop_edge_flag;
AbcGeom::OCharArrayProperty m_prop_edge_crease;
AbcGeom::OCharArrayProperty m_prop_edge_bweight;
/* MPoly attributes */
AbcGeom::OInt16ArrayProperty m_prop_poly_mat_nr;
AbcGeom::OCharArrayProperty m_prop_poly_flag;
/* MLoop attributes */
AbcGeom::OInt32ArrayProperty m_prop_loop_verts;
AbcGeom::OInt32ArrayProperty m_prop_loop_edges;
CustomDataWriter m_vert_data_writer;
CustomDataWriter m_edge_data_writer;
CustomDataWriter m_face_data_writer;
CustomDataWriter m_poly_data_writer;
CustomDataWriter m_loop_data_writer;
};
class AbcDerivedMeshReader : public DerivedMeshReader, public AbcReader {
public:
AbcDerivedMeshReader(const std::string &name, Object *ob);
~AbcDerivedMeshReader();
void init_abc(Abc::IObject parent);
PTCReadSampleResult read_sample(float frame);
private:
AbcGeom::IPolyMesh m_mesh;
/* MVert attributes */
AbcGeom::IN3fArrayProperty m_prop_vert_normals;
AbcGeom::ICharArrayProperty m_prop_vert_flag;
AbcGeom::ICharArrayProperty m_prop_vert_bweight;
/* MEdge attributes */
AbcGeom::IUInt32ArrayProperty m_prop_edge_verts;
AbcGeom::IInt16ArrayProperty m_prop_edge_flag;
AbcGeom::ICharArrayProperty m_prop_edge_crease;
AbcGeom::ICharArrayProperty m_prop_edge_bweight;
/* MPoly attributes */
AbcGeom::IInt16ArrayProperty m_prop_poly_mat_nr;
AbcGeom::ICharArrayProperty m_prop_poly_flag;
/* MLoop attributes */
AbcGeom::IInt32ArrayProperty m_prop_loop_verts;
AbcGeom::IInt32ArrayProperty m_prop_loop_edges;
CustomDataReader m_vert_data_reader;
CustomDataReader m_edge_data_reader;
CustomDataReader m_face_data_reader;
CustomDataReader m_poly_data_reader;
CustomDataReader m_loop_data_reader;
};
/* -------------------------------------------------------------------------
* Writing derived mesh results requires different variants
* depending on viewport/render output and whether a cache modifier is used.
*
* Render DMs are constructed on-the-fly for each sample write, since they
* are not constructed immediately during scene frame updates. The writer is
* expected to only be called once per frame and object.
*
* If a cache modifier is used it must be have be activate at the time when
* the DM is built. For viewport output this means it should activate the
* modifier during it's whole lifetime, so that it caches meshes during the
* scene frame update. For render output the modifier should only be active
* during the render DM construction.
* ------------------------------------------------------------------------- */
class AbcDerivedFinalRealtimeWriter : public AbcDerivedMeshWriter {
public:
AbcDerivedFinalRealtimeWriter(const std::string &name, Object *ob);
};
class AbcCacheModifierRealtimeWriter : public AbcDerivedMeshWriter {
public:
AbcCacheModifierRealtimeWriter(const std::string &name, Object *ob, CacheModifierData *cmd);
~AbcCacheModifierRealtimeWriter();
private:
CacheModifierData *m_cmd;
};
class AbcDerivedFinalRenderWriter : public AbcDerivedMeshWriter {
public:
AbcDerivedFinalRenderWriter(const std::string &name, Scene *scene, Object *ob, DerivedMesh **render_dm_ptr);
private:
Scene *m_scene;
};
class AbcCacheModifierRenderWriter : public AbcDerivedMeshWriter {
public:
AbcCacheModifierRenderWriter(const std::string &name, Scene *scene, Object *ob, CacheModifierData *cmd);
~AbcCacheModifierRenderWriter();
private:
Scene *m_scene;
CacheModifierData *m_cmd;
};
} /* namespace PTC */
#endif /* PTC_MESH_H */

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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.
*/
#include "abc_object.h"
extern "C" {
#include "BLI_math.h"
#include "DNA_object_types.h"
#include "BKE_object.h"
}
namespace PTC {
using namespace Abc;
using namespace AbcGeom;
AbcObjectWriter::AbcObjectWriter(const std::string &name, Scene *scene, Object *ob, bool do_mesh, bool do_hair) :
ObjectWriter(ob, name),
m_scene(scene),
m_final_dm(NULL),
m_dm_writer("mesh", ob, &m_final_dm),
m_do_mesh(do_mesh),
m_do_hair(do_hair)
{
m_do_mesh &= m_ob->type == OB_MESH;
}
void AbcObjectWriter::init_abc()
{
if (m_abc_object)
return;
m_abc_object = abc_archive()->add_id_object<OObject>((ID *)m_ob);
if (m_do_mesh) {
/* XXX not nice */
m_dm_writer.init(abc_archive());
m_dm_writer.init_abc(m_abc_object);
}
if (m_do_hair) {
/* TODO */
}
}
#if 0
void AbcObjectWriter::create_refs()
{
if ((m_ob->transflag & OB_DUPLIGROUP) && m_ob->dup_group) {
OObject abc_group = abc_archive()->get_id_object((ID *)m_ob->dup_group);
if (abc_group)
m_abc_object.addChildInstance(abc_group, "dup_group");
}
}
#endif
void AbcObjectWriter::write_sample()
{
if (!m_abc_object)
return;
if (m_do_mesh) {
if (abc_archive()->use_render()) {
m_final_dm = mesh_create_derived_render(m_scene, m_ob, CD_MASK_BAREMESH);
if (m_final_dm) {
m_dm_writer.write_sample();
m_final_dm->release(m_final_dm);
}
}
else {
m_final_dm = m_ob->derivedFinal;
if (!m_final_dm)
m_final_dm = mesh_get_derived_final(m_scene, m_ob, CD_MASK_BAREMESH);
if (m_final_dm) {
m_dm_writer.write_sample();
}
}
}
}
AbcObjectReader::AbcObjectReader(const std::string &name, Object *ob) :
ObjectReader(ob, name)
{
}
void AbcObjectReader::init_abc()
{
if (m_abc_object)
return;
m_abc_object = abc_archive()->get_id_object((ID *)m_ob);
}
PTCReadSampleResult AbcObjectReader::read_sample(float frame)
{
if (!m_abc_object)
return PTC_READ_SAMPLE_INVALID;
return PTC_READ_SAMPLE_EXACT;
}
} /* namespace PTC */

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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.
*/
#ifndef PTC_ABC_OBJECT_H
#define PTC_ABC_OBJECT_H
#include <Alembic/Abc/IObject.h>
#include <Alembic/Abc/OObject.h>
#include <Alembic/AbcGeom/IXform.h>
#include <Alembic/AbcGeom/OXform.h>
#include "ptc_types.h"
#include "abc_reader.h"
#include "abc_schema.h"
#include "abc_writer.h"
#include "abc_mesh.h"
struct DerivedMesh;
struct Object;
struct Scene;
namespace PTC {
class AbcObjectWriter : public ObjectWriter, public AbcWriter {
public:
AbcObjectWriter(const std::string &name, Scene *scene, Object *ob, bool do_mesh, bool do_hair);
void init_abc();
#if 0
void create_refs();
#endif
void write_sample();
private:
Scene *m_scene;
DerivedMesh *m_final_dm;
Abc::OObject m_abc_object;
AbcDerivedMeshWriter m_dm_writer;
bool m_do_mesh, m_do_hair;
};
class AbcObjectReader : public ObjectReader, public AbcReader {
public:
AbcObjectReader(const std::string &name, Object *ob);
void init_abc();
PTCReadSampleResult read_sample(float frame);
private:
Abc::IObject m_abc_object;
};
} /* namespace PTC */
#endif /* PTC_OBJECT_H */

View File

@@ -0,0 +1,499 @@
/*
* Copyright 2013, Blender Foundation.
*
* 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.
*/
#include "abc_cloth.h"
#include "abc_mesh.h"
#include "abc_particles.h"
extern "C" {
#include "BLI_math.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
#include "BKE_particle.h"
}
namespace PTC {
using namespace Abc;
using namespace AbcGeom;
AbcParticlesWriter::AbcParticlesWriter(const std::string &name, Object *ob, ParticleSystem *psys) :
ParticlesWriter(ob, psys, name)
{
}
AbcParticlesWriter::~AbcParticlesWriter()
{
}
void AbcParticlesWriter::init_abc(OObject parent)
{
if (m_points)
return;
m_points = OPoints(parent, m_name, abc_archive()->frame_sampling_index());
}
void AbcParticlesWriter::write_sample()
{
if (!m_points)
return;
OPointsSchema &schema = m_points.getSchema();
int totpart = m_psys->totpart;
ParticleData *pa;
int i;
/* XXX TODO only needed for the first frame/sample */
std::vector<Util::uint64_t> ids;
ids.reserve(totpart);
for (i = 0, pa = m_psys->particles; i < totpart; ++i, ++pa)
ids.push_back(i);
std::vector<V3f> positions;
positions.reserve(totpart);
for (i = 0, pa = m_psys->particles; i < totpart; ++i, ++pa) {
float *co = pa->state.co;
positions.push_back(V3f(co[0], co[1], co[2]));
}
OPointsSchema::Sample sample = OPointsSchema::Sample(V3fArraySample(positions), UInt64ArraySample(ids));
schema.set(sample);
}
AbcParticlesReader::AbcParticlesReader(const std::string &name, Object *ob, ParticleSystem *psys) :
ParticlesReader(ob, psys, name)
{
}
AbcParticlesReader::~AbcParticlesReader()
{
}
void AbcParticlesReader::init_abc(IObject parent)
{
if (m_points)
return;
if (parent.getChild(m_name)) {
m_points = IPoints(parent, m_name);
}
/* XXX TODO read first sample for info on particle count and times */
m_totpoint = 0;
}
PTCReadSampleResult AbcParticlesReader::read_sample(float frame)
{
ISampleSelector ss = abc_archive()->get_frame_sample_selector(frame);
if (!m_points.valid())
return PTC_READ_SAMPLE_INVALID;
IPointsSchema &schema = m_points.getSchema();
IPointsSchema::Sample sample;
schema.get(sample, ss);
const V3f *positions = sample.getPositions()->get();
int /*totpart = m_psys->totpart,*/ i;
ParticleData *pa;
for (i = 0, pa = m_psys->particles; i < sample.getPositions()->size(); ++i, ++pa) {
pa->state.co[0] = positions[i].x;
pa->state.co[1] = positions[i].y;
pa->state.co[2] = positions[i].z;
}
return PTC_READ_SAMPLE_EXACT;
}
AbcHairDynamicsWriter::AbcHairDynamicsWriter(const std::string &name, Object *ob, ParticleSystem *psys) :
ParticlesWriter(ob, psys, name),
m_cloth_writer(name+"__cloth", ob, psys->clmd)
{
}
void AbcHairDynamicsWriter::init_abc(OObject parent)
{
m_cloth_writer.init_abc(parent);
}
void AbcHairDynamicsWriter::write_sample()
{
m_cloth_writer.write_sample();
}
AbcHairDynamicsReader::AbcHairDynamicsReader(const std::string &name, Object *ob, ParticleSystem *psys) :
ParticlesReader(ob, psys, name),
m_cloth_reader(name+"__cloth", ob, psys->clmd)
{
}
void AbcHairDynamicsReader::init_abc(IObject parent)
{
m_cloth_reader.init_abc(parent);
}
PTCReadSampleResult AbcHairDynamicsReader::read_sample(float frame)
{
return m_cloth_reader.read_sample(frame);
}
AbcParticlePathcacheWriter::AbcParticlePathcacheWriter(const std::string &name, Object *ob, ParticleSystem *psys, ParticleCacheKey ***pathcache, int *totpath, const std::string &suffix) :
ParticlesWriter(ob, psys, name),
m_pathcache(pathcache),
m_totpath(totpath),
m_suffix(suffix)
{
}
AbcParticlePathcacheWriter::~AbcParticlePathcacheWriter()
{
}
void AbcParticlePathcacheWriter::init_abc(OObject parent)
{
if (m_curves)
return;
/* XXX non-escaped string construction here ... */
m_curves = OCurves(parent, m_name + m_suffix, abc_archive()->frame_sampling_index());
OCurvesSchema &schema = m_curves.getSchema();
OCompoundProperty geom_props = schema.getArbGeomParams();
m_param_velocities = OV3fGeomParam(geom_props, "velocities", false, kVertexScope, 1, 0);
m_param_rotations = OQuatfGeomParam(geom_props, "rotations", false, kVertexScope, 1, 0);
m_param_colors = OV3fGeomParam(geom_props, "colors", false, kVertexScope, 1, 0);
m_param_times = OFloatGeomParam(geom_props, "times", false, kVertexScope, 1, 0);
}
static int paths_count_totkeys(ParticleCacheKey **pathcache, int totpart)
{
int p;
int totkeys = 0;
for (p = 0; p < totpart; ++p) {
ParticleCacheKey *keys = pathcache[p];
totkeys += keys->segments + 1;
}
return totkeys;
}
static Int32ArraySample paths_create_sample_nvertices(ParticleCacheKey **pathcache, int totpart, std::vector<int32_t> &data)
{
int p;
data.reserve(totpart);
for (p = 0; p < totpart; ++p) {
ParticleCacheKey *keys = pathcache[p];
data.push_back(keys->segments + 1);
}
return Int32ArraySample(data);
}
static P3fArraySample paths_create_sample_positions(ParticleCacheKey **pathcache, int totpart, int totkeys, std::vector<V3f> &data)
{
int p, k;
data.reserve(totkeys);
for (p = 0; p < totpart; ++p) {
ParticleCacheKey *keys = pathcache[p];
int numkeys = keys->segments + 1;
for (k = 0; k < numkeys; ++k) {
float *co = keys[k].co;
data.push_back(V3f(co[0], co[1], co[2]));
}
}
return P3fArraySample(data);
}
static OV3fGeomParam::Sample paths_create_sample_velocities(ParticleCacheKey **pathcache, int totpart, int totkeys, std::vector<V3f> &data)
{
int p, k;
data.reserve(totkeys);
for (p = 0; p < totpart; ++p) {
ParticleCacheKey *keys = pathcache[p];
int numkeys = keys->segments + 1;
for (k = 0; k < numkeys; ++k) {
float *vel = keys[k].vel;
data.push_back(V3f(vel[0], vel[1], vel[2]));
}
}
OV3fGeomParam::Sample sample;
sample.setVals(V3fArraySample(data));
sample.setScope(kVertexScope);
return sample;
}
static OQuatfGeomParam::Sample paths_create_sample_rotations(ParticleCacheKey **pathcache, int totpart, int totkeys, std::vector<Quatf> &data)
{
int p, k;
data.reserve(totkeys);
for (p = 0; p < totpart; ++p) {
ParticleCacheKey *keys = pathcache[p];
int numkeys = keys->segments + 1;
for (k = 0; k < numkeys; ++k) {
float *rot = keys[k].rot;
data.push_back(Quatf(rot[0], rot[1], rot[2], rot[3]));
}
}
OQuatfGeomParam::Sample sample;
sample.setVals(QuatfArraySample(data));
sample.setScope(kVertexScope);
return sample;
}
static OV3fGeomParam::Sample paths_create_sample_colors(ParticleCacheKey **pathcache, int totpart, int totkeys, std::vector<V3f> &data)
{
int p, k;
data.reserve(totkeys);
for (p = 0; p < totpart; ++p) {
ParticleCacheKey *keys = pathcache[p];
int numkeys = keys->segments + 1;
for (k = 0; k < numkeys; ++k) {
float *col = keys[k].col;
data.push_back(V3f(col[0], col[1], col[2]));
}
}
OV3fGeomParam::Sample sample;
sample.setVals(V3fArraySample(data));
sample.setScope(kVertexScope);
return sample;
}
static OFloatGeomParam::Sample paths_create_sample_times(ParticleCacheKey **pathcache, int totpart, int totkeys, std::vector<float32_t> &data)
{
int p, k;
data.reserve(totkeys);
for (p = 0; p < totpart; ++p) {
ParticleCacheKey *keys = pathcache[p];
int numkeys = keys->segments + 1;
for (k = 0; k < numkeys; ++k) {
data.push_back(keys[k].time);
}
}
OFloatGeomParam::Sample sample;
sample.setVals(FloatArraySample(data));
sample.setScope(kVertexScope);
return sample;
}
void AbcParticlePathcacheWriter::write_sample()
{
if (!m_curves)
return;
if (!(*m_pathcache))
return;
int totkeys = paths_count_totkeys(*m_pathcache, *m_totpath);
if (totkeys == 0)
return;
OCurvesSchema &schema = m_curves.getSchema();
std::vector<V3f> positions_buffer;
std::vector<V3f> velocities_buffer;
std::vector<Quatf> rotations_buffer;
std::vector<V3f> colors_buffer;
std::vector<float32_t> times_buffer;
V3fArraySample positions = paths_create_sample_positions(*m_pathcache, *m_totpath, totkeys, positions_buffer);
OV3fGeomParam::Sample velocities = paths_create_sample_velocities(*m_pathcache, *m_totpath, totkeys, velocities_buffer);
OQuatfGeomParam::Sample rotations = paths_create_sample_rotations(*m_pathcache, *m_totpath, totkeys, rotations_buffer);
OV3fGeomParam::Sample colors = paths_create_sample_colors(*m_pathcache, *m_totpath, totkeys, colors_buffer);
OFloatGeomParam::Sample times = paths_create_sample_times(*m_pathcache, *m_totpath, totkeys, times_buffer);
OCurvesSchema::Sample sample;
if (schema.getNumSamples() == 0) {
/* write curve sizes only first time, assuming they are constant! */
std::vector<int32_t> nvertices_buffer;
Int32ArraySample nvertices = paths_create_sample_nvertices(*m_pathcache, *m_totpath, nvertices_buffer);
sample = OCurvesSchema::Sample(positions, nvertices);
}
else {
sample = OCurvesSchema::Sample(positions);
}
schema.set(sample);
m_param_velocities.set(velocities);
m_param_rotations.set(rotations);
m_param_colors.set(colors);
m_param_times.set(times);
}
AbcParticlePathcacheReader::AbcParticlePathcacheReader(const std::string &name, Object *ob, ParticleSystem *psys, ParticleCacheKey ***pathcache, int *totpath, const std::string &suffix) :
ParticlesReader(ob, psys, name),
m_pathcache(pathcache),
m_totpath(totpath),
m_suffix(suffix)
{
}
void AbcParticlePathcacheReader::init_abc(IObject parent)
{
if (m_curves)
return;
/* XXX non-escaped string construction here ... */
std::string curves_name = m_name + m_suffix;
if (parent.getChild(curves_name)) {
m_curves = ICurves(parent, curves_name);
ICurvesSchema &schema = m_curves.getSchema();
ICompoundProperty geom_props = schema.getArbGeomParams();
m_param_velocities = IV3fGeomParam(geom_props, "velocities", 0);
m_param_rotations = IQuatfGeomParam(geom_props, "rotations", 0);
m_param_colors = IV3fGeomParam(geom_props, "colors", 0);
m_param_times = IFloatGeomParam(geom_props, "times", 0);
}
}
static void paths_apply_sample_nvertices(ParticleCacheKey **pathcache, int totpart, Int32ArraySamplePtr sample)
{
int p, k;
BLI_assert(sample->size() == totpart);
const int32_t *data = sample->get();
for (p = 0; p < totpart; ++p) {
ParticleCacheKey *keys = pathcache[p];
int num_keys = data[p];
int segments = num_keys - 1;
for (k = 0; k < num_keys; ++k) {
keys[k].segments = segments;
}
}
}
/* Warning: apply_sample_nvertices has to be called before this! */
static void paths_apply_sample_data(ParticleCacheKey **pathcache, int totpart,
P3fArraySamplePtr sample_pos,
V3fArraySamplePtr sample_vel,
QuatfArraySamplePtr sample_rot,
V3fArraySamplePtr sample_col,
FloatArraySamplePtr sample_time)
{
int p, k;
// BLI_assert(sample->size() == totvert);
const V3f *data_pos = sample_pos->get();
const V3f *data_vel = sample_vel->get();
const Quatf *data_rot = sample_rot->get();
const V3f *data_col = sample_col->get();
const float32_t *data_time = sample_time->get();
ParticleCacheKey **pkeys = pathcache;
for (p = 0; p < totpart; ++p) {
ParticleCacheKey *key = *pkeys;
int num_keys = key->segments + 1;
for (k = 0; k < num_keys; ++k) {
copy_v3_v3(key->co, data_pos->getValue());
copy_v3_v3(key->vel, data_vel->getValue());
key->rot[0] = (*data_rot)[0];
key->rot[1] = (*data_rot)[1];
key->rot[2] = (*data_rot)[2];
key->rot[3] = (*data_rot)[3];
copy_v3_v3(key->col, data_col->getValue());
key->time = *data_time;
++key;
++data_pos;
++data_vel;
++data_rot;
++data_col;
++data_time;
}
++pkeys;
}
}
PTCReadSampleResult AbcParticlePathcacheReader::read_sample(float frame)
{
if (!(*m_pathcache))
return PTC_READ_SAMPLE_INVALID;
if (!m_curves)
return PTC_READ_SAMPLE_INVALID;
ISampleSelector ss = abc_archive()->get_frame_sample_selector(frame);
ICurvesSchema &schema = m_curves.getSchema();
if (!schema.valid() || schema.getPositionsProperty().getNumSamples() == 0)
return PTC_READ_SAMPLE_INVALID;
ICurvesSchema::Sample sample;
schema.get(sample, ss);
P3fArraySamplePtr positions = sample.getPositions();
Int32ArraySamplePtr nvertices = sample.getCurvesNumVertices();
IV3fGeomParam::Sample sample_vel = m_param_velocities.getExpandedValue(ss);
IQuatfGeomParam::Sample sample_rot = m_param_rotations.getExpandedValue(ss);
IV3fGeomParam::Sample sample_col = m_param_colors.getExpandedValue(ss);
IFloatGeomParam::Sample sample_time = m_param_times.getExpandedValue(ss);
// int totkeys = positions->size();
if (nvertices->valid()) {
BLI_assert(nvertices->size() == *m_totpath);
paths_apply_sample_nvertices(*m_pathcache, *m_totpath, nvertices);
}
paths_apply_sample_data(*m_pathcache, *m_totpath, positions, sample_vel.getVals(), sample_rot.getVals(), sample_col.getVals(), sample_time.getVals());
return PTC_READ_SAMPLE_EXACT;
}
} /* namespace PTC */

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