1
1

Compare commits

...

128 Commits

Author SHA1 Message Date
69f990ad7e Disabled data access in particle RNA.
Only the general attribute descriptions and state instance can be
accessed from plain bpy now. For detailed data read/write the bparticles
module has to be used.

This was forced by a change to collection iterators, which essentially
makes them unsuitable for anything other than ListBase and arrays
(state attributes and particle data in this case). It may be possible
to reeanble this later, but generally bparticles is the better approach.
2014-07-14 15:00:55 +02:00
911fe9dfa2 Fixed a few small merge errors. Sorted libs are now defined in
macros.cmake.
2014-07-14 14:59:17 +02:00
55cf7703fd Merge branch 'master' into particles_refactor
Conflicts:
	source/blender/blenkernel/intern/object.c
	source/blender/blenkernel/intern/rigidbody.c
	source/blender/blenloader/intern/writefile.c
	source/blender/python/intern/bpy_interface.c
	source/creator/CMakeLists.txt
2014-07-14 14:23:50 +02:00
f5abbee52a Fix for variable declaration after code (invalid C). 2014-04-24 12:41:23 +02:00
01a2253dfd Fix for dupli type bit flags exceeding short range.
The nparticle dupli flag was using 1<<15, which gives issues with signed
short variables. Fortunately there are unused bits in the
Object.transflag, now reuse the deprecated OB_POWERTRACK flag for this.

Also replaced dupli context int type with short to avoid errors with
strict compiler flags.
2014-04-22 15:52:13 +02:00
4684f2c70d Added missing support for quaternion attributes in the bparticles API. 2014-04-22 11:28:32 +02:00
5a6eccfe43 Replaced the RBO_GET_MASS and RBO_GET_MARGIN macros with proper
functions.

There is really no reason to use macros for this sort of thing.
2014-04-22 11:28:31 +02:00
79fc66872a Moved build/apply functions for constraints into rigidbody_objects too.
This is only about object-based constraints. Bullet constraints can be
added for other future use cases too outside the objects code.
2014-04-22 11:28:31 +02:00
b7d3160133 Moved functions for object component data management (RigidBodyObject
and RigidBodyCon) into rigidbody_objects.c as well.
2014-04-22 11:28:31 +02:00
da8b4f9112 Moved transform utility functions for objects into the rigidbody_objects
source file.

Renamed them a bit to make clear these are for objects only.
2014-04-22 11:28:31 +02:00
e2d7123674 Separation of concerns: Moved functions for building object rigid bodies
and applying Bullet results to them into a dedicated file.

The same should happen for particles, shapes, constraints etc. later.

The purpose of this is to keep the main Bullet world API limited to
dealing with Bullet primarily and avoid fixating it on Object DNA data.
2014-04-22 11:27:48 +02:00
843efe48ab A couple of small fixes for merge issues. 2014-04-22 11:23:50 +02:00
bb3cf1ded0 Use instanced object collision shapes for particles instead of plain
spheres. The "collision_shape" attribute is no longer needed, the shapes
can be retrieved from the instanced objects instead (which must be RBs
themselves).
2014-04-22 11:23:50 +02:00
137fa8a40b Sensible default value support for particle attributes. Some data types
(normal, color, quaternion, matrix) get common default values, others
are just 0 and have to be defined by the user if necessary.
2014-04-22 11:23:50 +02:00
547f42156e Added default rotation attribute. 2014-04-22 11:23:50 +02:00
54fe3f0285 Basic dupli display for particles.
Conflicts:
	source/blender/blenkernel/intern/anim.c
2014-04-22 11:23:50 +02:00
6821bec4eb Fixed read/write code for particle display dupli lists and added a
modifier object walk callback (also used in readfile for generic
modifier lib_link).
2014-04-22 11:23:50 +02:00
fd5b195ea7 Free dupli object lists correctly when freeing display structs. 2014-04-22 11:23:50 +02:00
3113007682 Boilerplate RNA for the particle display settings. 2014-04-22 11:23:50 +02:00
6529e53f40 Add a dupli display method by default. 2014-04-22 11:23:50 +02:00
d82c6ce507 Single display 'add' function, is easier to provide as API method. 2014-04-22 11:23:49 +02:00
0211fc88f9 Automatically set the object transflag for nparticle duplis, like
current particles (but actual code is in nparticle to stay out of object
code as much as possible).
2014-04-22 11:23:49 +02:00
5235a9ea75 Moved the particle display list from the modifier into the psys itself.
This makes the modifier more easily replaceable later on and allows
more detailed management of the particle object settings (in particular
dupli flags).
2014-04-22 11:23:49 +02:00
e93e2abae6 Particle display type for duplis. 2014-04-22 11:23:49 +02:00
13876fafbc Removed old unused nparticle modifier code. 2014-04-22 11:23:49 +02:00
7253c6752b Only call the 'validate' function for particles once, to prevent them
from being removed and added back to the world continuously, which
resets the motion state each time. Also set the USED flag outside of
validate since this is not executed every step and would otherwise
delete all existing particles.
2014-04-22 11:23:48 +02:00
772b08b8aa Added new bparticles function for copying the current particle state
instead of just creating a new empty state. Also clear the py_handle
when copying the state, otherwise the PyObject is invalid.
2014-04-22 11:23:48 +02:00
d4af9c8e6a Set some usable default values for a number of particle rigid body
settings.
2014-04-22 11:23:48 +02:00
3ae43a2ce2 Some missing stddef.h includes for NULL. 2014-04-22 11:23:47 +02:00
1edcfc363e Very basic sync method for particles, which copies the state and
updates the particle positions from rigid bodies.
2014-04-22 11:23:47 +02:00
f077d9f57c Fix for rigid body removal methods: Flag new rigid bodies for particles
as used to prevent freeing. Also remove bodies if they already exist,
to prevent double adding and subsequent assert failure.

Conflicts:
	source/blender/blenkernel/intern/rigidbody.c
2014-04-22 11:23:47 +02:00
839149ea90 Fix for RigidBodyWorld reading: initialize empty body mempool when
reading blend files, this is not actually stored.
2014-04-22 11:23:47 +02:00
6a3705690f Removed rigidbody build/apply functions from NParticle API. It's better
to keep this functionality inside RigidBody blenkernel for now.
2014-04-22 11:23:47 +02:00
7c666d168f Cleanup: Separate function for details of the object 'apply' method. 2014-04-22 11:23:47 +02:00
667728788d Added inline comment about possible memory management optimization. 2014-04-22 11:23:47 +02:00
2e9c9415eb Cleanup: Separated object and constraint build loops into own functions.
Renamed some more API methods to follow the new naming scheme.

Conflicts:
	source/blender/blenkernel/intern/rigidbody.c
2014-04-22 11:23:47 +02:00
2fbb7a7937 Cleanup: Renamed a number of internal rigidbody functions to clarify
the procedure:

  world_build:  create rbRigidBody instances for stuff in Scene
  validate_*:   ensure a rbRigidBody exists for an Object/particle/etc.
  sync_*:       define Bullet settings for an Object/particle/etc. based
                on Blender Scene data
  world_apply:  copy back data from Bullet after a step to the Blender
                Scene data

Conflicts:
	source/blender/blenkernel/intern/rigidbody.c
2014-04-22 11:23:47 +02:00
6cf17ddc48 Fix potential issue from early exit when no constraints exist. 2014-04-22 11:23:47 +02:00
93da0edf0c Particle validate function for adding particle rigid bodies. 2014-04-22 11:23:46 +02:00
dc60ec7505 Removed unused variables. 2014-04-22 11:23:46 +02:00
4472309bdd Added collision shape pointer attribute for particles. This will change
soon, for now is the easiest way to keep track of things.
2014-04-22 11:23:46 +02:00
f948f57a98 Pointer attribute get/set functions for particles. 2014-04-22 11:23:46 +02:00
0480a26d37 Use the rigidbody_world_free_bodies function for freeing bodies when
destroying the world, instead of looping over the object group. This is
in line with the memory ownership being at the RigidBodyWorld now
instead of the individual Objects and will ensure all RBs get destroyed
properly when using particles etc. later.
2014-04-22 11:23:46 +02:00
a5f193fe51 Basic mempool usage for creating and removing rbRigidBody instances.
This uses flags to indicate used rbRigidBodies and then loops over the
mempool to remove orphaned bodies. The same should eventually be done
for shapes and constraints.
2014-04-22 11:23:46 +02:00
1d6638d077 Shortcut variable for rbRigidBody, avoids repetitive rbo->physics_object
access.
2014-04-22 11:23:46 +02:00
dc4dd96db2 Generic flags for rbRigidBody. These can be used by the blenkernel API
to tag used rigid bodies and automatically remove unused bodies.
2014-04-22 11:23:46 +02:00
ddf86fb42c Use the mempool in RigidBodyWorld instead of allocating memory inside
the Bullet CAPI.

NOTE: this is broken atm because to free an Object's rigid body data
the RBW needs to be passed along, which would require a Scene argument
in the blenkernel function. This will get fixed by moving ownership of
the rigid body away from object and into the RBW memory management sync
procedure.

Conflicts:
	intern/rigidbody/RBI_api.h
2014-04-22 11:23:46 +02:00
c56fb3d108 Make the btRigidBody a direct component of the rbRigidBody wrapper
struct. This avoids one pointer indirection and makes future memory
management possible. Requires a constructur/destructor pair to
initialize the 'body' member correctly.
2014-04-22 11:23:46 +02:00
e93309556b Added a mempool to RigidBodyWorld as a memory manager for bodies.
Conflicts:
	intern/rigidbody/rb_bullet_api.cpp
2014-04-22 11:23:46 +02:00
39ce10c2f5 Added a new attribute type 'POINTER', for storing rigid body pointers.
This may not be the best way to map rigid bodies to particles,
eventually a nicer way could be to make use of the userpointer in Bullet
btRigidBody and store a weak reference to Blender types there instead.
Storing rigid body pointers in the particles just mimicks the way the
Object RBs work atm.

The pointer attribute gets a flag 'TEMPORARY' to prevent it from being
stored in the cache and .blend files, since it's only valid during the
Bullet stepping anyway.
2014-04-22 11:23:45 +02:00
b6ff000ec2 Stub functions for creating and updating rigid bodies from particle
systems in the RigidBodyWorld steps.
2014-04-22 11:23:45 +02:00
7f8997783f Cleanup: Removed old unused code from multi-layer paged buffers. 2014-04-22 11:23:45 +02:00
335ff9331a Include the standard type attributes in the dir function for particles. 2014-04-22 11:23:45 +02:00
3887c0f2f1 Fix for particle getattro: Throw an exception if iterator is not valid,
otherwise expect to find a correct void *data (assert is used to as a
sanity check, should never fail).
2014-04-22 11:23:45 +02:00
30d3fae8b7 Added a __dir__ method for particles to return the list of available
attributes.
2014-04-22 11:23:45 +02:00
10d17ae2b1 bpy particle objects are still valid if the particle id does not yet
exist. This allows a create-on-write feature, where a particle is
automatically added to the state if the pid does not yet exist.
2014-04-22 11:23:45 +02:00
97011304e4 New API function for replacing the current particle system's state. ATM
this creates a full copy of the given state, so the reference can be
used further. This may need some more thought.
2014-04-22 11:23:45 +02:00
1c84174ae9 Add particle sequence as a state attribute in the API. 2014-04-22 11:23:45 +02:00
2a4b80101b Fix for particle iterator validity check: also check for negative index,
this is used for indicating an invalid particle iterator.
2014-04-22 11:23:44 +02:00
89c74dfcf1 Custom get/set methods for the "Particle" type. This supports particle
attributes directly as python properties in the particle wrapper type.
If a particle identifier has no corresponding data in the state yet it
will be automatically created when writing.
2014-04-22 11:23:44 +02:00
1275e68c0e Store the particle ID alongside the particle iterator in the python
particle wrapper type, so it can be used to automatically create missing
particles later on.
2014-04-22 11:23:44 +02:00
3033fdd502 Added particles sequence in state bpy api. 2014-04-22 11:23:44 +02:00
6b4719e1e0 Added 'attributes' sequence property in the state type. 2014-04-22 11:23:44 +02:00
b8f54307fc Added "name" property (read-only) for attribute states. 2014-04-22 11:23:44 +02:00
2ec54df635 A bit shorter internal names for bparticles structs and functions. 2014-04-22 11:23:44 +02:00
f4344cdfa5 Added python type for particle attribute state in the bparticles module. 2014-04-22 11:23:43 +02:00
f3d1522272 Basic submodule 'types' in bparticles, defining a PyObject type for
the particle state.
2014-04-22 11:23:43 +02:00
eee0f75b1f Added new python module 'bparticles' for implementing a full python API
to define particle states. This is necessary because otherwise the RNA
can only refer to data that already exists in the DNA library (bpy.data)
but not create temporary structs. The state should be defined separately
before replacing a particle system's state with it. This is similar to
how bmesh works.
2014-04-22 11:23:43 +02:00
fe0bd22bcf Added missing read/write code for particle display. 2014-04-22 11:23:42 +02:00
dc93c57b41 Basic display feature for particles. This is organized as a list of
NParticleDisplay in the modifier for now. Each NParticleDisplay adds
a visualization element of some type in the viewport, which will allow
combining elements for custom attributes with standard display modes
for particles.
2014-04-22 11:23:42 +02:00
c991cd78e7 Add position attribute to particles by default. 2014-04-22 11:23:42 +02:00
6f9afa9775 Use a readonly flag for attributes and a second variant of the Data
RNA access types to prevent writing over immutable attributes ("id" in
particular).
2014-04-22 11:23:42 +02:00
5dd5c883fa Initialize the "id" attribute when adding particles to the state. 2014-04-22 11:23:42 +02:00
e93d2e0625 Use the new attribute flags to determine editability in RNA. 2014-04-22 11:23:42 +02:00
02e687d02c Flags for particle attributes:
- REQUIRED: These attributes are always existent in every particle
    system. Currently this is only the "id" layer, position might also
    be added
- PROTECTED: Attribute name, datatype, etc. can not be changed. Only
    user-defined attributes can be modified this way.
2014-04-22 11:23:42 +02:00
6ad40aa1ae RNA fix: using RNA_def_struct_sdna_from works only with actual pointers,
but not with directly nested structs (NParticleAttributeDescription in
this case). Resort to including "desc." prefix in the property paths.
2014-04-22 11:23:42 +02:00
4eda0a6f42 Clear the attribute buffers when adding new particles to a state. This
should probably use a specific default value for each attribute at some
point.
2014-04-22 11:23:42 +02:00
e1dc85f974 Copy the attribute descriptor to attribute states as well. The storage
overhead is negligible and this allows sanity type check assert as well
as correct RNA refining without access to the original attribute
descriptor.
2014-04-22 11:23:41 +02:00
7209bd4ebd Ensure the attribute states are synced to the attributes of the particle
system when adding/removing attribute descriptors. This is not a hard
requirement really, if an attribute has no state data that would still
work, but in most cases it should stay in sync.
2014-04-22 11:23:41 +02:00
ad9e4983dc Replaced the attribute state array with a ListBase. Eventually this
should use a hash table for O(1) lookup, but for now a linked list is
the easiest implementation.
2014-04-22 11:23:41 +02:00
5d4ae82cc0 Added accessor functions in particle state which allow extending the
particle state. These can be used later in python wrappers to support
more immediate collection-style access.
2014-04-22 11:23:41 +02:00
4b90b80c70 Fixed the particle attribute state data access functions. These have to
use an index as key rather than a particle ID, since the latter is not
available in a single attribute state without access to the parent
particle state.
2014-04-22 11:23:41 +02:00
f2bdf4bd4c New function for adding a particle based on particle id. 2014-04-22 11:23:41 +02:00
2496ab7f5d Alternative particle iterator init method using a specific particle ID. 2014-04-22 11:23:41 +02:00
5f3ae1c0d6 Unused RNA code for exposing particles directly in the state as a
collection. This doesn't work atm because for lookup it would need to
allocate a particle iterator, which can not be freed afterward. This
can probably be done nicer as a pure python wrapper instead of RNA.
2014-04-22 11:23:41 +02:00
971d22e5d0 Collection property for accessing the attribute states in a particle
state.
2014-04-22 11:23:41 +02:00
326a3b20f1 Store the particle state in iterators instead of the particle system. 2014-04-22 11:23:41 +02:00
408be6417d Yet another restructuring effort: Separate the state from the particle
system settings. Attributes can be accessed by name in the state data,
for now this uses plain linear search in a NULL-terminated array, but
can eventually use a hash table for O(1) lookup.
2014-04-22 11:23:41 +02:00
a5a6bd1c00 Added a comment in DNA about the concept of state/descriptor separation
and possible future optimization.
2014-04-22 11:23:40 +02:00
c7f285ca10 Iterator access functions for particles. 2014-04-22 11:23:40 +02:00
f92590e396 Implemented a simple iterator API for particle systems using a plain
index and the ID attribute for determining the state size. Have to see
how this plays out in terms of performance ...
2014-04-22 11:23:40 +02:00
5e90d3e803 Added 2 functions for looking up particles by their ID in the psys. 2014-04-22 11:23:40 +02:00
e750e0fc93 New function for getting a particle iterator at a given index. This will
be used for binary search in the particle id attribute layer.
2014-04-22 11:23:40 +02:00
649c8d6909 Copy the particle state when copying an attribute. 2014-04-22 11:23:40 +02:00
b6ced99abb Use a fixed "id" attribute, this will be required for all sorts of
particle functions and identify particles unambiguously.
2014-04-22 11:23:40 +02:00
5dccaa1ad6 Removed leftover #undefs. 2014-04-22 11:23:40 +02:00
206a0bd42f Removed unused data type mapping function in RNA, this is now directly
refined through the type of the attribute/state.
2014-04-22 11:23:39 +02:00
e7561274d7 More restructuring ... Putting state into attributes, otherwise mapping
between declared attributes in psys and attribute states becomes very
complicated.
2014-04-22 11:23:39 +02:00
fc51e04aec Fix for paged buffer iterator, can be constructed for a buffer without
any pages.
2014-04-22 11:23:39 +02:00
a0c7ee76a3 Disabled strict alignment in paged buffer for now, this fails for vector
attributes, needs a nicer way to handle this.
2014-04-22 11:23:39 +02:00
d99ff7fbee Renamed RNA property of the particle system in the psys modifier. 2014-04-22 11:23:39 +02:00
75aff0a75e Some renaming and DNA reorganization. Particle attributes now have a
descriptor as well as state data.
2014-04-22 11:23:39 +02:00
689d660adf Removed deprecated DNA data inside #if 0 block, C preprocessor doesn't
work with makesdna.
2014-04-22 11:23:39 +02:00
d5d5002c49 Disabled some unused DNA code for nparticles. 2014-04-22 11:23:39 +02:00
05791252b2 Collection properties for actual data in particle buffers. 2014-04-22 11:23:39 +02:00
8873e54701 Setter callback for particle attribute data type. Currently just throws an assert failure, later on this should make sure the particle data is converted to the correct type (or simply make datatype read-only). 2014-04-22 11:23:38 +02:00
e775f53b16 Basic properties for particle attribute descriptors. Uses a generic function to inject these properties using the nested 'desc' field. 2014-04-22 11:23:38 +02:00
af9e6b7fc5 Basic particle buffer implementation with RNA for adding and removing attributes. 2014-04-22 11:23:38 +02:00
34487cd754 Basic RNA for paged buffer and nparticle buffer. 2014-04-22 11:23:38 +02:00
857a403cd2 Updated read/write code for paged buffer for the new layer/page structure. 2014-04-22 11:23:38 +02:00
e65fb0661d Added missing DNA files to makesdna. 2014-04-22 11:23:38 +02:00
e1a9f63867 Added read/write code for NParticleSystemModifierData and NParticleBuffer. 2014-04-22 11:23:38 +02:00
da63e23ef7 Added missing draw function in the modifier panel. 2014-04-22 11:23:38 +02:00
4f7867247b Added applyModifier callback and AcceptsMesh flag so particle system can added on mesh objects. applyMesh is just a stub returning the unmodified mesh. 2014-04-22 11:23:38 +02:00
1da72ac496 Renamed the modifier to NParticleSystem since it will also define some simulation modes in addition to the actual buffer. 2014-04-22 11:23:38 +02:00
dce6d75726 Added a new modifier NParticleBuffer. This is just a thin wrapper around the NParticleBuffer struct to act as a particle container. Eventually could utilize a better object data system, for now this is ok. 2014-04-22 11:23:37 +02:00
2ab499cd1d Cleanup: disabled old modifier solution for now. 2014-04-22 11:23:37 +02:00
2cba992e9f Basic functions for creating/destroying buffers, adding/removing layers and adding elements. 2014-04-22 11:23:37 +02:00
e5777ec044 Started implementing individual paged layers. 2014-04-22 11:23:37 +02:00
bc3e02f8fe Copied over some old code, to be adapted. 2014-04-22 11:23:37 +02:00
46ffd66368 Removed unused code. 2014-04-22 11:23:37 +02:00
3fe2dc327e A few more macros to create typed access functions to paged buffer. 2014-04-22 11:23:37 +02:00
Lukas Tönne
075f6d4cf4 Skeleton files for particle buffer types. 2014-04-22 11:23:37 +02:00
Lukas Tönne
44633c67d1 Cleanup: use blenlib prefixes for iterator functions too. 2014-04-22 11:23:37 +02:00
Lukas Tönne
982c74edf0 Added basic read/write functions for pagedbuffer. 2014-04-22 11:23:37 +02:00
Lukas Tönne
dbf603c488 Better macros for low-level ultra fast access to paged buffers. 2014-04-22 11:23:14 +02:00
Lukas Tönne
2c0065295a Cleanup: follow the proposed naming scheme for blenlib (BLI_<prefix>_<function-name>). 2014-04-22 11:23:14 +02:00
Lukas Tönne
69692fdb0f Original paged buffer implementation. 2014-04-22 11:23:14 +02:00
47 changed files with 5170 additions and 837 deletions

View File

@@ -487,6 +487,7 @@ macro(SETUP_BLENDER_SORTED_LIBS)
bf_python_ext
bf_python_mathutils
bf_python_bmesh
bf_python_bparticles
bf_freestyle
bf_ikplugin
bf_modifiers

View File

@@ -37,6 +37,8 @@
extern "C" {
#endif
#include <string.h>
/* API Notes:
* Currently, this API is optimised for Bullet RigidBodies, and doesn't
* take into account other Physics Engines. Some tweaking may be necessary
@@ -56,6 +58,7 @@ typedef struct rbDynamicsWorld rbDynamicsWorld;
/* Rigid Body */
typedef struct rbRigidBody rbRigidBody;
extern size_t rbRigidBodySize;
/* Collision Shape */
typedef struct rbCollisionShape rbCollisionShape;
@@ -120,10 +123,10 @@ void RB_world_convex_sweep_test(
/* ............ */
/* Create new RigidBody instance */
rbRigidBody *RB_body_new(rbCollisionShape *shape, const float loc[3], const float rot[4]);
void RB_body_init(rbRigidBody *object, rbCollisionShape *shape, const float loc[3], const float rot[4]);
/* Delete the given RigidBody instance */
void RB_body_delete(rbRigidBody *body);
void RB_body_free(rbRigidBody *object);
/* Settings ------------------------- */
@@ -137,6 +140,11 @@ void RB_body_set_collision_shape(rbRigidBody *body, rbCollisionShape *shape);
/* ............ */
/* Generic flagging */
extern int RB_body_get_flags(rbRigidBody *body);
extern void RB_body_set_flag(rbRigidBody *body, int flag);
extern void RB_body_clear_flag(rbRigidBody *body, int flag);
/* Mass */
float RB_body_get_mass(rbRigidBody *body);
void RB_body_set_mass(rbRigidBody *body, float value);

View File

@@ -81,11 +81,23 @@ struct rbDynamicsWorld {
btConstraintSolver *constraintSolver;
btOverlapFilterCallback *filterCallback;
};
struct rbRigidBody {
btRigidBody *body;
rbRigidBody(const btRigidBody::btRigidBodyConstructionInfo& constructionInfo) :
body(constructionInfo),
col_groups(0),
flag(0)
{}
~rbRigidBody()
{}
btRigidBody body;
int col_groups;
int flag;
};
size_t rbRigidBodySize = sizeof(rbRigidBody);
struct rbVert {
float x, y, z;
};
@@ -252,7 +264,7 @@ void RB_dworld_export(rbDynamicsWorld *world, const char *filename)
void RB_dworld_add_body(rbDynamicsWorld *world, rbRigidBody *object, int col_groups)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
object->col_groups = col_groups;
world->dynamicsWorld->addRigidBody(body);
@@ -260,7 +272,7 @@ void RB_dworld_add_body(rbDynamicsWorld *world, rbRigidBody *object, int col_gro
void RB_dworld_remove_body(rbDynamicsWorld *world, rbRigidBody *object)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
world->dynamicsWorld->removeRigidBody(body);
}
@@ -272,7 +284,7 @@ void RB_world_convex_sweep_test(
const float loc_start[3], const float loc_end[3],
float v_location[3], float v_hitpoint[3], float v_normal[3], int *r_hit)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
btCollisionShape *collisionShape = body->getCollisionShape();
/* only convex shapes are supported, but user can specify a non convex shape */
if (collisionShape->isConvex()) {
@@ -320,9 +332,8 @@ void RB_world_convex_sweep_test(
/* ............ */
rbRigidBody *RB_body_new(rbCollisionShape *shape, const float loc[3], const float rot[4])
void RB_body_init(rbRigidBody *object, rbCollisionShape *shape, const float loc[3], const float rot[4])
{
rbRigidBody *object = new rbRigidBody;
/* current transform */
btTransform trans;
trans.setOrigin(btVector3(loc[0], loc[1], loc[2]));
@@ -331,19 +342,16 @@ rbRigidBody *RB_body_new(rbCollisionShape *shape, const float loc[3], const floa
/* create motionstate, which is necessary for interpolation (includes reverse playback) */
btDefaultMotionState *motionState = new btDefaultMotionState(trans);
/* make rigidbody */
btRigidBody::btRigidBodyConstructionInfo rbInfo(1.0f, motionState, shape->cshape);
object->body = new btRigidBody(rbInfo);
object->body->setUserPointer(object);
return object;
/* make rigidbody, using placement new to initialize given memory buffer */
new (object) rbRigidBody(rbInfo);
object->body.setUserPointer(object);
}
void RB_body_delete(rbRigidBody *object)
void RB_body_free(rbRigidBody *object)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
/* motion state */
btMotionState *ms = body->getMotionState();
@@ -361,15 +369,15 @@ void RB_body_delete(rbRigidBody *object)
body->removeConstraintRef(con);
}
delete body;
delete object;
/* only call destructor, memory management happens externally */
object->~rbRigidBody();
}
/* Settings ------------------------- */
void RB_body_set_collision_shape(rbRigidBody *object, rbCollisionShape *shape)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
/* set new collision shape */
body->setCollisionShape(shape->cshape);
@@ -380,9 +388,24 @@ void RB_body_set_collision_shape(rbRigidBody *object, rbCollisionShape *shape)
/* ............ */
int RB_body_get_flags(rbRigidBody *body)
{
return body->flag;
}
void RB_body_set_flag(rbRigidBody *body, int flag)
{
body->flag |= flag;
}
void RB_body_clear_flag(rbRigidBody *body, int flag)
{
body->flag &= ~flag;
}
float RB_body_get_mass(rbRigidBody *object)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
/* there isn't really a mass setting, but rather 'inverse mass'
* which we convert back to mass by taking the reciprocal again
@@ -397,7 +420,7 @@ float RB_body_get_mass(rbRigidBody *object)
void RB_body_set_mass(rbRigidBody *object, float value)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
btVector3 localInertia(0, 0, 0);
/* calculate new inertia if non-zero mass */
@@ -413,33 +436,33 @@ void RB_body_set_mass(rbRigidBody *object, float value)
float RB_body_get_friction(rbRigidBody *object)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
return body->getFriction();
}
void RB_body_set_friction(rbRigidBody *object, float value)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
body->setFriction(value);
}
float RB_body_get_restitution(rbRigidBody *object)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
return body->getRestitution();
}
void RB_body_set_restitution(rbRigidBody *object, float value)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
body->setRestitution(value);
}
float RB_body_get_linear_damping(rbRigidBody *object)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
return body->getLinearDamping();
}
@@ -450,7 +473,7 @@ void RB_body_set_linear_damping(rbRigidBody *object, float value)
float RB_body_get_angular_damping(rbRigidBody *object)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
return body->getAngularDamping();
}
@@ -461,14 +484,14 @@ void RB_body_set_angular_damping(rbRigidBody *object, float value)
void RB_body_set_damping(rbRigidBody *object, float linear, float angular)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
body->setDamping(linear, angular);
}
float RB_body_get_linear_sleep_thresh(rbRigidBody *object)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
return body->getLinearSleepingThreshold();
}
@@ -479,7 +502,7 @@ void RB_body_set_linear_sleep_thresh(rbRigidBody *object, float value)
float RB_body_get_angular_sleep_thresh(rbRigidBody *object)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
return body->getAngularSleepingThreshold();
}
@@ -490,7 +513,7 @@ void RB_body_set_angular_sleep_thresh(rbRigidBody *object, float value)
void RB_body_set_sleep_thresh(rbRigidBody *object, float linear, float angular)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
body->setSleepingThresholds(linear, angular);
}
@@ -498,14 +521,14 @@ void RB_body_set_sleep_thresh(rbRigidBody *object, float linear, float angular)
void RB_body_get_linear_velocity(rbRigidBody *object, float v_out[3])
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
copy_v3_btvec3(v_out, body->getLinearVelocity());
}
void RB_body_set_linear_velocity(rbRigidBody *object, const float v_in[3])
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
body->setLinearVelocity(btVector3(v_in[0], v_in[1], v_in[2]));
}
@@ -513,27 +536,27 @@ void RB_body_set_linear_velocity(rbRigidBody *object, const float v_in[3])
void RB_body_get_angular_velocity(rbRigidBody *object, float v_out[3])
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
copy_v3_btvec3(v_out, body->getAngularVelocity());
}
void RB_body_set_angular_velocity(rbRigidBody *object, const float v_in[3])
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
body->setAngularVelocity(btVector3(v_in[0], v_in[1], v_in[2]));
}
void RB_body_set_linear_factor(rbRigidBody *object, float x, float y, float z)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
body->setLinearFactor(btVector3(x, y, z));
}
void RB_body_set_angular_factor(rbRigidBody *object, float x, float y, float z)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
body->setAngularFactor(btVector3(x, y, z));
}
@@ -541,7 +564,7 @@ void RB_body_set_angular_factor(rbRigidBody *object, float x, float y, float z)
void RB_body_set_kinematic_state(rbRigidBody *object, int kinematic)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
if (kinematic)
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
else
@@ -552,7 +575,7 @@ void RB_body_set_kinematic_state(rbRigidBody *object, int kinematic)
void RB_body_set_activation_state(rbRigidBody *object, int use_deactivation)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
if (use_deactivation)
body->forceActivationState(ACTIVE_TAG);
else
@@ -560,12 +583,12 @@ void RB_body_set_activation_state(rbRigidBody *object, int use_deactivation)
}
void RB_body_activate(rbRigidBody *object)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
body->setActivationState(ACTIVE_TAG);
}
void RB_body_deactivate(rbRigidBody *object)
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
body->setActivationState(ISLAND_SLEEPING);
}
@@ -581,7 +604,7 @@ void RB_body_deactivate(rbRigidBody *object)
void RB_body_get_transform_matrix(rbRigidBody *object, float m_out[4][4])
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
btMotionState *ms = body->getMotionState();
btTransform trans;
@@ -592,7 +615,7 @@ void RB_body_get_transform_matrix(rbRigidBody *object, float m_out[4][4])
void RB_body_set_loc_rot(rbRigidBody *object, const float loc[3], const float rot[4])
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
btMotionState *ms = body->getMotionState();
/* set transform matrix */
@@ -605,7 +628,7 @@ void RB_body_set_loc_rot(rbRigidBody *object, const float loc[3], const float ro
void RB_body_set_scale(rbRigidBody *object, const float scale[3])
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
/* apply scaling factor from matrix above to the collision shape */
btCollisionShape *cshape = body->getCollisionShape();
@@ -623,14 +646,14 @@ void RB_body_set_scale(rbRigidBody *object, const float scale[3])
void RB_body_get_position(rbRigidBody *object, float v_out[3])
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
copy_v3_btvec3(v_out, body->getWorldTransform().getOrigin());
}
void RB_body_get_orientation(rbRigidBody *object, float v_out[4])
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
copy_quat_btquat(v_out, body->getWorldTransform().getRotation());
}
@@ -640,7 +663,7 @@ void RB_body_get_orientation(rbRigidBody *object, float v_out[4])
void RB_body_apply_central_force(rbRigidBody *object, const float v_in[3])
{
btRigidBody *body = object->body;
btRigidBody *body = &object->body;
body->applyCentralForce(btVector3(v_in[0], v_in[1], v_in[2]));
}
@@ -863,8 +886,8 @@ static void make_constraint_transforms(btTransform &transform1, btTransform &tra
rbConstraint *RB_constraint_new_point(float pivot[3], rbRigidBody *rb1, rbRigidBody *rb2)
{
btRigidBody *body1 = rb1->body;
btRigidBody *body2 = rb2->body;
btRigidBody *body1 = &rb1->body;
btRigidBody *body2 = &rb2->body;
btVector3 pivot1 = body1->getWorldTransform().inverse() * btVector3(pivot[0], pivot[1], pivot[2]);
btVector3 pivot2 = body2->getWorldTransform().inverse() * btVector3(pivot[0], pivot[1], pivot[2]);
@@ -876,8 +899,8 @@ rbConstraint *RB_constraint_new_point(float pivot[3], rbRigidBody *rb1, rbRigidB
rbConstraint *RB_constraint_new_fixed(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2)
{
btRigidBody *body1 = rb1->body;
btRigidBody *body2 = rb2->body;
btRigidBody *body1 = &rb1->body;
btRigidBody *body2 = &rb2->body;
btTransform transform1;
btTransform transform2;
@@ -890,8 +913,8 @@ rbConstraint *RB_constraint_new_fixed(float pivot[3], float orn[4], rbRigidBody
rbConstraint *RB_constraint_new_hinge(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2)
{
btRigidBody *body1 = rb1->body;
btRigidBody *body2 = rb2->body;
btRigidBody *body1 = &rb1->body;
btRigidBody *body2 = &rb2->body;
btTransform transform1;
btTransform transform2;
@@ -904,8 +927,8 @@ rbConstraint *RB_constraint_new_hinge(float pivot[3], float orn[4], rbRigidBody
rbConstraint *RB_constraint_new_slider(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2)
{
btRigidBody *body1 = rb1->body;
btRigidBody *body2 = rb2->body;
btRigidBody *body1 = &rb1->body;
btRigidBody *body2 = &rb2->body;
btTransform transform1;
btTransform transform2;
@@ -918,8 +941,8 @@ rbConstraint *RB_constraint_new_slider(float pivot[3], float orn[4], rbRigidBody
rbConstraint *RB_constraint_new_piston(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2)
{
btRigidBody *body1 = rb1->body;
btRigidBody *body2 = rb2->body;
btRigidBody *body1 = &rb1->body;
btRigidBody *body2 = &rb2->body;
btTransform transform1;
btTransform transform2;
@@ -933,8 +956,8 @@ rbConstraint *RB_constraint_new_piston(float pivot[3], float orn[4], rbRigidBody
rbConstraint *RB_constraint_new_6dof(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2)
{
btRigidBody *body1 = rb1->body;
btRigidBody *body2 = rb2->body;
btRigidBody *body1 = &rb1->body;
btRigidBody *body2 = &rb2->body;
btTransform transform1;
btTransform transform2;
@@ -947,8 +970,8 @@ rbConstraint *RB_constraint_new_6dof(float pivot[3], float orn[4], rbRigidBody *
rbConstraint *RB_constraint_new_6dof_spring(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2)
{
btRigidBody *body1 = rb1->body;
btRigidBody *body2 = rb2->body;
btRigidBody *body1 = &rb1->body;
btRigidBody *body2 = &rb2->body;
btTransform transform1;
btTransform transform2;
@@ -961,8 +984,8 @@ rbConstraint *RB_constraint_new_6dof_spring(float pivot[3], float orn[4], rbRigi
rbConstraint *RB_constraint_new_motor(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2)
{
btRigidBody *body1 = rb1->body;
btRigidBody *body2 = rb2->body;
btRigidBody *body1 = &rb1->body;
btRigidBody *body2 = &rb2->body;
btTransform transform1;
btTransform transform2;

View File

@@ -1222,5 +1222,8 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "material_offset", text="Material Offset")
def NPARTICLE_SYSTEM(self, layout, ob, md):
pass
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

View File

@@ -61,10 +61,12 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_modifier_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_nla_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_node_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_nparticle_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_object_fluidsim.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_object_force.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_object_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_outliner_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_pagedbuffer_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_packedFile_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_particle_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_property_types.h

View File

@@ -0,0 +1,133 @@
/*
* ***** 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.
*
* Copyright 2011, Blender Foundation.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BKE_NPARTICLE_H
#define BKE_NPARTICLE_H
/** \file BKE_nparticle.h
* \ingroup bke
*/
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
struct Object;
struct NParticleSystem;
struct NParticleAttribute;
struct NParticleState;
struct NParticleAttributeState;
struct NParticleDisplay;
struct NParticleDisplayDupliObject;
/* XXX where to put this? */
typedef uint32_t NParticleID;
const char *BKE_nparticle_datatype_name(int datatype);
struct NParticleSystem *BKE_nparticle_system_new(void);
void BKE_nparticle_system_free(struct NParticleSystem *psys);
struct NParticleSystem *BKE_nparticle_system_copy(struct NParticleSystem *psys);
void BKE_nparticle_system_set_state(struct NParticleSystem *psys, struct NParticleState *state);
struct NParticleState *BKE_nparticle_state_new(struct NParticleSystem *psys);
struct NParticleState *BKE_nparticle_state_copy(struct NParticleState *state);
void BKE_nparticle_state_free(struct NParticleState *state);
struct NParticleAttribute *BKE_nparticle_attribute_find(struct NParticleSystem *psys, const char *name);
struct NParticleAttribute *BKE_nparticle_attribute_new(struct NParticleSystem *psys, const char *name, int datatype, int flag);
void BKE_nparticle_attribute_remove(struct NParticleSystem *psys, struct NParticleAttribute *attr);
void BKE_nparticle_attribute_remove_all(struct NParticleSystem *psys);
void BKE_nparticle_attribute_move(struct NParticleSystem *psys, int from_index, int to_index);
struct NParticleAttribute *BKE_nparticle_attribute_copy(struct NParticleSystem *to_psys,
struct NParticleSystem *from_psys, struct NParticleAttribute *from_attr);
int BKE_nparticle_state_num_attributes(struct NParticleState *state);
struct NParticleAttributeState *BKE_nparticle_state_find_attribute(struct NParticleState *state, const char *name);
struct NParticleAttributeState *BKE_nparticle_state_get_attribute_by_index(struct NParticleState *state, int index);
int BKE_nparticle_state_num_particles(struct NParticleState *state);
void *BKE_nparticle_attribute_state_data(struct NParticleAttributeState *attrstate, int index);
typedef struct NParticleAttributeStateIterator {
/* XXX for now is simply a pointer, using ListBase next/prev.
* Eventually this will become a hash table iterator.
*/
struct NParticleAttributeState *attrstate;
} NParticleAttributeStateIterator;
void BKE_nparticle_state_attributes_begin(struct NParticleState *state, struct NParticleAttributeStateIterator *iter);
bool BKE_nparticle_state_attribute_iter_valid(struct NParticleAttributeStateIterator *iter);
void BKE_nparticle_state_attribute_iter_next(struct NParticleAttributeStateIterator *iter);
void BKE_nparticle_state_attribute_iter_end(struct NParticleAttributeStateIterator *iter);
int BKE_nparticle_find_index(struct NParticleState *state, NParticleID id);
bool BKE_nparticle_exists(struct NParticleState *state, NParticleID id);
int BKE_nparticle_add(struct NParticleState *state, NParticleID id);
void BKE_nparticle_remove(struct NParticleState *state, NParticleID id);
typedef struct NParticleIterator {
struct NParticleState *state;
int index;
} NParticleIterator;
void BKE_nparticle_iter_init(struct NParticleState *state, struct NParticleIterator *it);
void BKE_nparticle_iter_from_id(struct NParticleState *state, struct NParticleIterator *it, NParticleID id);
void BKE_nparticle_iter_from_index(struct NParticleState *state, struct NParticleIterator *it, int index);
void BKE_nparticle_iter_next(struct NParticleIterator *it);
bool BKE_nparticle_iter_valid(struct NParticleIterator *it);
/*void *BKE_nparticle_iter_get_data(struct NParticleIterator *it, const char *attr);*/
int BKE_nparticle_iter_get_int(struct NParticleIterator *it, const char *attr);
void BKE_nparticle_iter_set_int(struct NParticleIterator *it, const char *attr, int value);
float BKE_nparticle_iter_get_float(struct NParticleIterator *it, const char *attr);
void BKE_nparticle_iter_set_float(struct NParticleIterator *it, const char *attr, float value);
void BKE_nparticle_iter_get_vector(struct NParticleIterator *it, const char *attr, float *result);
void BKE_nparticle_iter_set_vector(struct NParticleIterator *it, const char *attr, const float *value);
void BKE_nparticle_iter_get_quaternion(struct NParticleIterator *it, const char *attr, float *result);
void BKE_nparticle_iter_set_quaternion(struct NParticleIterator *it, const char *attr, const float *value);
void *BKE_nparticle_iter_get_pointer(struct NParticleIterator *it, const char *attr);
void BKE_nparticle_iter_set_pointer(struct NParticleIterator *it, const char *attr, void *value);
BLI_INLINE NParticleID BKE_nparticle_iter_get_id(struct NParticleIterator *it)
{
return (NParticleID)BKE_nparticle_iter_get_int(it, "id");
}
struct NParticleDisplay *BKE_nparticle_display_add(struct NParticleSystem *psys, int type);
struct NParticleDisplay *BKE_nparticle_display_copy(struct NParticleSystem *psys, struct NParticleDisplay *display);
void BKE_nparticle_display_free(struct NParticleSystem *psys, struct NParticleDisplay *display);
/* update object transflag for nparticle duplis */
void BKE_nparticle_update_object_dupli_flags(struct Object *ob, struct NParticleSystem *psys);
struct NParticleDisplayDupliObject *BKE_nparticle_display_dupli_object_add(struct NParticleDisplay *display);
void BKE_nparticle_display_dupli_object_remove(struct NParticleDisplay *display, struct NParticleDisplayDupliObject *dupli_object);
void BKE_nparticle_display_dupli_object_remove_all(struct NParticleDisplay *display);
void BKE_nparticle_display_dupli_object_move(struct NParticleDisplay *display, int from_index, int to_index);
#endif /* BKE_NPARTICLE_H */

View File

@@ -29,13 +29,13 @@
* \ingroup blenkernel
* \brief API for Blender-side Rigid Body stuff
*/
#ifndef __BKE_RIGIDBODY_H__
#define __BKE_RIGIDBODY_H__
struct RigidBodyWorld;
struct RigidBodyOb;
struct rbRigidBody;
struct Scene;
struct Object;
@@ -45,28 +45,24 @@ struct Group;
/* Memory Management */
void BKE_rigidbody_free_world(struct RigidBodyWorld *rbw);
void BKE_rigidbody_free_object(struct Object *ob);
void BKE_rigidbody_free_constraint(struct Object *ob);
/* ...... */
struct RigidBodyOb *BKE_rigidbody_copy_object(struct Object *ob);
struct RigidBodyCon *BKE_rigidbody_copy_constraint(struct Object *ob);
void BKE_rigidbody_relink_constraint(struct RigidBodyCon *rbc);
/* -------------- */
/* Setup */
/* create Blender-side settings data - physics objects not initialized yet */
struct RigidBodyWorld *BKE_rigidbody_create_world(struct Scene *scene);
struct RigidBodyOb *BKE_rigidbody_create_object(struct Scene *scene, struct Object *ob, short type);
struct RigidBodyCon *BKE_rigidbody_create_constraint(struct Scene *scene, struct Object *ob, short type);
/* initialize mempools, for readfile */
void BKE_rigidbody_world_init_mempool(struct RigidBodyWorld *rbw);
/* copy */
struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw);
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw);
/* 'validate' (i.e. make new or replace old) Physics-Engine objects */
struct rbRigidBody *BKE_rigidbody_body_ensure_alloc(struct RigidBodyWorld *rbw, struct rbRigidBody *body, bool rebuild);
void BKE_rigidbody_body_tag_used(struct rbRigidBody *body);
void BKE_rigidbody_validate_sim_shape(Object *ob, bool rebuild);
void BKE_rigidbody_validate_sim_world(struct Scene *scene, struct RigidBodyWorld *rbw, bool rebuild);
void BKE_rigidbody_calc_volume(struct Object *ob, float *r_vol);
@@ -76,27 +72,49 @@ void BKE_rigidbody_calc_center_of_mass(struct Object *ob, float r_com[3]);
/* Utilities */
struct RigidBodyWorld *BKE_rigidbody_get_world(struct Scene *scene);
void BKE_rigidbody_remove_object(struct Scene *scene, struct Object *ob);
void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob);
/* -------------- */
/* Utility Macros */
/* get mass of Rigid Body Object to supply to RigidBody simulators */
#define RBO_GET_MASS(rbo) \
((rbo && ((rbo->type == RBO_TYPE_PASSIVE) || (rbo->flag & RBO_FLAG_KINEMATIC) || (rbo->flag & RBO_FLAG_DISABLED))) ? (0.0f) : (rbo->mass))
/* get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin, convex hull always uses custom margin */
#define RBO_GET_MARGIN(rbo) \
((rbo->flag & RBO_FLAG_USE_MARGIN || rbo->shape == RB_SHAPE_CONVEXH || rbo->shape == RB_SHAPE_TRIMESH || rbo->shape == RB_SHAPE_CONE) ? (rbo->margin) : (0.04f))
/* -------------- */
/* Simulation */
void BKE_rigidbody_aftertrans_update(struct Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle);
void BKE_rigidbody_sync_transforms(struct RigidBodyWorld *rbw, struct Object *ob, float ctime);
bool BKE_rigidbody_check_sim_running(struct RigidBodyWorld *rbw, float ctime);
void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw);
void BKE_rigidbody_rebuild_world(struct Scene *scene, float ctime);
void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime);
/* -------------- */
/* Objects (rigidbody_objects.c) */
/* Main Simulation Sync */
void BKE_rigidbody_objects_build(struct Scene *scene, struct RigidBodyWorld *rbw, bool rebuild);
void BKE_rigidbody_objects_apply(struct Scene *scene, struct RigidBodyWorld *rbw);
void BKE_rigidbody_constraints_build(struct Scene *scene, struct RigidBodyWorld *rbw, bool rebuild);
void BKE_rigidbody_constraints_apply(struct Scene *scene, struct RigidBodyWorld *rbw);
/* Transform Utils */
void BKE_rigidbody_object_aftertrans_update(struct Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle);
void BKE_rigidbody_object_apply_transforms(struct RigidBodyWorld *rbw, struct Object *ob, float ctime);
/* Object Data Management */
struct RigidBodyOb *BKE_rigidbody_create_object(struct Scene *scene, struct Object *ob, short type);
void BKE_rigidbody_remove_object(struct Scene *scene, struct Object *ob);
void BKE_rigidbody_free_object(struct Object *ob);
struct RigidBodyOb *BKE_rigidbody_copy_object(struct Object *ob);
struct RigidBodyCon *BKE_rigidbody_create_constraint(struct Scene *scene, struct Object *ob, short type);
void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob);
void BKE_rigidbody_free_constraint(struct Object *ob);
struct RigidBodyCon *BKE_rigidbody_copy_constraint(struct Object *ob);
void BKE_rigidbody_relink_constraint(struct RigidBodyCon *rbc);
/* Utilities */
/* get mass of Rigid Body Object to supply to RigidBody simulators */
float BKE_rigidbody_object_mass(struct RigidBodyOb *rbo);
/* get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin, convex hull always uses custom margin */
float BKE_rigidbody_object_margin(struct RigidBodyOb *rbo);
#endif /* __BKE_RIGIDBODY_H__ */

View File

@@ -125,6 +125,7 @@ set(SRC
intern/multires.c
intern/nla.c
intern/node.c
intern/nparticle.c
intern/object.c
intern/object_deform.c
intern/object_dupli.c
@@ -139,6 +140,7 @@ set(SRC
intern/property.c
intern/report.c
intern/rigidbody.c
intern/rigidbody_objects.c
intern/sca.c
intern/scene.c
intern/screen.c
@@ -230,6 +232,7 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
BKE_nparticle.h
BKE_object.h
BKE_object_deform.h
BKE_ocean.h

View File

@@ -0,0 +1,759 @@
/*
* ***** 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.
*
* Copyright 2011, Blender Foundation.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/nparticle.c
* \ingroup bke
*/
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h" /* XXX stupid, needed by ghash, should be included there ... */
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_pagedbuffer.h"
#include "BLI_string.h"
#include "DNA_nparticle_types.h"
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
#include "BKE_nparticle.h"
#include "BKE_rigidbody.h"
/* XXX TODO make this configurable */
#define PAGE_BYTES 65536
const char *BKE_nparticle_datatype_name(int datatype)
{
switch (datatype) {
case PAR_ATTR_DATATYPE_INTERNAL: return "internal";
case PAR_ATTR_DATATYPE_FLOAT: return "float";
case PAR_ATTR_DATATYPE_INT: return "int";
case PAR_ATTR_DATATYPE_BOOL: return "bool";
case PAR_ATTR_DATATYPE_VECTOR: return "vector";
case PAR_ATTR_DATATYPE_POINT: return "point";
case PAR_ATTR_DATATYPE_NORMAL: return "normal";
case PAR_ATTR_DATATYPE_QUATERNION: return "quaternion";
case PAR_ATTR_DATATYPE_COLOR: return "color";
case PAR_ATTR_DATATYPE_MATRIX: return "matrix";
case PAR_ATTR_DATATYPE_POINTER: return "pointer";
default: return "";
}
}
static size_t nparticle_elem_bytes(int datatype)
{
switch (datatype) {
case PAR_ATTR_DATATYPE_FLOAT: return sizeof(float);
case PAR_ATTR_DATATYPE_INT: return sizeof(int);
case PAR_ATTR_DATATYPE_BOOL: return sizeof(bool);
case PAR_ATTR_DATATYPE_VECTOR:
case PAR_ATTR_DATATYPE_POINT:
case PAR_ATTR_DATATYPE_NORMAL:
return sizeof(float)*3;
case PAR_ATTR_DATATYPE_QUATERNION: return sizeof(float)*4;
case PAR_ATTR_DATATYPE_COLOR: return sizeof(float)*4;
case PAR_ATTR_DATATYPE_MATRIX: return sizeof(float)*16;
case PAR_ATTR_DATATYPE_POINTER: return sizeof(void*);
default:
BLI_assert(false); /* unknown datatype, should never happen */
return 0;
}
}
static void nparticle_attribute_state_init(NParticleAttribute *attr, NParticleAttributeState *attrstate)
{
attrstate->desc = attr->desc;
attrstate->hashkey = BLI_ghashutil_strhash(attr->desc.name);
BLI_pbuf_init(&attrstate->data, PAGE_BYTES, nparticle_elem_bytes(attr->desc.datatype));
}
static void nparticle_attribute_state_free(NParticleAttributeState *state)
{
BLI_pbuf_free(&state->data);
}
static void nparticle_attribute_state_copy(NParticleAttributeState *to, NParticleAttributeState *from)
{
to->desc = from->desc;
to->hashkey = from->hashkey;
BLI_pbuf_copy(&to->data, &from->data);
}
static NParticleAttributeState *nparticle_state_add_attribute(NParticleState *state, NParticleAttribute *attr)
{
NParticleAttributeState *attrstate = MEM_callocN(sizeof(NParticleAttributeState), "particle attribute state");
nparticle_attribute_state_init(attr, attrstate);
BLI_addtail(&state->attributes, attrstate);
return attrstate;
}
static void nparticle_state_remove_attribute(NParticleState *state, const char *name)
{
NParticleAttributeState *attrstate = BKE_nparticle_state_find_attribute(state, name);
if (attrstate) {
BLI_remlink(&state->attributes, attrstate);
nparticle_attribute_state_free(attrstate);
MEM_freeN(attrstate);
}
}
static void nparticle_state_clear(NParticleState *state)
{
NParticleAttributeState *attrstate;
for (attrstate = state->attributes.first; attrstate; attrstate = attrstate->next)
nparticle_attribute_state_free(attrstate);
BLI_freelistN(&state->attributes);
}
static void nparticle_system_sync_state_attributes(NParticleSystem *psys, NParticleState *state)
{
NParticleAttribute *attr;
NParticleAttributeState *attrstate, *attrstate_next;
for (attrstate = state->attributes.first; attrstate; attrstate = attrstate->next)
attrstate->flag &= ~PAR_ATTR_STATE_TEST;
for (attr = psys->attributes.first; attr; attr = attr->next) {
attrstate = BKE_nparticle_state_find_attribute(state, attr->desc.name);
/* add missing attributes */
if (!attrstate) {
attrstate = nparticle_state_add_attribute(state, attr);
}
attrstate->flag |= PAR_ATTR_STATE_TEST;
}
/* remove unused attribute states */
for (attrstate = state->attributes.first; attrstate; attrstate = attrstate_next) {
attrstate_next = attrstate->next;
if (!(attrstate->flag & PAR_ATTR_STATE_TEST)) {
BLI_remlink(&state->attributes, attrstate);
nparticle_attribute_state_free(attrstate);
MEM_freeN(attrstate);
}
}
}
static void nparticle_system_default_attributes(NParticleSystem *psys)
{
/* required attributes */
BKE_nparticle_attribute_new(psys, "id", PAR_ATTR_DATATYPE_INT, PAR_ATTR_REQUIRED | PAR_ATTR_READONLY);
/* common attributes */
BKE_nparticle_attribute_new(psys, "position", PAR_ATTR_DATATYPE_POINT, PAR_ATTR_PROTECTED);
BKE_nparticle_attribute_new(psys, "rotation", PAR_ATTR_DATATYPE_QUATERNION, PAR_ATTR_PROTECTED);
/* XXX bullet RB pointers, this should be based on actual simulation settings and requirements */
BKE_nparticle_attribute_new(psys, "rigid_body", PAR_ATTR_DATATYPE_POINTER, PAR_ATTR_PROTECTED | PAR_ATTR_TEMPORARY);
}
NParticleSystem *BKE_nparticle_system_new(void)
{
NParticleSystem *psys = MEM_callocN(sizeof(NParticleSystem), "nparticle system");
nparticle_system_default_attributes(psys);
psys->state = BKE_nparticle_state_new(psys);
return psys;
}
void BKE_nparticle_system_free(NParticleSystem *psys)
{
NParticleDisplay *display, *display_next;
BKE_nparticle_attribute_remove_all(psys);
BKE_nparticle_state_free(psys->state);
for (display = psys->display.first; display; display = display_next) {
display_next = display->next;
BKE_nparticle_display_free(psys, display);
}
MEM_freeN(psys);
}
NParticleSystem *BKE_nparticle_system_copy(NParticleSystem *psys)
{
NParticleSystem *npsys = MEM_dupallocN(psys);
NParticleAttribute *attr, *nattr;
NParticleDisplay *display;
npsys->attributes.first = npsys->attributes.last = NULL;
for (attr = psys->attributes.first; attr; attr = attr->next) {
nattr = BKE_nparticle_attribute_copy(npsys, psys, attr);
}
if (psys->state)
npsys->state = BKE_nparticle_state_copy(psys->state);
npsys->display.first = npsys->display.last = NULL;
for (display = psys->display.first; display; display = display->next) {
BKE_nparticle_display_copy(npsys, display);
}
return npsys;
}
void BKE_nparticle_system_set_state(NParticleSystem *psys, NParticleState *state)
{
if (state) {
if (psys->state)
BKE_nparticle_state_free(psys->state);
psys->state = BKE_nparticle_state_copy(state);
}
}
NParticleState *BKE_nparticle_state_new(NParticleSystem *psys)
{
NParticleState *state = MEM_callocN(sizeof(NParticleState), "particle state");
nparticle_system_sync_state_attributes(psys, state);
return state;
}
NParticleState *BKE_nparticle_state_copy(NParticleState *state)
{
NParticleState *nstate = MEM_dupallocN(state);
NParticleAttributeState *attrstate, *nattrstate;
BLI_duplicatelist(&state->attributes, &nstate->attributes);
for (attrstate = state->attributes.first, nattrstate = nstate->attributes.first;
attrstate;
attrstate = attrstate->next, nattrstate = nattrstate->next)
nparticle_attribute_state_copy(nattrstate, attrstate);
nstate->py_handle = NULL;
return nstate;
}
void BKE_nparticle_state_free(NParticleState *state)
{
NParticleAttributeState *attrstate;
for (attrstate = state->attributes.first; attrstate; attrstate = attrstate->next)
nparticle_attribute_state_free(attrstate);
BLI_freelistN(&state->attributes);
MEM_freeN(state);
}
void BKE_nparticle_state_attributes_begin(NParticleState *state, NParticleAttributeStateIterator *iter)
{
iter->attrstate = state->attributes.first;
}
bool BKE_nparticle_state_attribute_iter_valid(NParticleAttributeStateIterator *iter)
{
return (iter->attrstate != NULL);
}
void BKE_nparticle_state_attribute_iter_next(NParticleAttributeStateIterator *iter)
{
iter->attrstate = iter->attrstate->next;
}
void BKE_nparticle_state_attribute_iter_end(NParticleAttributeStateIterator *iter)
{
iter->attrstate = NULL;
}
NParticleAttribute *BKE_nparticle_attribute_find(NParticleSystem *psys, const char *name)
{
NParticleAttribute *attr;
for (attr = psys->attributes.first; attr; attr = attr->next)
if (STREQ(attr->desc.name, name))
return attr;
return NULL;
}
NParticleAttribute *BKE_nparticle_attribute_new(NParticleSystem *psys, const char *name, int datatype, int flag)
{
NParticleAttribute *attr;
attr = BKE_nparticle_attribute_find(psys, name);
if (attr) {
/* if attribute with the same name exists, remove it first */
BKE_nparticle_attribute_remove(psys, attr);
}
attr = MEM_callocN(sizeof(NParticleAttribute), "particle system attribute");
BLI_strncpy(attr->desc.name, name, sizeof(attr->desc.name));
attr->desc.datatype = datatype;
attr->desc.flag = flag;
/* some data types should have more usable defaults
* without explicitly setting them.
*/
switch (datatype) {
case PAR_ATTR_DATATYPE_NORMAL:
((float*)attr->desc.default_value)[2] = 1.0f;
break;
case PAR_ATTR_DATATYPE_QUATERNION:
unit_qt((float*)attr->desc.default_value);
break;
case PAR_ATTR_DATATYPE_COLOR:
((float*)attr->desc.default_value)[3] = 1.0f;
break;
case PAR_ATTR_DATATYPE_MATRIX:
unit_m4((float(*)[4])attr->desc.default_value);
break;
}
BLI_addtail(&psys->attributes, attr);
if (psys->state)
nparticle_state_add_attribute(psys->state, attr);
return attr;
}
void BKE_nparticle_attribute_remove(NParticleSystem *psys, NParticleAttribute *attr)
{
if (psys->state)
nparticle_state_remove_attribute(psys->state, attr->desc.name);
BLI_remlink(&psys->attributes, attr);
MEM_freeN(attr);
}
void BKE_nparticle_attribute_remove_all(NParticleSystem *psys)
{
NParticleAttribute *attr, *attr_next;
if (psys->state)
nparticle_state_clear(psys->state);
for (attr = psys->attributes.first; attr; attr = attr_next) {
attr_next = attr->next;
MEM_freeN(attr);
}
psys->attributes.first = psys->attributes.last = NULL;
}
NParticleAttribute *BKE_nparticle_attribute_copy(NParticleSystem *to_psys, NParticleSystem *UNUSED(from_psys), NParticleAttribute *from_attr)
{
NParticleAttribute *to_attr = MEM_dupallocN(from_attr);
BLI_addtail(&to_psys->attributes, to_attr);
if (to_psys->state)
nparticle_state_add_attribute(to_psys->state, to_attr);
return to_attr;
}
void BKE_nparticle_attribute_move(NParticleSystem *psys, int from_index, int to_index)
{
NParticleAttribute *attr;
if (from_index == to_index)
return;
if (from_index < 0 || to_index < 0)
return;
attr = BLI_findlink(&psys->attributes, from_index);
if (to_index < from_index) {
NParticleAttribute *nextattr = BLI_findlink(&psys->attributes, to_index);
if (nextattr) {
BLI_remlink(&psys->attributes, attr);
BLI_insertlinkbefore(&psys->attributes, nextattr, attr);
}
}
else {
NParticleAttribute *prevattr = BLI_findlink(&psys->attributes, to_index);
if (prevattr) {
BLI_remlink(&psys->attributes, attr);
BLI_insertlinkafter(&psys->attributes, prevattr, attr);
}
}
}
int BKE_nparticle_state_num_attributes(NParticleState *state)
{
return BLI_countlist(&state->attributes);
}
NParticleAttributeState *BKE_nparticle_state_find_attribute(NParticleState *state, const char *name)
{
int hashkey = BLI_ghashutil_strhash(name);
NParticleAttributeState *attrstate;
for (attrstate = state->attributes.first; attrstate; attrstate = attrstate->next)
if (attrstate->hashkey == hashkey)
return attrstate;
return NULL;
}
BLI_INLINE NParticleAttributeState *nparticle_state_find_attribute_id(NParticleState *state)
{
return BKE_nparticle_state_find_attribute(state, "id");
}
NParticleAttributeState *BKE_nparticle_state_get_attribute_by_index(NParticleState *state, int index)
{
return BLI_findlink(&state->attributes, index);
}
int BKE_nparticle_state_num_particles(NParticleState *state)
{
NParticleAttributeState *attrstate = nparticle_state_find_attribute_id(state);
return attrstate ? attrstate->data.totelem : 0;
}
void *BKE_nparticle_attribute_state_data(NParticleAttributeState *attrstate, int index)
{
return BLI_pbuf_get(&attrstate->data, index);
}
int BKE_nparticle_find_index(NParticleState *state, NParticleID id)
{
NParticleAttributeState *attrstate = nparticle_state_find_attribute_id(state);
if (attrstate) {
bPagedBuffer *pbuf = &attrstate->data;
bPagedBufferIterator it;
for (BLI_pbuf_iter_init(pbuf, &it); BLI_pbuf_iter_valid(pbuf, &it); BLI_pbuf_iter_next(pbuf, &it)) {
if (*(int*)it.data == id)
return it.index;
}
}
return -1;
}
bool BKE_nparticle_exists(NParticleState *state, NParticleID id)
{
return BKE_nparticle_find_index(state, id) >= 0;
}
static bool nparticle_attribute_is_id(NParticleAttributeDescription *desc)
{
return STREQ(desc->name, "id");
}
int BKE_nparticle_add(NParticleState *state, NParticleID id)
{
int index = BKE_nparticle_find_index(state, id);
if (index < 0) {
NParticleAttributeState *attrstate;
for (attrstate = state->attributes.first; attrstate; attrstate = attrstate->next) {
BLI_pbuf_add_elements(&attrstate->data, 1);
index = attrstate->data.totelem - 1;
if (nparticle_attribute_is_id(&attrstate->desc)) {
*(int*)BLI_pbuf_get(&attrstate->data, index) = (int)id;
}
else {
memcpy(BLI_pbuf_get(&attrstate->data, index), attrstate->desc.default_value, attrstate->data.elem_bytes);
}
}
}
return index;
}
void BKE_nparticle_remove(NParticleState *state, NParticleID id)
{
int index = BKE_nparticle_find_index(state, id);
if (index >= 0) {
NParticleAttributeState *attrstate;
for (attrstate = state->attributes.first; attrstate; attrstate = attrstate->next) {
/* XXX TODO paged buffer doesn't support removing yet */
// BLI_pbuf_remove_elements(&attrstate->data, index);
}
}
}
void BKE_nparticle_iter_init(NParticleState *state, NParticleIterator *it)
{
it->state = state;
it->index = 0;
}
void BKE_nparticle_iter_from_id(NParticleState *state, NParticleIterator *it, NParticleID id)
{
it->state = state;
it->index = BKE_nparticle_find_index(state, id);
}
void BKE_nparticle_iter_from_index(NParticleState *state, NParticleIterator *it, int index)
{
NParticleAttributeState *attrstate = nparticle_state_find_attribute_id(state);
it->state = state;
if (index >= 0 && attrstate && index < attrstate->data.totelem)
it->index = index;
else
it->index = -1;
}
void BKE_nparticle_iter_next(NParticleIterator *it)
{
++it->index;
}
bool BKE_nparticle_iter_valid(NParticleIterator *it)
{
NParticleAttributeState *attrstate = nparticle_state_find_attribute_id(it->state);
if (attrstate)
return it->index >= 0 && it->index < attrstate->data.totelem;
else
return false;
}
BLI_INLINE void *nparticle_data_ptr(NParticleState *state, const char *name, int index)
{
NParticleAttributeState *attrstate = BKE_nparticle_state_find_attribute(state, name);
if (attrstate)
return BLI_pbuf_get(&attrstate->data, index);
else
return NULL;
}
BLI_INLINE bool nparticle_check_attribute_type(NParticleState *state, const char *name, eParticleAttributeDataType datatype)
{
/* sanity check to ensure the retrieved data attribute has the correct type.
* only happens in debug, no overhead created for release builds.
*/
NParticleAttributeState *attrstate = BKE_nparticle_state_find_attribute(state, name);
return !attrstate || attrstate->desc.datatype == datatype;
}
#if 0 /* unused */
void *BKE_nparticle_iter_get_data(struct NParticleIterator *it, const char *attr)
{
return nparticle_data_ptr(it->state, attr, it->index);
}
#endif
int BKE_nparticle_iter_get_int(NParticleIterator *it, const char *attr)
{
int *data = nparticle_data_ptr(it->state, attr, it->index);
BLI_assert(nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_INT));
return data ? *data : 0;
}
void BKE_nparticle_iter_set_int(NParticleIterator *it, const char *attr, int value)
{
int *data = nparticle_data_ptr(it->state, attr, it->index);
BLI_assert(nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_INT));
if (data)
*data = value;
}
float BKE_nparticle_iter_get_float(NParticleIterator *it, const char *attr)
{
float *data = nparticle_data_ptr(it->state, attr, it->index);
BLI_assert(nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_FLOAT));
return data ? *data : 0.0f;
}
void BKE_nparticle_iter_set_float(NParticleIterator *it, const char *attr, float value)
{
float *data = nparticle_data_ptr(it->state, attr, it->index);
BLI_assert(nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_FLOAT));
if (data)
*data = value;
}
void BKE_nparticle_iter_get_vector(NParticleIterator *it, const char *attr, float *result)
{
float *data = nparticle_data_ptr(it->state, attr, it->index);
BLI_assert(nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_VECTOR)
|| nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_POINT)
|| nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_NORMAL));
if (data)
copy_v3_v3(result, data);
else
zero_v3(result);
}
void BKE_nparticle_iter_set_vector(NParticleIterator *it, const char *attr, const float *value)
{
float *data = nparticle_data_ptr(it->state, attr, it->index);
BLI_assert(nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_VECTOR)
|| nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_POINT)
|| nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_NORMAL));
if (data)
copy_v3_v3(data, value);
}
void BKE_nparticle_iter_get_quaternion(NParticleIterator *it, const char *attr, float *result)
{
float *data = nparticle_data_ptr(it->state, attr, it->index);
BLI_assert(nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_QUATERNION));
if (data)
copy_qt_qt(result, data);
else
unit_qt(result);
}
void BKE_nparticle_iter_set_quaternion(NParticleIterator *it, const char *attr, const float *value)
{
float *data = nparticle_data_ptr(it->state, attr, it->index);
BLI_assert(nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_QUATERNION));
if (data)
copy_qt_qt(data, value);
}
void *BKE_nparticle_iter_get_pointer(NParticleIterator *it, const char *attr)
{
void **data = nparticle_data_ptr(it->state, attr, it->index);
BLI_assert(nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_POINTER));
return data ? *data : NULL;
}
void BKE_nparticle_iter_set_pointer(NParticleIterator *it, const char *attr, void *value)
{
void **data = nparticle_data_ptr(it->state, attr, it->index);
BLI_assert(nparticle_check_attribute_type(it->state, attr, PAR_ATTR_DATATYPE_POINTER));
if (data)
*data = value;
}
NParticleDisplay *BKE_nparticle_display_add(NParticleSystem *psys, int type)
{
NParticleDisplay *display = MEM_callocN(sizeof(NParticleDisplay), "particle display");
display->type = type;
switch (type) {
case PAR_DISPLAY_PARTICLE:
BLI_strncpy(display->attribute, "position", sizeof(display->attribute));
break;
}
BLI_addtail(&psys->display, display);
return display;
}
NParticleDisplay *BKE_nparticle_display_copy(NParticleSystem *psys, NParticleDisplay *display)
{
NParticleDisplay *ndisplay = MEM_dupallocN(display);
BLI_addtail(&psys->display, display);
return ndisplay;
}
void BKE_nparticle_display_free(NParticleSystem *psys, NParticleDisplay *display)
{
BLI_remlink(&psys->display, display);
switch (display->type) {
case PAR_DISPLAY_DUPLI: {
NParticleDisplayDupliObject *dob, *dob_next;
for (dob = display->dupli_objects.first; dob; dob = dob_next) {
dob_next = dob->next;
MEM_freeN(dob);
}
break;
}
}
MEM_freeN(display);
}
void BKE_nparticle_update_object_dupli_flags(Object *ob, NParticleSystem *psys)
{
NParticleDisplay *display;
ob->transflag &= ~OB_DUPLI_NPARTICLE;
for (display = psys->display.first; display; display = display->next) {
if (display->type == PAR_DISPLAY_DUPLI)
ob->transflag |= OB_DUPLI_NPARTICLE;
}
}
NParticleDisplayDupliObject *BKE_nparticle_display_dupli_object_add(NParticleDisplay *display)
{
NParticleDisplayDupliObject *dob;
BLI_assert(display->type == PAR_DISPLAY_DUPLI);
dob = MEM_callocN(sizeof(NParticleDisplayDupliObject), "particle dupli object");
BLI_addtail(&display->dupli_objects, dob);
return dob;
}
void BKE_nparticle_display_dupli_object_remove(NParticleDisplay *display, NParticleDisplayDupliObject *dupli_object)
{
BLI_assert(display->type == PAR_DISPLAY_DUPLI);
BLI_remlink(&display->dupli_objects, dupli_object);
MEM_freeN(dupli_object);
}
void BKE_nparticle_display_dupli_object_remove_all(NParticleDisplay *display)
{
NParticleDisplayDupliObject *dob, *dob_next;
BLI_assert(display->type == PAR_DISPLAY_DUPLI);
for (dob = display->dupli_objects.first; dob; dob = dob_next) {
dob_next = dob->next;
MEM_freeN(dob);
}
display->dupli_objects.first = display->dupli_objects.last = NULL;
}
void BKE_nparticle_display_dupli_object_move(NParticleDisplay *display, int from_index, int to_index)
{
NParticleDisplayDupliObject *dob;
BLI_assert(display->type == PAR_DISPLAY_DUPLI);
if (from_index == to_index)
return;
if (from_index < 0 || to_index < 0)
return;
dob = BLI_findlink(&display->dupli_objects, from_index);
if (to_index < from_index) {
NParticleDisplayDupliObject *nextdob = BLI_findlink(&display->dupli_objects, to_index);
if (nextdob) {
BLI_remlink(&display->dupli_objects, dob);
BLI_insertlinkbefore(&display->dupli_objects, nextdob, dob);
}
}
else {
NParticleDisplayDupliObject *prevdob = BLI_findlink(&display->dupli_objects, to_index);
if (prevdob) {
BLI_remlink(&display->dupli_objects, dob);
BLI_insertlinkafter(&display->dupli_objects, prevdob, dob);
}
}
}

View File

@@ -95,6 +95,7 @@
#include "BKE_editmesh.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
#include "BKE_nparticle.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
@@ -2333,7 +2334,7 @@ void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime,
/* try to fall back to the scene rigid body world if none given */
rbw = rbw ? rbw : scene->rigidbody_world;
/* read values pushed into RBO from sim/cache... */
BKE_rigidbody_sync_transforms(rbw, ob, ctime);
BKE_rigidbody_object_apply_transforms(rbw, ob, ctime);
/* solve constraints */
if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) {
@@ -2885,6 +2886,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
AnimData *adt = BKE_animdata_from_id(data_id);
Key *key;
float ctime = BKE_scene_frame_get(scene);
ModifierData *md;
if (G.debug & G_DEBUG_DEPSGRAPH)
printf("recalcdata %s\n", ob->id.name + 2);
@@ -3020,7 +3022,15 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
}
}
/* nparticles */
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_NParticleSystem) {
NParticleSystemModifierData *pmd = (NParticleSystemModifierData*)md;
BKE_nparticle_update_object_dupli_flags(ob, pmd->psys);
}
}
/* quick cache removed */
}

View File

@@ -44,6 +44,9 @@
#include "DNA_anim_types.h"
#include "DNA_group_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_nparticle_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
@@ -56,6 +59,7 @@
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_nparticle.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
@@ -1139,6 +1143,66 @@ const DupliGenerator gen_dupli_particles = {
/* ------------- */
/* OB_DUPLIPARTS */
static void make_duplis_nparticle_system(const DupliContext *ctx, NParticleSystem *psys, NParticleDisplay *display)
{
NParticleIterator iter;
NParticleDisplayDupliObject *dupli, *dob;
int totdupli, i;
float loc[3], rot[4], scale[3], obmat[4][4];
/* for faster index-based lookup make a temp array */
totdupli = BLI_countlist(&display->dupli_objects);
dupli = MEM_mallocN((unsigned int)totdupli * sizeof(NParticleDisplayDupliObject), "dupli objects");
for (dob = display->dupli_objects.first, i = 0; dob; dob = dob->next, ++i)
memcpy(&dupli[i], dob, sizeof(NParticleDisplayDupliObject));
scale[0] = scale[1] = scale[2] = 1.0f;
for (BKE_nparticle_iter_init(psys->state, &iter); BKE_nparticle_iter_valid(&iter); BKE_nparticle_iter_next(&iter)) {
i = BKE_nparticle_iter_get_int(&iter, "dupli");
if (i < 0 || i >= totdupli || dupli[i].object==NULL)
continue;
BKE_nparticle_iter_get_vector(&iter, "position", loc);
BKE_nparticle_iter_get_quaternion(&iter, "rotation", rot);
loc_quat_size_to_mat4(obmat, loc, rot, scale);
make_dupli(ctx, dupli[i].object, obmat, (int)BKE_nparticle_iter_get_id(&iter), false, false);
}
MEM_freeN(dupli);
}
static void make_duplis_nparticles(const DupliContext *ctx)
{
ModifierData *md;
int pmd_index = 0; /* XXX not really a persistent index, but modifier is only stop-gap design anyway */
for (md = ctx->object->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_NParticleSystem) {
NParticleSystemModifierData *pmd = (NParticleSystemModifierData *)md;
NParticleDisplay *display;
/* particles create one more level for persistent psys index */
DupliContext pctx;
copy_dupli_context(&pctx, ctx, ctx->object, NULL, pmd_index, false);
for (display = pmd->psys->display.first; display; display = display->next) {
if (display->type == PAR_DISPLAY_DUPLI)
make_duplis_nparticle_system(&pctx, pmd->psys, display);
}
++pmd_index;
}
}
}
const DupliGenerator gen_dupli_nparticles = {
OB_DUPLI_NPARTICLE, /* type */
make_duplis_nparticles /* make_duplis */
};
/* ------------- */
/* select dupli generator from given context */
static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
{
@@ -1155,6 +1219,9 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
if (transflag & OB_DUPLIPARTS) {
return &gen_dupli_particles;
}
else if (transflag & OB_DUPLI_NPARTICLE) {
return &gen_dupli_nparticles;
}
else if (transflag & OB_DUPLIVERTS) {
if (ctx->object->type == OB_MESH) {
return &gen_dupli_verts;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,863 @@
/*
* ***** 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.
*
* Contributor(s): Joshua Leung, Sergej Reich, Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file rigidbody_objects.c
* \ingroup blenkernel
* \brief Rigid body object simulation
*/
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#ifdef WITH_BULLET
# include "RBI_api.h"
#endif
#include "DNA_group_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_object.h"
#include "BKE_rigidbody.h"
/* ------------------------ */
/* Main Simulation Sync */
static void rigidbody_sync_object(Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
{
float loc[3];
float rot[4];
float scale[3];
/* only update if rigid body exists */
if (rbo->physics_object == NULL)
return;
if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) {
DerivedMesh *dm = ob->derivedDeform;
if (dm) {
MVert *mvert = dm->getVertArray(dm);
int totvert = dm->getNumVerts(dm);
BoundBox *bb = BKE_object_boundbox_get(ob);
RB_shape_trimesh_update(rbo->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]);
}
}
mat4_decompose(loc, rot, scale, ob->obmat);
/* update scale for all objects */
RB_body_set_scale(rbo->physics_object, scale);
/* compensate for embedded convex hull collision margin */
if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH)
RB_shape_set_margin(rbo->physics_shape, BKE_rigidbody_object_margin(rbo) * MIN3(scale[0], scale[1], scale[2]));
/* make transformed objects temporarily kinmatic so that they can be moved by the user during simulation */
if (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) {
RB_body_set_kinematic_state(rbo->physics_object, true);
RB_body_set_mass(rbo->physics_object, 0.0f);
}
/* update rigid body location and rotation for kinematic bodies */
if (rbo->flag & RBO_FLAG_KINEMATIC || (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) {
RB_body_activate(rbo->physics_object);
RB_body_set_loc_rot(rbo->physics_object, loc, rot);
}
/* update influence of effectors - but don't do it on an effector */
/* only dynamic bodies need effector update */
else if (rbo->type == RBO_TYPE_ACTIVE && ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
EffectorWeights *effector_weights = rbw->effector_weights;
EffectedPoint epoint;
ListBase *effectors;
/* get effectors present in the group specified by effector_weights */
effectors = pdInitEffectors(scene, ob, NULL, effector_weights, true);
if (effectors) {
float eff_force[3] = {0.0f, 0.0f, 0.0f};
float eff_loc[3], eff_vel[3];
/* create dummy 'point' which represents last known position of object as result of sim */
// XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals?
RB_body_get_position(rbo->physics_object, eff_loc);
RB_body_get_linear_velocity(rbo->physics_object, eff_vel);
pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);
/* calculate net force of effectors, and apply to sim object
* - we use 'central force' since apply force requires a "relative position" which we don't have...
*/
pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
if (G.f & G_DEBUG)
printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2);
/* activate object in case it is deactivated */
if (!is_zero_v3(eff_force))
RB_body_activate(rbo->physics_object);
RB_body_apply_central_force(rbo->physics_object, eff_force);
}
else if (G.f & G_DEBUG)
printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
/* cleanup */
pdEndEffectors(&effectors);
}
/* NOTE: passive objects don't need to be updated since they don't move */
/* NOTE: no other settings need to be explicitly updated here,
* since RNA setters take care of the rest :)
*/
}
/**
* Create physics sim representation of object given RigidBody settings
*
* \param rebuild Even if an instance already exists, replace it
*/
static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool rebuild)
{
RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL;
rbRigidBody *body;
float loc[3];
float rot[4];
/* sanity checks:
* - object doesn't have RigidBody info already: then why is it here?
*/
if (rbo == NULL)
return;
/* make sure collision shape exists */
/* FIXME we shouldn't always have to rebuild collision shapes when rebuilding objects, but it's needed for constraints to update correctly */
if (rbo->physics_shape == NULL || rebuild)
BKE_rigidbody_validate_sim_shape(ob, true);
rbo->physics_object = BKE_rigidbody_body_ensure_alloc(rbw, rbo->physics_object, rebuild);
body = rbo->physics_object; /* shortcut */
mat4_to_loc_quat(loc, rot, ob->obmat);
RB_body_init(body, rbo->physics_shape, loc, rot);
RB_body_set_friction(body, rbo->friction);
RB_body_set_restitution(body, rbo->restitution);
RB_body_set_damping(body, rbo->lin_damping, rbo->ang_damping);
RB_body_set_sleep_thresh(body, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh);
RB_body_set_activation_state(body, rbo->flag & RBO_FLAG_USE_DEACTIVATION);
if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED)
RB_body_deactivate(body);
RB_body_set_linear_factor(body,
(ob->protectflag & OB_LOCK_LOCX) == 0,
(ob->protectflag & OB_LOCK_LOCY) == 0,
(ob->protectflag & OB_LOCK_LOCZ) == 0);
RB_body_set_angular_factor(body,
(ob->protectflag & OB_LOCK_ROTX) == 0,
(ob->protectflag & OB_LOCK_ROTY) == 0,
(ob->protectflag & OB_LOCK_ROTZ) == 0);
RB_body_set_mass(body, BKE_rigidbody_object_mass(rbo));
RB_body_set_kinematic_state(body, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
if (rbw && rbw->physics_world)
RB_dworld_add_body(rbw->physics_world, rbo->physics_object, rbo->col_groups);
}
void BKE_rigidbody_objects_build(Scene *scene, struct RigidBodyWorld *rbw, bool rebuild)
{
GroupObject *go;
for (go = rbw->group->gobject.first; go; go = go->next) {
Object *ob = go->ob;
RigidBodyOb *rbo;
if (!ob || ob->type != OB_MESH)
continue;
/* validate that we've got valid object set up here... */
rbo = ob->rigidbody_object;
/* update transformation matrix of the object so we don't get a frame of lag for simple animations */
BKE_object_where_is_calc(scene, ob);
if (rbo == NULL) {
/* Since this object is included in the sim group but doesn't have
* rigid body settings (perhaps it was added manually), add!
* - assume object to be active? That is the default for newly added settings...
*/
ob->rigidbody_object = BKE_rigidbody_create_object(scene, ob, RBO_TYPE_ACTIVE);
rigidbody_validate_sim_object(rbw, ob, true);
rbo = ob->rigidbody_object;
}
else {
/* perform simulation data updates as tagged */
/* refresh object... */
if (rebuild) {
/* World has been rebuilt so rebuild object */
rigidbody_validate_sim_object(rbw, ob, true);
}
else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) {
rigidbody_validate_sim_object(rbw, ob, false);
}
/* refresh shape... */
if (rbo->flag & RBO_FLAG_NEEDS_RESHAPE) {
/* mesh/shape data changed, so force shape refresh */
BKE_rigidbody_validate_sim_shape(ob, true);
/* now tell RB sim about it */
// XXX: we assume that this can only get applied for active/passive shapes that will be included as rigidbodies
RB_body_set_collision_shape(rbo->physics_object, rbo->physics_shape);
}
rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE);
}
BKE_rigidbody_body_tag_used(rbo->physics_object);
/* update simulation object... */
rigidbody_sync_object(scene, rbw, ob, rbo);
}
}
/**
* Create physics sim representation of constraint given rigid body constraint settings
*
* \param rebuild Even if an instance already exists, replace it
*/
static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, bool rebuild)
{
RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
float loc[3];
float rot[4];
float lin_lower;
float lin_upper;
float ang_lower;
float ang_upper;
/* sanity checks:
* - object should have a rigid body constraint
* - rigid body constraint should have at least one constrained object
*/
if (rbc == NULL) {
return;
}
if (ELEM4(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) {
if (rbc->physics_constraint) {
RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
RB_constraint_delete(rbc->physics_constraint);
rbc->physics_constraint = NULL;
}
return;
}
if (rbc->physics_constraint && rebuild == false) {
RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
}
if (rbc->physics_constraint == NULL || rebuild) {
rbRigidBody *rb1 = rbc->ob1->rigidbody_object->physics_object;
rbRigidBody *rb2 = rbc->ob2->rigidbody_object->physics_object;
/* remove constraint if it already exists before creating a new one */
if (rbc->physics_constraint) {
RB_constraint_delete(rbc->physics_constraint);
rbc->physics_constraint = NULL;
}
mat4_to_loc_quat(loc, rot, ob->obmat);
if (rb1 && rb2) {
switch (rbc->type) {
case RBC_TYPE_POINT:
rbc->physics_constraint = RB_constraint_new_point(loc, rb1, rb2);
break;
case RBC_TYPE_FIXED:
rbc->physics_constraint = RB_constraint_new_fixed(loc, rot, rb1, rb2);
break;
case RBC_TYPE_HINGE:
rbc->physics_constraint = RB_constraint_new_hinge(loc, rot, rb1, rb2);
if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) {
RB_constraint_set_limits_hinge(rbc->physics_constraint, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper);
}
else
RB_constraint_set_limits_hinge(rbc->physics_constraint, 0.0f, -1.0f);
break;
case RBC_TYPE_SLIDER:
rbc->physics_constraint = RB_constraint_new_slider(loc, rot, rb1, rb2);
if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
RB_constraint_set_limits_slider(rbc->physics_constraint, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
else
RB_constraint_set_limits_slider(rbc->physics_constraint, 0.0f, -1.0f);
break;
case RBC_TYPE_PISTON:
rbc->physics_constraint = RB_constraint_new_piston(loc, rot, rb1, rb2);
if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) {
lin_lower = rbc->limit_lin_x_lower;
lin_upper = rbc->limit_lin_x_upper;
}
else {
lin_lower = 0.0f;
lin_upper = -1.0f;
}
if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) {
ang_lower = rbc->limit_ang_x_lower;
ang_upper = rbc->limit_ang_x_upper;
}
else {
ang_lower = 0.0f;
ang_upper = -1.0f;
}
RB_constraint_set_limits_piston(rbc->physics_constraint, lin_lower, lin_upper, ang_lower, ang_upper);
break;
case RBC_TYPE_6DOF_SPRING:
rbc->physics_constraint = RB_constraint_new_6dof_spring(loc, rot, rb1, rb2);
RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->flag & RBC_FLAG_USE_SPRING_X);
RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_stiffness_x);
RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_damping_x);
RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->flag & RBC_FLAG_USE_SPRING_Y);
RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_stiffness_y);
RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_damping_y);
RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->flag & RBC_FLAG_USE_SPRING_Z);
RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z);
RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z);
RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint);
/* fall-through */
case RBC_TYPE_6DOF:
if (rbc->type == RBC_TYPE_6DOF) /* a litte awkward but avoids duplicate code for limits */
rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2);
if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
else
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f);
if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y)
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper);
else
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f);
if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z)
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper);
else
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f);
if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X)
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper);
else
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f);
if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y)
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper);
else
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f);
if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z)
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper);
else
RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f);
break;
case RBC_TYPE_MOTOR:
rbc->physics_constraint = RB_constraint_new_motor(loc, rot, rb1, rb2);
RB_constraint_set_enable_motor(rbc->physics_constraint, rbc->flag & RBC_FLAG_USE_MOTOR_LIN, rbc->flag & RBC_FLAG_USE_MOTOR_ANG);
RB_constraint_set_max_impulse_motor(rbc->physics_constraint, rbc->motor_lin_max_impulse, rbc->motor_ang_max_impulse);
RB_constraint_set_target_velocity_motor(rbc->physics_constraint, rbc->motor_lin_target_velocity, rbc->motor_ang_target_velocity);
break;
}
}
else { /* can't create constraint without both rigid bodies */
return;
}
RB_constraint_set_enabled(rbc->physics_constraint, rbc->flag & RBC_FLAG_ENABLED);
if (rbc->flag & RBC_FLAG_USE_BREAKING)
RB_constraint_set_breaking_threshold(rbc->physics_constraint, rbc->breaking_threshold);
else
RB_constraint_set_breaking_threshold(rbc->physics_constraint, FLT_MAX);
if (rbc->flag & RBC_FLAG_OVERRIDE_SOLVER_ITERATIONS)
RB_constraint_set_solver_iterations(rbc->physics_constraint, rbc->num_solver_iterations);
else
RB_constraint_set_solver_iterations(rbc->physics_constraint, -1);
}
if (rbw && rbw->physics_world && rbc->physics_constraint) {
RB_dworld_add_constraint(rbw->physics_world, rbc->physics_constraint, rbc->flag & RBC_FLAG_DISABLE_COLLISIONS);
}
}
void BKE_rigidbody_constraints_build(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
GroupObject *go;
if (!rbw->constraints)
return;
for (go = rbw->constraints->gobject.first; go; go = go->next) {
Object *ob = go->ob;
if (ob) {
/* validate that we've got valid object set up here... */
RigidBodyCon *rbc = ob->rigidbody_constraint;
/* update transformation matrix of the object so we don't get a frame of lag for simple animations */
BKE_object_where_is_calc(scene, ob);
if (rbc == NULL) {
/* Since this object is included in the group but doesn't have
* constraint settings (perhaps it was added manually), add!
*/
ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
rigidbody_validate_sim_constraint(rbw, ob, true);
rbc = ob->rigidbody_constraint;
}
else {
/* perform simulation data updates as tagged */
if (rebuild) {
/* World has been rebuilt so rebuild constraint */
rigidbody_validate_sim_constraint(rbw, ob, true);
}
else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
rigidbody_validate_sim_constraint(rbw, ob, false);
}
rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
}
}
}
}
void BKE_rigidbody_constraints_apply(Scene *UNUSED(scene), RigidBodyWorld *UNUSED(rbw))
{
/* stub, just for consistency, might be useful later */
}
/* ------------------------ */
static void rigidbody_world_apply_object(Scene *UNUSED(scene), Object *ob)
{
RigidBodyOb *rbo;
rbo = ob->rigidbody_object;
/* reset kinematic state for transformed objects */
if (rbo && (ob->flag & SELECT) && (G.moving & G_TRANSFORM_OBJ)) {
RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
RB_body_set_mass(rbo->physics_object, BKE_rigidbody_object_mass(rbo));
/* deactivate passive objects so they don't interfere with deactivation of active objects */
if (rbo->type == RBO_TYPE_PASSIVE)
RB_body_deactivate(rbo->physics_object);
}
}
void BKE_rigidbody_objects_apply(Scene *scene, RigidBodyWorld *rbw)
{
GroupObject *go;
for (go = rbw->group->gobject.first; go; go = go->next) {
Object *ob = go->ob;
if (!ob)
continue;
rigidbody_world_apply_object(scene, ob);
}
}
/* ------------------------ */
/* Transform Utils */
/* Sync rigid body and object transformations */
void BKE_rigidbody_object_apply_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
{
RigidBodyOb *rbo = ob->rigidbody_object;
/* keep original transform for kinematic and passive objects */
if (ELEM(NULL, rbw, rbo) || rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE)
return;
/* use rigid body transform after cache start frame if objects is not being transformed */
if (BKE_rigidbody_check_sim_running(rbw, ctime) && !(ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) {
float mat[4][4], size_mat[4][4], size[3];
normalize_qt(rbo->orn); // RB_TODO investigate why quaternion isn't normalized at this point
quat_to_mat4(mat, rbo->orn);
copy_v3_v3(mat[3], rbo->pos);
mat4_to_size(size, ob->obmat);
size_to_mat4(size_mat, size);
mul_m4_m4m4(mat, mat, size_mat);
copy_m4_m4(ob->obmat, mat);
}
/* otherwise set rigid body transform to current obmat */
else {
mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat);
}
}
/* Used when canceling transforms - return rigidbody and object to initial states */
void BKE_rigidbody_object_aftertrans_update(Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle)
{
RigidBodyOb *rbo = ob->rigidbody_object;
/* return rigid body and object to their initial states */
copy_v3_v3(rbo->pos, ob->loc);
copy_v3_v3(ob->loc, loc);
if (ob->rotmode > 0) {
eulO_to_quat(rbo->orn, ob->rot, ob->rotmode);
copy_v3_v3(ob->rot, rot);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
axis_angle_to_quat(rbo->orn, ob->rotAxis, ob->rotAngle);
copy_v3_v3(ob->rotAxis, rotAxis);
ob->rotAngle = rotAngle;
}
else {
copy_qt_qt(rbo->orn, ob->quat);
copy_qt_qt(ob->quat, quat);
}
if (rbo->physics_object) {
/* allow passive objects to return to original transform */
if (rbo->type == RBO_TYPE_PASSIVE)
RB_body_set_kinematic_state(rbo->physics_object, true);
RB_body_set_loc_rot(rbo->physics_object, rbo->pos, rbo->orn);
}
// RB_TODO update rigid body physics object's loc/rot for dynamic objects here as well (needs to be done outside bullet's update loop)
}
/* ------------------------ */
/* Object Data Management */
/* Add rigid body settings to the specified object */
RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
{
RigidBodyOb *rbo;
RigidBodyWorld *rbw = scene->rigidbody_world;
/* sanity checks
* - rigidbody world must exist
* - object must exist
* - cannot add rigid body if it already exists
*/
if (ob == NULL || (ob->rigidbody_object != NULL))
return NULL;
/* create new settings data, and link it up */
rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb");
/* set default settings */
rbo->type = type;
rbo->mass = 1.0f;
rbo->friction = 0.5f; /* best when non-zero. 0.5 is Bullet default */
rbo->restitution = 0.0f; /* best when zero. 0.0 is Bullet default */
rbo->margin = 0.04f; /* 0.04 (in meters) is Bullet default */
rbo->lin_sleep_thresh = 0.4f; /* 0.4 is half of Bullet default */
rbo->ang_sleep_thresh = 0.5f; /* 0.5 is half of Bullet default */
rbo->lin_damping = 0.04f; /* 0.04 is game engine default */
rbo->ang_damping = 0.1f; /* 0.1 is game engine default */
rbo->col_groups = 1;
/* use triangle meshes for passive objects
* use convex hulls for active objects since dynamic triangle meshes are very unstable
*/
if (type == RBO_TYPE_ACTIVE)
rbo->shape = RB_SHAPE_CONVEXH;
else
rbo->shape = RB_SHAPE_TRIMESH;
rbo->mesh_source = RBO_MESH_DEFORM;
/* set initial transform */
mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat);
/* flag cache as outdated */
BKE_rigidbody_cache_reset(rbw);
/* return this object */
return rbo;
}
void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
RigidBodyOb *rbo = ob->rigidbody_object;
RigidBodyCon *rbc;
GroupObject *go;
int i;
if (rbw) {
/* remove from rigidbody world, free object won't do this */
if (rbw->physics_world && rbo->physics_object)
RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
/* remove object from array */
if (rbw && rbw->objects) {
for (i = 0; i < rbw->numbodies; i++) {
if (rbw->objects[i] == ob) {
rbw->objects[i] = NULL;
break;
}
}
}
/* remove object from rigid body constraints */
if (rbw->constraints) {
for (go = rbw->constraints->gobject.first; go; go = go->next) {
Object *obt = go->ob;
if (obt && obt->rigidbody_constraint) {
rbc = obt->rigidbody_constraint;
if (ELEM(ob, rbc->ob1, rbc->ob2)) {
BKE_rigidbody_remove_constraint(scene, obt);
}
}
}
}
}
/* remove object's settings */
BKE_rigidbody_free_object(ob);
/* flag cache as outdated */
BKE_rigidbody_cache_reset(rbw);
}
/* Free RigidBody settings and sim instances */
void BKE_rigidbody_free_object(Object *ob)
{
RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL;
/* sanity check */
if (rbo == NULL)
return;
/* free physics references */
if (rbo->physics_object) {
rbo->physics_object = NULL;
}
if (rbo->physics_shape) {
RB_shape_delete(rbo->physics_shape);
rbo->physics_shape = NULL;
}
/* free data itself */
MEM_freeN(rbo);
ob->rigidbody_object = NULL;
}
/* This just copies the data, clearing out references to physics objects.
* Anything that uses them MUST verify that the copied object will
* be added to relevant groups later...
*/
RigidBodyOb *BKE_rigidbody_copy_object(Object *ob)
{
RigidBodyOb *rboN = NULL;
if (ob->rigidbody_object) {
/* just duplicate the whole struct first (to catch all the settings) */
rboN = MEM_dupallocN(ob->rigidbody_object);
/* tag object as needing to be verified */
rboN->flag |= RBO_FLAG_NEEDS_VALIDATE;
/* clear out all the fields which need to be revalidated later */
rboN->physics_object = NULL;
rboN->physics_shape = NULL;
}
/* return new copy of settings */
return rboN;
}
/* ------------------------ */
/* Add rigid body constraint to the specified object */
RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type)
{
RigidBodyCon *rbc;
RigidBodyWorld *rbw = scene->rigidbody_world;
/* sanity checks
* - rigidbody world must exist
* - object must exist
* - cannot add constraint if it already exists
*/
if (ob == NULL || (ob->rigidbody_constraint != NULL))
return NULL;
/* create new settings data, and link it up */
rbc = MEM_callocN(sizeof(RigidBodyCon), "RigidBodyCon");
/* set default settings */
rbc->type = type;
rbc->ob1 = NULL;
rbc->ob2 = NULL;
rbc->flag |= RBC_FLAG_ENABLED;
rbc->flag |= RBC_FLAG_DISABLE_COLLISIONS;
rbc->breaking_threshold = 10.0f; /* no good default here, just use 10 for now */
rbc->num_solver_iterations = 10; /* 10 is Bullet default */
rbc->limit_lin_x_lower = -1.0f;
rbc->limit_lin_x_upper = 1.0f;
rbc->limit_lin_y_lower = -1.0f;
rbc->limit_lin_y_upper = 1.0f;
rbc->limit_lin_z_lower = -1.0f;
rbc->limit_lin_z_upper = 1.0f;
rbc->limit_ang_x_lower = -M_PI_4;
rbc->limit_ang_x_upper = M_PI_4;
rbc->limit_ang_y_lower = -M_PI_4;
rbc->limit_ang_y_upper = M_PI_4;
rbc->limit_ang_z_lower = -M_PI_4;
rbc->limit_ang_z_upper = M_PI_4;
rbc->spring_damping_x = 0.5f;
rbc->spring_damping_y = 0.5f;
rbc->spring_damping_z = 0.5f;
rbc->spring_stiffness_x = 10.0f;
rbc->spring_stiffness_y = 10.0f;
rbc->spring_stiffness_z = 10.0f;
rbc->motor_lin_max_impulse = 1.0f;
rbc->motor_lin_target_velocity = 1.0f;
rbc->motor_ang_max_impulse = 1.0f;
rbc->motor_ang_target_velocity = 1.0f;
/* flag cache as outdated */
BKE_rigidbody_cache_reset(rbw);
/* return this object */
return rbc;
}
void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
RigidBodyCon *rbc = ob->rigidbody_constraint;
/* remove from rigidbody world, free object won't do this */
if (rbw && rbw->physics_world && rbc->physics_constraint) {
RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
}
/* remove object's settings */
BKE_rigidbody_free_constraint(ob);
/* flag cache as outdated */
BKE_rigidbody_cache_reset(rbw);
}
/* Free RigidBody constraint and sim instance */
void BKE_rigidbody_free_constraint(Object *ob)
{
RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
/* sanity check */
if (rbc == NULL)
return;
/* free physics reference */
if (rbc->physics_constraint) {
RB_constraint_delete(rbc->physics_constraint);
rbc->physics_constraint = NULL;
}
/* free data itself */
MEM_freeN(rbc);
ob->rigidbody_constraint = NULL;
}
/* This just copies the data, clearing out references to physics objects.
* Anything that uses them MUST verify that the copied object will
* be added to relevant groups later...
*/
RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob)
{
RigidBodyCon *rbcN = NULL;
if (ob->rigidbody_constraint) {
/* just duplicate the whole struct first (to catch all the settings) */
rbcN = MEM_dupallocN(ob->rigidbody_constraint);
/* tag object as needing to be verified */
rbcN->flag |= RBC_FLAG_NEEDS_VALIDATE;
/* clear out all the fields which need to be revalidated later */
rbcN->physics_constraint = NULL;
}
/* return new copy of settings */
return rbcN;
}
/* preserve relationships between constraints and rigid bodies after duplication */
void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc)
{
ID_NEW(rbc->ob1);
ID_NEW(rbc->ob2);
}
/* ------------------------ */
/* Utilities */
float BKE_rigidbody_object_mass(RigidBodyOb *rbo)
{
if (!rbo)
return 0.0f;
if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED)
return 0.0f;
return rbo->mass;
}
float BKE_rigidbody_object_margin(RigidBodyOb *rbo)
{
if (!rbo)
return 0.0f;
if (rbo->flag & RBO_FLAG_USE_MARGIN || ELEM3(rbo->shape, RB_SHAPE_CONVEXH, RB_SHAPE_TRIMESH, RB_SHAPE_CONE))
return rbo->margin;
else
return 0.04f;
}

View File

@@ -0,0 +1,60 @@
/*
* ***** 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.
*
* Copyright 2011, Blender Foundation.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BLI_PAGEDBUFFER_H
#define BLI_PAGEDBUFFER_H
/** \file BLI_pbuffer.h
* \ingroup bli
* \brief Management and access functions for paged buffers.
*/
#include <stdlib.h>
#include "BLI_utildefines.h"
struct bPagedBuffer;
void BLI_pbuf_init(struct bPagedBuffer *pbuf, size_t page_bytes, size_t elem_bytes);
void BLI_pbuf_free(struct bPagedBuffer *pbuf);
void BLI_pbuf_copy(struct bPagedBuffer *to, struct bPagedBuffer *from);
void BLI_pbuf_add_elements(struct bPagedBuffer *pbuf, int num_elem);
void *BLI_pbuf_get(struct bPagedBuffer *pbuf, int index);
typedef struct bPagedBufferIterator
{
struct bPagedBufferPage *page;
void *data;
int index, page_index;
} bPagedBufferIterator;
void BLI_pbuf_iter_init(struct bPagedBuffer *pbuf, struct bPagedBufferIterator *iter);
void BLI_pbuf_iter_next(struct bPagedBuffer *pbuf, struct bPagedBufferIterator *iter);
bool BLI_pbuf_iter_valid(struct bPagedBuffer *pbuf, struct bPagedBufferIterator *iter);
void BLI_pbuf_iter_at(struct bPagedBuffer *pbuf, struct bPagedBufferIterator *iter, int index);
#endif /* BLI_PAGEDBUFFER_H */

View File

@@ -81,6 +81,7 @@ set(SRC
intern/math_vector_inline.c
intern/md5.c
intern/noise.c
intern/pagedbuffer.c
intern/path_util.c
intern/polyfill2d.c
intern/quadric.c
@@ -154,6 +155,7 @@ set(SRC
BLI_memarena.h
BLI_mempool.h
BLI_noise.h
BLI_pagedbuffer.h
BLI_path_util.h
BLI_polyfill2d.h
BLI_quadric.h

View File

@@ -0,0 +1,241 @@
/*
* ***** 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.
*
* Copyright 2011, Blender Foundation.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <assert.h>
#include "MEM_guardedalloc.h"
#include "memory.h"
#include "DNA_pagedbuffer_types.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_pagedbuffer.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
/* XXX how to handle alignment nicely? */
/*#define PBUF_ALIGN_STRICT*/
BLI_INLINE div_t div_ceil(int a, int b)
{
div_t result = div(a, b);
if (result.rem > 0)
result.quot += 1;
return result;
}
static int pbuf_page_size_from_bytes(size_t page_bytes, size_t elem_bytes)
{
div_t page_size = div(page_bytes, elem_bytes);
#ifdef PBUF_ALIGN_STRICT
BLI_assert(page_size.rem == 0);
#endif
return page_size.quot;
}
static void pbuf_page_alloc(bPagedBuffer *pbuf, int p)
{
bPagedBufferPage *page = &pbuf->pages[p];
if (!page->data) {
page->data = MEM_mallocN(pbuf->page_bytes, "paged buffer page");
pbuf->totalloc += pbuf->page_size;
}
}
static void pbuf_page_free(bPagedBuffer *pbuf, int p)
{
bPagedBufferPage *page = &pbuf->pages[p];
if (page->data) {
MEM_freeN(page->data);
pbuf->totalloc -= pbuf->page_size;
}
}
typedef enum {
PBUF_PAGE_ALLOC_NONE, /* don't allocate any page data */
PBUF_PAGE_ALLOC_EXTEND, /* allocate only new page data */
PBUF_PAGE_ALLOC_ALL /* allocate all page data */
} ePagedBufferPageAlloc;
static void pbuf_set_totelem(bPagedBuffer *pbuf, int totelem, ePagedBufferPageAlloc alloc_mode)
{
div_t div_elem = div_ceil(totelem, pbuf->page_size);
int totpages = div_elem.quot;
// int pagefill = div_elem.rem;
if (totpages == 0) {
pbuf->pages = NULL;
pbuf->totpages = 0;
pbuf->totelem = 0;
pbuf->totalloc = 0;
}
else {
bPagedBufferPage *pages = MEM_callocN(sizeof(bPagedBufferPage) * totpages, "paged buffer page array");
int startp = totelem / pbuf->page_size;
int p;
if (pbuf->pages) {
int copyp = min_ii(pbuf->totpages, totpages);
memcpy(pages, pbuf->pages, sizeof(bPagedBufferPage) * copyp);
MEM_freeN(pbuf->pages);
}
pbuf->pages = pages;
pbuf->totpages = totpages;
pbuf->totelem = totelem;
/* init data */
switch (alloc_mode) {
case PBUF_PAGE_ALLOC_EXTEND:
for (p = startp; p < totpages; ++p)
pbuf_page_alloc(pbuf, p);
break;
case PBUF_PAGE_ALLOC_ALL:
for (p = 0; p < totpages; ++p)
pbuf_page_alloc(pbuf, p);
break;
case PBUF_PAGE_ALLOC_NONE:
/* nothing to do, data pointers are NULL already */
break;
}
}
}
void BLI_pbuf_init(bPagedBuffer *pbuf, size_t page_bytes, size_t elem_bytes)
{
pbuf->page_bytes = page_bytes;
pbuf->elem_bytes = elem_bytes;
pbuf->page_size = pbuf_page_size_from_bytes(page_bytes, elem_bytes);
pbuf->pages = NULL;
pbuf->totpages = 0;
pbuf->totelem = 0;
pbuf->totalloc = 0;
}
void BLI_pbuf_free(bPagedBuffer *pbuf)
{
if (pbuf->pages) {
int p;
for (p = 0; p < pbuf->totpages; ++p)
pbuf_page_free(pbuf, p);
MEM_freeN(pbuf->pages);
pbuf->pages = NULL;
pbuf->totpages = 0;
}
pbuf->totelem = 0;
}
void BLI_pbuf_copy(bPagedBuffer *to, bPagedBuffer *from)
{
to->page_bytes = from->page_bytes;
to->elem_bytes = from->elem_bytes;
to->page_size = from->page_size;
if (from->pages) {
int p;
to->pages = MEM_dupallocN(from->pages);
for (p = 0; p < from->totpages; ++p)
if (from->pages[p].data)
to->pages[p].data = MEM_dupallocN(from->pages[p].data);
}
else {
to->pages = NULL;
}
to->totpages = from->totpages;
to->totelem = from->totelem;
to->totalloc = from->totalloc;
}
void BLI_pbuf_add_elements(bPagedBuffer *pbuf, int num_elem)
{
int ntotelem = pbuf->totelem + num_elem;
pbuf_set_totelem(pbuf, ntotelem, PBUF_PAGE_ALLOC_EXTEND);
}
void *BLI_pbuf_get(bPagedBuffer *pbuf, int index)
{
if (index < pbuf->totelem) {
div_t page_div = div(index, pbuf->page_size);
bPagedBufferPage *page = pbuf->pages + page_div.quot;
if (page->data)
return (char *)page->data + pbuf->elem_bytes * page_div.rem;
else
return NULL;
}
else
return NULL;
}
void BLI_pbuf_iter_init(bPagedBuffer *pbuf, bPagedBufferIterator *iter)
{
iter->index = 0;
iter->page = pbuf->pages;
iter->page_index = 0;
if (pbuf->pages) {
while (iter->page->data == NULL && iter->index < pbuf->totelem) {
iter->index += pbuf->page_size;
++iter->page;
}
iter->data = iter->page->data;
}
}
void BLI_pbuf_iter_next(bPagedBuffer *pbuf, bPagedBufferIterator *iter)
{
++iter->index;
++iter->page_index;
if (iter->page_index < pbuf->page_size) {
iter->data = (char *)iter->data + pbuf->elem_bytes;
}
else {
++iter->page;
iter->page_index = 0;
while (iter->page->data == NULL && iter->index < pbuf->totelem) {
iter->index += pbuf->page_size;
++iter->page;
}
iter->data = iter->page->data;
}
}
bool BLI_pbuf_iter_valid(bPagedBuffer *pbuf, bPagedBufferIterator *iter)
{
return iter->index < pbuf->totelem;
}
void BLI_pbuf_iter_at(bPagedBuffer *pbuf, bPagedBufferIterator *iter, int index)
{
div_t page_div = div(index, pbuf->page_size);
iter->index = index;
iter->page = pbuf->pages + page_div.quot;
iter->page_index = page_div.rem;
if (iter->page) {
iter->data = (char *)iter->page->data + pbuf->elem_bytes * iter->page_index;
}
}

View File

@@ -79,9 +79,11 @@
#include "DNA_meshdata_types.h"
#include "DNA_nla_types.h"
#include "DNA_node_types.h"
#include "DNA_nparticle_types.h"
#include "DNA_object_fluidsim.h" // NT
#include "DNA_object_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_pagedbuffer_types.h"
#include "DNA_particle_types.h"
#include "DNA_property_types.h"
#include "DNA_rigidbody_types.h"
@@ -134,6 +136,7 @@
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
#include "BKE_sca.h" // for init_actuator
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -4226,6 +4229,47 @@ static void direct_link_latt(FileData *fd, Lattice *lt)
}
/* ************ READ PAGED BUFFER ***************** */
static void direct_link_pagedbuffer(FileData *fd, bPagedBuffer *pbuf)
{
int p;
pbuf->pages = newdataadr(fd, pbuf->pages);
for (p = 0; p < pbuf->totpages; ++p) {
bPagedBufferPage *page = pbuf->pages + p;
page->data = newdataadr(fd, page->data);
}
}
/* ************ READ NPARTICLE BUFFER ***************** */
static void direct_link_nparticle_display(FileData *fd, NParticleDisplay *display)
{
link_list(fd, &display->dupli_objects);
}
static void direct_link_nparticle_system(FileData *fd, NParticleSystem *psys)
{
NParticleAttributeState *attrstate;
NParticleDisplay *display;
link_list(fd, &psys->attributes);
psys->state = newdataadr(fd, psys->state);
if (psys->state) {
link_list(fd, &psys->state->attributes);
for (attrstate = psys->state->attributes.first; attrstate; attrstate = attrstate->next)
direct_link_pagedbuffer(fd, &attrstate->data);
}
link_list(fd, &psys->display);
for (display = psys->display.first; display; display = display->next)
direct_link_nparticle_display(fd, display);
}
/* ************ READ OBJECT ***************** */
static void lib_link_modifiers__linkModifiers(void *userData, Object *ob,
@@ -4793,6 +4837,12 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
if (wmd->cmap_curve)
direct_link_curvemapping(fd, wmd->cmap_curve);
}
else if (md->type == eModifierType_NParticleSystem) {
NParticleSystemModifierData *pmd = (NParticleSystemModifierData *)md;
pmd->psys = newdataadr(fd, pmd->psys);
direct_link_nparticle_system(fd, pmd->psys);
}
else if (md->type == eModifierType_LaplacianDeform) {
LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md;
@@ -5191,6 +5241,8 @@ static void lib_link_scene(FileData *fd, Main *main)
rbw->constraints = newlibadr(fd, sce->id.lib, rbw->constraints);
if (rbw->effector_weights)
rbw->effector_weights->group = newlibadr(fd, sce->id.lib, rbw->effector_weights->group);
/* create empty mempool */
BKE_rigidbody_world_init_mempool(rbw);
}
if (sce->nodetree) {

View File

@@ -116,8 +116,10 @@
#include "DNA_meshdata_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_nparticle_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
#include "DNA_pagedbuffer_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_particle_types.h"
#include "DNA_property_types.h"
@@ -143,6 +145,7 @@
#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
#include "BLI_pagedbuffer.h"
#include "BLI_mempool.h"
#include "BKE_action.h"
@@ -1356,6 +1359,56 @@ static void write_defgroups(WriteData *wd, ListBase *defbase)
writestruct(wd, DATA, "bDeformGroup", 1, defgroup);
}
static void write_pagedbuffer(WriteData *wd, bPagedBuffer *pbuf)
{
int p;
if (pbuf->pages) {
writestruct(wd, DATA, "bPagedBufferPage", pbuf->totpages, pbuf->pages);
for (p = 0; p < pbuf->totpages; ++p) {
bPagedBufferPage *page = pbuf->pages + p;
if (page->data)
writedata(wd, DATA, pbuf->page_bytes, page->data);
}
}
}
static void write_nparticle_display(WriteData *wd, NParticleDisplay *display)
{
NParticleDisplayDupliObject *dob;
writestruct(wd, DATA, "NParticleDisplay", 1, display);
for (dob = display->dupli_objects.first; dob; dob = dob->next) {
writestruct(wd, DATA, "NParticleDisplayDupliObject", 1, dob);
}
}
static void write_nparticle_system(WriteData *wd, NParticleSystem *psys)
{
NParticleAttribute *attr;
NParticleDisplay *display;
writestruct(wd, DATA, "NParticleSystem", 1, psys);
for (attr = psys->attributes.first; attr; attr = attr->next) {
writestruct(wd, DATA, "NParticleAttribute", 1, attr);
}
if (psys->state) {
NParticleAttributeState *attrstate;
writestruct(wd, DATA, "NParticleState", 1, psys->state);
for (attrstate = psys->state->attributes.first; attrstate; attrstate = attrstate->next) {
writestruct(wd, DATA, "NParticleAttributeState", 1, attrstate);
write_pagedbuffer(wd, &attrstate->data);
}
}
for (display = psys->display.first; display; display = display->next)
write_nparticle_display(wd, display);
}
static void write_modifiers(WriteData *wd, ListBase *modbase)
{
ModifierData *md;
@@ -1473,6 +1526,11 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
if (wmd->cmap_curve)
write_curvemapping(wd, wmd->cmap_curve);
}
else if (md->type==eModifierType_NParticleSystem) {
NParticleSystemModifierData *pmd = (NParticleSystemModifierData *)md;
write_nparticle_system(wd, pmd->psys);
}
else if (md->type==eModifierType_LaplacianDeform) {
LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData*) md;
@@ -2329,9 +2387,10 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
/* writing RigidBodyWorld data to the blend file */
if (sce->rigidbody_world) {
writestruct(wd, DATA, "RigidBodyWorld", 1, sce->rigidbody_world);
writestruct(wd, DATA, "EffectorWeights", 1, sce->rigidbody_world->effector_weights);
write_pointcaches(wd, &(sce->rigidbody_world->ptcaches));
RigidBodyWorld *rbw = sce->rigidbody_world;
writestruct(wd, DATA, "RigidBodyWorld", 1, rbw);
writestruct(wd, DATA, "EffectorWeights", 1, rbw->effector_weights);
write_pointcaches(wd, &rbw->ptcaches);
}
sce= sce->id.next;

View File

@@ -990,6 +990,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_WIREFRAME); break;
case eModifierType_LaplacianDeform:
UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
case eModifierType_NParticleSystem:
UI_icon_draw(x, y, ICON_MOD_PARTICLES); break;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:

View File

@@ -43,6 +43,7 @@ set(SRC
drawarmature.c
drawmesh.c
drawobject.c
drawparticles.c
drawvolume.c
space_view3d.c
view3d_buttons.c

View File

@@ -37,6 +37,7 @@
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
#include "DNA_nparticle_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_smoke_types.h"
@@ -7536,6 +7537,25 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
}
/* nparticles */
if ((md = modifiers_findByType(ob, eModifierType_NParticleSystem))) {
NParticleSystemModifierData *pmd = (NParticleSystemModifierData *)md;
NParticleDisplay *display;
if (col || (ob->flag & SELECT))
cpack(0xFFFFFF);
glLoadMatrixf(rv3d->viewmat);
for (display = pmd->psys->display.first; display; display = display->next)
draw_nparticles(pmd->psys, display);
glMultMatrixf(ob->obmat);
if (col)
cpack(col);
}
/* draw code for smoke */
if ((md = modifiers_findByType(ob, eModifierType_Smoke))) {
SmokeModifierData *smd = (SmokeModifierData *)md;

View File

@@ -0,0 +1,72 @@
/*
* ***** 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 by the Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/space_view3d/drawparticles.c
* \ingroup spview3d
*/
#include "DNA_nparticle_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
#include "BKE_nparticle.h"
#include "BIF_gl.h"
#include "view3d_intern.h"
static void draw_particles(NParticleSystem *psys, const char *attr_pos)
{
NParticleIterator it;
float pos[3];
if (!psys->state)
return;
glPointSize(2.0);
glBegin(GL_POINTS);
for (BKE_nparticle_iter_init(psys->state, &it); BKE_nparticle_iter_valid(&it); BKE_nparticle_iter_next(&it)) {
BKE_nparticle_iter_get_vector(&it, attr_pos, pos);
glVertex3fv(pos);
}
glEnd();
glPointSize(1.0);
}
void draw_nparticles(NParticleSystem *psys, NParticleDisplay *display)
{
switch (display->type) {
case PAR_DISPLAY_PARTICLE:
draw_particles(psys, display->attribute);
break;
}
}

View File

@@ -39,6 +39,8 @@ struct ARegion;
struct ARegionType;
struct BoundBox;
struct DerivedMesh;
struct NParticleDisplay;
struct NParticleSystem;
struct Object;
struct SmokeDomainSettings;
struct ViewContext;
@@ -175,6 +177,9 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, struct DerivedMesh *dm,
void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
struct Object *ob, struct DerivedMesh *dm, const int draw_flags);
/* drawparticles.c */
void draw_nparticles(struct NParticleSystem *psys, struct NParticleDisplay *display);
/* view3d_draw.c */
void view3d_main_area_draw(const struct bContext *C, struct ARegion *ar);
void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride);

View File

@@ -5899,7 +5899,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
if (ob->rigidbody_object && canceled) {
float ctime = BKE_scene_frame_get(t->scene);
if (BKE_rigidbody_check_sim_running(t->scene->rigidbody_world, ctime))
BKE_rigidbody_aftertrans_update(ob, td->ext->oloc, td->ext->orot, td->ext->oquat, td->ext->orotAxis, td->ext->orotAngle);
BKE_rigidbody_object_aftertrans_update(ob, td->ext->oloc, td->ext->orot, td->ext->oquat, td->ext->orotAxis, td->ext->orotAngle);
}
}
}

View File

@@ -82,6 +82,7 @@ typedef enum ModifierType {
eModifierType_MeshCache = 46,
eModifierType_LaplacianDeform = 47,
eModifierType_Wireframe = 48,
eModifierType_NParticleSystem = 49,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -1362,6 +1363,12 @@ enum {
MOD_WIREFRAME_CREASE = (1 << 5),
};
/* nparticle modifier */
typedef struct NParticleSystemModifierData {
ModifierData modifier;
struct NParticleSystem *psys;
} NParticleSystemModifierData;
#endif /* __DNA_MODIFIER_TYPES_H__ */

View File

@@ -0,0 +1,128 @@
/*
* ***** 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.
*
* Copyright 2011, Blender Foundation.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef DNA_NPARTICLE_TYPES_H
#define DNA_NPARTICLE_TYPES_H
/** \file DNA_nparticle_types.h
* \ingroup DNA
*/
#include "DNA_pagedbuffer_types.h"
/* Attribute descriptor */
typedef struct NParticleAttributeDescription {
char name[64];
int datatype;
int flag;
char default_value[64];
} NParticleAttributeDescription;
typedef enum eParticleAttributeFlag {
PAR_ATTR_REQUIRED = 1, /* always exists */
PAR_ATTR_PROTECTED = 2, /* descriptor is immutable */
PAR_ATTR_READONLY = 4, /* attribute data is read-only */
PAR_ATTR_TEMPORARY = 8 /* temporary runtime attribute (not stored in cache or blend files) */
} eParticleAttributeFlag;
/* particle attribute types */
typedef enum eParticleAttributeDataType {
PAR_ATTR_DATATYPE_INTERNAL = 0, /* for static attributes with special types */
PAR_ATTR_DATATYPE_FLOAT = 1,
PAR_ATTR_DATATYPE_INT = 2,
PAR_ATTR_DATATYPE_BOOL = 3,
PAR_ATTR_DATATYPE_VECTOR = 4,
PAR_ATTR_DATATYPE_POINT = 5,
PAR_ATTR_DATATYPE_NORMAL = 6,
PAR_ATTR_DATATYPE_QUATERNION = 7,
PAR_ATTR_DATATYPE_COLOR = 8,
PAR_ATTR_DATATYPE_MATRIX = 9,
PAR_ATTR_DATATYPE_POINTER = 10
} eParticleAttributeDataType;
typedef struct NParticleAttributeState {
/* XXX next/prev only needed for storing in ListBase,
* can be removed when attribute states get stored
* in a hash table instead.
*/
struct NParticleAttributeState *next, *prev;
int hashkey;
int flag;
NParticleAttributeDescription desc; /* attribute descriptor */
bPagedBuffer data;
} NParticleAttributeState;
typedef enum eParticleAttributeStateFlag {
PAR_ATTR_STATE_TEST = 1 /* generic temporary test flag */
} eParticleAttributeStateFlag;
typedef struct NParticleState {
/* XXX just a list atm, uses linear search for lookup,
* could use a GHash instead for O(1) lookup.
*/
ListBase attributes;
void *py_handle;
} NParticleState;
typedef struct NParticleAttribute {
struct NParticleAttribute *next, *prev;
NParticleAttributeDescription desc; /* attribute descriptor */
} NParticleAttribute;
typedef struct NParticleSystem {
ListBase attributes; /* definition of available attributes */
struct NParticleState *state; /* current state */
ListBase display; /* display settings */
} NParticleSystem;
typedef struct NParticleDisplay {
struct NParticleDisplay *next, *prev;
int type;
int pad;
char attribute[64];
/* dupli settings */
ListBase dupli_objects;
} NParticleDisplay;
typedef struct NParticleDisplayDupliObject {
struct NParticleDisplayDupliObject *next, *prev;
struct Object *object;
} NParticleDisplayDupliObject;
typedef enum eParticleDisplayType {
PAR_DISPLAY_PARTICLE = 1,
PAR_DISPLAY_DUPLI = 2
} eParticleDisplayType;
#endif /* DNA_NPARTICLE_TYPES_H */

View File

@@ -396,7 +396,7 @@ enum {
OB_DUPLIVERTS = 1 << 4,
OB_DUPLIROT = 1 << 5,
OB_DUPLINOSPEED = 1 << 6,
/* OB_POWERTRACK = 1 << 7,*/ /*UNUSED*/
OB_DUPLI_NPARTICLE = 1 << 7,
OB_DUPLIGROUP = 1 << 8,
OB_DUPLIFACES = 1 << 9,
OB_DUPLIFACES_SCALE = 1 << 10,
@@ -405,7 +405,7 @@ enum {
OB_NO_CONSTRAINTS = 1 << 13, /* runtime constraints disable */
OB_NO_PSYS_UPDATE = 1 << 14, /* hack to work around particle issue */
OB_DUPLI = OB_DUPLIFRAMES | OB_DUPLIVERTS | OB_DUPLIGROUP | OB_DUPLIFACES | OB_DUPLIPARTS,
OB_DUPLI = OB_DUPLIFRAMES | OB_DUPLIVERTS | OB_DUPLIGROUP | OB_DUPLIFACES | OB_DUPLIPARTS | OB_DUPLI_NPARTICLE,
};
/* (short) ipoflag */

View File

@@ -0,0 +1,49 @@
/*
* ***** 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.
*
* Copyright 2011, Blender Foundation.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef DNA_PAGEDBUFFER_H
#define DNA_PAGEDBUFFER_H
/** \file DNA_pagedbuffer.h
* \ingroup DNA
* \brief bPaged buffers are optimized for dynamic creation and removal of elements.
*/
#include "DNA_listBase.h"
typedef struct bPagedBufferPage {
void *data; /* layer data */
} bPagedBufferPage;
typedef struct bPagedBuffer {
struct bPagedBufferPage *pages; /* page list */
int elem_bytes; /* size of a single element in bytes */
int page_bytes; /* size of a page in bytes */
int page_size; /* elements per page */
int totpages; /* number of allocated pages */
int totelem; /* number of elements in the buffer */
int totalloc; /* actually allocated elements (dead pages not counted) */
} bPagedBuffer;
#endif

View File

@@ -55,6 +55,8 @@ typedef struct RigidBodyWorld {
struct Group *constraints; /* Group containing objects to use for Rigid Body Constraints*/
struct BLI_mempool *body_pool;
int pad;
float ltime; /* last frame world was evaluated for (internal) */

View File

@@ -135,6 +135,8 @@ static const char *includefiles[] = {
"DNA_rigidbody_types.h",
"DNA_freestyle_types.h",
"DNA_linestyle_types.h",
"DNA_pagedbuffer_types.h",
"DNA_nparticle_types.h",
/* empty string to indicate end of includefiles */
""
@@ -1286,4 +1288,6 @@ int main(int argc, char **argv)
#include "DNA_rigidbody_types.h"
#include "DNA_freestyle_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_pagedbuffer_types.h"
#include "DNA_nparticle_types.h"
/* end of list */

View File

@@ -66,6 +66,7 @@ set(DEFSRC
rna_movieclip.c
rna_nla.c
rna_nodetree.c
rna_nparticle.c
rna_object.c
rna_object_force.c
rna_packedfile.c

View File

@@ -3262,6 +3262,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_modifier.c", NULL, RNA_def_modifier},
{"rna_nla.c", NULL, RNA_def_nla},
{"rna_nodetree.c", NULL, RNA_def_nodetree},
{"rna_nparticle.c", NULL, RNA_def_nparticle},
{"rna_object.c", "rna_object_api.c", RNA_def_object},
{"rna_object_force.c", NULL, RNA_def_object_force},
{"rna_packedfile.c", NULL, RNA_def_packedfile},

View File

@@ -161,9 +161,11 @@ void RNA_def_meta(struct BlenderRNA *brna);
void RNA_def_modifier(struct BlenderRNA *brna);
void RNA_def_nla(struct BlenderRNA *brna);
void RNA_def_nodetree(struct BlenderRNA *brna);
void RNA_def_nparticle(struct BlenderRNA *brna);
void RNA_def_object(struct BlenderRNA *brna);
void RNA_def_object_force(struct BlenderRNA *brna);
void RNA_def_packedfile(struct BlenderRNA *brna);
void RNA_def_pagedbuffer(struct BlenderRNA *brna);
void RNA_def_particle(struct BlenderRNA *brna);
void RNA_def_pose(struct BlenderRNA *brna);
void RNA_def_render(struct BlenderRNA *brna);

View File

@@ -108,6 +108,7 @@ EnumPropertyItem modifier_type_items[] = {
{eModifierType_Smoke, "SMOKE", ICON_MOD_SMOKE, "Smoke", ""},
{eModifierType_Softbody, "SOFT_BODY", ICON_MOD_SOFT, "Soft Body", ""},
{eModifierType_Surface, "SURFACE", ICON_MOD_PHYSICS, "Surface", ""},
{eModifierType_NParticleSystem, "NPARTICLE_SYSTEM", ICON_MOD_PARTICLES, "Particles (new)", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -244,6 +245,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_LaplacianDeformModifier;
case eModifierType_Wireframe:
return &RNA_WireframeModifier;
case eModifierType_NParticleSystem:
return &RNA_NParticleSystemModifier;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -3652,6 +3655,22 @@ static void rna_def_modifier_wireframe(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_nparticlesystem(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "NParticleSystemModifier", "Modifier");
RNA_def_struct_ui_text(srna, "NParticle System Modifier", "Particles");
RNA_def_struct_sdna(srna, "NParticleSystemModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_PARTICLES);
prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "psys");
RNA_def_property_ui_text(prop, "Particle System", "Particle data");
}
void RNA_def_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3764,6 +3783,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_meshcache(brna);
rna_def_modifier_laplaciandeform(brna);
rna_def_modifier_wireframe(brna);
rna_def_modifier_nparticlesystem(brna);
}
#endif

View File

@@ -0,0 +1,844 @@
/*
* ***** 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/makesrna/intern/rna_nparticle.c
* \ingroup RNA
*/
#include <stddef.h>
#include "DNA_nparticle_types.h"
#include "RNA_define.h"
#include "rna_internal.h"
static EnumPropertyItem nparticle_display_type_items[] = {
{PAR_DISPLAY_PARTICLE, "PARTICLE", ICON_NONE, "Particles", "Display particle symbols"},
{PAR_DISPLAY_DUPLI, "DUPLI", ICON_NONE, "Duplis", "Create object dupli instances from particles"},
{0, NULL, 0, NULL, NULL}
};
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_pagedbuffer.h"
#include "BKE_nparticle.h"
#include "BKE_report.h"
#include "RNA_access.h"
#if 0
static StructRNA *rna_NParticleAttributeState_refine(PointerRNA *ptr)
{
NParticleAttributeState *attrstate = ptr->data;
switch (attrstate->desc.datatype) {
case PAR_ATTR_DATATYPE_FLOAT:
return &RNA_NParticleAttributeStateFloat;
case PAR_ATTR_DATATYPE_INT:
return &RNA_NParticleAttributeStateInt;
case PAR_ATTR_DATATYPE_BOOL:
return &RNA_NParticleAttributeStateBool;
case PAR_ATTR_DATATYPE_VECTOR:
return &RNA_NParticleAttributeStateVector;
case PAR_ATTR_DATATYPE_POINT:
return &RNA_NParticleAttributeStatePoint;
case PAR_ATTR_DATATYPE_NORMAL:
return &RNA_NParticleAttributeStateNormal;
case PAR_ATTR_DATATYPE_COLOR:
return &RNA_NParticleAttributeStateColor;
case PAR_ATTR_DATATYPE_MATRIX:
return &RNA_NParticleAttributeStateMatrix;
default:
BLI_assert(false); /* unknown data type, should never happen */
return &RNA_NParticleAttributeState;
}
}
static void rna_NParticleAttributeState_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
NParticleAttributeState *state = ptr->data;
bPagedBufferIterator *internal = MEM_callocN(sizeof(bPagedBufferIterator), "particle data iterator");
BLI_pbuf_iter_init(&state->data, internal);
iter->internal = internal;
iter->valid = BLI_pbuf_iter_valid(&state->data, internal);
}
static void rna_NParticleAttributeState_data_next(CollectionPropertyIterator *iter)
{
NParticleAttributeState *state = iter->ptr.data;
bPagedBufferIterator *internal = iter->internal;
BLI_pbuf_iter_next(&state->data, internal);
iter->valid = BLI_pbuf_iter_valid(&state->data, internal);
}
static void rna_NParticleAttributeState_data_end(CollectionPropertyIterator *iter)
{
MEM_freeN(iter->internal);
iter->internal = NULL;
}
static PointerRNA rna_NParticleAttributeState_data_get(CollectionPropertyIterator *iter, StructRNA *data_srna)
{
bPagedBufferIterator *internal = iter->internal;
PointerRNA ptr;
RNA_pointer_create(iter->ptr.id.data, data_srna, internal->data, &ptr);
return ptr;
}
static int rna_NParticleAttributeState_data_length(PointerRNA *ptr)
{
NParticleAttributeState *state = ptr->data;
return state->data.totelem;
}
int rna_NParticleAttributeState_data_lookup_int(PointerRNA *ptr, int key, PointerRNA *r_ptr, StructRNA *data_srna)
{
NParticleAttributeState *state = ptr->data;
void *data = BLI_pbuf_get(&state->data, key);
RNA_pointer_create(ptr->id.data, data_srna, data, r_ptr);
return data != NULL;
}
int rna_NParticleAttributeState_data_assign_int(PointerRNA *ptr, int key, const PointerRNA *assign_ptr, StructRNA *UNUSED(data_srna))
{
NParticleAttributeState *state = ptr->data;
void *data = BLI_pbuf_get(&state->data, key);
if (data) {
memcpy(data, assign_ptr->data, state->data.elem_bytes);
return true;
}
else
return false;
}
#define DEF_ATTR_TYPE_FUNCS(lcase, ucase) \
static PointerRNA rna_NParticleAttributeState_data_get_##lcase (CollectionPropertyIterator *iter) \
{ return rna_NParticleAttributeState_data_get(iter, &RNA_NParticleData##ucase); } \
static int rna_NParticleAttributeState_data_lookup_int_##lcase (PointerRNA *ptr, int key, PointerRNA *r_ptr) \
{ return rna_NParticleAttributeState_data_lookup_int(ptr, key, r_ptr, &RNA_NParticleData##ucase); } \
static int rna_NParticleAttributeState_data_assign_int_##lcase (PointerRNA *ptr, int key, const PointerRNA *assign_ptr) \
{ return rna_NParticleAttributeState_data_assign_int(ptr, key, assign_ptr, &RNA_NParticleData##ucase); }
DEF_ATTR_TYPE_FUNCS(float, Float)
DEF_ATTR_TYPE_FUNCS(int, Int)
DEF_ATTR_TYPE_FUNCS(bool, Bool)
DEF_ATTR_TYPE_FUNCS(vector, Vector)
DEF_ATTR_TYPE_FUNCS(point, Point)
DEF_ATTR_TYPE_FUNCS(normal, Normal)
DEF_ATTR_TYPE_FUNCS(color, Color)
DEF_ATTR_TYPE_FUNCS(matrix, Matrix)
#undef DEF_ATTR_TYPE_FUNCS
static float rna_NParticleDataFloat_get(PointerRNA *ptr)
{
return *(float *)ptr->data;
}
static void rna_NParticleDataFloat_set(PointerRNA *ptr, float value)
{
*(float *)ptr->data = value;
}
static int rna_NParticleDataInt_get(PointerRNA *ptr)
{
return *(int *)ptr->data;
}
static void rna_NParticleDataInt_set(PointerRNA *ptr, int value)
{
*(int *)ptr->data = value;
}
static int rna_NParticleDataBool_get(PointerRNA *ptr)
{
return *(bool *)ptr->data;
}
static void rna_NParticleDataBool_set(PointerRNA *ptr, int value)
{
*(bool *)ptr->data = value;
}
static void rna_NParticleDataVector_get(PointerRNA *ptr, float *result)
{
copy_v3_v3(result, (float *)ptr->data);
}
static void rna_NParticleDataVector_set(PointerRNA *ptr, const float *value)
{
copy_v3_v3((float *)ptr->data, value);
}
static void rna_NParticleDataColor_get(PointerRNA *ptr, float *result)
{
copy_v4_v4(result, (float *)ptr->data);
}
static void rna_NParticleDataColor_set(PointerRNA *ptr, const float *value)
{
copy_v4_v4((float *)ptr->data, value);
}
static void rna_NParticleDataMatrix_get(PointerRNA *ptr, float *result)
{
copy_m4_m4((float(*)[4])result, (float(*)[4])ptr->data);
}
static void rna_NParticleDataMatrix_set(PointerRNA *ptr, const float *value)
{
copy_m4_m4((float(*)[4])ptr->data, (float(*)[4])value);
}
static void rna_NParticleState_attributes_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
NParticleState *state = ptr->data;
NParticleAttributeState *attrstate = state->attributes.first;
iter->internal = attrstate;
iter->valid = (attrstate != NULL);
}
static void rna_NParticleState_attributes_next(CollectionPropertyIterator *iter)
{
NParticleAttributeState *attrstate = iter->internal;
attrstate = attrstate->next;
iter->internal = attrstate;
iter->valid = (attrstate != NULL);
}
static void rna_NParticleState_attributes_end(CollectionPropertyIterator *iter)
{
iter->internal = NULL;
}
static PointerRNA rna_NParticleState_attributes_get(CollectionPropertyIterator *iter)
{
NParticleAttributeState *attrstate = iter->internal;
PointerRNA ptr;
RNA_pointer_create(iter->ptr.id.data, &RNA_NParticleAttributeState, attrstate, &ptr);
return ptr;
}
static int rna_NParticleState_attributes_length(PointerRNA *ptr)
{
NParticleState *state = ptr->data;
return BLI_countlist(&state->attributes);
}
int rna_NParticleState_attributes_lookup_string(PointerRNA *ptr, const char *key, PointerRNA *r_ptr)
{
NParticleState *state = ptr->data;
NParticleAttributeState *attrstate = BKE_nparticle_state_find_attribute(state, key);
RNA_pointer_create(ptr->id.data, &RNA_NParticleAttributeState, attrstate, r_ptr);
return attrstate != NULL;
}
#endif
#if 0
static void rna_NParticleState_particles_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
NParticleState *state = ptr->data;
NParticleIterator *piter = MEM_callocN(sizeof(NParticleIterator), "particle iterator");
BKE_nparticle_iter_init(state, piter);
iter->internal = piter;
iter->valid
}
static void rna_NParticleState_particles_next(CollectionPropertyIterator *iter)
{
NParticleState *state = iter->ptr.data;
NParticleIterator *piter = iter->internal;
BKE_nparticle_iter_next(piter);
iter->valid = BKE_nparticle_iter_valid(piter);
}
static void rna_NParticleState_particles_end(CollectionPropertyIterator *iter)
{
MEM_freeN(iter->internal);
iter->internal = NULL;
}
static PointerRNA rna_NParticleState_particles_get(CollectionPropertyIterator *iter)
{
NParticleIterator *piter = iter->internal;
PointerRNA ptr;
RNA_pointer_create(iter->ptr.id.data, &RNA_NParticleIterator, piter, &ptr);
return ptr;
}
static int rna_NParticleState_particles_length(PointerRNA *ptr)
{
NParticleState *state = ptr->data;
NParticleAttributeState *attrstate = BKE_nparticle_state_find_attribute(state, "id");
if (attrstate)
return attrstate->data.totelem;
else
return 0;
}
int rna_NParticleState_particles_lookup_int(PointerRNA *ptr, int key, PointerRNA *r_ptr)
{
/* XXX this is a problem: we cannot return a particle iterator here because
* PointerRNA can only reference data that exists permanently in the DNA ...
*/
NParticleState *state = ptr->data;
BKE_nparticle_iter_find_id(state, , NParticleID id)
BKE_nparticle_
void *data = BLI_pbuf_get(&state->data, key);
RNA_pointer_create(ptr->id.data, data_srna, data, r_ptr);
return true;
}
#endif
static int rna_NParticleState_find_particle(NParticleState *state, int id)
{
return BKE_nparticle_find_index(state, (NParticleID)id);
}
static int rna_NParticleState_add_particle(NParticleState *state, int id)
{
return BKE_nparticle_add(state, (NParticleID)id);
}
static void rna_NParticleState_remove_particle(NParticleState *state, int id)
{
BKE_nparticle_remove(state, (NParticleID)id);
}
static void rna_NParticleAttribute_update(Main *main, Scene *scene, PointerRNA *ptr)
{
/* XXX TODO */
}
static int rna_NParticleAttribute_editable(PointerRNA *ptr)
{
NParticleAttribute *attr = ptr->data;
return !(attr->desc.flag & (PAR_ATTR_PROTECTED | PAR_ATTR_REQUIRED));
}
static NParticleAttribute *rna_NParticleSystem_attributes_new(NParticleSystem *psys, ReportList *reports, const char *name, int datatype)
{
if (BKE_nparticle_attribute_find(psys, name)) {
BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "Particle attribute with name %s already exists", name);
return NULL;
}
return BKE_nparticle_attribute_new(psys, name, datatype, 0);
}
static void rna_NParticleSystem_attributes_remove(NParticleSystem *psys, NParticleAttribute *attr)
{
BKE_nparticle_attribute_remove(psys, attr);
}
static void rna_NParticleSystem_attributes_clear(NParticleSystem *psys)
{
BKE_nparticle_attribute_remove_all(psys);
}
static void rna_NParticleSystem_attributes_move(NParticleSystem *psys, int from_index, int to_index)
{
BKE_nparticle_attribute_move(psys, from_index, to_index);
}
static StructRNA *rna_NParticleDisplay_refine(PointerRNA *ptr)
{
NParticleDisplay *display = ptr->data;
switch (display->type) {
case PAR_DISPLAY_PARTICLE: return &RNA_NParticleDisplayParticle;
case PAR_DISPLAY_DUPLI: return &RNA_NParticleDisplayDupli;
default: return &RNA_NParticleDisplay;
}
}
static NParticleDisplayDupliObject *rna_NParticleDisplayDupli_dupli_objects_new(NParticleDisplay *display)
{
return BKE_nparticle_display_dupli_object_add(display);
}
static void rna_NParticleDisplayDupli_dupli_objects_remove(NParticleDisplay *display, NParticleDisplayDupliObject *dupli_object)
{
BKE_nparticle_display_dupli_object_remove(display, dupli_object);
}
static void rna_NParticleDisplayDupli_dupli_objects_clear(NParticleDisplay *display)
{
BKE_nparticle_display_dupli_object_remove_all(display);
}
static void rna_NParticleDisplayDupli_dupli_objects_move(NParticleDisplay *display, int from_index, int to_index)
{
BKE_nparticle_display_dupli_object_move(display, from_index, to_index);
}
#else
EnumPropertyItem nparticle_attribute_datatype_all[] = {
{PAR_ATTR_DATATYPE_INTERNAL, "INTERNAL", 0, "Internal" ""},
{PAR_ATTR_DATATYPE_FLOAT, "FLOAT", 0, "Float" ""},
{PAR_ATTR_DATATYPE_INT, "INT", 0, "Int" ""},
{PAR_ATTR_DATATYPE_BOOL, "BOOL", 0, "Bool" ""},
{PAR_ATTR_DATATYPE_VECTOR, "VECTOR", 0, "Vector" ""},
{PAR_ATTR_DATATYPE_POINT, "POINT", 0, "Point" ""},
{PAR_ATTR_DATATYPE_NORMAL, "NORMAL", 0, "Normal" ""},
{PAR_ATTR_DATATYPE_COLOR, "COLOR", 0, "Color" ""},
{PAR_ATTR_DATATYPE_MATRIX, "MATRIX", 0, "Matrix" ""},
{0, NULL, 0, NULL, NULL}
};
EnumPropertyItem nparticle_attribute_datatype_user[] = {
{PAR_ATTR_DATATYPE_FLOAT, "FLOAT", 0, "Float" ""},
{PAR_ATTR_DATATYPE_INT, "INT", 0, "Int" ""},
{PAR_ATTR_DATATYPE_BOOL, "BOOL", 0, "Bool" ""},
{PAR_ATTR_DATATYPE_VECTOR, "VECTOR", 0, "Vector" ""},
{PAR_ATTR_DATATYPE_POINT, "POINT", 0, "Point" ""},
{PAR_ATTR_DATATYPE_NORMAL, "NORMAL", 0, "Normal" ""},
{PAR_ATTR_DATATYPE_COLOR, "COLOR", 0, "Color" ""},
{PAR_ATTR_DATATYPE_MATRIX, "MATRIX", 0, "Matrix" ""},
{0, NULL, 0, NULL, NULL}
};
static void def_nparticle_attribute_description(StructRNA *srna, int update_flag, const char *update_cb, const char *editable_cb)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "desc.name");
RNA_def_property_ui_text(prop, "Name", "Unique name");
if (update_cb) {
if (editable_cb)
RNA_def_property_editable_func(prop, editable_cb);
RNA_def_property_update(prop, update_flag, update_cb);
}
else
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "datatype", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "desc.datatype");
RNA_def_property_enum_items(prop, nparticle_attribute_datatype_all);
RNA_def_property_ui_text(prop, "Data Type", "Basic data type");
if (update_cb) {
if (editable_cb)
RNA_def_property_editable_func(prop, editable_cb);
RNA_def_property_update(prop, update_flag, update_cb);
}
else
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
#if 0
/* defines a subtype of NParticleAttribute with a specific collection property for actual data */
static void def_nparticle_attribute_state_type(BlenderRNA *brna,
const char *state_structname, const char *data_structname,
const char *get_func, const char *lookup_int_func, const char *assign_int_func)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, state_structname, "NParticleAttributeState");
RNA_def_struct_sdna(srna, "NParticleAttributeState");
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, data_structname);
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_collection_funcs(prop, "rna_NParticleAttributeState_data_begin", "rna_NParticleAttributeState_data_next",
"rna_NParticleAttributeState_data_end", get_func,
"rna_NParticleAttributeState_data_length", lookup_int_func,
NULL, assign_int_func);
}
/* Subtypes for data access */
static void rna_def_nparticle_attribute_data_types(BlenderRNA *brna, bool readonly)
{
StructRNA *srna;
PropertyRNA *prop;
/* VOID */
if (readonly) {
srna = RNA_def_struct(brna, "NParticleDataVoid", NULL);
RNA_def_struct_ui_text(srna, "Particle Data", "Unknown particle data type");
}
/* FLOAT */
srna = RNA_def_struct(brna, readonly ? "NParticleDataFloatReadonly" : "NParticleDataFloat", NULL);
RNA_def_struct_ui_text(srna, "Particle Float Data", "");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_NParticleDataFloat_get", readonly ? NULL : "rna_NParticleDataFloat_set", NULL);
RNA_def_property_ui_text(prop, "Value", "");
if (readonly)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* INT */
srna = RNA_def_struct(brna, readonly ? "NParticleDataIntReadonly" : "NParticleDataInt", NULL);
RNA_def_struct_ui_text(srna, "Particle Int Data", "");
prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE);
RNA_def_property_int_funcs(prop, "rna_NParticleDataInt_get", readonly ? NULL : "rna_NParticleDataInt_set", NULL);
RNA_def_property_ui_text(prop, "Value", "");
if (readonly)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* BOOL */
srna = RNA_def_struct(brna, readonly ? "NParticleDataBoolReadonly" : "NParticleDataBool", NULL);
RNA_def_struct_ui_text(srna, "Particle Bool Data", "");
prop = RNA_def_property(srna, "value", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_NParticleDataBool_get", readonly ? NULL : "rna_NParticleDataBool_set");
RNA_def_property_ui_text(prop, "Value", "");
if (readonly)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* VECTOR */
srna = RNA_def_struct(brna, readonly ? "NParticleDataVectorReadonly" : "NParticleDataVector", NULL);
RNA_def_struct_ui_text(srna, "Particle Vector Data", "");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_XYZ);
RNA_def_property_array(prop, 3);
RNA_def_property_float_funcs(prop, "rna_NParticleDataVector_get", readonly ? NULL : "rna_NParticleDataVector_set", NULL);
RNA_def_property_ui_text(prop, "Value", "");
if (readonly)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* POINT */
srna = RNA_def_struct(brna, readonly ? "NParticleDataPointReadonly" : "NParticleDataPoint", NULL);
RNA_def_struct_ui_text(srna, "Particle Point Data", "");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_array(prop, 3);
RNA_def_property_float_funcs(prop, "rna_NParticleDataVector_get", readonly ? NULL : "rna_NParticleDataVector_set", NULL);
RNA_def_property_ui_text(prop, "Value", "");
if (readonly)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* NORMAL */
srna = RNA_def_struct(brna, readonly ? "NParticleDataNormalReadonly" : "NParticleDataNormal", NULL);
RNA_def_struct_ui_text(srna, "Particle Normal Data", "");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_array(prop, 3);
RNA_def_property_float_funcs(prop, "rna_NParticleDataVector_get", readonly ? NULL : "rna_NParticleDataVector_set", NULL);
RNA_def_property_ui_text(prop, "Value", "");
if (readonly)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* COLOR */
srna = RNA_def_struct(brna, readonly ? "NParticleDataColorReadonly" : "NParticleDataColor", NULL);
RNA_def_struct_ui_text(srna, "Particle Color Data", "");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_COLOR);
RNA_def_property_array(prop, 4);
RNA_def_property_float_funcs(prop, "rna_NParticleDataColor_get", readonly ? NULL : "rna_NParticleDataColor_set", NULL);
RNA_def_property_ui_text(prop, "Value", "");
if (readonly)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* MATRIX */
srna = RNA_def_struct(brna, readonly ? "NParticleDataMatrixReadonly" : "NParticleDataMatrix", NULL);
RNA_def_struct_ui_text(srna, "Particle Matrix Data", "");
prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_array(prop, 16);
RNA_def_property_float_funcs(prop, "rna_NParticleDataMatrix_get", readonly ? NULL : "rna_NParticleDataMatrix_set", NULL);
RNA_def_property_ui_text(prop, "Value", "");
if (readonly)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_nparticle_attribute_state(BlenderRNA *brna)
{
StructRNA *srna;
srna = RNA_def_struct(brna, "NParticleAttributeState", NULL);
RNA_def_struct_sdna(srna, "NParticleAttributeState");
RNA_def_struct_ui_text(srna, "Particle Attribute State", "Data for a particle attribute");
RNA_def_struct_refine_func(srna, "rna_NParticleAttributeState_refine");
def_nparticle_attribute_description(srna, 0, NULL, NULL);
rna_def_nparticle_attribute_data_types(brna, false);
rna_def_nparticle_attribute_data_types(brna, true);
#define DEF_ATTR_TYPE_RNA(lcase, ucase) \
def_nparticle_attribute_state_type(brna, "NParticleAttributeState"#ucase, "NParticleData"#ucase, \
"rna_NParticleAttributeState_data_get_"#lcase, \
"rna_NParticleAttributeState_data_lookup_int_"#lcase, \
"rna_NParticleAttributeState_data_assign_int_"#lcase);
DEF_ATTR_TYPE_RNA(float, Float)
DEF_ATTR_TYPE_RNA(int, Int)
DEF_ATTR_TYPE_RNA(bool, Bool)
DEF_ATTR_TYPE_RNA(vector, Vector)
DEF_ATTR_TYPE_RNA(point, Point)
DEF_ATTR_TYPE_RNA(normal, Normal)
DEF_ATTR_TYPE_RNA(color, Color)
DEF_ATTR_TYPE_RNA(matrix, Matrix)
#undef DEF_ATTR_TYPE_RNA
}
#endif
static void rna_def_nparticle_iterator(BlenderRNA *brna)
{
StructRNA *srna;
srna = RNA_def_struct(brna, "NParticleIterator", NULL);
RNA_def_struct_ui_text(srna, "Particle Iterator", "Access iterator for individual particles");
}
static void rna_def_nparticle_state(BlenderRNA *brna)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *prop, *parm;
srna = RNA_def_struct(brna, "NParticleState", NULL);
RNA_def_struct_ui_text(srna, "Particle State", "Data in a particle system for a specific frame");
#if 0
prop = RNA_def_property(srna, "attributes", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_funcs(prop, "rna_NParticleState_attributes_begin", "rna_NParticleState_attributes_next",
"rna_NParticleState_attributes_end", "rna_NParticleState_attributes_get",
"rna_NParticleState_attributes_length", NULL,
"rna_NParticleState_attributes_lookup_string", NULL);
RNA_def_property_ui_text(prop, "Attributes", "Data layers associated to particles");
RNA_def_property_struct_type(prop, "NParticleAttributeState");
#endif
#if 0
prop = RNA_def_property(srna, "particles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "NParticleIterator");
RNA_def_property_ui_text(prop, "Particles", "");
RNA_def_property_collection_funcs(prop, "rna_NParticleState_particles_begin", "rna_NParticleState_particles_next",
"rna_NParticleState_particles_end", "rna_NParticleState_particles_get",
"rna_NParticleState_particles_length", "rna_NParticleState_particles_lookup_int",
NULL, NULL);
#endif
func = RNA_def_function(srna, "find_particle", "rna_NParticleState_find_particle");
RNA_def_function_ui_description(func, "Get a particle's index");
parm = RNA_def_int(func, "id", 0, INT_MIN, INT_MAX, "Identifier", "Unique identifier of the particle", INT_MIN, INT_MAX);
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return value */
parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Index of the particle in attribute states", 0, INT_MAX);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "add_particle", "rna_NParticleState_add_particle");
RNA_def_function_ui_description(func, "Add a particle");
parm = RNA_def_int(func, "id", 0, INT_MIN, INT_MAX, "Identifier", "Unique identifier of the particle", INT_MIN, INT_MAX);
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return value */
parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Index of the particle in attribute states", 0, INT_MAX);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove_particle", "rna_NParticleState_remove_particle");
RNA_def_function_ui_description(func, "Remove a particle");
parm = RNA_def_int(func, "id", 0, INT_MIN, INT_MAX, "Identifier", "Unique identifier of the particle", INT_MIN, INT_MAX);
RNA_def_property_flag(parm, PROP_REQUIRED);
}
static void rna_def_nparticle_attribute(BlenderRNA *brna)
{
StructRNA *srna;
srna = RNA_def_struct(brna, "NParticleAttribute", NULL);
RNA_def_struct_sdna(srna, "NParticleAttribute");
RNA_def_struct_ui_text(srna, "Particle Attribute", "Attribute in a particle system");
def_nparticle_attribute_description(srna, 0, "rna_NParticleAttribute_update", "rna_NParticleAttribute_editable");
}
static void rna_def_nparticle_system_attributes_api(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
PropertyRNA *parm;
FunctionRNA *func;
RNA_def_property_srna(cprop, "NParticleAttributes");
srna = RNA_def_struct(brna, "NParticleAttributes", NULL);
RNA_def_struct_sdna(srna, "NParticleSystem");
RNA_def_struct_ui_text(srna, "Attributes", "Collection of particle attributes");
func = RNA_def_function(srna, "new", "rna_NParticleSystem_attributes_new");
RNA_def_function_ui_description(func, "Add a particle attribute");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", NULL, 64, "Name", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_enum(func, "datatype", nparticle_attribute_datatype_user, PAR_ATTR_DATATYPE_FLOAT, "Data Type", "Base data type");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return value */
parm = RNA_def_pointer(func, "attr", "NParticleAttribute", "", "Attribute");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_NParticleSystem_attributes_remove");
RNA_def_function_ui_description(func, "Remove an attribute from the buffer");
parm = RNA_def_pointer(func, "attr", "NParticleAttribute", "", "The attribute to remove");
RNA_def_property_flag(parm, PROP_REQUIRED);
func = RNA_def_function(srna, "clear", "rna_NParticleSystem_attributes_clear");
RNA_def_function_ui_description(func, "Remove all attributes from the buffer");
func = RNA_def_function(srna, "move", "rna_NParticleSystem_attributes_move");
RNA_def_function_ui_description(func, "Move an attribute to another position");
parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the attribute to move", 0, 10000);
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the attribute", 0, 10000);
RNA_def_property_flag(parm, PROP_REQUIRED);
}
static void rna_def_nparticle_display_dupli_object(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "NParticleDisplayDupliObject", NULL);
RNA_def_struct_ui_text(srna, "Particle Display Dupli Object", "Object dupli settings");
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "object");
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Object", "Object to use for dupli instances");
}
static void rna_def_nparticle_display_dupli_objects_api(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
PropertyRNA *parm;
FunctionRNA *func;
RNA_def_property_srna(cprop, "NParticleDisplayDupliObjects");
srna = RNA_def_struct(brna, "NParticleDisplayDupliObjects", NULL);
RNA_def_struct_sdna(srna, "NParticleDisplay");
RNA_def_struct_ui_text(srna, "Dupli Objects", "Collection of dupli objects in a particle system");
func = RNA_def_function(srna, "new", "rna_NParticleDisplayDupli_dupli_objects_new");
RNA_def_function_ui_description(func, "Add a particle dupli object");
/* return value */
parm = RNA_def_pointer(func, "dupli_object", "NParticleDisplayDupliObject", "Dupli Object", "");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_NParticleDisplayDupli_dupli_objects_remove");
RNA_def_function_ui_description(func, "Remove an particle dupli object");
parm = RNA_def_pointer(func, "dupli_object", "NParticleDisplayDupliObject", "", "The dupli object to remove");
RNA_def_property_flag(parm, PROP_REQUIRED);
func = RNA_def_function(srna, "clear", "rna_NParticleDisplayDupli_dupli_objects_clear");
RNA_def_function_ui_description(func, "Remove all particle dupli objects");
func = RNA_def_function(srna, "move", "rna_NParticleDisplayDupli_dupli_objects_move");
RNA_def_function_ui_description(func, "Move a particle dupli object to another index");
parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the attribute to move", 0, 10000);
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the attribute", 0, 10000);
RNA_def_property_flag(parm, PROP_REQUIRED);
}
static void rna_def_nparticle_display(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "NParticleDisplay", NULL);
RNA_def_struct_sdna(srna, "NParticleDisplay");
RNA_def_struct_ui_text(srna, "Particle Display", "Display mode for particles");
RNA_def_struct_refine_func(srna, "rna_NParticleDisplay_refine");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, nparticle_display_type_items);
RNA_def_property_ui_text(prop, "Type", "");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
srna = RNA_def_struct(brna, "NParticleDisplayParticle", "NParticleDisplay");
RNA_def_struct_sdna(srna, "NParticleDisplay");
RNA_def_struct_ui_text(srna, "Particle Symbol Display", "Displays particle symbols");
srna = RNA_def_struct(brna, "NParticleDisplayDupli", "NParticleDisplay");
RNA_def_struct_sdna(srna, "NParticleDisplay");
RNA_def_struct_ui_text(srna, "Particle Dupli Display", "Create object dupli instances");
prop = RNA_def_property(srna, "dupli_objects", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "dupli_objects", NULL);
RNA_def_property_ui_text(prop, "Dupli Objects", "Usable objects for dupli instances");
RNA_def_property_struct_type(prop, "NParticleDisplayDupliObject");
rna_def_nparticle_display_dupli_objects_api(brna, prop);
}
static void rna_def_nparticle_system(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "NParticleSystem", NULL);
RNA_def_struct_ui_text(srna, "Particle System", "Container for particles");
prop = RNA_def_property(srna, "attributes", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "attributes", NULL);
RNA_def_property_ui_text(prop, "Attributes", "Data layers associated to particles");
RNA_def_property_struct_type(prop, "NParticleAttribute");
rna_def_nparticle_system_attributes_api(brna, prop);
prop = RNA_def_property(srna, "state", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "state");
RNA_def_property_struct_type(prop, "NParticleState");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "State", "");
prop = RNA_def_property(srna, "display", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "display", NULL);
RNA_def_property_ui_text(prop, "Display", "Display modes");
RNA_def_property_struct_type(prop, "NParticleDisplay");
}
void RNA_def_nparticle(BlenderRNA *brna)
{
#if 0
rna_def_nparticle_attribute_state(brna);
#endif
rna_def_nparticle_iterator(brna);
rna_def_nparticle_state(brna);
rna_def_nparticle_attribute(brna);
rna_def_nparticle_display_dupli_object(brna);
rna_def_nparticle_display(brna);
rna_def_nparticle_system(brna);
}
#endif

View File

@@ -192,7 +192,7 @@ static void rna_RigidBodyOb_disabled_set(PointerRNA *ptr, int value)
#ifdef WITH_BULLET
/* update kinematic state if necessary - only needed for active bodies */
if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
RB_body_set_mass(rbo->physics_object, BKE_rigidbody_object_mass(rbo));
RB_body_set_kinematic_state(rbo->physics_object, !value);
rbo->flag |= RBO_FLAG_NEEDS_VALIDATE;
}
@@ -208,7 +208,7 @@ static void rna_RigidBodyOb_mass_set(PointerRNA *ptr, float value)
#ifdef WITH_BULLET
/* only active bodies need mass update */
if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) {
RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
RB_body_set_mass(rbo->physics_object, BKE_rigidbody_object_mass(rbo));
}
#endif
}
@@ -246,7 +246,7 @@ static void rna_RigidBodyOb_collision_margin_set(PointerRNA *ptr, float value)
#ifdef WITH_BULLET
if (rbo->physics_shape) {
RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo));
RB_shape_set_margin(rbo->physics_shape, BKE_rigidbody_object_margin(rbo));
}
#endif
}
@@ -274,7 +274,7 @@ static void rna_RigidBodyOb_kinematic_state_set(PointerRNA *ptr, int value)
#ifdef WITH_BULLET
/* update kinematic state if necessary */
if (rbo->physics_object) {
RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
RB_body_set_mass(rbo->physics_object, BKE_rigidbody_object_mass(rbo));
RB_body_set_kinematic_state(rbo->physics_object, value);
rbo->flag |= RBO_FLAG_NEEDS_VALIDATE;
}

View File

@@ -73,6 +73,7 @@ set(SRC
intern/MOD_mirror.c
intern/MOD_multires.c
intern/MOD_none.c
intern/MOD_nparticle.c
intern/MOD_ocean.c
intern/MOD_particleinstance.c
intern/MOD_particlesystem.c

View File

@@ -81,6 +81,7 @@ extern ModifierTypeInfo modifierType_UVWarp;
extern ModifierTypeInfo modifierType_MeshCache;
extern ModifierTypeInfo modifierType_LaplacianDeform;
extern ModifierTypeInfo modifierType_Wireframe;
extern ModifierTypeInfo modifierType_NParticleSystem;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);

View File

@@ -0,0 +1,126 @@
/*
* $Id$
*
* ***** 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) 2005 by the Blender Foundation.
* All rights reserved.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
/** \file blender/modifiers/intern/MOD_nparticles.c
* \ingroup modifiers
*/
#include <stddef.h>
#include "BLI_listbase.h"
#include "DNA_modifier_types.h"
#include "DNA_nparticle_types.h"
#include "BKE_modifier.h"
#include "BKE_nparticle.h"
struct DerivedMesh;
struct Object;
static void nparticle_system_initData(ModifierData *md)
{
NParticleSystemModifierData *pmd= (NParticleSystemModifierData *)md;
pmd->psys = BKE_nparticle_system_new();
/* add default particle display */
BKE_nparticle_display_add(pmd->psys, PAR_DISPLAY_PARTICLE);
BKE_nparticle_display_add(pmd->psys, PAR_DISPLAY_DUPLI);
}
static void nparticle_system_freeData(ModifierData *md)
{
NParticleSystemModifierData *pmd= (NParticleSystemModifierData *)md;
BKE_nparticle_system_free(pmd->psys);
pmd->psys = NULL;
}
static void nparticle_system_copyData(ModifierData *md, ModifierData *target)
{
NParticleSystemModifierData *pmd= (NParticleSystemModifierData *)md;
NParticleSystemModifierData *tpmd= (NParticleSystemModifierData *)target;
tpmd->psys = BKE_nparticle_system_copy(pmd->psys);
}
static struct DerivedMesh *nparticle_system_applyModifier(ModifierData *UNUSED(md), struct Object *UNUSED(ob),
struct DerivedMesh *derivedData,
ModifierApplyFlag UNUSED(flag))
{
/*NParticleSystemModifierData *pmd= (NParticleSystemModifierData *)md;*/
return derivedData;
}
static void nparticle_system_foreachObjectLink(ModifierData *md, struct Object *ob,
void (*walk)(void *userData, struct Object *ob, struct Object **obpoin),
void *userData)
{
NParticleSystemModifierData *pmd = (NParticleSystemModifierData *)md;
NParticleDisplay *display;
for (display = pmd->psys->display.first; display; display = display->next) {
switch (display->type) {
case PAR_DISPLAY_DUPLI: {
NParticleDisplayDupliObject *dob;
for (dob = display->dupli_objects.first; dob; dob = dob->next) {
walk(userData, ob, &dob->object);
}
break;
}
}
}
}
ModifierTypeInfo modifierType_NParticleSystem = {
/* name */ "Particles",
/* structName */ "NParticleSystemModifierData",
/* structSize */ sizeof(NParticleSystemModifierData),
/* type */ eModifierTypeType_NonGeometrical,
/* flags */ eModifierTypeFlag_AcceptsMesh /* for now only allow single particle buffer for unambiguous access */
| eModifierTypeFlag_Single
| eModifierTypeFlag_UsesPointCache,
/* copyData */ nparticle_system_copyData,
/* deformVerts */ NULL,
/* deformVertsEM */ NULL,
/* deformMatrices */ NULL,
/* deformMatricesEM */ NULL,
/* applyModifier */ nparticle_system_applyModifier,
/* applyModifierEM */ NULL,
/* initData */ nparticle_system_initData,
/* requiredDataMask */ NULL,
/* freeData */ nparticle_system_freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ nparticle_system_foreachObjectLink,
/* foreachIDLink */ NULL,
};

View File

@@ -309,5 +309,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(MeshCache);
INIT_TYPE(LaplacianDeform);
INIT_TYPE(Wireframe);
INIT_TYPE(NParticleSystem);
#undef INIT_TYPE
}

View File

@@ -20,3 +20,4 @@ add_subdirectory(intern)
add_subdirectory(generic)
add_subdirectory(mathutils)
add_subdirectory(bmesh)
add_subdirectory(bparticles)

View File

@@ -0,0 +1,41 @@
# ***** 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): Campbell Barton
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
../../blenkernel
../../blenlib
../../makesdna
../../../../intern/guardedalloc
)
set(INC_SYS
${PYTHON_INCLUDE_DIRS}
)
set(SRC
bparticles_py_api.c
bparticles_py_types.c
bparticles_py_api.h
bparticles_py_types.h
)
blender_add_lib(bf_python_bparticles "${SRC}" "${INC}" "${INC_SYS}")

View File

@@ -0,0 +1,167 @@
/*
* ***** 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.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/python/bparticles/bparticles_py_api.c
* \ingroup pybparticles
*
* This file defines the 'bparticles' module.
*/
#include <Python.h>
#include "BLI_utildefines.h"
#include "DNA_nparticle_types.h"
#include "BKE_nparticle.h"
#include "bparticles_py_types.h"
#include "../generic/py_capi_utils.h"
#include "bparticles_py_api.h" /* own include */
#include "bparticles_py_types.h"
PyDoc_STRVAR(bpy_bpar_new_doc,
".. method:: new()\n"
"\n"
" :arg psys: The particle system.\n"
" :type psys: :class:`bpy.types.NParticleSystem`\n"
" :return: Return a new, empty NParticleState.\n"
" :rtype: :class:`bparticles.types.NParticleState`\n"
);
static PyObject *bpy_bpar_new(PyObject *UNUSED(self), PyObject *value)
{
NParticleSystem *psys = PyC_RNA_AsPointer(value, "NParticleSystem");
NParticleState *state;
if (!psys)
return NULL;
state = BKE_nparticle_state_new(psys);
return BPy_NParticleState_CreatePyObject(state);
}
PyDoc_STRVAR(bpy_bpar_copy_doc,
".. method:: copy()\n"
"\n"
" :arg psys: The particle system.\n"
" :type psys: :class:`bpy.types.NParticleSystem`\n"
" :return: Return a copy of the current NParticleState.\n"
" :rtype: :class:`bparticles.types.NParticleState`\n"
);
static PyObject *bpy_bpar_copy(PyObject *UNUSED(self), PyObject *value)
{
NParticleSystem *psys = PyC_RNA_AsPointer(value, "NParticleSystem");
NParticleState *state;
if (!psys)
return NULL;
if (psys->state)
state = BKE_nparticle_state_copy(psys->state);
else
state = BKE_nparticle_state_new(psys);
return BPy_NParticleState_CreatePyObject(state);
}
PyDoc_STRVAR(bpy_bpar_set_current_state_doc,
".. method:: set_current_state()\n"
"\n"
" :arg psys: The particle system.\n"
" :type psys: :class:`bpy.types.NParticleSystem`\n"
" :arg state: The particle state.\n"
" :type state: :class:`bparticles.types.NParticleState`\n"
);
static PyObject *bpy_bpar_set_current_state(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
static const char *kwlist[] = {"psys", "state", NULL};
PyObject *py_psys;
BPy_NParticleState *py_state;
NParticleSystem *psys;
NParticleState *state;
if (!PyArg_ParseTupleAndKeywords(args, kw, "OO:set_current_state", (char **)kwlist,
&py_psys, &py_state))
{
return NULL;
}
psys = PyC_RNA_AsPointer(py_psys, "NParticleSystem");
state = BPy_NParticleState_Check(py_state) ? py_state->state : NULL;
if (psys == NULL || state == NULL) {
return NULL;
}
/* XXX currently makes a full copy of the state ... */
BKE_nparticle_system_set_state(psys, state);
Py_RETURN_NONE;
}
static struct PyMethodDef BPy_BPAR_methods[] = {
{"new", (PyCFunction)bpy_bpar_new, METH_O, bpy_bpar_new_doc},
{"copy", (PyCFunction)bpy_bpar_copy, METH_O, bpy_bpar_copy_doc},
{"set_current_state", (PyCFunction)bpy_bpar_set_current_state, METH_VARARGS | METH_KEYWORDS, bpy_bpar_set_current_state_doc},
{NULL, NULL, 0, NULL}
};
PyDoc_STRVAR(BPy_BPAR_doc,
"This module provides access to blenders particle data structures.\n"
"\n"
".. include:: include__bparticles.rst\n"
);
static struct PyModuleDef BPy_BPAR_module_def = {
PyModuleDef_HEAD_INIT,
"bparticles", /* m_name */
BPy_BPAR_doc, /* m_doc */
0, /* m_size */
BPy_BPAR_methods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
PyObject *BPyInit_bparticles(void)
{
PyObject *mod;
PyObject *submodule;
PyObject *sys_modules = PyThreadState_GET()->interp->modules;
BPy_BPAR_init_types();
mod = PyModule_Create(&BPy_BPAR_module_def);
/* bparticles.types */
PyModule_AddObject(mod, "types", (submodule = BPyInit_bparticles_types()));
PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
Py_INCREF(submodule);
return mod;
}

View File

@@ -0,0 +1,35 @@
/*
* ***** 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.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/python/bparticles/bparticles_py_api.h
* \ingroup pybparticles
*/
#ifndef __BPARTICLES_PY_API_H__
#define __BPARTICLES_PY_API_H__
PyObject *BPyInit_bparticles(void);
#endif /* __BPARTICLES_PY_API_H__ */

View File

@@ -0,0 +1,882 @@
/*
* ***** 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.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/python/bparticles/bparticles_py_types.c
* \ingroup pybparticles
*/
#include <Python.h>
#include "BLI_math.h"
#include "BLI_string.h"
#include "DNA_nparticle_types.h"
#include "BKE_nparticle.h"
#include "../mathutils/mathutils.h"
#include "../generic/py_capi_utils.h"
#include "bparticles_py_types.h" /* own include */
/* Type Docstrings
* =============== */
PyDoc_STRVAR(bpy_bpar_state_doc,
"Particle state data\n"
);
PyDoc_STRVAR(bpy_bpar_attrstate_doc,
"Particle attribute state data\n"
);
PyDoc_STRVAR(bpy_bpar_attrstateseq_doc,
"Particle attribute state sequence\n"
);
PyDoc_STRVAR(bpy_bpar_attrstateiter_doc,
"Iterator for looping over particle attribute states\n"
);
PyDoc_STRVAR(bpy_bpar_particle_doc,
"Single particle in state data\n"
);
PyDoc_STRVAR(bpy_bpar_particleseq_doc,
"Particle sequence\n"
);
PyDoc_STRVAR(bpy_bpar_particleiter_doc,
"Iterator for looping over particles\n"
);
PyDoc_STRVAR(bpy_bpar_state_attributes_doc,
"State attributes (read-only).\n\n:type: :class:`NParticleAttributeStateSeq`"
);
static PyObject *bpy_bpar_state_attributes_get(BPy_NParticleState *self, void *UNUSED(closure))
{
return BPy_NParticleAttributeStateSeq_CreatePyObject(self->state);
}
PyDoc_STRVAR(bpy_bpar_state_particles_doc,
"Particles.\n\n:type: :class:`NParticleParticleSeq`"
);
static PyObject *bpy_bpar_state_particles_get(BPy_NParticleState *self, void *UNUSED(closure))
{
return BPy_NParticleParticleSeq_CreatePyObject(self->state);
}
PyDoc_STRVAR(bpy_bpar_attrstate_name_doc,
"Attribute name\n"
);
static PyObject *bpy_bpar_attrstate_name_get(BPy_NParticleAttributeState *self)
{
return PyUnicode_FromString(self->attrstate->desc.name);
}
static PyObject *bpy_bpar_particle_dir(BPy_NParticleParticle *self)
{
NParticleAttributeStateIterator iter;
PyObject *dict;
PyObject *ret;
PyObject *pystring;
// PYRNA_STRUCT_CHECK_OBJ(self);
dict = BPy_NParticleParticle_Type.tp_dict;
if (dict)
ret = PyDict_Keys(dict);
else
ret = PyList_New(0);
for (BKE_nparticle_state_attributes_begin(self->state, &iter);
BKE_nparticle_state_attribute_iter_valid(&iter);
BKE_nparticle_state_attribute_iter_next(&iter)) {
pystring = PyUnicode_FromString(iter.attrstate->desc.name);
PyList_Append(ret, pystring);
Py_DECREF(pystring);
}
return ret;
}
static PyObject *bpy_bpar_state_repr(BPy_NParticleState *self)
{
NParticleState *state = self->state;
if (state) {
return PyUnicode_FromFormat("<NParticleState(%p)>",
state);
}
else {
return PyUnicode_FromFormat("<NParticleState dead at %p>", self);
}
}
static PyObject *bpy_bpar_attrstate_repr(BPy_NParticleAttributeState *self)
{
NParticleAttributeState *attrstate = self->attrstate;
if (attrstate) {
return PyUnicode_FromFormat("<NParticleAttributeState(%p) name=%s, datatype=%s>",
attrstate, attrstate->desc.name,
BKE_nparticle_datatype_name(attrstate->desc.datatype));
}
else {
return PyUnicode_FromFormat("<NParticleAttributeState dead at %p>", self);
}
}
static PyObject *bpy_bpar_particle_repr(BPy_NParticleParticle *self)
{
NParticleIterator *iter = &self->iter;
if (iter->index >= 0) {
return PyUnicode_FromFormat("<NParticleParticle index=%d>", iter->index);
}
else {
return PyUnicode_FromFormat("<NParticleParticle invalid>");
}
}
static PyGetSetDef bpy_bpar_state_getseters[] = {
{(char *)"attributes", (getter)bpy_bpar_state_attributes_get, (setter)NULL, (char *)bpy_bpar_state_attributes_doc, NULL},
{(char *)"particles", (getter)bpy_bpar_state_particles_get, (setter)NULL, (char *)bpy_bpar_state_particles_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
static PyGetSetDef bpy_bpar_attrstate_getseters[] = {
{(char *)"name", (getter)bpy_bpar_attrstate_name_get, (setter)NULL, (char *)bpy_bpar_attrstate_name_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
static struct PyMethodDef bpy_bpar_state_methods[] = {
{NULL, NULL, 0, NULL}
};
static struct PyMethodDef bpy_bpar_attrstate_methods[] = {
{NULL, NULL, 0, NULL}
};
static struct PyMethodDef bpy_bpar_particle_methods[] = {
{"__dir__", (PyCFunction)bpy_bpar_particle_dir, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
};
static Py_hash_t bpy_bpar_state_hash(PyObject *self)
{
return _Py_HashPointer(((BPy_NParticleState *)self)->state);
}
static Py_hash_t bpy_bpar_attrstate_hash(PyObject *self)
{
return _Py_HashPointer(((BPy_NParticleAttributeState *)self)->attrstate);
}
static Py_ssize_t bpy_bpar_attrstateseq_length(BPy_NParticleAttributeStateSeq *self)
{
return BKE_nparticle_state_num_attributes(self->state);
}
static PyObject *bpy_bpar_attrstateseq_subscript_int(BPy_NParticleAttributeStateSeq *self, int keynum)
{
if (keynum < 0)
keynum += BKE_nparticle_state_num_attributes(self->state);
if (keynum >= 0) {
NParticleAttributeState *attrstate = BKE_nparticle_state_get_attribute_by_index(self->state, keynum);
if (attrstate)
return BPy_NParticleAttributeState_CreatePyObject(self->state, attrstate);
}
PyErr_Format(PyExc_IndexError,
"NParticleAttributeStateSeq[index]: index %d out of range", keynum);
return NULL;
}
static PyObject *bpy_bpar_attrstateseq_subscript_str(BPy_NParticleAttributeStateSeq *self, const char *keyname)
{
NParticleAttributeState *attrstate = BKE_nparticle_state_find_attribute(self->state, keyname);
if (attrstate)
return BPy_NParticleAttributeState_CreatePyObject(self->state, attrstate);
PyErr_Format(PyExc_KeyError, "NParticleAttributeStateSeq[key]: key \"%.200s\" not found", keyname);
return NULL;
}
static PyObject *bpy_bpar_attrstateseq_subscript_slice(BPy_NParticleAttributeStateSeq *self, Py_ssize_t start, Py_ssize_t stop)
{
NParticleAttributeStateIterator iter;
int count;
PyObject *list;
PyObject *item;
list = PyList_New(0);
/* skip to start */
for (count = 0, BKE_nparticle_state_attributes_begin(self->state, &iter);
count < start && BKE_nparticle_state_attribute_iter_valid(&iter);
++count, BKE_nparticle_state_attribute_iter_next(&iter))
{}
/* add items until stop */
for (; count < stop && BKE_nparticle_state_attribute_iter_valid(&iter);
++count, BKE_nparticle_state_attribute_iter_next(&iter))
{
item = BPy_NParticleAttributeState_CreatePyObject(self->state, iter.attrstate);
PyList_Append(list, item);
Py_DECREF(item);
}
BKE_nparticle_state_attribute_iter_end(&iter);
return list;
}
static int bpy_bpar_attrstateseq_contains(BPy_NParticleAttributeStateSeq *self, PyObject *value)
{
if (BPy_NParticleAttributeState_Check(value)) {
BPy_NParticleAttributeState *attrstate_py = (BPy_NParticleAttributeState *)value;
NParticleAttributeState *attrstate = attrstate_py->attrstate;
if (BKE_nparticle_state_find_attribute(self->state, attrstate->desc.name) == attrstate)
return 1;
}
return 0;
}
static PyObject *bpy_bpar_attrstateseq_subscript(BPy_NParticleAttributeStateSeq *self, PyObject *key)
{
if (PyUnicode_Check(key)) {
return bpy_bpar_attrstateseq_subscript_str(self, _PyUnicode_AsString(key));
}
else if (PyIndex_Check(key)) {
Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
return NULL;
return bpy_bpar_attrstateseq_subscript_int(self, i);
}
else if (PySlice_Check(key)) {
PySliceObject *key_slice = (PySliceObject *)key;
Py_ssize_t step = 1;
if (key_slice->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
return NULL;
}
else if (step != 1) {
PyErr_SetString(PyExc_TypeError, "NParticleAttributeStateSeq[slice]: slice steps not supported");
return NULL;
}
else if (key_slice->start == Py_None && key_slice->stop == Py_None) {
return bpy_bpar_attrstateseq_subscript_slice(self, 0, PY_SSIZE_T_MAX);
}
else {
Py_ssize_t start = 0, stop = PY_SSIZE_T_MAX;
/* avoid PySlice_GetIndicesEx because it needs to know the length ahead of time. */
if (key_slice->start != Py_None && !_PyEval_SliceIndex(key_slice->start, &start)) return NULL;
if (key_slice->stop != Py_None && !_PyEval_SliceIndex(key_slice->stop, &stop)) return NULL;
if (start < 0 || stop < 0) {
/* only get the length for negative values */
Py_ssize_t len = (Py_ssize_t)BKE_nparticle_state_num_attributes(self->state);
if (start < 0) start += len;
if (stop < 0) stop += len;
}
if (stop - start <= 0) {
return PyList_New(0);
}
else {
return bpy_bpar_attrstateseq_subscript_slice(self, start, stop);
}
}
}
else {
PyErr_Format(PyExc_TypeError,
"NParticleAttributeStateSeq[key]: invalid key, "
"must be a string or an int, not %.200s",
Py_TYPE(key)->tp_name);
return NULL;
}
}
static PySequenceMethods bpy_bpar_attrstateseq_as_sequence = {
(lenfunc)bpy_bpar_attrstateseq_length, /* sq_length */
NULL, /* sq_concat */
NULL, /* sq_repeat */
(ssizeargfunc)bpy_bpar_attrstateseq_subscript_int, /* sq_item */ /* Only set this so PySequence_Check() returns True */
NULL, /* sq_slice */
(ssizeobjargproc)NULL, /* sq_ass_item */
NULL, /* *was* sq_ass_slice */
(objobjproc)bpy_bpar_attrstateseq_contains, /* sq_contains */
(binaryfunc) NULL, /* sq_inplace_concat */
(ssizeargfunc) NULL, /* sq_inplace_repeat */
};
static PyMappingMethods bpy_bpar_attrstateseq_as_mapping = {
(lenfunc)bpy_bpar_attrstateseq_length, /* mp_length */
(binaryfunc)bpy_bpar_attrstateseq_subscript, /* mp_subscript */
(objobjargproc)NULL, /* mp_ass_subscript */
};
static Py_ssize_t bpy_bpar_particleseq_length(BPy_NParticleAttributeStateSeq *self)
{
return BKE_nparticle_state_num_particles(self->state);
}
static PyObject *bpy_bpar_particleseq_subscript_int(BPy_NParticleAttributeStateSeq *self, int keynum)
{
NParticleIterator iter;
NParticleID id = (NParticleID)keynum;
BKE_nparticle_iter_from_id(self->state, &iter, id);
return BPy_NParticleParticle_CreatePyObject(self->state, id, iter);
}
static int bpy_bpar_particleseq_contains(BPy_NParticleParticleSeq *self, PyObject *value)
{
if (BPy_NParticleParticle_Check(value)) {
BPy_NParticleParticle *particle_py = (BPy_NParticleParticle *)value;
return particle_py->state == self->state && BKE_nparticle_iter_valid(&particle_py->iter);
}
return 0;
}
static PyObject *bpy_bpar_particleseq_subscript(BPy_NParticleAttributeStateSeq *self, PyObject *key)
{
if (PyIndex_Check(key)) {
Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
return NULL;
return bpy_bpar_particleseq_subscript_int(self, i);
}
else {
PyErr_Format(PyExc_TypeError,
"NParticleAttributeStateSeq[key]: invalid key, "
"must be an int, not %.200s",
Py_TYPE(key)->tp_name);
return NULL;
}
}
static PySequenceMethods bpy_bpar_particleseq_as_sequence = {
(lenfunc)bpy_bpar_particleseq_length, /* sq_length */
NULL, /* sq_concat */
NULL, /* sq_repeat */
(ssizeargfunc)bpy_bpar_particleseq_subscript_int, /* sq_item */ /* Only set this so PySequence_Check() returns True */
NULL, /* sq_slice */
(ssizeobjargproc)NULL, /* sq_ass_item */
NULL, /* *was* sq_ass_slice */
(objobjproc)bpy_bpar_particleseq_contains, /* sq_contains */
(binaryfunc) NULL, /* sq_inplace_concat */
(ssizeargfunc) NULL, /* sq_inplace_repeat */
};
static PyMappingMethods bpy_bpar_particleseq_as_mapping = {
(lenfunc)bpy_bpar_particleseq_length, /* mp_length */
(binaryfunc)bpy_bpar_particleseq_subscript, /* mp_subscript */
(objobjargproc)NULL, /* mp_ass_subscript */
};
/* Iterator
* -------- */
static PyObject *bpy_bpar_attrstateseq_iter(BPy_NParticleAttributeStateSeq *self)
{
BPy_NParticleAttributeStateIter *py_iter;
py_iter = (BPy_NParticleAttributeStateIter *)BPy_NParticleAttributeStateIter_CreatePyObject(self->state);
BKE_nparticle_state_attributes_begin(self->state, &py_iter->iter);
return (PyObject *)py_iter;
}
static PyObject *bpy_bpar_attrstateiter_next(BPy_NParticleAttributeStateIter *self)
{
if (BKE_nparticle_state_attribute_iter_valid(&self->iter)) {
PyObject *result = BPy_NParticleAttributeState_CreatePyObject(self->state, self->iter.attrstate);
BKE_nparticle_state_attribute_iter_next(&self->iter);
return result;
}
else {
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
}
static PyObject *bpy_bpar_particleseq_iter(BPy_NParticleParticleSeq *self)
{
BPy_NParticleParticleIter *py_iter;
py_iter = (BPy_NParticleParticleIter *)BPy_NParticleParticleIter_CreatePyObject(self->state);
BKE_nparticle_iter_init(self->state, &py_iter->iter);
return (PyObject *)py_iter;
}
static PyObject *bpy_bpar_particleiter_next(BPy_NParticleParticleIter *self)
{
if (BKE_nparticle_iter_valid(&self->iter)) {
NParticleID id = BKE_nparticle_iter_get_id(&self->iter);
PyObject *result = BPy_NParticleParticle_CreatePyObject(self->state, id, self->iter);
BKE_nparticle_iter_next(&self->iter);
return result;
}
else {
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
}
/* Get/Set Functions
* ================= */
static PyObject *bpy_bpar_particle_data_read(NParticleAttributeDescription *desc, void *data)
{
switch (desc->datatype) {
case PAR_ATTR_DATATYPE_FLOAT:
return PyFloat_FromDouble(*(float*)data);
case PAR_ATTR_DATATYPE_INT:
return PyLong_FromLong(*(int*)data);
case PAR_ATTR_DATATYPE_BOOL:
return PyBool_FromLong(*(bool*)data);
case PAR_ATTR_DATATYPE_VECTOR:
case PAR_ATTR_DATATYPE_POINT:
case PAR_ATTR_DATATYPE_NORMAL:
return Vector_CreatePyObject((float*)data, 3, Py_WRAP, NULL);
case PAR_ATTR_DATATYPE_QUATERNION:
return Quaternion_CreatePyObject((float*)data, Py_WRAP, NULL);
case PAR_ATTR_DATATYPE_COLOR:
return Color_CreatePyObject((float*)data, Py_WRAP, NULL);
case PAR_ATTR_DATATYPE_MATRIX:
return Matrix_CreatePyObject((float*)data, 4, 4, Py_WRAP, NULL);
default:
return NULL;
}
}
static int bpy_bpar_particle_data_write(NParticleAttributeDescription *desc, void *data, PyObject *value)
{
/* XXX do we accept this sort of overhead just for error prints?
* only needs to happen for actual errors, but mathutils_array_parse needs string in advance.
*/
// char error_prefix[128];
// BLI_snprintf(error_prefix, sizeof(error_prefix), "NParticleParticle.%.200s", desc->name);
switch (desc->datatype) {
case PAR_ATTR_DATATYPE_FLOAT:
if (PyFloat_Check(value))
*(float*)data = (float)PyFloat_AsDouble(value);
else {
PyErr_Format(PyExc_TypeError,
"NParticleParticle.%.200s expects float, not %.200s",
desc->name, Py_TYPE(value)->tp_name);
return -1;
}
break;
case PAR_ATTR_DATATYPE_INT:
if (PyLong_Check(value))
*(int*)data = (int)PyLong_AsLong(value);
else {
PyErr_Format(PyExc_TypeError,
"NParticleParticle.%.200s expects int, not %.200s",
desc->name, Py_TYPE(value)->tp_name);
return -1;
}
break;
case PAR_ATTR_DATATYPE_BOOL:
if (PyBool_Check(value))
*(bool*)data = (bool)PyLong_AsLong(value);
else {
PyErr_Format(PyExc_TypeError,
"NParticleParticle.%.200s expects bool, not %.200s",
desc->name, Py_TYPE(value)->tp_name);
return -1;
}
break;
case PAR_ATTR_DATATYPE_VECTOR:
case PAR_ATTR_DATATYPE_POINT:
case PAR_ATTR_DATATYPE_NORMAL: {
if (mathutils_array_parse((float*)data, 3, 3, value, "NParticleParticle") == -1)
return -1;
break;
}
case PAR_ATTR_DATATYPE_QUATERNION: {
if (mathutils_array_parse((float*)data, 4, 4, value, "NParticleParticle") == -1)
return -1;
break;
}
case PAR_ATTR_DATATYPE_COLOR: {
if (mathutils_array_parse((float*)data, 3, 3, value, "NParticleParticle") == -1)
return -1;
break;
}
case PAR_ATTR_DATATYPE_MATRIX: {
if (mathutils_array_parse((float*)data, 16, 16, value, "NParticleParticle") == -1)
return -1;
break;
}
}
return 0;
}
static PyObject *bpy_bpar_particle_getattro(BPy_NParticleParticle *self, PyObject *pyname)
{
const char *name = _PyUnicode_AsString(pyname);
PyObject *ret;
// PYRNA_STRUCT_CHECK_OBJ(self);
if (name == NULL) {
PyErr_SetString(PyExc_AttributeError, "NParticleParticle: __getattr__ must be a string");
ret = NULL;
}
else if (!BKE_nparticle_iter_valid(&self->iter)) {
PyErr_Format(PyExc_AttributeError, "NParticleParticle: particle %d does not exist", self->id);
ret = NULL;
}
else {
NParticleAttributeState *attrstate = BKE_nparticle_state_find_attribute(self->state, name);
void *data;
if (!attrstate) {
PyErr_Format(PyExc_AttributeError, "NParticleParticle.%.200s not found", name);
ret = NULL;
}
else {
data = BKE_nparticle_attribute_state_data(attrstate, self->iter.index);
BLI_assert(data != NULL); /* the iterator is valid, so this should never happen */
ret = bpy_bpar_particle_data_read(&attrstate->desc, data);
}
}
return ret;
}
static int bpy_bpar_particle_setattro(BPy_NParticleParticle *self, PyObject *pyname, PyObject *value)
{
const char *name = _PyUnicode_AsString(pyname);
// PYRNA_STRUCT_CHECK_INT(self);
if (name == NULL) {
PyErr_SetString(PyExc_AttributeError, "NParticleParticle: __setattr__ must be a string");
return -1;
}
else {
NParticleAttributeState *attrstate = BKE_nparticle_state_find_attribute(self->state, name);
void *data;
if (!attrstate) {
PyErr_Format(PyExc_AttributeError, "NParticleParticle.%.200s not found", name);
return -1;
}
if (!BKE_nparticle_iter_valid(&self->iter)) {
int index = BKE_nparticle_add(self->state, self->id);
BKE_nparticle_iter_from_index(self->state, &self->iter, index);
}
data = BKE_nparticle_attribute_state_data(attrstate, self->iter.index);
if (!data) {
return -1;
}
if (bpy_bpar_particle_data_write(&attrstate->desc, data, value) == -1) {
return -1;
}
}
return 0;
}
/* Dealloc Functions
* ================= */
static void bpy_bpar_state_dealloc(BPy_NParticleState *self)
{
NParticleState *state = self->state;
if (state) {
state->py_handle = NULL;
BKE_nparticle_state_free(state);
}
PyObject_DEL(self);
}
static void bpy_bpar_attrstate_dealloc(BPy_NParticleAttributeState *self)
{
PyObject_DEL(self);
}
static void bpy_bpar_attrstateseq_dealloc(BPy_NParticleAttributeStateSeq *self)
{
PyObject_DEL(self);
}
static void bpy_bpar_attrstateiter_dealloc(BPy_NParticleAttributeStateIter *self)
{
BKE_nparticle_state_attribute_iter_end(&self->iter);
PyObject_DEL(self);
}
static void bpy_bpar_particle_dealloc(BPy_NParticleParticle *self)
{
PyObject_DEL(self);
}
static void bpy_bpar_particleseq_dealloc(BPy_NParticleParticleSeq *self)
{
PyObject_DEL(self);
}
static void bpy_bpar_particleiter_dealloc(BPy_NParticleParticleIter *self)
{
PyObject_DEL(self);
}
/* Types
* ===== */
PyTypeObject BPy_NParticleState_Type = {{{0}}};
PyTypeObject BPy_NParticleAttributeState_Type = {{{0}}};
PyTypeObject BPy_NParticleAttributeStateSeq_Type = {{{0}}};
PyTypeObject BPy_NParticleAttributeStateIter_Type = {{{0}}};
PyTypeObject BPy_NParticleParticle_Type = {{{0}}};
PyTypeObject BPy_NParticleParticleSeq_Type = {{{0}}};
PyTypeObject BPy_NParticleParticleIter_Type = {{{0}}};
void BPy_BPAR_init_types(void)
{
BPy_NParticleState_Type.tp_basicsize = sizeof(BPy_NParticleState);
BPy_NParticleAttributeState_Type.tp_basicsize = sizeof(BPy_NParticleAttributeState);
BPy_NParticleAttributeStateSeq_Type.tp_basicsize = sizeof(BPy_NParticleAttributeStateSeq);
BPy_NParticleAttributeStateIter_Type.tp_basicsize = sizeof(BPy_NParticleAttributeStateIter);
BPy_NParticleParticle_Type.tp_basicsize = sizeof(BPy_NParticleParticle);
BPy_NParticleParticleSeq_Type.tp_basicsize = sizeof(BPy_NParticleParticleSeq);
BPy_NParticleParticleIter_Type.tp_basicsize = sizeof(BPy_NParticleParticleIter);
BPy_NParticleState_Type.tp_name = "NParticleState";
BPy_NParticleAttributeState_Type.tp_name = "NParticleAttributeState";
BPy_NParticleAttributeStateSeq_Type.tp_name = "NParticleAttributeStateSeq";
BPy_NParticleAttributeStateIter_Type.tp_name = "NParticleAttributeStateIter";
BPy_NParticleParticle_Type.tp_name = "NParticleParticle";
BPy_NParticleParticleSeq_Type.tp_name = "NParticleParticleSeq";
BPy_NParticleParticleIter_Type.tp_name = "NParticleParticleIter";
BPy_NParticleState_Type.tp_doc = bpy_bpar_state_doc;
BPy_NParticleAttributeState_Type.tp_doc = bpy_bpar_attrstate_doc;
BPy_NParticleAttributeStateSeq_Type.tp_doc = bpy_bpar_attrstateseq_doc;
BPy_NParticleAttributeStateIter_Type.tp_doc = bpy_bpar_attrstateiter_doc;
BPy_NParticleParticle_Type.tp_doc = bpy_bpar_particle_doc;
BPy_NParticleParticleSeq_Type.tp_doc = bpy_bpar_particleseq_doc;
BPy_NParticleParticleIter_Type.tp_doc = bpy_bpar_particleiter_doc;
BPy_NParticleState_Type.tp_repr = (reprfunc)bpy_bpar_state_repr;
BPy_NParticleAttributeState_Type.tp_repr = (reprfunc)bpy_bpar_attrstate_repr;
BPy_NParticleAttributeStateSeq_Type.tp_repr = NULL;
BPy_NParticleAttributeStateIter_Type.tp_repr = NULL;
BPy_NParticleParticle_Type.tp_repr = (reprfunc)bpy_bpar_particle_repr;
BPy_NParticleParticleSeq_Type.tp_repr = NULL;
BPy_NParticleParticleIter_Type.tp_repr = NULL;
BPy_NParticleState_Type.tp_getset = bpy_bpar_state_getseters;
BPy_NParticleAttributeState_Type.tp_getset = bpy_bpar_attrstate_getseters;
BPy_NParticleAttributeStateSeq_Type.tp_getset = NULL;
BPy_NParticleAttributeStateIter_Type.tp_getset = NULL;
BPy_NParticleParticleSeq_Type.tp_getset = NULL;
BPy_NParticleParticleIter_Type.tp_getset = NULL;
BPy_NParticleParticle_Type.tp_getattro = (getattrofunc)bpy_bpar_particle_getattro;
BPy_NParticleParticle_Type.tp_setattro = (setattrofunc)bpy_bpar_particle_setattro;
BPy_NParticleState_Type.tp_methods = bpy_bpar_state_methods;
BPy_NParticleAttributeState_Type.tp_methods = bpy_bpar_attrstate_methods;
BPy_NParticleAttributeStateSeq_Type.tp_methods = NULL;
BPy_NParticleAttributeStateIter_Type.tp_methods = NULL;
BPy_NParticleParticle_Type.tp_methods = bpy_bpar_particle_methods;
BPy_NParticleParticleSeq_Type.tp_methods = NULL;
BPy_NParticleParticleIter_Type.tp_methods = NULL;
BPy_NParticleState_Type.tp_hash = bpy_bpar_state_hash;
BPy_NParticleAttributeState_Type.tp_hash = bpy_bpar_attrstate_hash;
BPy_NParticleAttributeStateSeq_Type.tp_hash = NULL;
BPy_NParticleAttributeStateIter_Type.tp_hash = NULL;
BPy_NParticleParticle_Type.tp_hash = NULL;
BPy_NParticleParticleSeq_Type.tp_hash = NULL;
BPy_NParticleParticleIter_Type.tp_hash = NULL;
BPy_NParticleAttributeStateSeq_Type.tp_as_sequence = &bpy_bpar_attrstateseq_as_sequence;
BPy_NParticleParticleSeq_Type.tp_as_sequence = &bpy_bpar_particleseq_as_sequence;
BPy_NParticleAttributeStateSeq_Type.tp_as_mapping = &bpy_bpar_attrstateseq_as_mapping;
BPy_NParticleParticleSeq_Type.tp_as_mapping = &bpy_bpar_particleseq_as_mapping;
BPy_NParticleAttributeStateSeq_Type.tp_iter = (getiterfunc)bpy_bpar_attrstateseq_iter;
BPy_NParticleParticleSeq_Type.tp_iter = (getiterfunc)bpy_bpar_particleseq_iter;
BPy_NParticleAttributeStateIter_Type.tp_iternext = (iternextfunc)bpy_bpar_attrstateiter_next;
BPy_NParticleAttributeStateIter_Type.tp_iter = PyObject_SelfIter;
BPy_NParticleParticleIter_Type.tp_iternext = (iternextfunc)bpy_bpar_particleiter_next;
BPy_NParticleParticleIter_Type.tp_iter = PyObject_SelfIter;
BPy_NParticleState_Type.tp_dealloc = (destructor)bpy_bpar_state_dealloc;
BPy_NParticleAttributeState_Type.tp_dealloc = (destructor)bpy_bpar_attrstate_dealloc;
BPy_NParticleAttributeStateSeq_Type.tp_dealloc = (destructor)bpy_bpar_attrstateseq_dealloc;
BPy_NParticleAttributeStateIter_Type.tp_dealloc = (destructor)bpy_bpar_attrstateiter_dealloc;
BPy_NParticleParticle_Type.tp_dealloc = (destructor)bpy_bpar_particle_dealloc;
BPy_NParticleParticleSeq_Type.tp_dealloc = (destructor)bpy_bpar_particleseq_dealloc;
BPy_NParticleParticleIter_Type.tp_dealloc = (destructor)bpy_bpar_particleiter_dealloc;
BPy_NParticleState_Type.tp_flags = Py_TPFLAGS_DEFAULT;
BPy_NParticleAttributeState_Type.tp_flags = Py_TPFLAGS_DEFAULT;
BPy_NParticleAttributeStateSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
BPy_NParticleAttributeStateIter_Type.tp_flags = Py_TPFLAGS_DEFAULT;
BPy_NParticleParticle_Type.tp_flags = Py_TPFLAGS_DEFAULT;
BPy_NParticleParticleSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
BPy_NParticleParticleIter_Type.tp_flags = Py_TPFLAGS_DEFAULT;
PyType_Ready(&BPy_NParticleState_Type);
PyType_Ready(&BPy_NParticleAttributeState_Type);
PyType_Ready(&BPy_NParticleAttributeStateSeq_Type);
PyType_Ready(&BPy_NParticleAttributeStateIter_Type);
PyType_Ready(&BPy_NParticleParticle_Type);
PyType_Ready(&BPy_NParticleParticleSeq_Type);
PyType_Ready(&BPy_NParticleParticleIter_Type);
}
/* bparticles.types submodule
* ********************* */
static struct PyModuleDef BPy_BPAR_types_module_def = {
PyModuleDef_HEAD_INIT,
"bparticles.types", /* m_name */
NULL, /* m_doc */
0, /* m_size */
NULL, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
PyObject *BPyInit_bparticles_types(void)
{
PyObject *submodule;
submodule = PyModule_Create(&BPy_BPAR_types_module_def);
#define MODULE_TYPE_ADD(s, t) \
PyModule_AddObject(s, t.tp_name, (PyObject *)&t); Py_INCREF((PyObject *)&t)
/* bparticles_py_types.c */
MODULE_TYPE_ADD(submodule, BPy_NParticleState_Type);
MODULE_TYPE_ADD(submodule, BPy_NParticleAttributeState_Type);
MODULE_TYPE_ADD(submodule, BPy_NParticleAttributeStateSeq_Type);
MODULE_TYPE_ADD(submodule, BPy_NParticleAttributeStateIter_Type);
MODULE_TYPE_ADD(submodule, BPy_NParticleParticle_Type);
MODULE_TYPE_ADD(submodule, BPy_NParticleParticleSeq_Type);
MODULE_TYPE_ADD(submodule, BPy_NParticleParticleIter_Type);
#undef MODULE_TYPE_ADD
return submodule;
}
/* Utility Functions
* ***************** */
PyObject *BPy_NParticleState_CreatePyObject(NParticleState *state)
{
BPy_NParticleState *self;
if (state->py_handle) {
self = state->py_handle;
Py_INCREF(self);
}
else {
self = PyObject_New(BPy_NParticleState, &BPy_NParticleState_Type);
self->state = state;
state->py_handle = self; /* point back */
}
return (PyObject *)self;
}
PyObject *BPy_NParticleAttributeState_CreatePyObject(NParticleState *state, NParticleAttributeState *attr)
{
BPy_NParticleAttributeState *self = PyObject_New(BPy_NParticleAttributeState, &BPy_NParticleAttributeState_Type);
self->state = state;
self->attrstate = attr;
return (PyObject *)self;
}
PyObject *BPy_NParticleAttributeStateSeq_CreatePyObject(NParticleState *state)
{
BPy_NParticleAttributeStateSeq *self = PyObject_New(BPy_NParticleAttributeStateSeq, &BPy_NParticleAttributeStateSeq_Type);
self->state = state;
return (PyObject *)self;
}
PyObject *BPy_NParticleAttributeStateIter_CreatePyObject(NParticleState *state)
{
BPy_NParticleAttributeStateIter *self = PyObject_New(BPy_NParticleAttributeStateIter, &BPy_NParticleAttributeStateIter_Type);
self->state = state;
/* caller must initialize 'iter' member */
return (PyObject *)self;
}
PyObject *BPy_NParticleParticle_CreatePyObject(NParticleState *state, NParticleID id, NParticleIterator iter)
{
BPy_NParticleParticle *self = PyObject_New(BPy_NParticleParticle, &BPy_NParticleParticle_Type);
self->state = state;
self->id = id;
self->iter = iter;
return (PyObject *)self;
}
PyObject *BPy_NParticleParticleSeq_CreatePyObject(NParticleState *state)
{
BPy_NParticleParticleSeq *self = PyObject_New(BPy_NParticleParticleSeq, &BPy_NParticleParticleSeq_Type);
self->state = state;
return (PyObject *)self;
}
PyObject *BPy_NParticleParticleIter_CreatePyObject(NParticleState *state)
{
BPy_NParticleParticleIter *self = PyObject_New(BPy_NParticleParticleIter, &BPy_NParticleParticleIter_Type);
self->state = state;
/* caller must initialize 'iter' member */
return (PyObject *)self;
}

View File

@@ -0,0 +1,101 @@
/*
* ***** 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.
*
* Contributor(s): Lukas Toenne
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/python/bparticles/bparticles_py_types.h
* \ingroup pybparticles
*/
#ifndef __BPARTICLES_PY_TYPES_H__
#define __BPARTICLES_PY_TYPES_H__
extern PyTypeObject BPy_NParticleState_Type;
extern PyTypeObject BPy_NParticleAttributeState_Type;
extern PyTypeObject BPy_NParticleAttributeStateSeq_Type;
extern PyTypeObject BPy_NParticleAttributeStateIter_Type;
extern PyTypeObject BPy_NParticleParticle_Type;
extern PyTypeObject BPy_NParticleParticleSeq_Type;
extern PyTypeObject BPy_NParticleParticleIter_Type;
#define BPy_NParticleState_Check(v) (Py_TYPE(v) == &BPy_NParticleState_Type)
#define BPy_NParticleAttributeState_Check(v) (Py_TYPE(v) == &BPy_NParticleAttributeState_Type)
#define BPy_NParticleAttributeStateSeq_Check(v) (Py_TYPE(v) == &BPy_NParticleAttributeStateSeq_Type)
#define BPy_NParticleAttributeStateIter_Check(v) (Py_TYPE(v) == &BPy_NParticleAttributeStateIter_Type)
#define BPy_NParticleParticle_Check(v) (Py_TYPE(v) == &BPy_NParticleParticle_Type)
#define BPy_NParticleParticleSeq_Check(v) (Py_TYPE(v) == &BPy_NParticleParticleSeq_Type)
#define BPy_NParticleParticleIter_Check(v) (Py_TYPE(v) == &BPy_NParticleParticleIter_Type)
typedef struct BPy_NParticleState {
PyObject_VAR_HEAD
struct NParticleState *state; /* keep first */
} BPy_NParticleState;
typedef struct BPy_NParticleAttributeState {
PyObject_VAR_HEAD
struct NParticleState *state; /* keep first */
struct NParticleAttributeState *attrstate;
} BPy_NParticleAttributeState;
typedef struct BPy_NParticleAttributeStateSeq {
PyObject_VAR_HEAD
struct NParticleState *state; /* keep first */
} BPy_NParticleAttributeStateSeq;
typedef struct BPy_NParticleAttributeStateIter {
PyObject_VAR_HEAD
struct NParticleState *state; /* keep first */
NParticleAttributeStateIterator iter;
} BPy_NParticleAttributeStateIter;
typedef struct BPy_NParticleParticle {
PyObject_VAR_HEAD
struct NParticleState *state; /* keep first */
NParticleID id;
NParticleIterator iter;
} BPy_NParticleParticle;
typedef struct BPy_NParticleParticleSeq {
PyObject_VAR_HEAD
struct NParticleState *state; /* keep first */
} BPy_NParticleParticleSeq;
typedef struct BPy_NParticleParticleIter {
PyObject_VAR_HEAD
struct NParticleState *state; /* keep first */
NParticleIterator iter;
} BPy_NParticleParticleIter;
void BPy_BPAR_init_types(void);
PyObject *BPyInit_bparticles_types(void);
PyObject *BPy_NParticleState_CreatePyObject(NParticleState *state);
PyObject *BPy_NParticleAttributeState_CreatePyObject(NParticleState *state, NParticleAttributeState *attr);
PyObject *BPy_NParticleAttributeStateSeq_CreatePyObject(NParticleState *state);
PyObject *BPy_NParticleAttributeStateIter_CreatePyObject(NParticleState *state);
PyObject *BPy_NParticleParticle_CreatePyObject(NParticleState *state, NParticleID id, NParticleIterator iter);
PyObject *BPy_NParticleParticleSeq_CreatePyObject(NParticleState *state);
PyObject *BPy_NParticleParticleIter_CreatePyObject(NParticleState *state);
#endif /* __BPARTICLES_PY_TYPES_H__ */

View File

@@ -80,6 +80,7 @@
#include "../generic/blf_py_api.h"
#include "../generic/idprop_py_api.h"
#include "../bmesh/bmesh_py_api.h"
#include "../bparticles/bparticles_py_api.h"
#include "../mathutils/mathutils.h"
@@ -227,6 +228,7 @@ static struct _inittab bpy_internal_modules[] = {
{"bmesh.utils", BPyInit_bmesh_utils},
{"bmesh.utils", BPyInit_bmesh_geometry},
#endif
{(char *)"bparticles", BPyInit_bparticles},
#ifdef WITH_AUDASPACE
{"aud", AUD_initPython},
#endif