diff options
Diffstat (limited to 'source/blender/blenkernel')
152 files changed, 33640 insertions, 18388 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 7ee8a424d03..06103596be1 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -51,6 +51,7 @@ struct MEdge; struct MFace; struct MTFace; struct Object; +struct Scene; struct Mesh; struct EditMesh; struct ModifierData; @@ -84,7 +85,7 @@ struct DerivedMesh { /* copy a single vert/edge/face from the derived mesh into * *{vert/edge/face}_r. note that the current implementation * of this function can be quite slow, iterating over all - * elements (editmesh, verse mesh) + * elements (editmesh) */ void (*getVert)(DerivedMesh *dm, int index, struct MVert *vert_r); void (*getEdge)(DerivedMesh *dm, int index, struct MEdge *edge_r); @@ -420,49 +421,49 @@ void vDM_ColorBand_store(struct ColorBand *coba); /* Simple function to get me->totvert amount of vertices/normals, correctly deformed and subsurfered. Needed especially when vertexgroups are involved. In use now by vertex/weigt paint and particles */ -float *mesh_get_mapped_verts_nors(struct Object *ob); +float *mesh_get_mapped_verts_nors(struct Scene *scene, struct Object *ob); /* */ -DerivedMesh *mesh_get_derived_final(struct Object *ob, +DerivedMesh *mesh_get_derived_final(struct Scene *scene, struct Object *ob, CustomDataMask dataMask); -DerivedMesh *mesh_get_derived_deform(struct Object *ob, +DerivedMesh *mesh_get_derived_deform(struct Scene *scene, struct Object *ob, CustomDataMask dataMask); -DerivedMesh *mesh_create_derived_for_modifier(struct Object *ob, struct ModifierData *md); +DerivedMesh *mesh_create_derived_for_modifier(struct Scene *scene, struct Object *ob, struct ModifierData *md); -DerivedMesh *mesh_create_derived_render(struct Object *ob, +DerivedMesh *mesh_create_derived_render(struct Scene *scene, struct Object *ob, CustomDataMask dataMask); -DerivedMesh *mesh_create_derived_index_render(struct Object *ob, CustomDataMask dataMask, int index); +DerivedMesh *mesh_create_derived_index_render(struct Scene *scene, struct Object *ob, CustomDataMask dataMask, int index); /* same as above but wont use render settings */ -DerivedMesh *mesh_create_derived_view(struct Object *ob, +DerivedMesh *mesh_create_derived_view(struct Scene *scene, struct Object *ob, CustomDataMask dataMask); -DerivedMesh *mesh_create_derived_no_deform(struct Object *ob, +DerivedMesh *mesh_create_derived_no_deform(struct Scene *scene, struct Object *ob, float (*vertCos)[3], CustomDataMask dataMask); -DerivedMesh *mesh_create_derived_no_deform_render(struct Object *ob, +DerivedMesh *mesh_create_derived_no_deform_render(struct Scene *scene, struct Object *ob, float (*vertCos)[3], CustomDataMask dataMask); /* for gameengine */ -DerivedMesh *mesh_create_derived_no_virtual(struct Object *ob, float (*vertCos)[3], +DerivedMesh *mesh_create_derived_no_virtual(struct Scene *scene, struct Object *ob, float (*vertCos)[3], CustomDataMask dataMask); -DerivedMesh *editmesh_get_derived_base(void); -DerivedMesh *editmesh_get_derived_cage(CustomDataMask dataMask); -DerivedMesh *editmesh_get_derived_cage_and_final(DerivedMesh **final_r, +DerivedMesh *editmesh_get_derived_base(struct Object *, struct EditMesh *em); +DerivedMesh *editmesh_get_derived_cage(struct Scene *scene, struct Object *, + struct EditMesh *em, CustomDataMask dataMask); +DerivedMesh *editmesh_get_derived_cage_and_final(struct Scene *scene, struct Object *, + struct EditMesh *em, DerivedMesh **final_r, CustomDataMask dataMask); +void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct EditMesh *em, CustomDataMask dataMask); /* returns an array of deform matrices for crazyspace correction, and the number of modifiers left */ -int editmesh_get_first_deform_matrices(float (**deformmats)[3][3], +int editmesh_get_first_deform_matrices(struct Object *, struct EditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3]); void weight_to_rgb(float input, float *fr, float *fg, float *fb); -/* determines required DerivedMesh data according to view and edit modes */ -CustomDataMask get_viewedit_datamask(); - /* convert layers requested by a GLSL material to actually available layers in * the DerivedMesh, with both a pointer for arrays and an offset for editmesh */ typedef struct DMVertexAttribs { diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 37ced4cb00b..d35acb5447a 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -1,6 +1,6 @@ /* BKE_action.h May 2001 * - * Blender kernel action functionality + * Blender kernel action and pose functionality * * Reevan McKay * @@ -26,6 +26,7 @@ * All rights reserved. * * Contributor(s): Full recode, Ton Roosendaal, Crete 2005 + * Full recode, Joshua Leung, 2009 * * ***** END GPL LICENSE BLOCK ***** */ @@ -35,15 +36,14 @@ #include "DNA_listBase.h" -/** - * The following structures are defined in DNA_action_types.h - */ - +/* The following structures are defined in DNA_action_types.h, and DNA_anim_types.h */ struct bAction; -struct bActionChannel; +struct bActionGroup; +struct FCurve; struct bPose; struct bPoseChannel; struct Object; +struct Scene; struct ID; /* Kernel prototypes */ @@ -51,6 +51,42 @@ struct ID; extern "C" { #endif +/* Action API ----------------- */ + +/* Allocate a new bAction with the given name */ +struct bAction *add_empty_action(const char name[]); + +/* Allocate a copy of the given Action and all its data */ +struct bAction *copy_action(struct bAction *src); + +/* Deallocate all of the Action's data, but not the Action itself */ +void free_action(struct bAction *act); + +// XXX is this needed? +void make_local_action(struct bAction *act); + +/* Some kind of bounding box operation on the action */ +void calc_action_range(const struct bAction *act, float *start, float *end, int incl_hidden); + +/* Does action have any motion data at all? */ +short action_has_motion(const struct bAction *act); + +/* Action Groups API ----------------- */ + +/* Make the given Action Group the active one */ +void set_active_action_group(struct bAction *act, struct bActionGroup *agrp, short select); + +/* Add given channel into (active) group */ +void action_groups_add_channel(struct bAction *act, struct bActionGroup *agrp, struct FCurve *fcurve); + +/* Remove the given channel from all groups */ +void action_groups_remove_channel(struct bAction *act, struct FCurve *fcu); + +/* Find a group with the given name */ +struct bActionGroup *action_groups_find_named(struct bAction *act, const char name[]); + + +/* Pose API ----------------- */ /** * Removes and deallocates all channels from a pose. @@ -67,101 +103,61 @@ void free_pose(struct bPose *pose); * Allocate a new pose on the heap, and copy the src pose and it's channels * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL. */ -void copy_pose(struct bPose **dst, struct bPose *src, - int copyconstraints); +void copy_pose(struct bPose **dst, struct bPose *src, int copyconstraints); -/** - * Deallocate the action's channels including constraint channels. - * does not free the action structure. - */ -void free_action(struct bAction * id); - -void make_local_action(struct bAction *act); - -/* only for armatures, doing pose actions only too */ -void do_all_pose_actions(struct Object *); -/* only for objects, doing only 1 channel */ -void do_all_object_actions(struct Object *); -/* only for Mesh, Curve, Surface, Lattice, doing only Shape channel */ -void do_all_shape_actions(struct Object *); /** * Return a pointer to the pose channel of the given name * from this pose. */ -struct bPoseChannel *get_pose_channel(const struct bPose *pose, - const char *name); +struct bPoseChannel *get_pose_channel(const struct bPose *pose, const char *name); + +/** + * Return a pointer to the active pose channel from this Object. + * (Note: Object, not bPose is used here, as we need layer info from Armature) + */ +struct bPoseChannel *get_active_posechannel(struct Object *ob); /** * Looks to see if the channel with the given name * already exists in this pose - if not a new one is * allocated and initialized. */ -struct bPoseChannel *verify_pose_channel(struct bPose* pose, - const char* name); +struct bPoseChannel *verify_pose_channel(struct bPose* pose, const char* name); + + /* sets constraint flags */ void update_pose_constraint_flags(struct bPose *pose); /* clears BONE_UNKEYED flags for frame changing */ +// XXX to be depreceated for a more general solution in animsys... void framechange_poses_clear_unkeyed(void); -/** - * Allocate a new bAction on the heap and copy - * the contents of src into it. If src is NULL NULL is returned. - */ +/* Bone Groups API --------------------- */ -struct bAction *copy_action(struct bAction *src); +/* Adds a new bone-group */ +void pose_add_group(struct Object *ob); -/** - * Some kind of bounding box operation on the action. - */ -void calc_action_range(const struct bAction *act, float *start, float *end, int incl_hidden); +/* Remove the active bone-group */ +void pose_remove_group(struct Object *ob); -/** - * Set the pose channels from the given action. - */ -void extract_pose_from_action(struct bPose *pose, struct bAction *act, float ctime); +/* Assorted Evaluation ----------------- */ -/** - * Get the effects of the given action using a workob - */ -void what_does_obaction(struct Object *ob, struct bAction *act, float cframe); - -/** - * Iterate through the action channels of the action - * and return the channel with the given name. - * Returns NULL if no channel. - */ -struct bActionChannel *get_action_channel(struct bAction *act, const char *name); -/** - * Iterate through the action channels of the action - * and return the channel with the given name. - * Returns and adds new channel if no channel. - */ -struct bActionChannel *verify_action_channel(struct bAction *act, const char *name); - - /* baking */ -struct bAction *bake_obIPO_to_action(struct Object *ob); - -/* exported for game engine */ -void blend_poses(struct bPose *dst, struct bPose *src, float srcweight, short mode); -void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); +/* Used for the Action Constraint */ +void what_does_obaction(struct Scene *scene, struct Object *ob, struct Object *workob, struct bPose *pose, struct bAction *act, char groupname[], float cframe); /* for proxy */ void copy_pose_result(struct bPose *to, struct bPose *from); /* clear all transforms */ void rest_pose(struct bPose *pose); -/* map global time (frame nr) to strip converted time, doesn't clip */ -float get_action_frame(struct Object *ob, float cframe); -/* map strip time to global time (frame nr) */ -float get_action_frame_inv(struct Object *ob, float cframe); -/* builds a list of NlaIpoChannel with ipo values to write in datablock */ -void extract_ipochannels_from_action(ListBase *lb, struct ID *id, struct bAction *act, const char *name, float ctime); -/* write values returned by extract_ipochannels_from_action, returns the number of value written */ -int execute_ipochannels(ListBase *lb); +/* Game Engine ------------------------- */ + +/* exported for game engine */ +void game_blend_poses(struct bPose *dst, struct bPose *src, float srcweight/*, short mode*/); /* was blend_poses */ +void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); /* functions used by the game engine */ void game_copy_pose(struct bPose **dst, struct bPose *src); diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h new file mode 100644 index 00000000000..2447d1823af --- /dev/null +++ b/source/blender/blenkernel/BKE_animsys.h @@ -0,0 +1,107 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + * + * Contributor(s): Joshua Leung (original author) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_ANIM_SYS_H +#define BKE_ANIM_SYS_H + +struct ID; +struct ListBase; +struct Main; +struct AnimData; +struct KeyingSet; +struct KS_Path; + +struct PointerRNA; +struct bAction; +struct bActionGroup; +struct AnimMapper; + +/* ************************************* */ +/* AnimData API */ + +/* Get AnimData from the given ID-block. */ +struct AnimData *BKE_animdata_from_id(struct ID *id); + +/* Add AnimData to the given ID-block */ +struct AnimData *BKE_id_add_animdata(struct ID *id); + +/* Free AnimData */ +void BKE_free_animdata(struct ID *id); + +/* Copy AnimData */ +struct AnimData *BKE_copy_animdata(struct AnimData *adt); + +/* ************************************* */ +/* KeyingSets API */ + +/* Used to create a new 'custom' KeyingSet for the user, that will be automatically added to the stack */ +struct KeyingSet *BKE_keyingset_add(struct ListBase *list, const char name[], short flag, short keyingflag); + +/* Add a destination to a KeyingSet */ +void BKE_keyingset_add_destination(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode); + +struct KS_Path *BKE_keyingset_find_destination(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, int group_mode); + +/* Free data for KeyingSet but not set itself */ +void BKE_keyingset_free(struct KeyingSet *ks); + +/* Free all the KeyingSets in the given list */ +void BKE_keyingsets_free(struct ListBase *list); + +/* ************************************* */ +// TODO: overrides, remapping, and path-finding api's + +/* ************************************* */ +/* Evaluation API */ + +/* ------------- Main API -------------------- */ +/* In general, these ones should be called to do all animation evaluation */ + +/* Evaluation loop for evaluating animation data */ +void BKE_animsys_evaluate_animdata(struct ID *id, struct AnimData *adt, float ctime, short recalc); + +/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */ +void BKE_animsys_evaluate_all_animation(struct Main *main, float ctime); + + +/* ------------ Specialised API --------------- */ +/* There are a few special tools which require these following functions. They are NOT to be used + * for standard animation evaluation UNDER ANY CIRCUMSTANCES! + * + * i.e. Pose Library (PoseLib) uses some of these for selectively applying poses, but + * Particles/Sequencer performing funky time manipulation is not ok. + */ + +/* Evaluate Action (F-Curve Bag) */ +void animsys_evaluate_action(struct PointerRNA *ptr, struct bAction *act, struct AnimMapper *remap, float ctime); + +/* Evaluate Action Group */ +void animsys_evaluate_action_group(struct PointerRNA *ptr, struct bAction *act, struct bActionGroup *agrp, struct AnimMapper *remap, float ctime); + +/* ************************************* */ + +#endif /* BKE_ANIM_SYS_H*/ diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 62061238131..0595134f5c9 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -37,6 +37,7 @@ struct bArmature; struct bPose; struct bPoseChannel; struct bConstraint; +struct Scene; struct Object; struct MDeformVert; struct Mesh; @@ -68,7 +69,9 @@ typedef struct PoseTree #ifdef __cplusplus extern "C" { #endif + struct bArmature *add_armature(char *name); +struct bArmature *get_armature(struct Object *ob); void free_boneChildren(struct Bone *bone); void free_bones (struct bArmature *arm); void unlink_armature(struct bArmature *arm); @@ -79,7 +82,6 @@ struct bArmature *copy_armature(struct bArmature *arm); void bone_flip_name (char *name, int strip_number); void bone_autoside_name (char *name, int strip_number, short axis, float head, float tail); -struct bArmature *get_armature (struct Object *ob); struct Bone *get_named_bone (struct bArmature *arm, const char *name); float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, float rad2, float rdist); @@ -87,7 +89,7 @@ float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, fl void where_is_armature (struct bArmature *arm); void where_is_armature_bone(struct Bone *bone, struct Bone *prevbone); void armature_rebuild_pose(struct Object *ob, struct bArmature *arm); -void where_is_pose (struct Object *ob); +void where_is_pose (struct Scene *scene, struct Object *ob); /* get_objectspace_bone_matrix has to be removed still */ void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed); diff --git a/source/blender/blenkernel/BKE_bad_level_calls.h b/source/blender/blenkernel/BKE_bad_level_calls.h deleted file mode 100644 index 71f8aee8e99..00000000000 --- a/source/blender/blenkernel/BKE_bad_level_calls.h +++ /dev/null @@ -1,242 +0,0 @@ -/** - * blenlib/BKE_bad_level_calls.h (mar-2001 nzc) - * - * Stuff that definitely does not belong in the kernel! These will all - * have to be removed in order to restore sanity. - * - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ -#ifndef BKE_BAD_LEVEL_CALLS_H -#define BKE_BAD_LEVEL_CALLS_H - -/* blender.c */ -void freeAllRad(void); -void free_editText(void); -void free_vertexpaint(void); - -/* readfile.c */ -struct SpaceButs; -void set_rects_butspace(struct SpaceButs *buts); -struct SpaceImaSel; -void check_imasel_copy(struct SpaceImaSel *simasel); -struct ScrArea; -struct bScreen; -void unlink_screen(struct bScreen *sc); -void setscreen(struct bScreen *sc); -void force_draw_all(int); - /* otherwise the WHILE_SEQ doesn't work */ -struct Sequence; -struct ListBase; -void build_seqar(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq); - -/* BPython API */ -struct ID; -struct Script; -struct Text; -struct IpoDriver; /* DNA_curve_types.h */ -struct Object; -struct PyObject; -struct Node_Type; -struct BPy_Node; -struct bNode; -struct bNodeStack; -struct ShadeInput; -struct bPythonConstraint; -struct bConstraintOb; -struct bConstraintTarget; -void BPY_do_pyscript (struct ID *id, short int event); -void BPY_clear_script (struct Script *script); -void BPY_free_compiled_text (struct Text *text); -/* pydrivers */ -struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver); -float BPY_pydriver_eval(struct IpoDriver *driver); -void BPY_pydriver_update(void); -/* button python evaluation */ -int BPY_button_eval(char *expr, double *value); -/* pyconstraints */ -void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets); -void BPY_pyconstraint_targets(struct bPythonConstraint *con, struct bConstraintTarget *ct); -/* pynodes */ -int EXPP_dict_set_item_str(struct PyObject *dict, char *key, struct PyObject *value); -void Node_SetStack(struct BPy_Node *self, struct bNodeStack **stack, int type); -void InitNode(struct BPy_Node *self, struct bNode *node); -void Node_SetShi(struct BPy_Node *self, struct ShadeInput *shi); -struct BPy_NodeSockets *Node_CreateSocketLists(struct bNode *node); -int pytype_is_pynode(struct PyObject *pyob); -/* writefile.c */ -struct Oops; -void free_oops(struct Oops *oops); -void error(char *str, ...); -int okee(char *str, ...); - -/* anim.c */ -extern struct ListBase editNurb; - -void mainqenter (unsigned short event, short val); -void waitcursor(int); -void allqueue(unsigned short event, short val); -#define REDRAWVIEW3D 0x4010 -#define REDRAWBUTSOBJECT 0x4018 -#define REDRAWBUTSEDIT 0x4019 -struct Material; -extern struct Material defmaterial; - - -/* exotic.c */ -void load_editMesh(void); -void make_editMesh(void); -struct EditMesh; -void free_editMesh(struct EditMesh *); -void free_editArmature(void); -void docenter_new(void); -int saveover(char *str); - -/* ipo.c */ -void copy_view3d_lock(short val); // was a hack, to make scene layer ipo's possible - -/* library.c */ -void allspace(unsigned short event, short val) ; -#define OOPS_TEST 2 - -/* mball.c */ -extern struct ListBase editelems; - -/* object.c */ -struct ScriptLink; -void BPY_free_scriptlink(struct ScriptLink *slink); -void BPY_copy_scriptlink(struct ScriptLink *scriptlink); -float *give_cursor(void); // become a callback or argument -void exit_posemode(int freedata); - -/* packedFile.c */ -short pupmenu(char *instr); // will be general callback - -/* sca.c */ -#define LEFTMOUSE 0x001 // because of mouse sensor - -/* scene.c */ -#include "DNA_sequence_types.h" -void free_editing(struct Editing *ed); // scenes and sequences problem... -void BPY_do_all_scripts (short int event, short int anim); -int BPY_call_importloader(char *name); - - -extern char texstr[20][12]; /* buttons.c */ - - -/* editsca.c */ -void make_unique_prop_names(char *str); - -/* DerivedMesh.c */ -void bglBegin(int mode); -void bglVertex3fv(float *vec); -void bglVertex3f(float x, float y, float z); -void bglEnd(void); - -struct Object; - -/* booleanops.c */ -struct DerivedMesh *NewBooleanDerivedMesh(struct DerivedMesh *dm, struct Object *ob, struct DerivedMesh *dm_select, struct Object *ob_select, - int int_op_type); - -/* verse_*.c */ -struct VerseVert; -struct VerseFace; -struct VerseSession; -struct VNode; -struct VTag; -struct VTagGroup; -struct VBitmapLayer; -struct VLink; -struct VLayer; -struct Mesh; - -void post_vertex_create(struct VerseVert *vvert); -void post_vertex_set_xyz(struct VerseVert *vvert); -void post_vertex_delete(struct VerseVert *vvert); -void post_vertex_free_constraint(struct VerseVert *vvert); -void post_polygon_create(struct VerseFace *vface); -void post_polygon_set_corner(struct VerseFace *vface); -void post_polygon_delete(struct VerseFace *vface); -void post_polygon_free_constraint(struct VerseFace *vface); -void post_polygon_set_uint8(struct VerseFace *vface); -void post_node_create(struct VNode *vnode); -void post_node_destroy(struct VNode *vnode); -void post_node_name_set(struct VNode *vnode); -void post_tag_change(struct VTag *vtag); -void post_taggroup_create(struct VTagGroup *vtaggroup); -char *verse_client_name(void); -void post_transform(struct VNode *vnode); -void post_transform_pos(struct VNode *vnode); -void post_transform_rot(struct VNode *vnode); -void post_transform_scale(struct VNode *vnode); -void post_object_free_constraint(struct VNode *vnode); -void post_link_set(struct VLink *vlink); -void post_link_destroy(struct VLink *vlink); -void post_connect_accept(struct VerseSession *session); -void post_connect_terminated(struct VerseSession *session); -void post_connect_update(struct VerseSession *session); -void add_screenhandler(struct bScreen *sc, short eventcode, short val); -void post_bitmap_dimension_set(struct VNode *vnode); -void post_bitmap_layer_create(struct VBitmapLayer *vblayer); -void post_bitmap_layer_destroy(struct VBitmapLayer *vblayer); -void post_bitmap_tile_set(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys); -void create_meshdata_from_geom_node(struct Mesh *me, struct VNode *vnode); -void post_geometry_free_constraint(struct VNode *vnode); -void post_layer_create(struct VLayer *vlayer); -void post_layer_destroy(struct VLayer *vlayer); -void post_server_add(void); - -/* zbuf.c */ -void antialias_tagbuf(int xsize, int ysize, char *rectmove); - -/* imagetexture.c */ -void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result); - -/* modifier.c */ -struct MeshDeformModifierData; - -void harmonic_coordinates_bind(struct MeshDeformModifierData *mmd, - float (*vertexcos)[3], int totvert, float cagemat[][4]); - -/* particle.c */ -struct ParticleSystem; - -void PE_free_particle_edit(struct ParticleSystem *psys); -void PE_get_colors(char sel[4], char nosel[4]); -void PE_recalc_world_cos(struct Object *ob, struct ParticleSystem *psys); - -/* texture.c */ -struct Tex; -struct TexResult; -int multitex_thread(struct Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, struct TexResult *texres, short thread, short which_output); - - - -#endif - diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 30e68b83149..19b9c315939 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -39,21 +39,29 @@ extern "C" { struct ListBase; struct MemFile; +struct bContext; +struct ReportList; -#define BLENDER_VERSION 249 -#define BLENDER_SUBVERSION 2 +#define BLENDER_VERSION 250 +#define BLENDER_SUBVERSION 0 -#define BLENDER_MINVERSION 245 -#define BLENDER_MINSUBVERSION 15 +#define BLENDER_MINVERSION 250 +#define BLENDER_MINSUBVERSION 0 -int BKE_read_file(char *dir, void *type_r); -int BKE_read_file_from_memory(char* filebuf, int filelength, void *type_r); -int BKE_read_file_from_memfile(struct MemFile *memfile); +int BKE_read_file(struct bContext *C, char *dir, void *type_r, struct ReportList *reports); +int BKE_read_file_from_memory(struct bContext *C, char* filebuf, int filelength, void *type_r, struct ReportList *reports); +int BKE_read_file_from_memfile(struct bContext *C, struct MemFile *memfile, struct ReportList *reports); -void duplicatelist(struct ListBase *list1, struct ListBase *list2); void free_blender(void); void initglobals(void); +/* load new userdef from file, exit blender */ +void BKE_userdef_free(void); + +/* set this callback when a UI is running */ +void set_blender_test_break_cb(void (*func)(void) ); +int blender_test_break(void); + void pushdata(void *data, int len); void popfirst(void *data); void poplast(void *data); @@ -61,11 +69,12 @@ void free_pushpop(void); void pushpop_test(void); /* global undo */ -extern void BKE_write_undo(char *name); -extern void BKE_undo_step(int step); +extern void BKE_write_undo(struct bContext *C, char *name); +extern void BKE_undo_step(struct bContext *C, int step); +extern void BKE_undo_name(struct bContext *C, const char *name); extern void BKE_reset_undo(void); extern char *BKE_undo_menu_string(void); -extern void BKE_undo_number(int nr); +extern void BKE_undo_number(struct bContext *C, int nr); extern void BKE_undo_save_quit(void); #ifdef __cplusplus diff --git a/source/blender/blenkernel/BKE_bmesh.h b/source/blender/blenkernel/BKE_bmesh.h index 04ffc0a4092..957cd8ef9bd 100644 --- a/source/blender/blenkernel/BKE_bmesh.h +++ b/source/blender/blenkernel/BKE_bmesh.h @@ -44,7 +44,7 @@ #include "DNA_image_types.h" #include "BLI_editVert.h" #include "BKE_DerivedMesh.h" -#include "transform.h" +//XXX #include "transform.h" /*forward declerations*/ struct BME_Vert; @@ -247,7 +247,7 @@ struct BME_Mesh *BME_bevel(struct BME_Mesh *bm, float value, int res, int option /*CONVERSION FUNCTIONS*/ struct BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em); -struct EditMesh *BME_bmesh_to_editmesh(struct BME_Mesh *bm, BME_TransData_Head *td); +void BME_bmesh_to_editmesh(struct BME_Mesh *bm, BME_TransData_Head *td, EditMesh *em); struct BME_Mesh *BME_derivedmesh_to_bmesh(struct DerivedMesh *dm); struct DerivedMesh *BME_bmesh_to_derivedmesh(struct BME_Mesh *bm, struct DerivedMesh *dm); #endif diff --git a/source/blender/blenkernel/BKE_boids.h b/source/blender/blenkernel/BKE_boids.h new file mode 100644 index 00000000000..acceff863b9 --- /dev/null +++ b/source/blender/blenkernel/BKE_boids.h @@ -0,0 +1,62 @@ +/* BKE_particle.h + * + * + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 by Janne Karhu. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_BOIDS_H +#define BKE_BOIDS_H + +#include "DNA_boid_types.h" + +typedef struct BoidBrainData { + Scene *scene; + struct Object *ob; + struct ParticleSystem *psys; + struct ParticleSettings *part; + float timestep, cfra, dfra; + float wanted_co[3], wanted_speed; + + /* Goal stuff */ + struct Object *goal_ob; + float goal_co[3]; + float goal_nor[3]; + float goal_priority; +} BoidBrainData; + +void boids_precalc_rules(struct ParticleSettings *part, float cfra); +void boid_brain(BoidBrainData *bbd, int p, struct ParticleData *pa); +void boid_body(BoidBrainData *bbd, struct ParticleData *pa); +void boid_default_settings(BoidSettings *boids); +BoidRule *boid_new_rule(int type); +BoidState *boid_new_state(BoidSettings *boids); +BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state); +void boid_free_settings(BoidSettings *boids); +BoidSettings *boid_copy_settings(BoidSettings *boids); +BoidState *boid_get_current_state(BoidSettings *boids); +#endif diff --git a/source/blender/blenkernel/BKE_booleanops.h b/source/blender/blenkernel/BKE_booleanops.h index 118066e3806..a32f21af859 100644 --- a/source/blender/blenkernel/BKE_booleanops.h +++ b/source/blender/blenkernel/BKE_booleanops.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * The Original Code is Copyright (C) Blender Foundation. * All rights reserved. * * The Original Code is: all of this file. @@ -29,6 +29,7 @@ #ifndef BKE_BOOLEANOPS_H #define BKE_BOOLEANOPS_H +struct Scene; struct Object; struct Base; struct DerivedMesh; @@ -36,7 +37,7 @@ struct DerivedMesh; /* Performs a boolean between two mesh objects, it is assumed that both objects are in fact a mesh object. On success returns 1 and creates a new mesh object into blender data structures. On failure returns 0 and reports an error. */ -int NewBooleanMesh(struct Base *base, struct Base *base_select, int op); +int NewBooleanMesh(struct Scene *scene, struct Base *base, struct Base *base_select, int op); /* Performs a boolean between two mesh objects, it is assumed that both objects diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 398d203709f..9eb0b15aed4 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -34,6 +34,8 @@ struct ID; struct Brush; struct ImBuf; +struct Scene; +struct wmOperator; /* datablock functions */ struct Brush *add_brush(char *name); @@ -42,6 +44,7 @@ void make_local_brush(struct Brush *brush); void free_brush(struct Brush *brush); /* brush library operations used by different paint panels */ +struct Brush **current_brush_source(struct Scene *sce); int brush_set_nr(struct Brush **current_brush, int nr); int brush_delete(struct Brush **current_brush); void brush_check_exists(struct Brush **brush); @@ -51,6 +54,15 @@ int brush_texture_delete(struct Brush *brush); int brush_clone_image_set_nr(struct Brush *brush, int nr); int brush_clone_image_delete(struct Brush *brush); +/* brush curve */ +typedef enum { + BRUSH_PRESET_SHARP, + BRUSH_PRESET_SMOOTH, + BRUSH_PRESET_MAX +} BrushCurvePreset; +void brush_curve_preset(struct Brush *b, BrushCurvePreset preset); +float brush_curve_strength(struct Brush *br, float p, const float len); + /* sampling */ float brush_sample_falloff(struct Brush *brush, float dist); float brush_sample_falloff_noalpha(struct Brush *brush, float dist); @@ -71,5 +83,12 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, void brush_painter_break_stroke(BrushPainter *painter); void brush_painter_free(BrushPainter *painter); +/* texture */ +unsigned int *brush_gen_texture_cache(struct Brush *br, int half_side); + +/* radial control */ +void brush_radial_control_invoke(struct wmOperator *op, struct Brush *br, float size_weight); +int brush_radial_control_exec(struct wmOperator *op, struct Brush *br, float size_weight); + #endif diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index b537536043d..bc4585106e6 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -46,11 +46,12 @@ #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BKE_collision.h" struct Object; - +struct Scene; struct MFace; struct DerivedMesh; struct ClothModifierData; @@ -207,7 +208,7 @@ typedef enum //////////////////////////////////////////////// // needed for implicit.c -int cloth_bvh_objcollision ( Object *ob, ClothModifierData * clmd, float step, float dt ); +int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, float dt ); //////////////////////////////////////////////// @@ -235,7 +236,7 @@ void clmdSetInterruptCallBack ( int ( *f ) ( void ) ); void cloth_free_modifier_extern ( ClothModifierData *clmd ); void cloth_free_modifier ( Object *ob, ClothModifierData *clmd ); void cloth_init ( ClothModifierData *clmd ); -DerivedMesh *clothModifier_do ( ClothModifierData *clmd,Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc ); +DerivedMesh *clothModifier_do ( ClothModifierData *clmd, struct Scene *scene, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc ); void cloth_update_normals ( ClothVertex *verts, int nVerts, MFace *face, int totface ); @@ -243,10 +244,6 @@ void cloth_update_normals ( ClothVertex *verts, int nVerts, MFace *face, int tot void bvhtree_update_from_cloth ( ClothModifierData *clmd, int moving ); void bvhselftree_update_from_cloth ( ClothModifierData *clmd, int moving ); -// needed for editmesh.c -void cloth_write_cache ( Object *ob, ClothModifierData *clmd, float framenr ); -int cloth_read_cache ( Object *ob, ClothModifierData *clmd, float framenr ); - // needed for button_object.c void cloth_clear_cache ( Object *ob, ClothModifierData *clmd, float framenr ); diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index 5e6485d48a3..e4eed084a3d 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -50,6 +50,7 @@ #include "BLI_kdopbvh.h" struct Object; +struct Scene; struct Cloth; struct MFace; struct DerivedMesh; @@ -138,7 +139,7 @@ void interpolateOnTriangle ( float to[3], float v1[3], float v2[3], float v3[3], ///////////////////////////////////////////////// // used in effect.c ///////////////////////////////////////////////// -CollisionModifierData **get_collisionobjects(Object *self, int *numcollobj); +CollisionModifierData **get_collisionobjects(struct Scene *scene, Object *self, int *numcollobj); ///////////////////////////////////////////////// diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h index 555b467b1d6..c83a260690b 100644 --- a/source/blender/blenkernel/BKE_colortools.h +++ b/source/blender/blenkernel/BKE_colortools.h @@ -33,7 +33,16 @@ struct CurveMapping; struct CurveMap; struct ImBuf; struct rctf; - + +void gamma_correct_rec709(float *c, float gamma); +void gamma_correct(float *c, float gamma); +float srgb_to_linearrgb(float c); +float linearrgb_to_srgb(float c); +void color_manage_linearize(float *col_to, float *col_from); + +void floatbuf_to_srgb_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w); +void floatbuf_to_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w); + struct CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy); void curvemapping_free(struct CurveMapping *cumap); struct CurveMapping *curvemapping_copy(struct CurveMapping *cumap); @@ -58,6 +67,8 @@ void curvemapping_premultiply(struct CurveMapping *cumap, int restore); int curvemapping_RGBA_does_something(struct CurveMapping *cumap); void curvemapping_initialize(struct CurveMapping *cumap); void curvemapping_table_RGBA(struct CurveMapping *cumap, float **array, int *size); +void colorcorrection_do_ibuf(struct ImBuf *ibuf, const char *profile); + #endif diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 2f92fadd5ee..6e69906b71d 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -34,13 +34,14 @@ struct bConstraint; struct bConstraintTarget; struct ListBase; struct Object; -struct bConstraintChannel; +struct Scene; struct bPoseChannel; /* ---------------------------------------------------------------------------- */ /* special struct for use in constraint evaluation */ typedef struct bConstraintOb { + struct Scene *scene; /* for system time, part of deglobalization, code nicer later with local time (ton) */ struct Object *ob; /* if pchan, then armature that it comes from, otherwise constraint owner */ struct bPoseChannel *pchan; /* pose channel that owns the constraints being evaluated */ @@ -77,7 +78,7 @@ typedef struct bConstraintTypeInfo { void (*relink_data)(struct bConstraint *con); /* copy any special data that is allocated separately (optional) */ void (*copy_data)(struct bConstraint *con, struct bConstraint *src); - /* set settings for data that will be used for bConstraint.data (memory already allocated) */ + /* set settings for data that will be used for bConstraint.data (memory already allocated using MEM_callocN) */ void (*new_data)(void *cdata); /* target handling function pointers */ @@ -109,26 +110,19 @@ bConstraintTypeInfo *get_constraint_typeinfo(int type); /* Constraint function prototypes */ void unique_constraint_name(struct bConstraint *con, struct ListBase *list); -void free_constraints(struct ListBase *conlist); +void free_constraints(struct ListBase *list); void copy_constraints(struct ListBase *dst, struct ListBase *src); void relink_constraints(struct ListBase *list); void free_constraint_data(struct bConstraint *con); +struct bConstraint *constraints_get_active(struct ListBase *list); + /* Constraints + Proxies function prototypes */ void extract_proxylocal_constraints(struct ListBase *dst, struct ListBase *src); short proxylocked_constraints_owner(struct Object *ob, struct bPoseChannel *pchan); -/* Constraint Channel function prototypes */ -struct bConstraintChannel *get_constraint_channel(struct ListBase *list, const char *name); -struct bConstraintChannel *verify_constraint_channel(struct ListBase *list, const char *name); -void do_constraint_channels(struct ListBase *conbase, struct ListBase *chanbase, float ctime, short onlydrivers); -void copy_constraint_channels(struct ListBase *dst, struct ListBase *src); -void clone_constraint_channels(struct ListBase *dst, struct ListBase *src); -void free_constraint_channels(struct ListBase *chanbase); - - /* Constraint Evaluation function prototypes */ -struct bConstraintOb *constraints_make_evalob(struct Object *ob, void *subdata, short datatype); +struct bConstraintOb *constraints_make_evalob(struct Scene *scene, struct Object *ob, void *subdata, short datatype); void constraints_clear_evalob(struct bConstraintOb *cob); void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[][4], short from, short to); diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h new file mode 100644 index 00000000000..e47ad969b91 --- /dev/null +++ b/source/blender/blenkernel/BKE_context.h @@ -0,0 +1,234 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation (2008). + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_CONTEXT_H +#define BKE_CONTEXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "DNA_listBase.h" +#include "RNA_types.h" + +struct ARegion; +struct bScreen; +struct EditMesh; +struct ListBase; +struct Main; +struct Object; +struct PointerRNA; +struct ReportList; +struct Scene; +struct ScrArea; +struct SpaceLink; +struct View3D; +struct RegionView3D; +struct StructRNA; +struct ToolSettings; +struct Image; +struct Text; +struct ImBuf; +struct EditBone; +struct bPoseChannel; +struct wmWindow; +struct wmWindowManager; +struct SpaceText; +struct SpaceImage; +struct ID; + +/* Structs */ + +struct bContext; +typedef struct bContext bContext; + +struct bContextDataResult; +typedef struct bContextDataResult bContextDataResult; + +typedef int (*bContextDataCallback)(const bContext *C, + const char *member, bContextDataResult *result); + +typedef struct bContextStoreEntry { + struct bContextStoreEntry *next, *prev; + + char name[128]; + PointerRNA ptr; +} bContextStoreEntry; + +typedef struct bContextStore { + struct bContextStore *next, *prev; + + ListBase entries; + int used; +} bContextStore; + +/* Context */ + +bContext *CTX_create(void); +void CTX_free(bContext *C); + +bContext *CTX_copy(const bContext *C); + +/* Stored Context */ + +bContextStore *CTX_store_add(ListBase *contexts, char *name, PointerRNA *ptr); +void CTX_store_set(bContext *C, bContextStore *store); +bContextStore *CTX_store_copy(bContextStore *store); +void CTX_store_free(bContextStore *store); +void CTX_store_free_list(ListBase *contexts); + +/* need to store if python is initialized or not */ +int CTX_py_init_get(bContext *C); +void CTX_py_init_set(bContext *C, int value); + +/* Window Manager Context */ + +struct wmWindowManager *CTX_wm_manager(const bContext *C); +struct wmWindow *CTX_wm_window(const bContext *C); +struct bScreen *CTX_wm_screen(const bContext *C); +struct ScrArea *CTX_wm_area(const bContext *C); +struct SpaceLink *CTX_wm_space_data(const bContext *C); +struct ARegion *CTX_wm_region(const bContext *C); +void *CTX_wm_region_data(const bContext *C); +struct ARegion *CTX_wm_menu(const bContext *C); +struct ReportList *CTX_wm_reports(const bContext *C); + +struct View3D *CTX_wm_view3d(const bContext *C); +struct RegionView3D *CTX_wm_region_view3d(const bContext *C); +struct SpaceText *CTX_wm_space_text(const bContext *C); +struct SpaceImage *CTX_wm_space_image(const bContext *C); +struct SpaceConsole *CTX_wm_space_console(const bContext *C); +struct SpaceButs *CTX_wm_space_buts(const bContext *C); +struct SpaceFile *CTX_wm_space_file(const bContext *C); +struct SpaceSeq *CTX_wm_space_seq(const bContext *C); +struct SpaceOops *CTX_wm_space_outliner(const bContext *C); +struct SpaceNla *CTX_wm_space_nla(const bContext *C); +struct SpaceTime *CTX_wm_space_time(const bContext *C); +struct SpaceNode *CTX_wm_space_node(const bContext *C); +struct SpaceLogic *CTX_wm_space_logic(const bContext *C); +struct SpaceIpo *CTX_wm_space_graph(const bContext *C); +struct SpaceAction *CTX_wm_space_action(const bContext *C); +struct SpaceInfo *CTX_wm_space_info(const bContext *C); + +void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm); +void CTX_wm_window_set(bContext *C, struct wmWindow *win); +void CTX_wm_screen_set(bContext *C, struct bScreen *screen); /* to be removed */ +void CTX_wm_area_set(bContext *C, struct ScrArea *sa); +void CTX_wm_region_set(bContext *C, struct ARegion *region); +void CTX_wm_menu_set(bContext *C, struct ARegion *menu); + +/* Data Context + + - listbases consist of CollectionPointerLink items and must be + freed with BLI_freelistN! + - the dir listbase consits of LinkData items */ + +PointerRNA CTX_data_pointer_get(const bContext *C, const char *member); +PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type); +ListBase CTX_data_collection_get(const bContext *C, const char *member); +ListBase CTX_data_dir_get(const bContext *C); +void CTX_data_get(const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb); + +void CTX_data_id_pointer_set(bContextDataResult *result, struct ID *id); +void CTX_data_pointer_set(bContextDataResult *result, struct ID *id, StructRNA *type, void *data); + +void CTX_data_id_list_add(bContextDataResult *result, struct ID *id); +void CTX_data_list_add(bContextDataResult *result, struct ID *id, StructRNA *type, void *data); + +void CTX_data_dir_set(bContextDataResult *result, const char **member); + +int CTX_data_equals(const char *member, const char *str); +int CTX_data_dir(const char *member); + +/*void CTX_data_pointer_set(bContextDataResult *result, void *data); +void CTX_data_list_add(bContextDataResult *result, void *data);*/ + +#define CTX_DATA_BEGIN(C, Type, instance, member) \ + { \ + ListBase ctx_data_list; \ + CollectionPointerLink *ctx_link; \ + CTX_data_##member(C, &ctx_data_list); \ + for(ctx_link=ctx_data_list.first; ctx_link; ctx_link=ctx_link->next) { \ + Type instance= ctx_link->ptr.data; + +#define CTX_DATA_END \ + } \ + BLI_freelistN(&ctx_data_list); \ + } + +int ctx_data_list_count(const bContext *C, int (*func)(const bContext*, ListBase*)); + +#define CTX_DATA_COUNT(C, member) \ + ctx_data_list_count(C, CTX_data_##member) + +/* Data Context Members */ + +struct Main *CTX_data_main(const bContext *C); +struct Scene *CTX_data_scene(const bContext *C); +struct ToolSettings *CTX_data_tool_settings(const bContext *C); + +void CTX_data_main_set(bContext *C, struct Main *bmain); +void CTX_data_scene_set(bContext *C, struct Scene *bmain); + +int CTX_data_selected_editable_objects(const bContext *C, ListBase *list); +int CTX_data_selected_editable_bases(const bContext *C, ListBase *list); + +int CTX_data_selected_objects(const bContext *C, ListBase *list); +int CTX_data_selected_bases(const bContext *C, ListBase *list); + +int CTX_data_visible_objects(const bContext *C, ListBase *list); +int CTX_data_visible_bases(const bContext *C, ListBase *list); + +int CTX_data_selectable_objects(const bContext *C, ListBase *list); +int CTX_data_selectable_bases(const bContext *C, ListBase *list); + +struct Object *CTX_data_active_object(const bContext *C); +struct Base *CTX_data_active_base(const bContext *C); +struct Object *CTX_data_edit_object(const bContext *C); + +struct Image *CTX_data_edit_image(const bContext *C); + +struct Text *CTX_data_edit_text(const bContext *C); + +int CTX_data_selected_nodes(const bContext *C, ListBase *list); + +struct EditBone *CTX_data_active_bone(const bContext *C); +int CTX_data_selected_bones(const bContext *C, ListBase *list); +int CTX_data_selected_editable_bones(const bContext *C, ListBase *list); +int CTX_data_visible_bones(const bContext *C, ListBase *list); +int CTX_data_editable_bones(const bContext *C, ListBase *list); + +struct bPoseChannel *CTX_data_active_pchan(const bContext *C); +int CTX_data_selected_pchans(const bContext *C, ListBase *list); +int CTX_data_visible_pchans(const bContext *C, ListBase *list); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 79f4708fd41..e5a8df1a932 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -34,6 +34,7 @@ struct Curve; struct ListBase; struct Object; +struct Scene; struct Nurb; struct ListBase; struct BezTriple; @@ -52,6 +53,7 @@ struct BevList; void unlink_curve( struct Curve *cu); void free_curve( struct Curve *cu); +void BKE_free_editfont(struct Curve *cu); struct Curve *add_curve(char *name, int type); struct Curve *copy_curve( struct Curve *cu); void make_local_curve( struct Curve *cu); @@ -72,9 +74,9 @@ void makeknots( struct Nurb *nu, short uv); void makeNurbfaces(struct Nurb *nu, float *coord_array, int rowstride); void makeNurbcurve(struct Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, int resolu); void forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride); -float *make_orco_curve( struct Object *ob); +float *make_orco_curve(struct Scene *scene, struct Object *ob); float *make_orco_surf( struct Object *ob); -void makebevelcurve( struct Object *ob, struct ListBase *disp); +void makebevelcurve(struct Scene *scene, struct Object *ob, struct ListBase *disp); void makeBevelList( struct Object *ob); @@ -82,8 +84,8 @@ void calchandleNurb( struct BezTriple *bezt, struct BezTriple *prev, struct Bez void calchandlesNurb( struct Nurb *nu); void testhandlesNurb( struct Nurb *nu); void autocalchandlesNurb( struct Nurb *nu, int flag); -void autocalchandlesNurb_all(int flag); -void sethandlesNurb(short code); +void autocalchandlesNurb_all(ListBase *editnurb, int flag); +void sethandlesNurb(ListBase *editnurb, short code); void switchdirectionNurb( struct Nurb *nu); diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 10791968f79..95ee918a888 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -32,11 +32,9 @@ #ifndef BKE_CUSTOMDATA_H #define BKE_CUSTOMDATA_H -#include "BLO_sys_types.h" // for intptr_t support - struct CustomData; struct CustomDataLayer; -typedef intptr_t CustomDataMask; +typedef unsigned int CustomDataMask; extern const CustomDataMask CD_MASK_BAREMESH; extern const CustomDataMask CD_MASK_MESH; diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h index b86a58780dc..70b6c1d13f4 100644 --- a/source/blender/blenkernel/BKE_depsgraph.h +++ b/source/blender/blenkernel/BKE_depsgraph.h @@ -36,6 +36,7 @@ struct Scene; struct DagNodeQueue; struct DagForest; struct DagNode; +struct GHash; /* **** DAG relation types *** */ diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 9108846330c..da625b946ce 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -54,13 +54,14 @@ /* prototypes */ struct Base; +struct Scene; struct Object; struct Curve; struct ListBase; struct Material; struct Bone; struct Mesh; - +struct EditMesh; /* used for curves, nurbs, mball, importing */ typedef struct DispList { @@ -85,21 +86,21 @@ extern void addnormalsDispList(struct Object *ob, struct ListBase *lb); extern void count_displist(struct ListBase *lb, int *totvert, int *totface); extern void freedisplist(struct ListBase *lb); extern int displist_has_faces(struct ListBase *lb); -extern void makeDerivedMesh(struct Object *ob, CustomDataMask dataMask); -extern void makeDispListSurf(struct Object *ob, struct ListBase *dispbase, int forRender, int forOrco); -extern void makeDispListCurveTypes(struct Object *ob, int forOrco); -extern void makeDispListMBall(struct Object *ob); -extern void shadeDispList(struct Base *base); -extern void shadeMeshMCol(struct Object *ob, struct Mesh *me); + +extern void makeDispListSurf(struct Scene *scene, struct Object *ob, struct ListBase *dispbase, int forRender, int forOrco); +extern void makeDispListCurveTypes(struct Scene *scene, struct Object *ob, int forOrco); +extern void makeDispListMBall(struct Scene *scene, struct Object *ob); +extern void shadeDispList(struct Scene *scene, struct Base *base); +extern void shadeMeshMCol(struct Scene *scene, struct Object *ob, struct Mesh *me); int surfindex_displist(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4); void imagestodisplist(void); -void reshadeall_displist(void); +void reshadeall_displist(struct Scene *scene); void filldisplist(struct ListBase *dispbase, struct ListBase *to); void fastshade_free_render(void); -float calc_taper(struct Object *taperobj, int cur, int tot); +float calc_taper(struct Scene *scene, struct Object *taperobj, int cur, int tot); #endif diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 6475f7a71ac..e21e83bf5cf 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -33,12 +33,16 @@ #include "DNA_object_types.h" +struct Object; +struct Scene; struct Effect; struct ListBase; struct Particle; struct Group; struct RNG; +struct PartDeflect *object_add_collision_fields(void); + typedef struct pEffectorCache { struct pEffectorCache *next, *prev; Object *ob; @@ -61,12 +65,16 @@ void deselectall_eff(struct Object *ob); #define PE_WIND_AS_SPEED 0x00000001 struct PartEff *give_parteff(struct Object *ob); -struct ListBase *pdInitEffectors(struct Object *obsrc, struct Group *group); +struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *obsrc, struct Group *group); void pdEndEffectors(struct ListBase *lb); -void pdDoEffectors(struct ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags); +void pdDoEffectors(struct Scene *scene, struct ListBase *lb, float *opco, float *force, + float *speed, float cur_time, float loc_time, unsigned int flags); /* required for particle_system.c */ -void do_physical_effector(Object *ob, float *opco, short type, float force_val, float distance, float falloff, float size, float damp, float *eff_velocity, float *vec_to_part, float *velocity, float *field, int planar, struct RNG *rng, float noise_factor, float charge, float pa_size); +void do_physical_effector(struct Scene *scene, struct Object *ob, float *opco, short type, float force_val, float distance, + float falloff, float size, float damp, float *eff_velocity, float *vec_to_part, + float *velocity, float *field, int planar, struct RNG *rng, float noise_factor, + float charge, float pa_size); float effector_falloff(struct PartDeflect *pd, float *eff_velocity, float *vec_to_part); diff --git a/source/blender/blenkernel/BKE_exotic.h b/source/blender/blenkernel/BKE_exotic.h index 3814518a9e7..5c47eeabfe8 100644 --- a/source/blender/blenkernel/BKE_exotic.h +++ b/source/blender/blenkernel/BKE_exotic.h @@ -32,6 +32,7 @@ #define BKE_EXOTIC_H struct Mesh; +struct Scene; void mcol_to_rgba(unsigned int col, float *r, float *g, float *b, float *a); unsigned int *mcol_to_vcol(struct Mesh *me); // used in py_main.c @@ -42,12 +43,11 @@ unsigned int *mcol_to_vcol(struct Mesh *me); // used in py_main.c * @retval 1 The file was read succesfully. * @attention Used in filesel.c */ -int BKE_read_exotic(char *name); +int BKE_read_exotic(struct Scene *scene, char *name); -void write_dxf(char *str); -void write_vrml(char *str); -void write_videoscape(char *str); -void write_stl(char *str); +void write_dxf(struct Scene *scene, char *str); +void write_vrml(struct Scene *scene, char *str); +void write_stl(struct Scene *scene, char *str); #endif diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h new file mode 100644 index 00000000000..cda64c6b241 --- /dev/null +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -0,0 +1,200 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + * + * Contributor(s): Joshua Leung (full recode) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_FCURVE_H +#define BKE_FCURVE_H + +struct FCurve; +struct FModifier; +struct ChannelDriver; +struct DriverTarget; + +struct BezTriple; + +/* ************** Keyframe Tools ***************** */ + +// XXX this stuff is defined in BKE_ipo.h too, so maybe skip for now? +typedef struct CfraElem { + struct CfraElem *next, *prev; + float cfra; + int sel; +} CfraElem; + +void bezt_add_to_cfra_elem(ListBase *lb, struct BezTriple *bezt); + +/* ************** F-Curve Drivers ***************** */ + +void fcurve_free_driver(struct FCurve *fcu); +struct ChannelDriver *fcurve_copy_driver(struct ChannelDriver *driver); + +void driver_free_target(struct ChannelDriver *driver, struct DriverTarget *dtar); +struct DriverTarget *driver_add_new_target(struct ChannelDriver *driver); + +float driver_get_target_value(struct ChannelDriver *driver, struct DriverTarget *dtar); + +/* ************** F-Curve Modifiers *************** */ + +/* F-Curve Modifier Type-Info (fmi): + * This struct provides function pointers for runtime, so that functions can be + * written more generally (with fewer/no special exceptions for various modifiers). + * + * Callers of these functions must check that they actually point to something useful, + * as some constraints don't define some of these. + * + * Warning: it is not too advisable to reorder order of members of this struct, + * as you'll have to edit quite a few ($FMODIFIER_NUM_TYPES) of these + * structs. + */ +typedef struct FModifierTypeInfo { + /* admin/ident */ + short type; /* FMODIFIER_TYPE_### */ + short size; /* size in bytes of the struct */ + short acttype; /* eFMI_Action_Types */ + short requires; /* eFMI_Requirement_Flags */ + char name[64]; /* name of modifier in interface */ + char structName[64]; /* name of struct for SDNA */ + + /* data management function pointers - special handling */ + /* free any data that is allocated separately (optional) */ + void (*free_data)(struct FModifier *fcm); + /* copy any special data that is allocated separately (optional) */ + void (*copy_data)(struct FModifier *fcm, struct FModifier *src); + /* set settings for data that will be used for FCuModifier.data (memory already allocated using MEM_callocN) */ + void (*new_data)(void *mdata); + /* verifies that the modifier settings are valid */ + void (*verify_data)(struct FModifier *fcm); + + /* evaluation */ + /* evaluate time that the modifier requires the F-Curve to be evaluated at */ + float (*evaluate_modifier_time)(struct FCurve *fcu, struct FModifier *fcm, float cvalue, float evaltime); + /* evaluate the modifier for the given time and 'accumulated' value */ + void (*evaluate_modifier)(struct FCurve *fcu, struct FModifier *fcm, float *cvalue, float evaltime); +} FModifierTypeInfo; + +/* Values which describe the behaviour of a FModifier Type */ +enum { + /* modifier only modifies values outside of data range */ + FMI_TYPE_EXTRAPOLATION = 0, + /* modifier leaves data-points alone, but adjusts the interpolation between and around them */ + FMI_TYPE_INTERPOLATION, + /* modifier only modifies the values of points (but times stay the same) */ + FMI_TYPE_REPLACE_VALUES, + /* modifier generates a curve regardless of what came before */ + FMI_TYPE_GENERATE_CURVE, +} eFMI_Action_Types; + +/* Flags for the requirements of a FModifier Type */ +enum { + /* modifier requires original data-points (kindof beats the purpose of a modifier stack?) */ + FMI_REQUIRES_ORIGINAL_DATA = (1<<0), + /* modifier doesn't require on any preceeding data (i.e. it will generate a curve). + * Use in conjunction with FMI_TYPE_GENRATE_CURVE + */ + FMI_REQUIRES_NOTHING = (1<<1), + /* refer to modifier instance */ + FMI_REQUIRES_RUNTIME_CHECK = (1<<2), +} eFMI_Requirement_Flags; + +/* Function Prototypes for FModifierTypeInfo's */ +FModifierTypeInfo *fmodifier_get_typeinfo(struct FModifier *fcm); +FModifierTypeInfo *get_fmodifier_typeinfo(int type); + +/* ---------------------- */ + +struct FModifier *add_fmodifier(ListBase *modifiers, int type); +void copy_fmodifiers(ListBase *dst, ListBase *src); +void remove_fmodifier(ListBase *modifiers, struct FModifier *fcm); +void free_fmodifiers(ListBase *modifiers); + +struct FModifier *find_active_fmodifier(ListBase *modifiers); +void set_active_fmodifier(ListBase *modifiers, struct FModifier *fcm); + +short list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype); + +float evaluate_time_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float cvalue, float evaltime); +void evaluate_value_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float *cvalue, float evaltime); + +void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end); + +/* ************** F-Curves API ******************** */ + +/* -------- Data Managemnt -------- */ + +void free_fcurve(struct FCurve *fcu); +struct FCurve *copy_fcurve(struct FCurve *fcu); + +void free_fcurves(ListBase *list); +void copy_fcurves(ListBase *dst, ListBase *src); + +/* find matching F-Curve in the given list of F-Curves */ +struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index); + +/* get the time extents for F-Curve */ +void calc_fcurve_range(struct FCurve *fcu, float *min, float *max); + +/* get the bounding-box extents for F-Curve */ +void calc_fcurve_bounds(struct FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax); + +/* -------- Curve Sanity -------- */ + +void calchandles_fcurve(struct FCurve *fcu); +void testhandles_fcurve(struct FCurve *fcu); +void sort_time_fcurve(struct FCurve *fcu); +short test_time_fcurve(struct FCurve *fcu); + +void correct_bezpart(float *v1, float *v2, float *v3, float *v4); + +/* -------- Evaluation -------- */ + +/* evaluate fcurve */ +float evaluate_fcurve(struct FCurve *fcu, float evaltime); +/* evaluate fcurve and store value */ +void calculate_fcurve(struct FCurve *fcu, float ctime); + +/* ************* F-Curve Samples API ******************** */ + +/* -------- Defines -------- */ + +/* Basic signature for F-Curve sample-creation function + * - fcu: the F-Curve being operated on + * - data: pointer to some specific data that may be used by one of the callbacks + */ +typedef float (*FcuSampleFunc)(struct FCurve *fcu, void *data, float evaltime); + +/* ----- Sampling Callbacks ------ */ + +/* Basic sampling callback which acts as a wrapper for evaluate_fcurve() */ +float fcurve_samplingcb_evalcurve(struct FCurve *fcu, void *data, float evaltime); + +/* -------- Main Methods -------- */ + +/* Main API function for creating a set of sampled curve data, given some callback function + * used to retrieve the values to store. + */ +void fcurve_store_samples(struct FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb); + +#endif /* BKE_FCURVE_H*/ diff --git a/source/blender/blenkernel/BKE_fluidsim.h b/source/blender/blenkernel/BKE_fluidsim.h index 4aac5eafa00..145ae48e732 100644 --- a/source/blender/blenkernel/BKE_fluidsim.h +++ b/source/blender/blenkernel/BKE_fluidsim.h @@ -1,6 +1,5 @@ /** - * BKE_fluidsim.h - * + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -28,29 +27,40 @@ * ***** END GPL LICENSE BLOCK ***** */ -#include "DNA_modifier_types.h" -#include "DNA_object_fluidsim.h" // N_T -#include "DNA_object_types.h" +#ifndef BKE_FLUIDSIM_H +#define BKE_FLUIDSIM_H -#include "BKE_DerivedMesh.h" +struct Object; +struct Scene; +struct FluidsimModifierData; +struct DerivedMesh; +struct MVert; /* old interface */ -FluidsimSettings *fluidsimSettingsNew(Object *srcob); - -void initElbeemMesh(Object *ob, int *numVertices, float **vertices, int *numTriangles, int **triangles, int useGlobalCoords, int modifierIndex); +struct FluidsimSettings *fluidsimSettingsNew(struct Object *srcob); +void initElbeemMesh(struct Scene *scene, struct Object *ob, + int *numVertices, float **vertices, + int *numTriangles, int **triangles, + int useGlobalCoords, int modifierIndex); /* new fluid-modifier interface */ -void fluidsim_init(FluidsimModifierData *fluidmd); -void fluidsim_free(FluidsimModifierData *fluidmd); +void fluidsim_init(struct FluidsimModifierData *fluidmd); +void fluidsim_free(struct FluidsimModifierData *fluidmd); -DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams); -void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *dm, char *filename); -DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc); +struct DerivedMesh *fluidsim_read_cache(struct Object *ob, struct DerivedMesh *orgdm, + struct FluidsimModifierData *fluidmd, int framenr, int useRenderParams); +void fluidsim_read_vel_cache(struct FluidsimModifierData *fluidmd, struct DerivedMesh *dm, + char *filename); +struct DerivedMesh *fluidsimModifier_do(struct FluidsimModifierData *fluidmd, + struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, + int useRenderParams, int isFinalCalc); -// get bounding box of mesh -void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4], - /*RET*/ float start[3], /*RET*/ float size[3] ); +/* bounding box & memory estimate */ +void fluid_get_bb(struct MVert *mvert, int totvert, float obmat[][4], + float start[3], float size[3]); +void fluid_estimate_memory(struct Object *ob, struct FluidsimSettings *fss, char *value); +#endif diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h index 33747eb35a3..d328ccd57f4 100644 --- a/source/blender/blenkernel/BKE_font.h +++ b/source/blender/blenkernel/BKE_font.h @@ -38,9 +38,12 @@ extern "C" { #include <wchar.h> struct VFont; +struct Scene; struct Object; struct Curve; struct objfnt; +struct TmpFont; +struct CharInfo; struct chartrans { float xof, yof; @@ -53,18 +56,31 @@ typedef struct SelBox { float x, y, w, h; } SelBox; -extern struct SelBox *selboxes; +typedef struct EditFont { + wchar_t *copybuf; + wchar_t *copybufinfo; + + wchar_t *textbuf; + struct CharInfo *textbufinfo; + wchar_t *oldstr; + struct CharInfo *oldstrinfo; + + float textcurs[4][2]; + +} EditFont; + void BKE_font_register_builtin(void *mem, int size); void free_vfont(struct VFont *sc); +void free_ttfont(void); +struct VFont *get_builtin_font(void); struct VFont *load_vfont(char *name); +struct TmpFont *vfont_find_tmpfont(struct VFont *vfont); -struct chartrans *text_to_curve(struct Object *ob, int mode); -int style_to_sel(int style, int toggle); -int mat_to_sel(void); +struct chartrans *BKE_text_to_curve(struct Scene *scene, struct Object *ob, int mode); -int getselection(int *start, int *end); +int BKE_font_getselection(struct Object *ob, int *start, int *end); void chtoutf8(unsigned long c, char *o); void wcs2utf8s(char *dst, wchar_t *src); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index e8918bcdce6..315fe2a39cb 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -42,46 +42,15 @@ extern "C" { #endif /* forwards */ -struct View3D; -struct View2D; -struct SpaceIpo; -struct SpaceButs; -struct SpaceImage; -struct SpaceOops; -struct SpaceText; -struct SpaceSound; -struct SpaceAction; -struct SpaceNla; struct Main; -struct Scene; -struct bScreen; struct Object; -struct bSoundListener; -struct BMF_Font; -struct EditMesh; struct BME_Glob; typedef struct Global { /* active pointers */ - struct View3D *vd; - struct View2D *v2d; - struct SpaceIpo *sipo; - struct SpaceButs *buts; - struct SpaceImage *sima; - struct SpaceOops *soops; - struct SpaceSound *ssound; - struct SpaceAction *saction; /* __NLA */ - struct SpaceNla *snla; struct Main *main; - struct Scene *scene; /* denk aan file.c */ - struct bScreen *curscreen; - struct Object *obedit; - char editModeTitleExtra[64]; - /* fonts, allocated global data */ - struct BMF_Font *font, *fonts, *fontss; - /* strings: lastsaved */ char ima[256], sce[256], lib[256]; @@ -90,38 +59,22 @@ typedef struct Global { /* strings of recent opend files */ struct ListBase recent_files; - - /* totals */ - int totobj, totlamp, totobjsel, totcurve, totmesh; - int totbone, totbonesel; - int totvert, totedge, totface, totvertsel, totedgesel, totfacesel; - + short afbreek, moving; - short qual, background; + short background; short winpos, displaymode; /* used to be in Render */ short rendering; /* to indicate render is busy, prevent renderwindow events etc */ - /** - * The current version of Blender. - */ - short version; - short simulf, order, rt; + + short rt; int f; - /* Editmode lists */ - struct EditMesh *editMesh; - /* Used for BMesh transformations */ struct BME_Glob *editBMesh; - float textcurs[4][2]; - /* Frank's variables */ int save_over; - /* Reevan's __NLA variables */ - struct ListBase edbo; /* Armature Editmode bones */ - - /* Rob's variables */ + /* Rob's variables (keep here for WM recode) */ int have_quicktime; int ui_international; int charstart; @@ -139,13 +92,6 @@ typedef struct Global { /* save the allowed windowstate of blender when using -W or -w */ int windowstate; - /* Janco's playing ground */ - struct bSoundListener* listener; - - /* Test thingy for Nzc */ - int compat; /* toggle compatibility mode for edge rendering */ - int notonlysolid;/* T-> also edge-render transparent faces */ - /* ndof device found ? */ int ndofdevice; @@ -158,45 +104,29 @@ typedef struct Global { /* G.f */ #define G_RENDER_OGL (1 << 0) -#define G_PLAYANIM (1 << 1) +#define G_SWAP_EXCHANGE (1 << 1) /* also uses G_FILE_AUTOPLAY */ #define G_RENDER_SHADOW (1 << 3) #define G_BACKBUFSEL (1 << 4) #define G_PICKSEL (1 << 5) -#define G_DRAWNORMALS (1 << 6) -#define G_DRAWFACES (1 << 7) + #define G_FACESELECT (1 << 8) -#define G_DRAW_EXT (1 << 9) + #define G_VERTEXPAINT (1 << 10) -#define G_ALLEDGES (1 << 11) + #define G_DEBUG (1 << 12) #define G_DOSCRIPTLINKS (1 << 13) -#define G_DRAW_VNORMALS (1 << 14) + #define G_WEIGHTPAINT (1 << 15) #define G_TEXTUREPAINT (1 << 16) /* #define G_NOFROZEN (1 << 17) also removed */ #define G_GREASEPENCIL (1 << 17) -#define G_DRAWEDGES (1 << 18) -#define G_DRAWCREASES (1 << 19) -#define G_DRAWSEAMS (1 << 20) -#define G_HIDDENEDGES (1 << 21) -/* Measurement info Drawing */ -#define G_DRAW_EDGELEN (1 << 22) -#define G_DRAW_FACEAREA (1 << 23) -#define G_DRAW_EDGEANG (1 << 24) - -/* #define G_RECORDKEYS (1 << 25) also removed */ -/*#ifdef WITH_VERSE*/ -#define G_VERSE_CONNECTED (1 << 26) -#define G_DRAW_VERSE_DEBUG (1 << 27) -/*#endif*/ -#define G_DRAWSHARP (1 << 28) /* draw edges with the sharp flag */ + #define G_SCULPTMODE (1 << 29) #define G_PARTICLEEDIT (1 << 30) /* #define G_AUTOMATKEYS (1 << 30) also removed */ #define G_HIDDENHANDLES (1 << 31) /* used for curves only */ -#define G_DRAWBWEIGHTS (1 << 31) /* macro for testing face select mode * Texture paint could be removed since selected faces are not used @@ -234,28 +164,11 @@ typedef struct Global { #define G_WINDOWSTATE_BORDER 1 #define G_WINDOWSTATE_FULLSCREEN 2 -/* G.simulf */ -#define G_LOADFILE 2 -#define G_RESTART 4 -#define G_QUIT 8 -#define G_SETSCENE 16 - -/* G.qual */ -#define R_SHIFTKEY 1 -#define L_SHIFTKEY 2 -#define LR_SHIFTKEY 3 -#define R_ALTKEY 4 -#define L_ALTKEY 8 -#define LR_ALTKEY 12 -#define R_CTRLKEY 16 -#define L_CTRLKEY 32 -#define LR_CTRLKEY 48 -#define LR_COMMANDKEY 64 - -/* G.order: indicates what endianness the platform where the file was +/* ENDIAN_ORDER: indicates what endianness the platform where the file was * written had. */ #define L_ENDIAN 1 #define B_ENDIAN 0 +extern short ENDIAN_ORDER; /* G.moving, signals drawing in (3d) window to denote transform */ #define G_TRANSFORM_OBJ 1 diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h new file mode 100644 index 00000000000..1892c8e71a4 --- /dev/null +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -0,0 +1,63 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2008, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_GPENCIL_H +#define BKE_GPENCIL_H + +struct ListBase; +struct bGPdata; +struct bGPDlayer; +struct bGPDframe; + +/* ------------ Grease-Pencil API ------------------ */ + +void free_gpencil_strokes(struct bGPDframe *gpf); +void free_gpencil_frames(struct bGPDlayer *gpl); +void free_gpencil_layers(struct ListBase *list); +void free_gpencil_data(struct bGPdata *gpd); + +struct bGPDframe *gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe); +struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd); +struct bGPdata *gpencil_data_addnew(char name[]); + +struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src); +struct bGPDlayer *gpencil_layer_duplicate(struct bGPDlayer *src); +struct bGPdata *gpencil_data_duplicate(struct bGPdata *gpd); + +//struct bGPdata *gpencil_data_getactive(struct ScrArea *sa); +//short gpencil_data_setactive(struct ScrArea *sa, struct bGPdata *gpd); +//struct ScrArea *gpencil_data_findowner(struct bGPdata *gpd); + +void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf); + +struct bGPDframe *gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, short addnew); +void gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf); +struct bGPDlayer *gpencil_layer_getactive(struct bGPdata *gpd); +void gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active); +void gpencil_layer_delactive(struct bGPdata *gpd); + +#endif /* BKE_GPENCIL_H */ diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index 764bdf5d910..35084aabadf 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -35,6 +35,7 @@ struct Group; struct GroupObject; struct Object; struct bAction; +struct Scene; void free_group_object(struct GroupObject *go); void free_group(struct Group *group); @@ -47,7 +48,7 @@ int object_in_group(struct Object *ob, struct Group *group); int group_is_animated(struct Object *parent, struct Group *group); void group_tag_recalc(struct Group *group); -void group_handle_recalc_and_update(struct Object *parent, struct Group *group); +void group_handle_recalc_and_update(struct Scene *scene, struct Object *parent, struct Group *group); struct Object *group_get_member_with_action(struct Group *group, struct bAction *act); void group_relink_nla_objects(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 2274c54ad3b..1980ba78c86 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -30,16 +30,6 @@ #include "DNA_ID.h" -/* -these two are included for their (new :P )function -pointers. -*/ -#include "BLO_readfile.h" -#include "BLO_writefile.h" - -struct WriteData; -struct FileData; - struct IDProperty; struct ID; @@ -59,7 +49,22 @@ typedef union { } matrix_or_vector; } IDPropertyTemplate; -/* ----------- Array Type ----------- */ +/* ----------- Property Array Type ---------- */ + +/*note: as a start to move away from the stupid IDP_New function, this type + has it's own allocation function.*/ +IDProperty *IDP_NewIDPArray(const char *name); +IDProperty *IDP_CopyIDPArray(IDProperty *array); + +void IDP_FreeIDPArray(IDProperty *prop); + +/* shallow copies item */ +void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item); +struct IDProperty *IDP_GetIndexArray(struct IDProperty *prop, int index); +struct IDProperty *IDP_AppendArray(struct IDProperty *prop, struct IDProperty *item); +void IDP_ResizeIDPArray(struct IDProperty *prop, int len); + +/* ----------- Numeric Array Type ----------- */ /*this function works for strings too!*/ void IDP_ResizeArray(struct IDProperty *prop, int newlen); void IDP_FreeArray(struct IDProperty *prop); @@ -137,6 +142,8 @@ void IDP_FreeIterBeforeEnd(void *vself); struct IDProperty *IDP_GetProperties(struct ID *id, int create_if_needed); struct IDProperty *IDP_CopyProperty(struct IDProperty *prop); +int IDP_EqualsProperties(struct IDProperty *prop1, struct IDProperty *prop2); + /* Allocate a new ID. @@ -162,7 +169,7 @@ Note that you MUST either attach the id property to an id property group with IDP_AddToGroup or MEM_freeN the property, doing anything else might result in a memory leak. */ -struct IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name); +struct IDProperty *IDP_New(int type, IDPropertyTemplate val, const char *name); \ /*NOTE: this will free all child properties of list arrays and groups! Also, note that this does NOT unlink anything! Plus it doesn't free @@ -172,9 +179,11 @@ void IDP_FreeProperty(struct IDProperty *prop); /*Unlinks any struct IDProperty<->ID linkage that might be going on.*/ void IDP_UnlinkProperty(struct IDProperty *prop); -#define IDP_Int(prop) (prop->data.val) -#define IDP_Float(prop) (*(float*)&prop->data.val) -#define IDP_String(prop) ((char*)prop->data.pointer) -#define IDP_Array(prop) (prop->data.pointer) +#define IDP_Int(prop) ((prop)->data.val) +#define IDP_Float(prop) (*(float*)&(prop)->data.val) +#define IDP_String(prop) ((char*)(prop)->data.pointer) +#define IDP_Array(prop) ((prop)->data.pointer) +#define IDP_IDPArray(prop) ((IDProperty*)(prop)->data.pointer) +#define IDP_Double(prop) (*(double*)&(prop)->data.val) #endif /* _BKE_IDPROP_H */ diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 8dac282eedf..816baa20467 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -39,15 +39,16 @@ struct Image; struct ImBuf; struct Tex; struct anim; +struct Scene; /* call from library */ void free_image(struct Image *me); -void BKE_stamp_info(struct ImBuf *ibuf); -void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height, int channels); -int BKE_write_ibuf(struct ImBuf *ibuf, char *name, int imtype, int subimtype, int quality); -void BKE_makepicstring(char *string, char *base, int frame, int imtype); -void BKE_add_image_extension(char *string, int imtype); +void BKE_stamp_info(struct Scene *scene, struct ImBuf *ibuf); +void BKE_stamp_buf(struct Scene *scene, unsigned char *rect, float *rectf, int width, int height, int channels); +int BKE_write_ibuf(struct Scene *scene, struct ImBuf *ibuf, char *name, int imtype, int subimtype, int quality); +void BKE_makepicstring(struct Scene *scene, char *string, char *base, int frame, int imtype); +void BKE_add_image_extension(struct Scene *scene, char *string, int imtype); int BKE_ftype_to_imtype(int ftype); int BKE_imtype_to_ftype(int imtype); int BKE_imtype_is_movie(int imtype); @@ -81,7 +82,6 @@ struct RenderResult; #define IMA_TYPE_MULTILAYER 1 /* generated */ #define IMA_TYPE_UV_TEST 2 -#define IMA_TYPE_VERSE 3 /* viewers */ #define IMA_TYPE_R_RESULT 4 #define IMA_TYPE_COMPOSITE 5 @@ -107,8 +107,8 @@ struct RenderResult; /* always call to make signals work */ struct ImBuf *BKE_image_get_ibuf(struct Image *ima, struct ImageUser *iuser); -/* returns existing Image when filename/type is same */ -struct Image *BKE_add_image_file(const char *name); +/* returns existing Image when filename/type is same (frame optional) */ +struct Image *BKE_add_image_file(const char *name, int frame); /* adds image, adds ibuf, generates color or pattern */ struct Image *BKE_add_image_size(int width, int height, char *name, int floatbuf, short uvtestgrid, float color[4]); @@ -132,7 +132,7 @@ void BKE_image_user_new_image(struct Image *ima, struct ImageUser *iuser); struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser); /* for multilayer images as well as for render-viewer */ -struct RenderResult *BKE_image_get_renderresult(struct Image *ima); +struct RenderResult *BKE_image_get_renderresult(struct Scene *scene, struct Image *ima); /* goes over all textures that use images */ void BKE_image_free_all_textures(void); @@ -148,6 +148,12 @@ void BKE_image_memorypack(struct Image *ima); /* prints memory statistics for images */ void BKE_image_print_memlist(void); +/* empty image block, of similar type and filename */ +struct Image *BKE_image_copy(struct Image *ima); + +/* merge source into dest, and free source */ +void BKE_image_merge(struct Image *dest, struct Image *source); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_ipo.h b/source/blender/blenkernel/BKE_ipo.h index fdd176e0e64..e12170b73c9 100644 --- a/source/blender/blenkernel/BKE_ipo.h +++ b/source/blender/blenkernel/BKE_ipo.h @@ -24,7 +24,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): 2008,2009 Joshua Leung (Animation Cleanup, Animation Systme Recode) * * ***** END GPL LICENSE BLOCK ***** */ @@ -35,110 +35,18 @@ extern "C" { #endif -typedef struct CfraElem { - struct CfraElem *next, *prev; - float cfra; - int sel; -} CfraElem; - +struct Main; struct Ipo; -struct IpoCurve; -struct MTex; -struct Material; -struct Object; -struct Sequence; -struct ListBase; -struct BezTriple; -struct ID; -struct bPoseChannel; -struct bActionChannel; -struct rctf; - -/* ------------ Time Management ------------ */ -float frame_to_float(int cfra); +void do_versions_ipos_to_animato(struct Main *main); -/* ------------ IPO Management ---------- */ +/* --------------------- xxx stuff ------------------------ */ -void free_ipo_curve(struct IpoCurve *icu); void free_ipo(struct Ipo *ipo); -void ipo_default_v2d_cur(int blocktype, struct rctf *cur); - -struct Ipo *add_ipo(char *name, int idcode); -struct Ipo *copy_ipo(struct Ipo *ipo); - -void ipo_idnew(struct Ipo *ipo); - -struct IpoCurve *find_ipocurve(struct Ipo *ipo, int adrcode); -short has_ipo_code(struct Ipo *ipo, int code); - -/* -------------- Make Local -------------- */ - -void make_local_obipo(struct Ipo *ipo); -void make_local_matipo(struct Ipo *ipo); -void make_local_keyipo(struct Ipo *ipo); -void make_local_ipo(struct Ipo *ipo); - -/* ------------ IPO-Curve Sanity ---------------- */ - -void calchandles_ipocurve(struct IpoCurve *icu); -void testhandles_ipocurve(struct IpoCurve *icu); -void sort_time_ipocurve(struct IpoCurve *icu); -int test_time_ipocurve(struct IpoCurve *icu); - -/* -------- IPO-Curve (Bezier) Calculations ---------- */ - +// xxx perhaps this should be in curve api not in anim api void correct_bezpart(float *v1, float *v2, float *v3, float *v4); -int findzero(float x, float q0, float q1, float q2, float q3, float *o); -void berekeny(float f1, float f2, float f3, float f4, float *o, int b); -void berekenx(float *f, float *o, int b); - -/* -------- IPO Curve Calculation and Evaluation --------- */ - -float eval_icu(struct IpoCurve *icu, float ipotime); -void calc_icu(struct IpoCurve *icu, float ctime); -float calc_ipo_time(struct Ipo *ipo, float ctime); -void calc_ipo(struct Ipo *ipo, float ctime); - -/* ------------ Keyframe Column Tools -------------- */ - -void add_to_cfra_elem(struct ListBase *lb, struct BezTriple *bezt); -void make_cfra_list(struct Ipo *ipo, struct ListBase *elems); - -/* ---------------- IPO DataAPI ----------------- */ - -void write_ipo_poin(void *poin, int type, float val); -float read_ipo_poin(void *poin, int type); - -void *give_mtex_poin(struct MTex *mtex, int adrcode ); -void *get_pchan_ipo_poin(struct bPoseChannel *pchan, int adrcode); -void *get_ipo_poin(struct ID *id, struct IpoCurve *icu, int *type); - -void set_icu_vars(struct IpoCurve *icu); - -/* ---------------- IPO Execution --------------- */ - -void execute_ipo(struct ID *id, struct Ipo *ipo); -void execute_action_ipo(struct bActionChannel *achan, struct bPoseChannel *pchan); - -void do_ipo_nocalc(struct Ipo *ipo); -void do_ipo(struct Ipo *ipo); -void do_mat_ipo(struct Material *ma); -void do_ob_ipo(struct Object *ob); -void do_seq_ipo(struct Sequence *seq, int cfra); -void do_ob_ipodrivers(struct Object *ob, struct Ipo *ipo, float ctime); - -void do_all_data_ipos(void); -short calc_ipo_spec(struct Ipo *ipo, int adrcode, float *ctime); -void clear_delta_obipo(struct Ipo *ipo); - -/* ----------- IPO <-> GameEngine API ---------------- */ - -/* the short is an IPO_Channel... */ - -short IPO_GetChannels(struct Ipo *ipo, short *channels); -float IPO_GetFloatValue(struct Ipo *ipo, short c, float ctime); + #ifdef __cplusplus }; diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index faf8692b89a..e2f9dff6226 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -37,6 +37,7 @@ struct ID; struct ListBase; struct Curve; struct Object; +struct Scene; struct Lattice; struct Mesh; @@ -57,11 +58,12 @@ void set_afgeleide_four_ipo(float d, float *data, int type); /* only exported to curve.c! */ void cp_cu_key(struct Curve *cu, struct KeyBlock *kb, int start, int end); -int do_ob_key(struct Object *ob); +int do_ob_key(struct Scene *scene, struct Object *ob); struct Key *ob_get_key(struct Object *ob); struct KeyBlock *ob_get_keyblock(struct Object *ob); struct KeyBlock *key_get_keyblock(struct Key *key, int index); +struct KeyBlock *key_get_named_keyblock(struct Key *key, const char name[]); // needed for the GE void do_rel_key(int start, int end, int tot, char *basispoin, struct Key *key, int mode); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index dc7c9dcd5e5..2e4a5334c68 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -33,28 +33,29 @@ struct Lattice; struct Object; +struct Scene; struct DerivedMesh; struct BPoint; struct MDeformVert; -extern struct Lattice *editLatt; - - void resizelattice(struct Lattice *lt, int u, int v, int w, struct Object *ltOb); struct Lattice *add_lattice(char *name); struct Lattice *copy_lattice(struct Lattice *lt); void free_lattice(struct Lattice *lt); void make_local_lattice(struct Lattice *lt); void calc_lat_fudu(int flag, int res, float *fu, float *du); + void init_latt_deform(struct Object *oblatt, struct Object *ob); -void calc_latt_deform(float *co, float weight); -void end_latt_deform(void); +void calc_latt_deform(struct Object *, float *co, float weight); +void end_latt_deform(struct Object *); + int object_deform_mball(struct Object *ob); void outside_lattice(struct Lattice *lt); -void curve_deform_verts(struct Object *cuOb, struct Object *target, + +void curve_deform_verts(struct Scene *scene, struct Object *cuOb, struct Object *target, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis); -void curve_deform_vector(struct Object *cuOb, struct Object *target, +void curve_deform_vector(struct Scene *scene, struct Object *cuOb, struct Object *target, float *orco, float *vec, float mat[][3], int no_rot_axis); void lattice_deform_verts(struct Object *laOb, struct Object *target, @@ -64,9 +65,10 @@ void armature_deform_verts(struct Object *armOb, struct Object *target, struct DerivedMesh *dm, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts, int deformflag, float (*prevCos)[3], const char *defgrp_name); + float (*lattice_getVertexCos(struct Object *ob, int *numVerts_r))[3]; void lattice_applyVertexCos(struct Object *ob, float (*vertexCos)[3]); -void lattice_calc_modifiers(struct Object *ob); +void lattice_calc_modifiers(struct Scene *scene, struct Object *ob); struct MDeformVert* lattice_get_deform_verts(struct Object *lattice); diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 095db4860ce..4e7db115168 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -37,12 +37,15 @@ struct ListBase; struct ID; struct Main; struct Library; +struct wmWindowManager; +struct bContext; void *alloc_libblock(struct ListBase *lb, short type, const char *name); void *copy_libblock(void *rt); void id_lib_extern(struct ID *id); void id_us_plus(struct ID *id); +void id_us_min(struct ID *id); int check_for_dupid(struct ListBase *lb, struct ID *id, char *name); int new_id(struct ListBase *lb, struct ID *id, const char *name); @@ -60,6 +63,7 @@ void tag_main(struct Main *mainvar, int tag); void splitIDname(char *name, char *left, int *nr); void rename_id(struct ID *id, char *name); void test_idbutton(char *name); +void text_idbutton(struct ID *id, char *text); void all_local(struct Library *lib, int untagged_only); struct ID *find_id(char *type, char *name); void clear_id_newpoins(void); @@ -71,5 +75,7 @@ void IPOnames_to_pupstring(char **str, char *title, char *extraops, struct ListB void flag_listbase_ids(ListBase *lb, short flag, short value); void flag_all_listbases_ids(short flag, short value); +void set_free_windowmanager_cb(void (*func)(struct bContext *, struct wmWindowManager *) ); + #endif diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index d1cc7515159..6881bdfdb2c 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -62,7 +62,7 @@ typedef struct Main { ListBase latt; ListBase lamp; ListBase camera; - ListBase ipo; + ListBase ipo; // XXX depreceated ListBase key; ListBase world; ListBase screen; @@ -76,6 +76,8 @@ typedef struct Main { ListBase nodetree; ListBase brush; ListBase particle; + ListBase wm; + ListBase gpencil; } Main; diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index efb64fbf0a3..382754ee2b2 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -39,6 +39,8 @@ struct Material; struct ID; struct Object; +/* materials */ + void init_def_material(void); void free_material(struct Material *sc); void test_object_materials(struct ID *id); @@ -47,15 +49,22 @@ struct Material *add_material(char *name); struct Material *copy_material(struct Material *ma); void make_local_material(struct Material *ma); +void automatname(struct Material *); + +/* material slots */ + struct Material ***give_matarar(struct Object *ob); short *give_totcolp(struct Object *ob); struct Material *give_current_material(struct Object *ob, int act); struct ID *material_from(struct Object *ob, int act); void assign_material(struct Object *ob, struct Material *ma, int act); -void new_material_to_objectdata(struct Object *ob); int find_material_index(struct Object *ob, struct Material *ma); +void object_add_material_slot(struct Object *ob); +void object_remove_material_slot(struct Object *ob); + +/* rendering */ void init_render_material(struct Material *, int, float *); void init_render_materials(int, float *); @@ -64,12 +73,8 @@ void end_render_materials(void); int material_in_material(struct Material *parmat, struct Material *mat); -void automatname(struct Material *); -void delete_material_index(void); - void ramp_blend(int type, float *r, float *g, float *b, float fac, float *col); - #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 0dfc8ae6b28..ff9ac693ba8 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -33,6 +33,7 @@ struct MetaBall; struct Object; +struct Scene; struct MetaElem; typedef struct point { /* a three-dimensional point */ @@ -154,7 +155,7 @@ void subdivide_metaball_octal_node(octal_node *node, float size_x, float size_y, void free_metaball_octal_node(octal_node *node); void init_metaball_octal_tree(int depth); void polygonize(PROCESS *mbproc, struct MetaBall *mb); -float init_meta(struct Object *ob); +float init_meta(struct Scene *scene, struct Object *ob); void unlink_mball(struct MetaBall *mb); void free_mball(struct MetaBall *mb); @@ -163,9 +164,10 @@ struct MetaBall *copy_mball(struct MetaBall *mb); void make_local_mball(struct MetaBall *mb); void tex_space_mball(struct Object *ob); float *make_orco_mball(struct Object *ob); -struct Object *find_basis_mball( struct Object *ob); +void copy_mball_properties(struct Scene *scene, struct Object *active_object); +struct Object *find_basis_mball(struct Scene *scene, struct Object *ob); int is_basis_mball(struct Object *ob); -void metaball_polygonize(struct Object *ob); +void metaball_polygonize(struct Scene *scene, struct Object *ob); void calc_mballco(struct MetaElem *ml, float *vec); float densfunc(struct MetaElem *ball, float x, float y, float z); float metaball(float x, float y, float z); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 2ca4b3aa39a..24e7b3957a7 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -36,9 +36,11 @@ struct BoundBox; struct DispList; struct ListBase; +struct EditMesh; struct MDeformVert; struct Mesh; struct MFace; +struct MEdge; struct MVert; struct MCol; struct Object; @@ -50,6 +52,9 @@ struct CustomData; extern "C" { #endif +struct EditMesh *BKE_mesh_get_editmesh(struct Mesh *me); +void BKE_mesh_end_editmesh(struct Mesh *me, struct EditMesh *em); + void unlink_mesh(struct Mesh *me); void free_mesh(struct Mesh *me); struct Mesh *add_mesh(char *name); @@ -109,6 +114,16 @@ UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned UvMapVert *get_uv_map_vert(UvVertMap *vmap, unsigned int v); void free_uv_vert_map(UvVertMap *vmap); +/* Connectivity data */ +typedef struct IndexNode { + struct IndexNode *next, *prev; + int index; +} IndexNode; +void create_vert_face_map(ListBase **map, IndexNode **mem, const struct MFace *mface, + const int totvert, const int totface); +void create_vert_edge_map(ListBase **map, IndexNode **mem, const struct MEdge *medge, + const int totvert, const int totedge); + /* Partial Mesh Visibility */ struct PartialVisibility *mesh_pmv_copy(struct PartialVisibility *); void mesh_pmv_free(struct PartialVisibility *); diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index e6d83793f94..b65d77751e2 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -33,11 +33,13 @@ #include "DNA_modifier_types.h" /* needed for all enum typdefs */ #include "BKE_customdata.h" +struct ID; struct EditMesh; struct DerivedMesh; struct DagForest; struct DagNode; struct Object; +struct Scene; struct ListBase; struct LinkNode; struct bArmature; @@ -61,7 +63,7 @@ typedef enum { * used for particles modifier that doesn't actually modify the object * unless it's a mesh and can be exploded -> curve can also emit particles */ - eModifierTypeType_DeformOrConstruct + eModifierTypeType_DeformOrConstruct, } ModifierTypeType; typedef enum { @@ -86,6 +88,9 @@ typedef enum { /* For modifiers that support pointcache, so we can check to see if it has files we need to deal with */ eModifierTypeFlag_UsesPointCache = (1<<6), + + /* For physics modifiers, max one per type */ + eModifierTypeFlag_Single = (1<<7) } ModifierTypeFlag; typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin); @@ -123,7 +128,8 @@ typedef struct ModifierTypeInfo { */ void (*deformVerts)(struct ModifierData *md, struct Object *ob, struct DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts); + float (*vertexCos)[3], int numVerts, + int useRenderParams, int isFinalCalc); /* Like deformVerts but called during editmode (for supporting modifiers) */ @@ -226,7 +232,7 @@ typedef struct ModifierTypeInfo { * * This function is optional. */ - void (*updateDepgraph)(struct ModifierData *md, struct DagForest *forest, + void (*updateDepgraph)(struct ModifierData *md, struct DagForest *forest, struct Scene *scene, struct Object *ob, struct DagNode *obNode); /* Should return true if the modifier needs to be recalculated on time @@ -291,7 +297,7 @@ int modifiers_isParticleEnabled(struct Object *ob); struct Object *modifiers_isDeformedByArmature(struct Object *ob); struct Object *modifiers_isDeformedByLattice(struct Object *ob); int modifiers_usesArmature(struct Object *ob, struct bArmature *arm); -int modifiers_isDeformed(struct Object *ob); +int modifiers_isDeformed(struct Scene *scene, struct Object *ob); void modifier_freeTemporaryData(struct ModifierData *md); int modifiers_indexInObject(struct Object *ob, struct ModifierData *md); diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index df565ddc7fe..6558212519f 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -27,42 +27,49 @@ * ***** END GPL LICENSE BLOCK ***** */ -struct CustomData; -struct EditMesh; -struct Multires; -struct MultiresLevel; +struct DerivedMesh; struct Mesh; +struct MFace; +struct MultiresModifierData; struct Object; -/* Level access */ -struct MultiresLevel *current_level(struct Multires *mr); -struct MultiresLevel *multires_level_n(struct Multires *mr, int n); +typedef struct MultiresSubsurf { + struct MultiresModifierData *mmd; + struct Mesh *me; +} MultiresSubsurf; + +/* MultiresDM */ +struct Mesh *MultiresDM_get_mesh(struct DerivedMesh *dm); +struct DerivedMesh *MultiresDM_new(struct MultiresSubsurf *, struct DerivedMesh*, int, int, int); +void *MultiresDM_get_vertnorm(struct DerivedMesh *); +void *MultiresDM_get_orco(struct DerivedMesh *); +struct MVert *MultiresDM_get_subco(struct DerivedMesh *); +struct ListBase *MultiresDM_get_vert_face_map(struct DerivedMesh *); +struct ListBase *MultiresDM_get_vert_edge_map(struct DerivedMesh *); +int *MultiresDM_get_face_offsets(struct DerivedMesh *); +int MultiresDM_get_totlvl(struct DerivedMesh *); +int MultiresDM_get_lvl(struct DerivedMesh *); +void MultiresDM_set_update(struct DerivedMesh *, void (*)(struct DerivedMesh*)); -/* Level control */ -void multires_add_level(struct Object *ob, struct Mesh *me, const char subdiv_type); -void multires_set_level(struct Object *ob, struct Mesh *me, const int render); -void multires_free_level(struct MultiresLevel *lvl); +/* The displacements will only be updated when + the MultiresDM has been marked as modified */ +void MultiresDM_mark_as_modified(struct DerivedMesh *); +void multires_mark_as_modified(struct Object *ob); -void multires_edge_level_update(struct Object *ob, struct Mesh *me); +void multires_force_update(struct Object *ob); -void multires_free(struct Multires *mr); -struct Multires *multires_copy(struct Multires *orig); -void multires_create(struct Object *ob, struct Mesh *me); +struct DerivedMesh *multires_dm_create_from_derived(struct MultiresModifierData*, struct DerivedMesh*, + struct Mesh *, int, int); -/* CustomData */ -void multires_delete_layer(struct Mesh *me, struct CustomData *cd, const int type, int n); -void multires_add_layer(struct Mesh *me, struct CustomData *cd, const int type, const int n); -void multires_del_lower_customdata(struct Multires *mr, struct MultiresLevel *cr_lvl); -void multires_to_mcol(struct MultiresColFace *f, MCol mcol[4]); -/* After adding or removing vcolor layers, run this */ -void multires_load_cols(struct Mesh *me); +struct MultiresModifierData *find_multires_modifier(struct Object *ob); +int multiresModifier_switch_level(struct Object *, const int); +void multiresModifier_join(struct Object *); +void multiresModifier_del_levels(struct MultiresModifierData *, struct Object *, int direction); +void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob, int distance, + int updateblock, int simple); +int multiresModifier_reshape(struct MultiresModifierData *mmd, struct Object *dst, struct Object *src); -/* Private (used in multires-firstlevel.c) */ -void multires_level_to_mesh(struct Object *ob, struct Mesh *me, const int render); -void multires_update_levels(struct Mesh *me, const int render); -void multires_update_first_level(struct Mesh *me, struct EditMesh *em); -void multires_update_customdata(struct MultiresLevel *lvl1, struct EditMesh *em, struct CustomData *src, - struct CustomData *dst, const int type); -void multires_customdata_to_mesh(struct Mesh *me, struct EditMesh *em, - struct MultiresLevel *lvl, struct CustomData *src, - struct CustomData *dst, const int type); +/* Related to the old multires */ +struct Multires; +void multires_load_old(struct DerivedMesh *, struct Multires *); +void multires_free(struct Multires*); diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index 230096d7ea7..989043c1d67 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -17,12 +17,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung * All rights reserved. * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Joshua Leung (full recode) * * ***** END GPL LICENSE BLOCK ***** */ @@ -30,15 +30,93 @@ #ifndef BKE_NLA_H #define BKE_NLA_H -struct bActionStrip; -struct ListBase; -struct Object; +struct AnimData; +struct NlaStrip; +struct NlaTrack; +struct bAction; + +/* ----------------------------- */ +/* Data Management */ + +void free_nlastrip(ListBase *strips, struct NlaStrip *strip); +void free_nlatrack(ListBase *tracks, struct NlaTrack *nlt); +void free_nladata(ListBase *tracks); + +struct NlaStrip *copy_nlastrip(struct NlaStrip *strip); +struct NlaTrack *copy_nlatrack(struct NlaTrack *nlt); +void copy_nladata(ListBase *dst, ListBase *src); + +struct NlaTrack *add_nlatrack(struct AnimData *adt, struct NlaTrack *prev); +struct NlaStrip *add_nlastrip(struct bAction *act); +struct NlaStrip *add_nlastrip_to_stack(struct AnimData *adt, struct bAction *act); + +/* ----------------------------- */ +/* API */ + +short BKE_nlastrips_has_space(ListBase *strips, float start, float end); +void BKE_nlastrips_sort_strips(ListBase *strips); + +short BKE_nlastrips_add_strip(ListBase *strips, struct NlaStrip *strip); + + +void BKE_nlastrips_make_metas(ListBase *strips, short temp); +void BKE_nlastrips_clear_metas(ListBase *strips, short onlySel, short onlyTemp); +void BKE_nlastrips_clear_metastrip(ListBase *strips, struct NlaStrip *strip); +short BKE_nlameta_add_strip(struct NlaStrip *mstrip, struct NlaStrip *strip); +void BKE_nlameta_flush_transforms(struct NlaStrip *mstrip); + +/* ............ */ + +struct NlaTrack *BKE_nlatrack_find_active(ListBase *tracks); +void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt); + +void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt); + +short BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end); +void BKE_nlatrack_sort_strips(struct NlaTrack *nlt); + +short BKE_nlatrack_add_strip(struct NlaTrack *nlt, struct NlaStrip *strip); + +/* ............ */ + +struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt); +void BKE_nlastrip_set_active(struct AnimData *adt, struct NlaStrip *strip); + +short BKE_nlastrip_within_bounds(struct NlaStrip *strip, float min, float max); + +void BKE_nlastrip_validate_name(struct AnimData *adt, struct NlaStrip *strip); + +/* ............ */ + +short BKE_nlatrack_has_animated_strips(struct NlaTrack *nlt); +short BKE_nlatracks_have_animated_strips(ListBase *tracks); +void BKE_nlastrip_validate_fcurves(struct NlaStrip *strip); + +void BKE_nla_validate_state(struct AnimData *adt); + +/* ............ */ + +void BKE_nla_action_pushdown(struct AnimData *adt); + +short BKE_nla_tweakmode_enter(struct AnimData *adt); +void BKE_nla_tweakmode_exit(struct AnimData *adt); + +/* ----------------------------- */ +/* Time Mapping */ + +/* time mapping conversion modes */ +enum { + /* convert from global time to strip time - for evaluation */ + NLATIME_CONVERT_EVAL = 0, + /* convert from global time to strip time - for editing corrections */ + // XXX old 0 invert + NLATIME_CONVERT_UNMAP, + /* convert from strip time to global time */ + // xxx old 1 invert + NLATIME_CONVERT_MAP, +} eNlaTime_ConvertModes; + +float BKE_nla_tweakedit_remap(struct AnimData *adt, float cframe, short mode); -void free_actionstrip (struct bActionStrip* strip); -void free_nlastrips (struct ListBase *nlalist); -void copy_nlastrips (struct ListBase *dst, struct ListBase *src); -void copy_actionstrip (struct bActionStrip **dst, struct bActionStrip **src); -void find_stridechannel(struct Object *ob, struct bActionStrip *strip); -struct bActionStrip *convert_action_to_strip (struct Object *ob); #endif diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 66e8492b357..87ee8f9cab3 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -52,9 +52,6 @@ struct GPUMaterial; struct GPUNode; struct GPUNodeStack; -#define SOCK_IN 1 -#define SOCK_OUT 2 - /* ************** NODE TYPE DEFINITIONS ***** */ typedef struct bNodeSocketType { @@ -106,6 +103,7 @@ typedef struct bNodeType { #define NODE_BREAK 2 #define NODE_FINISHED 4 #define NODE_FREEBUFS 8 +#define NODE_SKIPPED 16 /* nodetype->nclass, for add-menu and themes */ #define NODE_CLASS_INPUT 0 @@ -148,6 +146,11 @@ void ntreeInitPreview(struct bNodeTree *, int xsize, int ysize); void ntreeClearPreview(struct bNodeTree *ntree); void ntreeFreeCache(struct bNodeTree *ntree); + + /* calls allowing threaded composite */ +struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree); +void ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree); +void ntreeLocalMerge(struct bNodeTree *localtree, struct bNodeTree *ntree); /* ************** GENERIC API, NODES *************** */ @@ -376,7 +379,7 @@ struct CompBuf; void ntreeCompositTagRender(struct Scene *sce); int ntreeCompositTagAnimated(struct bNodeTree *ntree); void ntreeCompositTagGenerators(struct bNodeTree *ntree); -void ntreeCompositForceHidden(struct bNodeTree *ntree); +void ntreeCompositForceHidden(struct bNodeTree *ntree, struct Scene *scene); void free_compbuf(struct CompBuf *cbuf); /* internal...*/ @@ -418,7 +421,7 @@ extern struct ListBase node_all_textures; /* API */ int ntreeTexTagAnimated(struct bNodeTree *ntree); void ntreeTexUpdatePreviews( struct bNodeTree* nodetree ); -void ntreeTexExecTree(struct bNodeTree *ntree, struct TexResult *target, float *coord, char do_preview, short thread, struct Tex *tex, short which_output); +void ntreeTexExecTree(struct bNodeTree *ntree, struct TexResult *target, float *coord, char do_preview, short thread, struct Tex *tex, short which_output, int cfra); void ntreeTexCheckCyclics(struct bNodeTree *ntree); void ntreeTexAssignIndex(struct bNodeTree *ntree, struct bNode *node); char* ntreeTexOutputMenu(struct bNodeTree *ntree); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index a4a06b704bc..a57529ccf75 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -36,6 +36,7 @@ extern "C" { #endif struct Base; +struct Scene; struct Object; struct Camera; struct BoundBox; @@ -45,9 +46,11 @@ struct BulletSoftBody; struct Group; struct bAction; -void clear_workob(void); -void copy_baseflags(void); -void copy_objectflags(void); +void clear_workob(struct Object *workob); +void what_does_parent(struct Scene *scene, struct Object *ob, struct Object *workob); + +void copy_baseflags(struct Scene *scene); +void copy_objectflags(struct Scene *scene); struct SoftBody *copy_softbody(struct SoftBody *sb); struct BulletSoftBody *copy_bulletsoftbody(struct BulletSoftBody *sb); void copy_object_particlesystems(struct Object *obn, struct Object *ob); @@ -55,7 +58,7 @@ void copy_object_softbody(struct Object *obn, struct Object *ob); void object_free_particlesystems(struct Object *ob); void object_free_softbody(struct Object *ob); void object_free_bulletsoftbody(struct Object *ob); -void update_base_layer(struct Object *ob); +void update_base_layer(struct Scene *scene, struct Object *ob); void free_object(struct Object *ob); void object_free_display(struct Object *ob); @@ -63,7 +66,7 @@ void object_free_modifiers(struct Object *ob); void object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob); -void unlink_object(struct Object *ob); +void unlink_object(struct Scene *scene, struct Object *ob); int exist_object(struct Object *obtest); void *add_camera(char *name); struct Camera *copy_camera(struct Camera *cam); @@ -77,17 +80,17 @@ void free_lamp(struct Lamp *la); void *add_wave(void); struct Object *add_only_object(int type, char *name); -struct Object *add_object(int type); -void base_init_from_view3d(struct Base *base, struct View3D *v3d); +struct Object *add_object(struct Scene *scene, int type); struct Object *copy_object(struct Object *ob); void expand_local_object(struct Object *ob); void make_local_object(struct Object *ob); +int object_data_is_libdata(struct Object *ob); void set_mblur_offs(float blur); void set_field_offs(float field); void disable_speed_curve(int val); -float bsystem_time(struct Object *ob, float cfra, float ofs); +float bsystem_time(struct Scene *scene, struct Object *ob, float cfra, float ofs); void object_scale_to_mat3(struct Object *ob, float mat[][3]); void object_rot_to_mat3(struct Object *ob, float mat[][3]); void object_to_mat3(struct Object *ob, float mat[][3]); @@ -95,27 +98,20 @@ void object_to_mat4(struct Object *ob, float mat[][4]); void set_no_parent_ipo(int val); -void disable_where_script(short on); -int during_script(void); -void disable_where_scriptlink(short on); -int during_scriptlink(void); - -void where_is_object_time(struct Object *ob, float ctime); -void where_is_object(struct Object *ob); -void where_is_object_simul(struct Object *ob); - -void what_does_parent(struct Object *ob); +void where_is_object_time(struct Scene *scene, struct Object *ob, float ctime); +void where_is_object(struct Scene *scene, struct Object *ob); +void where_is_object_simul(struct Scene *scene, struct Object *ob); struct BoundBox *unit_boundbox(void); void boundbox_set_from_min_max(struct BoundBox *bb, float min[3], float max[3]); struct BoundBox *object_get_boundbox(struct Object *ob); void object_boundbox_flag(struct Object *ob, int flag, int set); void minmax_object(struct Object *ob, float *min, float *max); -void minmax_object_duplis(struct Object *ob, float *min, float *max); +void minmax_object_duplis(struct Scene *scene, struct Object *ob, float *min, float *max); void solve_tracking (struct Object *ob, float targetmat[][4]); int ray_hit_boundbox(struct BoundBox *bb, float ray_start[3], float ray_normal[3]); -void object_handle_update(struct Object *ob); +void object_handle_update(struct Scene *scene, struct Object *ob); float give_timeoffset(struct Object *ob); int give_obdata_texspace(struct Object *ob, int **texflag, float **loc, float **size, float **rot); diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h index 2d5acc51b7b..b6513bede99 100644 --- a/source/blender/blenkernel/BKE_packedFile.h +++ b/source/blender/blenkernel/BKE_packedFile.h @@ -31,31 +31,42 @@ #ifndef BKE_PACKEDFILE_H #define BKE_PACKEDFILE_H -#define RET_OK 0 -#define RET_ERROR 1 +#define RET_OK 0 +#define RET_ERROR 1 -struct PackedFile; -struct VFont; -struct bSample; struct bSound; struct Image; +struct Main; +struct PackedFile; +struct ReportList; +struct VFont; + +/* pack */ +struct PackedFile *newPackedFile(struct ReportList *reports, char *filename); +struct PackedFile *newPackedFileMemory(void *mem, int memlen); + +void packAll(struct Main *bmain, struct ReportList *reports); + +/* unpack */ +char *unpackFile(struct ReportList *reports, char *abs_name, char *local_name, struct PackedFile *pf, int how); +int unpackVFont(struct ReportList *reports, struct VFont *vfont, int how); +int unpackSound(struct ReportList *reports, struct bSound *sound, int how); +int unpackImage(struct ReportList *reports, struct Image *ima, int how); +void unpackAll(struct Main *bmain, struct ReportList *reports, int how); + +int writePackedFile(struct ReportList *reports, char *filename, struct PackedFile *pf, int guimode); + +/* free */ +void freePackedFile(struct PackedFile *pf); + +/* info */ +int countPackedFiles(struct Main *bmain); +int checkPackedFile(char *filename, struct PackedFile *pf); + +/* read */ +int seekPackedFile(struct PackedFile *pf, int offset, int whence); +void rewindPackedFile(struct PackedFile *pf); +int readPackedFile(struct PackedFile *pf, void *data, int size); -struct PackedFile * newPackedFile(char * filename); -struct PackedFile * newPackedFileMemory(void *mem, int memlen); - -int seekPackedFile(struct PackedFile * pf, int offset, int whence); -void rewindPackedFile(struct PackedFile * pf); -int readPackedFile(struct PackedFile * pf, void * data, int size); -int countPackedFiles(void); -void freePackedFile(struct PackedFile * pf); -void packAll(void); -int writePackedFile(char * filename, struct PackedFile *pf, int guimode); -int checkPackedFile(char * filename, struct PackedFile * pf); -char * unpackFile(char * abs_name, char * local_name, struct PackedFile * pf, int how); -int unpackVFont(struct VFont * vfont, int how); -int unpackSample(struct bSample *sample, int how); -int unpackImage(struct Image * ima, int how); -void unpackAll(int how); - #endif diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 5f5635bae1f..cf02efc34ac 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -44,6 +44,7 @@ struct HairKey; struct Main; struct Group; struct Object; +struct Scene; struct DerivedMesh; struct ModifierData; struct MTFace; @@ -54,6 +55,9 @@ struct IpoCurve; struct LinkNode; struct KDTree; struct RNG; +struct SurfaceModifierData; +struct BVHTreeRay; +struct BVHTreeRayHit; typedef struct ParticleEffectorCache { struct ParticleEffectorCache *next, *prev; @@ -90,19 +94,10 @@ typedef struct ParticleTexture{ float ivel; /* used in reset */ float time, life, exist, size; /* used in init */ float pvel[3]; /* used in physics */ - float length, clump, kink, rough; /* used in path caching */ + float length, clump, kink, effector;/* used in path caching */ + float rough1, rough2, roughe; /* used in path caching */ } ParticleTexture; -typedef struct BoidVecFunc{ - void (*Addf)(float *v, float *v1, float *v2); - void (*Subf)(float *v, float *v1, float *v2); - void (*Mulf)(float *v, float f); - float (*Length)(float *v); - float (*Normalize)(float *v); - float (*Inpf)(float *v1, float *v2); - void (*Copyf)(float *v1, float *v2); -} BoidVecFunc; - typedef struct ParticleSeam{ float v0[3], v1[3]; float nor[3], dir[3], tan[3]; @@ -138,19 +133,25 @@ typedef struct ParticleUndo { char name[64]; } ParticleUndo; -typedef struct ParticleEdit{ +typedef struct ParticleEdit { ListBase undo; struct ParticleUndo *curundo; - struct KDTree *emitter_field; + ParticleEditKey **keys; + int totkeys; + int *mirror_cache; + + struct KDTree *emitter_field; float *emitter_cosnos; - int totkeys; + char sel_col[3]; + char nosel_col[3]; } ParticleEdit; typedef struct ParticleThreadContext { /* shared */ + struct Scene *scene; struct Object *ob; struct DerivedMesh *dm; struct ParticleSystemModifierData *psmd; @@ -201,6 +202,19 @@ typedef struct ParticleBillboardData } ParticleBillboardData; +/* container for moving data between deflet_particle and particle_intersect_face */ +typedef struct ParticleCollision +{ + struct Object *ob, *ob_t; // collided and current objects + struct CollisionModifierData *md; // collision modifier for ob_t; + float nor[3]; // normal at collision point + float vel[3]; // velocity of collision point + float co1[3], co2[3]; // ray start and end points + float ray_len; // original length of co2-co1, needed for collision time evaluation + float t; // time of previous collision, needed for substracting face velocity +} +ParticleCollision; + /* ----------- functions needed outside particlesystem ---------------- */ /* particle.c */ int count_particles(struct ParticleSystem *psys); @@ -210,17 +224,20 @@ char *psys_menu_string(struct Object *ob, int for_sb); struct ParticleSystem *psys_get_current(struct Object *ob); short psys_get_current_num(struct Object *ob); +void psys_set_current_num(Object *ob, int index); +struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys); //struct ParticleSystem *psys_get(struct Object *ob, int index); struct ParticleData *psys_get_selected_particle(struct ParticleSystem *psys, int *index); struct ParticleKey *psys_get_selected_key(struct ParticleSystem *psys, int pa_index, int *key_index); void psys_change_act(void *ob_v, void *act_v); -struct Object *psys_get_lattice(struct Object *ob, struct ParticleSystem *psys); +struct Object *psys_get_lattice(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); void psys_disable_all(struct Object *ob); void psys_enable_all(struct Object *ob); int psys_ob_has_hair(struct Object *ob); -int psys_in_edit_mode(struct ParticleSystem *psys); +int psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys); int psys_check_enabled(struct Object *ob, struct ParticleSystem *psys); +void psys_free_boid_rules(struct ListBase *list); void psys_free_settings(struct ParticleSettings *part); void free_child_path_cache(struct ParticleSystem *psys); void psys_free_path_cache(struct ParticleSystem *psys); @@ -242,32 +259,34 @@ void copy_particle_key(struct ParticleKey *to, struct ParticleKey *from, int tim void psys_particle_on_emitter(struct ParticleSystemModifierData *psmd, int distr, int index, int index_dmcache, float *fuv, float foffset, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor); struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct ParticleSystem *psys); +void object_add_particle_system(struct Scene *scene, struct Object *ob); +void object_remove_particle_system(struct Scene *scene, struct Object *ob); struct ParticleSettings *psys_new_settings(char *name, struct Main *main); struct ParticleSettings *psys_copy_settings(struct ParticleSettings *part); -void psys_flush_settings(struct ParticleSettings *part, int event, int hair_recalc); +void psys_flush_particle_settings(struct Scene *scene, struct ParticleSettings *part, int recalc); void make_local_particlesettings(struct ParticleSettings *part); -struct LinkNode *psys_using_settings(struct ParticleSettings *part, int flush_update); -void psys_changed_type(struct ParticleSystem *psys); +struct LinkNode *psys_using_settings(struct Scene *scene, struct ParticleSettings *part, int flush_update); void psys_reset(struct ParticleSystem *psys, int mode); void psys_find_parents(struct Object *ob, struct ParticleSystemModifierData *psmd, struct ParticleSystem *psys); -void psys_cache_paths(struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate); -void psys_cache_child_paths(struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate); -int do_guide(struct ParticleKey *state, int pa_num, float time, struct ListBase *lb); +void psys_cache_paths(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate); +void psys_cache_child_paths(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float cfra, int editupdate); +void psys_update_world_cos(struct Object *ob, struct ParticleSystem *psys); +int do_guide(struct Scene *scene, struct ParticleKey *state, int pa_num, float time, struct ListBase *lb); float psys_get_size(struct Object *ob, struct Material *ma, struct ParticleSystemModifierData *psmd, struct IpoCurve *icu_size, struct ParticleSystem *psys, struct ParticleSettings *part, struct ParticleData *pa, float *vg_size); float psys_get_timestep(struct ParticleSettings *part); -float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra); +float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *birthtime, float *dietime); float psys_get_child_size(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *pa_time); -void psys_get_particle_on_path(struct Object *ob, struct ParticleSystem *psys, int pa_num, struct ParticleKey *state, int vel); -int psys_get_particle_state(struct Object *ob, struct ParticleSystem *psys, int p, struct ParticleKey *state, int always); +void psys_get_particle_on_path(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, int pa_num, struct ParticleKey *state, int vel); +int psys_get_particle_state(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, int p, struct ParticleKey *state, int always); void psys_get_dupli_texture(struct Object *ob, struct ParticleSettings *part, struct ParticleSystemModifierData *psmd, struct ParticleData *pa, struct ChildParticle *cpa, float *uv, float *orco); void psys_get_dupli_path_transform(struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd, struct ParticleData *pa, struct ChildParticle *cpa, struct ParticleCacheKey *cache, float mat[][4], float *scale); -ParticleThread *psys_threads_create(struct Object *ob, struct ParticleSystem *psys); -int psys_threads_init_distribution(ParticleThread *threads, struct DerivedMesh *dm, int from); -int psys_threads_init_path(ParticleThread *threads, float cfra, int editupdate); +ParticleThread *psys_threads_create(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); +int psys_threads_init_distribution(ParticleThread *threads, struct Scene *scene, struct DerivedMesh *dm, int from); +int psys_threads_init_path(ParticleThread *threads, struct Scene *scene, float cfra, int editupdate); void psys_threads_free(ParticleThread *threads); void psys_thread_distribute_particle(ParticleThread *thread, struct ParticleData *pa, struct ChildParticle *cpa, int p); @@ -276,16 +295,24 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]); /* particle_system.c */ -int psys_count_keyed_targets(struct Object *ob, struct ParticleSystem *psys); +struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt); +void psys_count_keyed_targets(struct Object *ob, struct ParticleSystem *psys); void psys_get_reactor_target(struct Object *ob, struct ParticleSystem *psys, struct Object **target_ob, struct ParticleSystem **target_psys); -void psys_init_effectors(struct Object *obsrc, struct Group *group, struct ParticleSystem *psys); +void psys_init_effectors(struct Scene *scene, struct Object *obsrc, struct Group *group, struct ParticleSystem *psys); void psys_end_effectors(struct ParticleSystem *psys); -void particle_system_update(struct Object *ob, struct ParticleSystem *psys); +void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys); +void psys_end_temp_pointcache(struct ParticleSystem *psys); +void psys_get_pointcache_start_end(struct Scene *scene, struct ParticleSystem *psys, int *sfra, int *efra); + +void psys_check_boid_data(struct ParticleSystem *psys); + +void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); /* ----------- functions needed only inside particlesystem ------------ */ /* particle.c */ +void psys_interpolate_particle(short type, struct ParticleKey keys[4], float dt, struct ParticleKey *result, int velocity); void psys_key_to_object(struct Object *ob, struct ParticleKey *key, float imat[][4]); //void psys_key_to_geometry(struct DerivedMesh *dm, struct ParticleData *pa, struct ParticleKey *key); //void psys_key_from_geometry(struct DerivedMesh *dm, struct ParticleData *pa, struct ParticleKey *key); @@ -303,18 +330,23 @@ float psys_particle_value_from_verts(struct DerivedMesh *dm, short from, struct float psys_interpolate_value_from_verts(struct DerivedMesh *dm, short from, int index, float *fw, float *values); void psys_get_from_key(struct ParticleKey *key, float *loc, float *vel, float *rot, float *time); -int psys_intersect_dm(struct Object *ob, struct DerivedMesh *dm, float *vert_cos, float *co1, float* co2, float *min_d, int *min_face, float *min_uv, float *face_minmax, float *pa_minmax, float radius, float *ipoint); +int psys_intersect_dm(struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, float *vert_cos, float *co1, float* co2, float *min_d, int *min_face, float *min_uv, float *face_minmax, float *pa_minmax, float radius, float *ipoint); +void particle_intersect_face(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit); void psys_particle_on_dm(struct DerivedMesh *dm, int from, int index, int index_dmcache, float *fw, float foffset, float *vec, float *nor, float *utan, float *vtan, float *orco, float *ornor); /* particle_system.c */ void initialize_particle(struct ParticleData *pa, int p, struct Object *ob, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd); -void reset_particle(struct ParticleData *pa, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd, struct Object *ob, float dtime, float cfra, float *vg_vel, float *vg_tan, float *vg_rot); -void do_effectors(int pa_no, struct ParticleData *pa, struct ParticleKey *state, struct Object *ob, struct ParticleSystem *psys, float *texco, float *force_field, float *vel,float framestep, float cfra); +int effector_find_co(struct Scene *scene, float *pco, struct SurfaceModifierData *sur, struct Object *ob, struct PartDeflect *pd, float *co, float *nor, float *vel, int *index); +void do_effectors(int pa_no, struct ParticleData *pa, struct ParticleKey *state, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, float *texco, float *force_field, float *vel,float framestep, float cfra); void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm, struct ParticleSystem *psys); int psys_particle_dm_face_lookup(struct Object *ob, struct DerivedMesh *dm, int index, float *fw, struct LinkNode *node); +void reset_particle(struct Scene *scene, struct ParticleData *pa, struct ParticleSystem *psys, struct ParticleSystemModifierData *psmd, struct Object *ob, + float dtime, float cfra, float *vg_vel, float *vg_tan, float *vg_rot); + + /* psys_reset */ #define PSYS_RESET_ALL 1 #define PSYS_RESET_DEPSGRAPH 2 diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 5bc467465a8..5d9dddfe30d 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -30,6 +30,10 @@ #define BKE_POINTCACHE_H #include "DNA_ID.h" +#include "DNA_object_force.h" +#include "DNA_boid_types.h" + +#include "MEM_guardedalloc.h" /* Point cache clearing option, for BKE_ptcache_id_clear, before * and after are non inclusive (they wont remove the cfra) */ @@ -42,6 +46,7 @@ #define PTCACHE_RESET_DEPSGRAPH 0 #define PTCACHE_RESET_BAKED 1 #define PTCACHE_RESET_OUTDATED 2 +#define PTCACHE_RESET_FREE 3 /* Add the blendfile name after blendcache_ */ #define PTCACHE_EXT ".bphys" @@ -52,63 +57,169 @@ #define PTCACHE_FILE_WRITE 1 /* PTCacheID types */ -#define PTCACHE_TYPE_SOFTBODY 0 -#define PTCACHE_TYPE_PARTICLES 1 -#define PTCACHE_TYPE_CLOTH 2 +#define PTCACHE_TYPE_SOFTBODY 0 +#define PTCACHE_TYPE_PARTICLES 1 +#define PTCACHE_TYPE_CLOTH 2 +#define PTCACHE_TYPE_SMOKE_DOMAIN_LOW 3 +#define PTCACHE_TYPE_SMOKE_DOMAIN_HIGH 4 + +/* PTCache read return code */ +#define PTCACHE_READ_EXACT 1 +#define PTCACHE_READ_INTERPOLATED 2 +#define PTCACHE_READ_OLD 3 /* Structs */ struct Object; +struct Scene; struct SoftBody; struct ParticleSystem; +struct ParticleKey; struct ClothModifierData; +struct SmokeModifierData; struct PointCache; struct ListBase; +/* temp structure for read/write */ +typedef struct PTCacheData { + int index; + float loc[3]; + float vel[3]; + float rot[4]; + float ave[3]; + float size; + float times[3]; + struct BoidData boids; +} PTCacheData; + typedef struct PTCacheFile { FILE *fp; + + int totpoint, type; + unsigned int data_types; + + struct PTCacheData data; + void *cur[BPHYS_TOT_DATA]; } PTCacheFile; typedef struct PTCacheID { struct PTCacheID *next, *prev; + struct Scene *scene; struct Object *ob; - void *data; + void *calldata; int type; int stack_index; + /* flags defined in DNA_object_force.h */ + unsigned int data_types, info_types; + + /* copies point data to cache data */ + int (*write_elem)(int index, void *calldata, void **data); + /* copies point data to cache data */ + int (*write_stream)(PTCacheFile *pf, void *calldata); + /* copies cache cata to point data */ + void (*read_elem)(int index, void *calldata, void **data, float frs_sec, float cfra, float *old_data); + /* copies cache cata to point data */ + void (*read_stream)(PTCacheFile *pf, void *calldata); + /* interpolated between previously read point data and cache data */ + void (*interpolate_elem)(int index, void *calldata, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data); + + /* total number of simulated points */ + int (*totpoint)(void *calldata); + /* number of points written for current cache frame (currently not used) */ + int (*totwrite)(void *calldata); + + int (*write_header)(PTCacheFile *pf); + int (*read_header)(PTCacheFile *pf); + struct PointCache *cache; + /* used for setting the current cache from ptcaches list */ + struct PointCache **cache_ptr; + struct ListBase *ptcaches; } PTCacheID; -/* Creating ID's */ +typedef struct PTCacheBaker { + struct Scene *scene; + int bake; + int render; + int anim_init; + int quick_step; + struct PTCacheID *pid; + int (*break_test)(void *data); + void *break_data; + void (*progressbar)(void *data, int num); + void *progresscontext; +} PTCacheBaker; + +/* Particle functions */ +void BKE_ptcache_make_particle_key(struct ParticleKey *key, int index, void **data, float time); + +/**************** Creating ID's ****************************/ void BKE_ptcache_id_from_softbody(PTCacheID *pid, struct Object *ob, struct SoftBody *sb); void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct ParticleSystem *psys); void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd); +void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd, int num); void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob); -/* Global funcs */ +/***************** Global funcs ****************************/ void BKE_ptcache_remove(void); -/* ID specific functions */ +/************ ID specific functions ************************/ void BKE_ptcache_id_clear(PTCacheID *id, int mode, int cfra); int BKE_ptcache_id_exist(PTCacheID *id, int cfra); -int BKE_ptcache_id_reset(PTCacheID *id, int mode); -void BKE_ptcache_id_time(PTCacheID *pid, float cfra, int *startframe, int *endframe, float *timescale); -int BKE_ptcache_object_reset(struct Object *ob, int mode); - -/* File reading/writing */ -PTCacheFile *BKE_ptcache_file_open(PTCacheID *id, int mode, int cfra); -void BKE_ptcache_file_close(PTCacheFile *pf); -int BKE_ptcache_file_read_floats(PTCacheFile *pf, float *f, int tot); -int BKE_ptcache_file_write_floats(PTCacheFile *pf, float *f, int tot); - -/* Continue physics */ -void BKE_ptcache_set_continue_physics(int enable); +int BKE_ptcache_id_reset(struct Scene *scene, PTCacheID *id, int mode); +void BKE_ptcache_id_time(PTCacheID *pid, struct Scene *scene, float cfra, int *startframe, int *endframe, float *timescale); +int BKE_ptcache_object_reset(struct Scene *scene, struct Object *ob, int mode); + +void BKE_ptcache_update_info(PTCacheID *pid); + +/*********** General cache reading/writing ******************/ + +/* Size of cache data type. */ +int BKE_ptcache_data_size(int data_type); + +/* Copy a specific data type from cache data to point data. */ +void BKE_ptcache_data_get(void **data, int type, int index, void *to); + +/* Copy a specific data type from point data to cache data. */ +void BKE_ptcache_data_set(void **data, int type, void *from); + +/* Main cache reading call. */ +int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec); + +/* Main cache writing call. */ +int BKE_ptcache_write_cache(PTCacheID *pid, int cfra); + +/****************** Continue physics ***************/ +void BKE_ptcache_set_continue_physics(struct Scene *scene, int enable); int BKE_ptcache_get_continue_physics(void); -/* Point Cache */ -struct PointCache *BKE_ptcache_add(void); +/******************* Allocate & free ***************/ +struct PointCache *BKE_ptcache_add(struct ListBase *ptcaches); +void BKE_ptache_free_mem(struct PointCache *cache); void BKE_ptcache_free(struct PointCache *cache); -struct PointCache *BKE_ptcache_copy(struct PointCache *cache); +void BKE_ptcache_free_list(struct ListBase *ptcaches); +struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, struct ListBase *ptcaches_old); + +/********************** Baking *********************/ + +/* Bakes cache with cache_step sized jumps in time, not accurate but very fast. */ +void BKE_ptcache_quick_cache_all(struct Scene *scene); + +/* Bake cache or simulate to current frame with settings defined in the baker. */ +void BKE_ptcache_make_cache(struct PTCacheBaker* baker); + +/* Convert disk cache to memory cache. */ +void BKE_ptcache_disk_to_mem(struct PTCacheID *pid); + +/* Convert memory cache to disk cache. */ +void BKE_ptcache_mem_to_disk(struct PTCacheID *pid); + +/* Convert disk cache to memory cache and vice versa. Clears the cache that was converted. */ +void BKE_ptcache_toggle_disk_cache(struct PTCacheID *pid); + +/* Loads simulation from external (disk) cache files. */ +void BKE_ptcache_load_external(struct PTCacheID *pid); #endif diff --git a/source/blender/blenkernel/BKE_property.h b/source/blender/blenkernel/BKE_property.h index 6af1deda727..78a9ecddaac 100644 --- a/source/blender/blenkernel/BKE_property.h +++ b/source/blender/blenkernel/BKE_property.h @@ -41,6 +41,7 @@ struct bProperty *copy_property(struct bProperty *prop); void copy_properties(struct ListBase *lbn, struct ListBase *lbo); void init_property(struct bProperty *prop); struct bProperty *new_property(int type); +void unique_property(struct bProperty *first, struct bProperty *prop, int force); struct bProperty *get_ob_property(struct Object *ob, char *name); void set_ob_property(struct Object *ob, struct bProperty *propc); int compare_property(struct bProperty *prop, char *str); diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h new file mode 100644 index 00000000000..1d72b1c81f0 --- /dev/null +++ b/source/blender/blenkernel/BKE_report.h @@ -0,0 +1,67 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation (2008). + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_REPORT_H +#define BKE_REPORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "DNA_windowmanager_types.h" + +/* Reporting Information and Errors + * + * These functions also accept NULL in case no error reporting + * is needed. */ + +/* report structures are stored in DNA */ + +void BKE_reports_init(ReportList *reports, int flag); +void BKE_reports_clear(ReportList *reports); + +void BKE_report(ReportList *reports, ReportType type, const char *message); +void BKE_reportf(ReportList *reports, ReportType type, const char *format, ...); + +void BKE_reports_prepend(ReportList *reports, const char *prepend); +void BKE_reports_prependf(ReportList *reports, const char *prepend, ...); + +ReportType BKE_report_print_level(ReportList *reports); +void BKE_report_print_level_set(ReportList *reports, ReportType level); + +ReportType BKE_report_store_level(ReportList *reports); +void BKE_report_store_level_set(ReportList *reports, ReportType level); + +char *BKE_reports_string(ReportList *reports, ReportType level); +void BKE_reports_print(ReportList *reports, ReportType level); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 647f7e95fd9..9bb246f88cc 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -38,20 +38,8 @@ struct Base; struct Text; struct AviCodecData; struct QuicktimeCodecData; -struct SculptData; struct RenderData; - -/* sequence related defines */ -#define WHILE_SEQ(base) { \ - int totseq_, seq_; Sequence **seqar; \ - build_seqar( base, &seqar, &totseq_); \ - for(seq_ = 0; seq_ < totseq_; seq_++) { \ - seq= seqar[seq_]; - - -#define END_SEQ } \ - if(seqar) MEM_freeN(seqar); \ -} +struct Text; /* note; doesn't work when scene is empty */ #define SETLOOPER(s, b) sce= s, b= (Base*)sce->base.first; b; b= (Base*)(b->next?b->next:sce->set?(sce=sce->set)->base.first:NULL) @@ -67,7 +55,7 @@ struct Base *object_in_scene(struct Object *ob, struct Scene *sce); void set_scene_bg(struct Scene *sce); void set_scene_name(char *name); -int next_object(int val, struct Base **base, struct Object **ob); +int next_object(struct Scene *scene, int val, struct Base **base, struct Object **ob); struct Object *scene_find_camera(struct Scene *sc); struct Base *scene_add_base(struct Scene *sce, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index df904d3e08a..4fcb7c881be 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -31,7 +31,210 @@ #ifndef BKE_SCREEN_H #define BKE_SCREEN_H +struct ARegion; +struct bContext; +struct bContextDataResult; +struct bScreen; +struct ListBase; +struct Panel; +struct Header; +struct Menu; +struct ScrArea; +struct SpaceType; +struct wmNotifier; +struct wmWindow; +struct wmWindowManager; +struct uiLayout; +struct uiMenuItem; + +#include "RNA_types.h" + +/* spacetype has everything stored to get an editor working, it gets initialized via + ED_spacetypes_init() in editors/area/spacetypes.c */ +/* an editor in Blender is a combined ScrArea + SpaceType + SpaceData */ + +#define BKE_ST_MAXNAME 32 + +typedef struct SpaceType { + struct SpaceType *next, *prev; + + char name[BKE_ST_MAXNAME]; /* for menus */ + int spaceid; /* unique space identifier */ + int iconid; /* icon lookup for menus */ + + /* initial allocation, after this WM will call init() too */ + struct SpaceLink *(*new)(const struct bContext *C); + /* not free spacelink itself */ + void (*free)(struct SpaceLink *); + + /* init is to cope with file load, screen (size) changes, check handlers */ + void (*init)(struct wmWindowManager *, struct ScrArea *); + /* Listeners can react to bContext changes */ + void (*listener)(struct ScrArea *, struct wmNotifier *); + + /* refresh context, called after filereads, ED_area_tag_refresh() */ + void (*refresh)(const struct bContext *, struct ScrArea *); + + /* after a spacedata copy, an init should result in exact same situation */ + struct SpaceLink *(*duplicate)(struct SpaceLink *); + + /* register operator types on startup */ + void (*operatortypes)(void); + /* add default items to WM keymap */ + void (*keymap)(struct wmWindowManager *); + + /* return context data */ + int (*context)(const struct bContext *, const char*, struct bContextDataResult *); + + /* region type definitions */ + ListBase regiontypes; + + /* tool shelf definitions */ + ListBase toolshelf; + + /* read and write... */ + + /* default keymaps to add */ + int keymapflag; + +} SpaceType; + +/* region types are also defined using spacetypes_init, via a callback */ + +typedef struct ARegionType { + struct ARegionType *next, *prev; + + int regionid; /* unique identifier within this space */ + + /* add handlers, stuff you only do once or on area/region type/size changes */ + void (*init)(struct wmWindowManager *, struct ARegion *); + /* draw entirely, view changes should be handled here */ + void (*draw)(const struct bContext *, struct ARegion *); + /* contextual changes should be handled here */ + void (*listener)(struct ARegion *, struct wmNotifier *); + + void (*free)(struct ARegion *); + + /* split region, copy data optionally */ + void *(*duplicate)(void *); + + + /* register operator types on startup */ + void (*operatortypes)(void); + /* add own items to keymap */ + void (*keymap)(struct wmWindowManager *); + /* allows default cursor per region */ + void (*cursor)(struct wmWindow *, struct ScrArea *, struct ARegion *ar); + + /* return context data */ + int (*context)(const struct bContext *, const char *, struct bContextDataResult *); + + /* custom drawing callbacks */ + ListBase drawcalls; + + /* panels type definitions */ + ListBase paneltypes; + + /* header type definitions */ + ListBase headertypes; + + /* menu type definitions */ + ListBase menutypes; + + /* hardcoded constraints, smaller than these values region is not visible */ + int minsizex, minsizey; + /* default keymaps to add */ + int keymapflag; +} ARegionType; + +/* panel types */ + +typedef struct PanelType { + struct PanelType *next, *prev; + + char idname[BKE_ST_MAXNAME]; /* unique name */ + char label[BKE_ST_MAXNAME]; /* for panel header */ + char context[BKE_ST_MAXNAME]; /* for buttons window */ + int space_type; + int region_type; + + int flag; + + /* verify if the panel should draw or not */ + int (*poll)(const struct bContext *, struct PanelType *); + /* draw header (optional) */ + void (*draw_header)(const struct bContext *, struct Panel *); + /* draw entirely, view changes should be handled here */ + void (*draw)(const struct bContext *, struct Panel *); + + /* RNA integration */ + ExtensionRNA ext; +} PanelType; + +/* header types */ + +typedef struct HeaderType { + struct HeaderType *next, *prev; + + char idname[BKE_ST_MAXNAME]; /* unique name */ + int space_type; + + /* draw entirely, view changes should be handled here */ + void (*draw)(const struct bContext *, struct Header *); + + /* RNA integration */ + ExtensionRNA ext; +} HeaderType; + +typedef struct Header { + struct HeaderType *type; /* runtime */ + struct uiLayout *layout; /* runtime for drawing */ +} Header; + + +/* menu types */ + +typedef struct MenuType { + struct MenuType *next, *prev; + + char idname[BKE_ST_MAXNAME]; /* unique name */ + char label[BKE_ST_MAXNAME]; /* for button text */ + int space_type; + + /* verify if the menu should draw or not */ + int (*poll)(const struct bContext *, struct MenuType *); + /* draw entirely, view changes should be handled here */ + void (*draw)(const struct bContext *, struct Menu *); + + /* RNA integration */ + ExtensionRNA ext; +} MenuType; + +typedef struct Menu { + struct MenuType *type; /* runtime */ + struct uiLayout *layout; /* runtime for drawing */ +} Menu; + +/* spacetypes */ +struct SpaceType *BKE_spacetype_from_id(int spaceid); +struct ARegionType *BKE_regiontype_from_id(struct SpaceType *st, int regionid); +const struct ListBase *BKE_spacetypes_list(void); +void BKE_spacetype_register(struct SpaceType *st); +void BKE_spacetypes_free(void); /* only for quitting blender */ + +/* spacedata */ +void BKE_spacedata_freelist(ListBase *lb); +void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2); +void BKE_spacedata_copyfirst(ListBase *lb1, ListBase *lb2); + +/* area/regions */ +struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar); +void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar); + +void BKE_screen_area_free(struct ScrArea *sa); + void free_screen(struct bScreen *sc); + #endif diff --git a/source/blender/blenkernel/BKE_sculpt.h b/source/blender/blenkernel/BKE_sculpt.h index 5d7ed28f561..54cafc984a6 100644 --- a/source/blender/blenkernel/BKE_sculpt.h +++ b/source/blender/blenkernel/BKE_sculpt.h @@ -30,24 +30,26 @@ #ifndef BKE_SCULPT_H #define BKE_SCULPT_H -struct NumInput; -struct RadialControl; -struct Scene; -struct SculptData; -struct SculptSession; +struct MFace; +struct MultireModifierData; +struct MVert; +struct Sculpt; +struct StrokeCache; typedef struct SculptSession { struct ProjVert *projverts; - struct bglMats *mats; + /* Mesh data (not copied) can come either directly from a Mesh, or from a MultiresDM */ + struct MultiresModifierData *multires; /* Special handling for multires meshes */ + struct MVert *mvert; + struct MFace *mface; + int totvert, totface; + float *face_normals; - /* An array of lists; array is sized as - large as the number of verts in the mesh, - the list for each vert contains the index - for all the faces that use that vertex */ - struct ListBase *vertex_users; - struct IndexNode *vertex_users_mem; - int vertex_users_size; + /* Mesh connectivity */ + struct ListBase *fmap; + struct IndexNode *fmap_mem; + int fmap_size; /* Used temporarily per-stroke */ float *vertexcosnos; @@ -55,17 +57,19 @@ typedef struct SculptSession { ListBase damaged_verts; /* Used to cache the render of the active texture */ - unsigned int texcache_w, texcache_h, *texcache; - - struct RadialControl *radialcontrol; - + unsigned int texcache_side, *texcache, texcache_actual; + + /* Layer brush persistence between strokes */ + float (*mesh_co_orig)[3]; /* Copy of the mesh vertices' locations */ + float *layer_disps; /* Displacements for each vertex */ + + void *cursor; /* wm handle */ + struct SculptStroke *stroke; + + struct StrokeCache *cache; } SculptSession; -void sculptdata_init(struct Scene *sce); -void sculptdata_free(struct Scene *sce); -void sculptsession_free(struct Scene *sce); -void sculpt_vertexusers_free(struct SculptSession *ss); -void sculpt_reset_curve(struct SculptData *sd); +void sculptsession_free(struct Sculpt *sculpt); #endif diff --git a/source/blender/blenkernel/BKE_sequence.h b/source/blender/blenkernel/BKE_sequence.h new file mode 100644 index 00000000000..35cff5c9422 --- /dev/null +++ b/source/blender/blenkernel/BKE_sequence.h @@ -0,0 +1,186 @@ +/** + * $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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation (2008). + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_SEQUENCE_H +#define BKE_SEQUENCE_H + +struct Editing; +struct Sequence; +struct Strip; +struct StripElem; +struct ImBuf; +struct Scene; +struct bContext; + +#define MAXSEQ 32 + +#define BUILD_SEQAR_COUNT_NOTHING 0 +#define BUILD_SEQAR_COUNT_CURRENT 1 +#define BUILD_SEQAR_COUNT_CHILDREN 2 + +/* sequence iterator */ + +typedef struct SeqIterator { + struct Sequence **array; + int tot, cur; + + struct Sequence *seq; + int valid; +} SeqIterator; + +void seq_begin(struct Editing *ed, SeqIterator *iter, int use_pointer); +void seq_next(SeqIterator *iter); +void seq_end(SeqIterator *iter); +void seq_array(struct Editing *ed, struct Sequence ***seqarray, int *tot, int use_pointer); + +#define SEQP_BEGIN(ed, seq) \ +{ \ + SeqIterator iter;\ + for(seq_begin(ed, &iter, 1); iter.valid; seq_next(&iter)) { \ + seq= iter.seq; + +#define SEQ_BEGIN(ed, seq) \ + { \ + SeqIterator iter;\ + for(seq_begin(ed, &iter, 0); iter.valid; seq_next(&iter)) { \ + seq= iter.seq; + +#define SEQ_END \ + } \ + seq_end(&iter); \ + } + +#endif + + +/* Wipe effect */ +enum {DO_SINGLE_WIPE, DO_DOUBLE_WIPE, DO_BOX_WIPE, DO_CROSS_WIPE, + DO_IRIS_WIPE,DO_CLOCK_WIPE}; + + +struct SeqEffectHandle { + /* constructors & destructor */ + /* init & init_plugin are _only_ called on first creation */ + void (*init)(struct Sequence *seq); + void (*init_plugin)(struct Sequence *seq, const char *fname); + + /* number of input strips needed + (called directly after construction) */ + int (*num_inputs)(); + + /* load is called first time after readblenfile in + get_sequence_effect automatically */ + void (*load)(struct Sequence *seq); + + /* duplicate */ + void (*copy)(struct Sequence *dst, struct Sequence *src); + + /* destruct */ + void (*free)(struct Sequence *seq); + + /* returns: -1: no input needed, + 0: no early out, + 1: out = ibuf1, + 2: out = ibuf2 */ + int (*early_out)(struct Sequence *seq, + float facf0, float facf1); + + /* stores the y-range of the effect IPO */ + void (*store_icu_yrange)(struct Sequence * seq, + short adrcode, float *ymin, float *ymax); + + /* stores the default facf0 and facf1 if no IPO is present */ + void (*get_default_fac)(struct Sequence *seq, int cfra, + float * facf0, float * facf1); + + /* execute the effect + sequence effects are only required to either support + float-rects or byte-rects + (mixed cases are handled one layer up...) */ + + void (*execute)(struct Sequence *seq, int cfra, + float facf0, float facf1, + int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out); +}; + +/* ********************* prototypes *************** */ + +/* sequence.c */ + +// extern +void seq_free_sequence(struct Scene *scene, struct Sequence *seq); +void seq_free_strip(struct Strip *strip); +void seq_free_editing(struct Scene *scene); +struct Editing *seq_give_editing(struct Scene *scene, int alloc); +char *give_seqname(struct Sequence *seq); +struct ImBuf *give_ibuf_seq(struct Scene *scene, int rectx, int recty, int cfra, int chanshown, int render_size); +struct ImBuf *give_ibuf_seq_threaded(struct Scene *scene, int rectx, int recty, int cfra, int chanshown, int render_size); +struct ImBuf *give_ibuf_seq_direct(struct Scene *scene, int rectx, int recty, int cfra, int render_size, struct Sequence *seq); +void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown, int render_size); +void calc_sequence(struct Sequence *seq); +void calc_sequence_disp(struct Sequence *seq); +void new_tstripdata(struct Sequence *seq); +void reload_sequence_new_file(struct Scene *scene, struct Sequence * seq); +void sort_seq(struct Scene *scene); +void build_seqar_cb(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq, + int (*test_func)(struct Sequence * seq)); +int evaluate_seq_frame(struct Scene *scene, int cfra); +struct StripElem *give_stripelem(struct Sequence *seq, int cfra); + +// intern? +void update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_seq, int len_change, int ibuf_change); + +/* seqeffects.c */ +// intern? +struct SeqEffectHandle get_sequence_blend(struct Sequence *seq); +void sequence_effect_speed_rebuild_map(struct Sequence *seq, int force); + +// extern +struct SeqEffectHandle get_sequence_effect(struct Sequence *seq); +int get_sequence_effect_num_inputs(int seq_type); + +/* for transform but also could use elsewhere */ +int seq_tx_get_start(struct Sequence *seq); +int seq_tx_get_end(struct Sequence *seq); +int seq_tx_get_final_left(struct Sequence *seq, int metaclip); +int seq_tx_get_final_right(struct Sequence *seq, int metaclip); +void seq_tx_set_final_left(struct Sequence *seq, int val); +void seq_tx_set_final_right(struct Sequence *seq, int val); +void seq_tx_handle_xlimits(struct Sequence *seq, int leftflag, int rightflag); +int seq_tx_test(struct Sequence * seq); +int check_single_seq(struct Sequence *seq); +void fix_single_seq(struct Sequence *seq); +int seq_test_overlap(struct ListBase * seqbasep, struct Sequence *test); +int shuffle_seq(struct ListBase * seqbasep, struct Sequence *test); +void free_imbuf_seq(struct ListBase * seqbasep, int check_mem_usage); + +void seq_update_sound(struct Sequence *seq); diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 6ce449f7824..eb0e3c4ef00 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -30,11 +30,12 @@ #define BKE_SHRINKWRAP_H /* mesh util */ + //TODO: move this somewhere else #include "BKE_customdata.h" struct DerivedMesh; struct Object; -struct DerivedMesh *object_get_derived_final(struct Object *ob, CustomDataMask dataMask); +struct DerivedMesh *object_get_derived_final(struct Scene *scene, struct Object *ob, CustomDataMask dataMask); /* SpaceTransform stuff */ @@ -69,14 +70,11 @@ typedef struct SpaceTransform } SpaceTransform; -void space_transform_from_matrixs(SpaceTransform *data, float local[][4], float target[][4]); -#define space_transform_setup(data, local, target) space_transform_from_matrixs(data, (local)->obmat, (target)->obmat) - -void space_transform_apply (const SpaceTransform *data, float *co); -void space_transform_invert(const SpaceTransform *data, float *co); +void space_transform_from_matrixs(struct SpaceTransform *data, float local[4][4], float target[4][4]); +void space_transform_apply(const struct SpaceTransform *data, float *co); +void space_transform_invert(const struct SpaceTransform *data, float *co); -void space_transform_apply_normal (const SpaceTransform *data, float *no); -void space_transform_invert_normal(const SpaceTransform *data, float *no); +#define space_transform_setup(data, local, target) space_transform_from_matrixs(data, (local)->obmat, (target)->obmat) /* Shrinkwrap stuff */ #include "BKE_bvhutils.h" @@ -94,6 +92,7 @@ void space_transform_invert_normal(const SpaceTransform *data, float *no); */ struct Object; +struct Scene; struct DerivedMesh; struct MVert; struct MDeformVert; @@ -122,11 +121,7 @@ typedef struct ShrinkwrapCalcData } ShrinkwrapCalcData; -void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *data); -void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *data); -void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *data); - -void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts); +void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts); /* * This function casts a ray in the given BVHTree.. but it takes into consideration the space_transform, that is: diff --git a/source/blender/blenkernel/BKE_sketch.h b/source/blender/blenkernel/BKE_sketch.h new file mode 100644 index 00000000000..424dd5c9f80 --- /dev/null +++ b/source/blender/blenkernel/BKE_sketch.h @@ -0,0 +1,157 @@ +/** + * + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef BKE_SKETCH_H +#define BKE_SKETCH_H + +typedef enum SK_PType +{ + PT_CONTINUOUS, + PT_EXACT, +} SK_PType; + +typedef enum SK_PMode +{ + PT_SNAP, + PT_PROJECT, +} SK_PMode; + +typedef struct SK_Point +{ + float p[3]; + short p2d[2]; + float no[3]; + float size; + SK_PType type; + SK_PMode mode; +} SK_Point; + +typedef struct SK_Stroke +{ + struct SK_Stroke *next, *prev; + + SK_Point *points; + int nb_points; + int buf_size; + int selected; +} SK_Stroke; + +#define SK_OVERDRAW_LIMIT 5 + +typedef struct SK_Overdraw +{ + SK_Stroke *target; + int start, end; + int count; +} SK_Overdraw; + +#define SK_Stroke_BUFFER_INIT_SIZE 20 + +typedef struct SK_DrawData +{ + short mval[2]; + short previous_mval[2]; + SK_PType type; +} SK_DrawData; + +typedef struct SK_Intersection +{ + struct SK_Intersection *next, *prev; + SK_Stroke *stroke; + int before; + int after; + int gesture_index; + float p[3]; + float lambda; /* used for sorting intersection points */ +} SK_Intersection; + +typedef struct SK_Sketch +{ + ListBase strokes; + ListBase depth_peels; + SK_Stroke *active_stroke; + SK_Stroke *gesture; + SK_Point next_point; + SK_Overdraw over; +} SK_Sketch; + + +typedef struct SK_Gesture { + SK_Stroke *stk; + SK_Stroke *segments; + + ListBase intersections; + ListBase self_intersections; + + int nb_self_intersections; + int nb_intersections; + int nb_segments; +} SK_Gesture; + + +/************************************************/ + +void freeSketch(SK_Sketch *sketch); +SK_Sketch* createSketch(); + +void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk); + +void sk_freeStroke(SK_Stroke *stk); +SK_Stroke* sk_createStroke(); + +SK_Point *sk_lastStrokePoint(SK_Stroke *stk); + +void sk_allocStrokeBuffer(SK_Stroke *stk); +void sk_shrinkStrokeBuffer(SK_Stroke *stk); +void sk_growStrokeBuffer(SK_Stroke *stk); +void sk_growStrokeBufferN(SK_Stroke *stk, int n); + +void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n); +void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n); +void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt); +void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end); + +void sk_trimStroke(SK_Stroke *stk, int start, int end); +void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3]); +void sk_polygonizeStroke(SK_Stroke *stk, int start, int end); +void sk_flattenStroke(SK_Stroke *stk, int start, int end); +void sk_reverseStroke(SK_Stroke *stk); + +void sk_filterLastContinuousStroke(SK_Stroke *stk); +void sk_filterStroke(SK_Stroke *stk, int start, int end); + +void sk_initPoint(SK_Point *pt, SK_DrawData *dd, float *no); +void sk_copyPoint(SK_Point *dst, SK_Point *src); + +int sk_stroke_filtermval(SK_DrawData *dd); +void sk_endContinuousStroke(SK_Stroke *stk); + +void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk); + +void sk_initDrawData(SK_DrawData *dd, short mval[2]); + +void sk_deleteSelectedStrokes(SK_Sketch *sketch); +void sk_selectAllSketch(SK_Sketch *sketch, int mode); + +#endif diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h new file mode 100644 index 00000000000..8dc38640e9a --- /dev/null +++ b/source/blender/blenkernel/BKE_smoke.h @@ -0,0 +1,55 @@ +/** + * BKE_smoke.h + * + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Daniel Genrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_SMOKE_H_ +#define BKE_SMOKE_H_ + +void smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, int useRenderParams, int isFinalCalc); + +void smokeModifier_free (struct SmokeModifierData *smd); +void smokeModifier_reset(struct SmokeModifierData *smd); +void smokeModifier_createType(struct SmokeModifierData *smd); + +void smoke_set_tray(struct SmokeModifierData *smd, size_t index, float transparency); +float smoke_get_tray(struct SmokeModifierData *smd, size_t index); +float smoke_get_tvox(struct SmokeModifierData *smd, size_t index); +void smoke_set_tvox(struct SmokeModifierData *smd, size_t index, float tvox); + +void smoke_set_bigtray(struct SmokeModifierData *smd, size_t index, float transparency); +float smoke_get_bigtray(struct SmokeModifierData *smd, size_t index); +float smoke_get_bigtvox(struct SmokeModifierData *smd, size_t index); +void smoke_set_bigtvox(struct SmokeModifierData *smd, size_t index, float tvox); + +long long smoke_get_mem_req(int xres, int yres, int zres, int amplify); +void smoke_prepare_View(struct SmokeModifierData *smd, float *light); +void smoke_prepare_bigView(struct SmokeModifierData *smd, float *light); + +#endif /* BKE_SMOKE_H_ */ diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h index a0691b635da..d8053281ceb 100644 --- a/source/blender/blenkernel/BKE_softbody.h +++ b/source/blender/blenkernel/BKE_softbody.h @@ -32,6 +32,7 @@ #define BKE_SOFTBODY_H struct Object; +struct Scene; struct SoftBody; typedef struct BodyPoint { @@ -49,7 +50,7 @@ typedef struct BodyPoint { } BodyPoint; /* allocates and initializes general main data */ -extern struct SoftBody *sbNew(void); +extern struct SoftBody *sbNew(struct Scene *scene); /* frees internal data and softbody itself */ extern void sbFree(struct SoftBody *sb); @@ -58,7 +59,7 @@ extern void sbFree(struct SoftBody *sb); extern void sbFreeSimulation(struct SoftBody *sb); /* do one simul step, reading and writing vertex locs from given array */ -extern void sbObjectStep(struct Object *ob, float framnr, float (*vertexCos)[3], int numVerts); +extern void sbObjectStep(struct Scene *scene, struct Object *ob, float framnr, float (*vertexCos)[3], int numVerts); /* makes totally fresh start situation, resets time */ extern void sbObjectToSoftbody(struct Object *ob); @@ -67,8 +68,5 @@ extern void sbObjectToSoftbody(struct Object *ob); /* pass NULL to unlink again */ extern void sbSetInterruptCallBack(int (*f)(void)); -/* writing to cache for bake editing */ -extern void sbWriteCache(struct Object *ob, int framenr); - #endif diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index f3bed467c3a..ef66b29f112 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -1,7 +1,7 @@ /** * sound.h (mar-2001 nzc) - * - * $Id$ + * + * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -33,20 +33,47 @@ struct PackedFile; struct bSound; -struct bSample; +struct bContext; struct ListBase; +struct Main; + +void sound_init(); -/* bad bad global... */ -extern struct ListBase *samples; +void sound_reinit(struct bContext *C); -void sound_free_all_samples(void); +void sound_exit(); -/* void *sound_get_listener(void); implemented in src!also declared there now */ +struct bSound* sound_new_file(struct Main *main, char* filename); -void sound_set_packedfile(struct bSample* sample, struct PackedFile* pf); -struct PackedFile* sound_find_packedfile(struct bSound* sound); -void sound_free_sample(struct bSample* sample); -void sound_free_sound(struct bSound* sound); +// XXX unused currently +#if 0 +struct bSound* sound_new_buffer(struct bContext *C, struct bSound *source); +struct bSound* sound_new_limiter(struct bContext *C, struct bSound *source, float start, float end); #endif +void sound_delete(struct bContext *C, struct bSound* sound); + +void sound_cache(struct bSound* sound, int ignore); + +void sound_load(struct bSound* sound); + +void sound_free(struct bSound* sound); + +void sound_unlink(struct bContext *C, struct bSound* sound); + +struct SoundHandle* sound_new_handle(struct Scene *scene, struct bSound* sound, int startframe, int endframe, int frameskip); + +void sound_delete_handle(struct Scene *scene, struct SoundHandle *handle); + +void sound_update_playing(struct bContext *C); + +void sound_scrub(struct bContext *C); + +#ifdef AUD_CAPI +AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end); +#endif + +void sound_stop_all(struct bContext *C); + +#endif diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h index c3c6b8d9edd..f6dc22f650a 100644 --- a/source/blender/blenkernel/BKE_subsurf.h +++ b/source/blender/blenkernel/BKE_subsurf.h @@ -32,6 +32,7 @@ struct Mesh; struct Object; struct DerivedMesh; struct EditMesh; +struct MultiresSubsurf; struct SubsurfModifierData; struct DerivedMesh *subsurf_make_derived_from_derived( @@ -40,6 +41,13 @@ struct DerivedMesh *subsurf_make_derived_from_derived( int useRenderParams, float (*vertCos)[3], int isFinalCalc, int editMode); +struct DerivedMesh *subsurf_make_derived_from_derived_with_multires( + struct DerivedMesh *dm, + struct SubsurfModifierData *smd, + struct MultiresSubsurf *ms, + int useRenderParams, float (*vertCos)[3], + int isFinalCalc, int editMode); + void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]); #endif diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index 002c804f17f..d288c0b6516 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -44,11 +44,9 @@ void txt_set_undostate (int u); int txt_get_undostate (void); struct Text* add_empty_text (char *name); int reopen_text (struct Text *text); -struct Text* add_text (char *file); +struct Text* add_text (char *file, const char *relpath); struct Text* copy_text (struct Text *ta); -void txt_free_cut_buffer (void); - char* txt_to_buf (struct Text *text); void txt_clean_text (struct Text *text); void txt_order_cursors (struct Text *text); @@ -70,14 +68,11 @@ void txt_move_to (struct Text *text, unsigned int line, unsigned int ch, short void txt_pop_sel (struct Text *text); void txt_delete_char (struct Text *text); void txt_delete_word (struct Text *text); -void txt_copy_sel (struct Text *text); +void txt_delete_selected (struct Text *text); void txt_sel_all (struct Text *text); void txt_sel_line (struct Text *text); -void txt_print_cutbuffer (void); -void txt_cut_sel (struct Text *text); char* txt_sel_to_buf (struct Text *text); void txt_insert_buf (struct Text *text, char *in_buffer); -void txt_paste (struct Text *text); void txt_print_undo (struct Text *text); void txt_undo_add_toop (struct Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc); void txt_do_undo (struct Text *text); @@ -87,9 +82,6 @@ void txt_backspace_char (struct Text *text); void txt_backspace_word (struct Text *text); int txt_add_char (struct Text *text, char add); int txt_replace_char (struct Text *text, char add); -void find_and_replace (struct SpaceText *st, short mode); -void run_python_script (struct SpaceText *st); -int jumptoline_interactive (struct SpaceText *st); void txt_export_to_object (struct Text *text); void txt_export_to_objects(struct Text *text); void unindent (struct Text *text); @@ -97,9 +89,6 @@ void comment (struct Text *text); void indent (struct Text *text); void uncomment (struct Text *text); int setcurr_tab (struct Text *text); -void convert_tabs (struct SpaceText *st, int tab); -void txt_copy_clipboard (struct Text *text); -void txt_paste_clipboard (struct Text *text); void txt_add_marker (struct Text *text, struct TextLine *line, int start, int end, char color[4], int group, int flags); short txt_clear_marker_region (struct Text *text, struct TextLine *line, int start, int end, int group, int flags); @@ -152,10 +141,6 @@ struct TextMarker *txt_next_marker_color (struct Text *text, struct TextMarker * #define UNDO_COMMENT 034 #define UNDO_UNCOMMENT 035 -/* Find and replace flags */ -#define TXT_FIND_WRAP 0x01 -#define TXT_FIND_ALLTEXTS 0x02 - /* Marker flags */ #define TMARK_TEMP 0x01 /* Remove on non-editing events, don't save */ #define TMARK_EDITALL 0x02 /* Edit all markers of the same group as one */ diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index cfcae3c44bc..a1600ce5473 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -31,6 +31,7 @@ #ifndef BKE_TEXTURE_H #define BKE_TEXTURE_H +struct Scene; struct Tex; struct MTex; struct PluginTex; @@ -63,7 +64,7 @@ struct Tex *copy_texture(struct Tex *tex); void make_local_texture(struct Tex *tex); void autotexname(struct Tex *tex); struct Tex *give_current_texture(struct Object *ob, int act); -struct Tex *give_current_world_texture(void); +struct Tex *give_current_world_texture(struct Scene *scene); struct TexMapping *add_mapping(void); void init_mapping(struct TexMapping *texmap); diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h new file mode 100644 index 00000000000..54d5bba057a --- /dev/null +++ b/source/blender/blenkernel/BKE_unit.h @@ -0,0 +1,68 @@ +/** + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BKE_UNIT_H +#define BKE_UNIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* in all cases the value is assumed to be scaled by the user preference */ + +/* humanly readable representation of a value in units (used for button drawing) */ +void bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, int split, int pad); + +/* replace units with values, used before python button evaluation */ +int bUnit_ReplaceString(char *str, int len_max, char *str_prev, double scale_pref, int system, int type); + +/* the size of the unit used for this value (used for calculating the ckickstep) */ +double bUnit_ClosestScalar(double value, int system, int type); + +/* base scale for these units */ +double bUnit_BaseScalar(int system, int type); + +/* loop over scales, coudl add names later */ +//double bUnit_Iter(void **unit, char **name, int system, int type); + +void bUnit_GetSystem(void **usys_pt, int *len, int system, int type); +char* bUnit_GetName(void *usys_pt, int index); +char* bUnit_GetNamePlural(void *usys_pt, int index); +double bUnit_GetScaler(void *usys_pt, int index); + +/* aligned with PropertyUnit */ +#define B_UNIT_NONE 0 +#define B_UNIT_LENGTH 1 +#define B_UNIT_AREA 2 +#define B_UNIT_VOLUME 3 +#define B_UNIT_MASS 4 +#define B_UNIT_ROTATION 5 +#define B_UNIT_TIME 6 +#define B_UNIT_VELOCITY 7 +#define B_UNIT_ACCELERATION 8 + +#ifdef __cplusplus +} +#endif + +#endif /* BKE_UNIT_H */ diff --git a/source/blender/blenkernel/BKE_utildefines.h b/source/blender/blenkernel/BKE_utildefines.h index 6584af085cd..f6c305b202d 100644 --- a/source/blender/blenkernel/BKE_utildefines.h +++ b/source/blender/blenkernel/BKE_utildefines.h @@ -128,9 +128,10 @@ #define IS_EQT(a, b, c) ((a > b)? (((a-b) <= c)? 1:0) : ((((b-a) <= c)? 1:0))) #define IN_RANGE(a, b, c) ((b < c)? ((b<a && a<c)? 1:0) : ((c<a && a<b)? 1:0)) +#define IN_RANGE_INCL(a, b, c) ((b < c)? ((b<=a && a<=c)? 1:0) : ((c<=a && a<=b)? 1:0)) /* this weirdo pops up in two places ... */ -#if !defined(WIN32) && !defined(__BeOS) +#if !defined(WIN32) #ifndef O_BINARY #define O_BINARY 0 #endif @@ -148,12 +149,6 @@ #define ID_NEW(a) if( (a) && (a)->id.newid ) (a)= (void *)(a)->id.newid #define FORM MAKE_ID('F','O','R','M') -#define DDG1 MAKE_ID('3','D','G','1') -#define DDG2 MAKE_ID('3','D','G','2') -#define DDG3 MAKE_ID('3','D','G','3') -#define DDG4 MAKE_ID('3','D','G','4') - -#define GOUR MAKE_ID('G','O','U','R') #define BLEN MAKE_ID('B','L','E','N') #define DER_ MAKE_ID('D','E','R','_') diff --git a/source/blender/blenkernel/BKE_verse.h b/source/blender/blenkernel/BKE_verse.h deleted file mode 100644 index e67696dc62a..00000000000 --- a/source/blender/blenkernel/BKE_verse.h +++ /dev/null @@ -1,583 +0,0 @@ -/** - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Contributor(s): Jiri Hnidek. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/* #define WITH_VERSE */ - -#ifndef BKE_VERSE_H -#define BKE_VERSE_H - -#include "DNA_listBase.h" -#include "BLI_dynamiclist.h" - -#include "verse.h" -#include "verse_ms.h" - -struct VNode; -struct VerseEdge; - -/* - * Verse Edge Hash (similar to edit edge hash) - */ -#define VEDHASHSIZE (512*512) -#define VEDHASH(a, b) ((a<b ? a : b) % VEDHASHSIZE) - -/* - * verse data: 4 float value - */ -typedef struct quat_real32_item { - struct quat_real32_item *next, *prev; - struct VLayer *vlayer; /* pointer at VerseLayer */ - uint32 id; /* id of item */ - real32 value[4]; -} quat_real32_item; - -/* - * verse data: 4 uint32 values - */ -typedef struct quat_uint32_item { - struct quat_uint32_item *next, *prev; - struct VLayer *vlayer; /* pointer at VerseLayer */ - uint32 id; /* id of item */ - uint32 value[4]; -} quat_uint32_item; - -/* - * verse data: 3 float values - */ -typedef struct vec_real32_item { - struct vec_real32_item *next, *prev; - struct VLayer *vlayer; /* pointer at VerseLayer */ - uint32 id; /* id of item */ - real32 value[3]; -} vec_real32_item; - -/* - * verse data: float value (weight) - */ -typedef struct real32_item { - struct real32_item *next, *prev; - struct VLayer *vlayer; /* pointer at VerseLayer */ - uint32 id; /* id of item */ - real32 value; -} real32_item; - -/* - * verse data: uint32 value - */ -typedef struct uint32_item { - struct uint32_item *next, *prev; - struct VLayer *vlayer; /* pointer at VerseLayer */ - uint32 id; /* id of item */ - uint32 value; -} uint32_item; - -/* - * verse data: uint8 value - */ -typedef struct uint8_item { - struct uint8_item *next, *prev; - struct VLayer *vlayer; /* pointer at VerseLayer */ - uint32 id; /* id of item */ - uint8 value; -} uint8_item; - -/* - * verse data: vertex - */ -typedef struct VerseVert { - struct VerseVert *next, *prev; - /* verse data */ - struct VLayer *vlayer; /* pointer at VerseLayer */ - uint32 id; /* id of vertex */ - real32 co[3]; /* x,y,z-coordinates of vertex */ - real32 no[3]; /* normal of vertex */ - /* blender internals */ - short flag; /* flags: VERT_DELETED, VERT_RECEIVED, etc. */ - void *vertex; /* pointer at EditVert or MVert */ - int counter; /* counter of VerseFaces using this VerseVert */ - union { - unsigned int index; /* counter need during transformation to mesh */ - struct VerseVert *vvert; - } tmp; /* pointer at new created verse vert, it is - * used during duplicating geometry node */ - float *cos; /* modified coordinates of vertex */ - float *nos; /* modified normal vector */ -} VerseVert; - -/* - * structture used for verse edge hash - */ -typedef struct HashVerseEdge { - struct VerseEdge *vedge; - struct HashVerseEdge *next; -} HashVerseEdge; - -/* - * fake verse data: edge - */ -typedef struct VerseEdge { - struct VerseEdge *next, *prev; - uint32 v0, v1; /* indexes of verse vertexes */ - int counter; /* counter of verse faces using this edge */ - struct HashVerseEdge hash; /* hash table */ - union { - unsigned int index; /* temporary index of edge */ - } tmp; -} VerseEdge; - -/* - * verse data: polygon - */ -typedef struct VerseFace { - struct VerseFace *next, *prev; - /* verse data */ - struct VLayer *vlayer; /* pointer at VerseLayer */ - uint32 id; /* id of face */ - struct VerseVert *vvert0; /* pointer at 1st VerseVert */ - struct VerseVert *vvert1; /* pointer at 2nd VerseVert */ - struct VerseVert *vvert2; /* pointer at 3th VerseVert */ - struct VerseVert *vvert3; /* pointer at 4th VerseVert */ - unsigned int v0, v1, v2, v3; /* indexes of VerseVerts ... needed during receiving */ - /* blender internals */ - char flag; /* flags: FACE_SEND_READY, FACE_SENT, FACE_RECEIVED, FACE_CHANGED*/ - short counter; /* counter of missed VerseVertexes */ - void *face; /* pointer at EditFace */ - float no[3]; /* normal vector */ - float *nos; /* modified normal vector */ -} VerseFace; - -/* - * verse data: layer - */ -typedef struct VLayer { - struct VLayer *next, *prev; - /* verse data*/ - struct VNode *vnode; /* pointer at VerseNode */ - uint16 id; /* id of layer */ - char *name; /* name of layer */ - VNGLayerType type; /* type of layer (VN_G_LAYER_VERTEX_XYZ, VN_G_LAYER_POLYGON_CORNER_UINT32) */ - uint32 def_int; /* default integer value */ - real64 def_real; /* default float value */ - /* blender internals */ - char flag; /* flags: LAYER_SENT, LAYER_RECEIVED, LAYER_DELETED, LAYER_OBSOLETE */ - short content; /* type of content (VERTEX_LAYER, POLYGON_LAYER) */ - struct DynamicList dl; /* vertexes, polygons, etc. */ - struct ListBase queue; /* queue of vertexes, polygons, etc. waiting for sending to verse server */ - struct ListBase orphans; /* list of versedata (polygons, etc.), that can be added to the DynamicList - * due to not received VerseVerts */ - unsigned int counter; /* counter of sent items */ - /* client dependent methods */ - void (*post_layer_create)(struct VLayer *vlayer); - void (*post_layer_destroy)(struct VLayer *vlayer); -} VLayer; - -/* - * verse data: link - */ -typedef struct VLink{ - struct VLink *next, *prev; - /* verse data */ - struct VerseSession *session; /* session pointer */ - struct VNode *source; /* object VerseNode "pointing" at some other VerseNode */ - struct VNode *target; /* VerseNode linked with some object node */ - unsigned int id; /* id of VerseLink */ - unsigned int target_id; /* some unknow id */ - char *label; /* name/label of VerseLink */ - /* blender internals */ - char flag; /* flags: LINK_SEND_READY */ - /* client dependent methods */ - void (*post_link_set)(struct VLink *vlink); - void (*post_link_destroy)(struct VLink *vlink); -} VLink; - -/* - * bitmap layer - */ -typedef struct VBitmapLayer { - struct VBitmapLayer *next, *prev; - /* verse data */ - struct VNode *vnode; /* pointer at Verse Node */ - VLayerID id; /* id of layer */ - char *name; /* name of layer */ - VNBLayerType type; /* type of layer (bits per channel) 1, 8, 16, 32, 64 */ - void *data; /* dynamic allocated data */ - /* blender internals */ - char flag; -} VBitmapLayer; - -/* - * data of bitmap node - */ -typedef struct VBitmapData { - struct DynamicList layers; /* dynamic list with access array of bitmap layers */ - struct ListBase queue; /* queue of layers waiting for receiving from verse server */ - uint16 width; /* width of all verse layers */ - uint16 height; /* height of all verse layers */ - uint16 depth; /* depth of bitmap 1 is 2D bitmap, >1 is 3D bitmap */ - /* blender internals */ - uint16 t_width; /* = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */ - uint16 t_height; /* = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */ - void *image; /* pointer at image */ - /* client dependent methods */ - void (*post_bitmap_dimension_set)(struct VNode *vnode); - void (*post_bitmap_layer_create)(struct VBitmapLayer *vblayer); - void (*post_bitmap_layer_destroy)(struct VBitmapLayer *vblayer); - void (*post_bitmap_tile_set)(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys); -}VBitmapData; - -/* - * data of geometry node - */ -typedef struct VGeomData { - struct DynamicList layers; /* dynamic list with access array of Layers */ - struct VLink *vlink; /* pointer at VerseLink connecting object node and geom node */ - struct ListBase queue; /* queue of our layers waiting for receiving from verse server */ - void *mesh; /* pointer at Mesh (object node) */ - void *editmesh; /* pointer at EditMesh (edit mode) */ - struct HashVerseEdge *hash; /* verse edge hash */ - struct ListBase edges; /* list of fake verse edges */ - /* client dependent methods */ - void (*post_vertex_create)(struct VerseVert *vvert); - void (*post_vertex_set_xyz)(struct VerseVert *vvert); - void (*post_vertex_delete)(struct VerseVert *vvert); - void (*post_vertex_free_constraint)(struct VerseVert *vvert); - void (*post_polygon_create)(struct VerseFace *vface); - void (*post_polygon_set_corner)(struct VerseFace *vface); - void (*post_polygon_delete)(struct VerseFace *vface); - void (*post_polygon_free_constraint)(struct VerseFace *vface); - void (*post_geometry_free_constraint)(struct VNode *vnode); - void (*post_polygon_set_uint8)(struct VerseFace *vface); -} VGeomData; - -/* - * data of object node - */ -typedef struct VObjectData { - struct DynamicList links; /* dynamic list with access array of links between other nodes */ - struct ListBase queue; /* queue of links waiting for sending and receiving from verse server */ - float pos[3]; /* position of object VerseNode */ - float quat[4]; /* rotation of object VerseNode stored in quat */ - float scale[3]; /* scale of object VerseNode */ - void *object; /* pointer at object */ - short flag; /* flag: POS_RECEIVE_READY, ROT_RECEIVE_READY. SCALE_RECEIVE_READY */ - /* client dependent methods */ -/* void (*post_transform)(struct VNode *vnode);*/ - void (*post_transform_pos)(struct VNode *vnode); - void (*post_transform_rot)(struct VNode *vnode); - void (*post_transform_scale)(struct VNode *vnode); - void (*post_object_free_constraint)(struct VNode *vnode); -} VObjectData; - -/* - * Verse Tag - */ -typedef struct VTag { - struct VTag *next, *prev; - /* verse data*/ - struct VTagGroup *vtaggroup; /* pointer at Verse Tag Group */ - uint16 id; /* id of this tag */ - char *name; /* name of this tag*/ - VNTagType type; /* type: VN_TAG_BOOLEAN, VN_TAG_UINT32, VN_TAG_REAL64, VN_TAG_REAL64_VEC3, - VN_TAG_LINK, VN_TAG_ANIMATION, VN_TAG_BLOB */ - VNTag *tag; /* pointer at value (enum: vboolean, vuint32, vreal64, vstring, - vreal64_vec3, vlink, vanimation, vblob)*/ - /* blender internals */ - void *value; /* pointer at blender value */ -} VTag; - -/* - * Verse Tag Group (verse tags are grouped in tag groups) - */ -typedef struct VTagGroup { - struct VTagGroup *next, *prev; - /* verse data*/ - struct VNode *vnode; /* pointer at Verse Node */ - uint16 id; /* id of this tag group */ - char *name; /* name of this tag group */ - /* blender internals */ - struct DynamicList tags; /* dynamic list with access array containing tags */ - struct ListBase queue; /* list of tags waiting for receiving from verse server */ - /* client dependent methods */ - void (*post_tag_change)(struct VTag *vatg); - void (*post_taggroup_create)(struct VTagGroup *vtaggroup); -} VTagGroup; - - /* - * Verse Method Group - */ -typedef struct VMethodGroup -{ - struct VMethodGroup *next, *prev; - uint16 group_id; - char name[16]; - struct ListBase methods; -} VMethodGroup; - -/* - * Verse Method - */ -typedef struct VMethod -{ - struct VMethod *next, *prev; - uint16 id; - char name[500]; - uint8 param_count; - VNOParamType *param_type; - char **param_name; -} VMethod; - -/* - * Verse Node - */ -typedef struct VNode { - struct VNode *next, *prev; - /* verse data*/ - struct VerseSession *session; /* session pointer */ - VNodeID id; /* node id */ - VNodeID owner_id; /* owner's id of this node */ - char *name; /* name of this node */ - uint32 type; /* type of node (V_NT_OBJECT, V_NT_GEOMETRY, V_NT_BITMAP) */ - /* blender internals */ - char flag; /* flags: NODE_SENT, NODE_RECEIVED, NODE_DELTED, NODE_OBSOLETE */ - struct DynamicList taggroups; /* dynamic list with access array of taggroups */ - struct ListBase methodgroups; /* method groups */ - struct ListBase queue; /* list of taggroups waiting for receiving from verse server */ - void *data; /* generic pointer at some data (VObjectData, VGeomData, ...) */ - int counter; /* counter of verse link pointing at this vnode (vlink->target) */ - /* client dependent methods */ - void (*post_node_create)(struct VNode *vnode); - void (*post_node_destroy)(struct VNode *vnode); - void (*post_node_name_set)(struct VNode *vnode); -#ifdef VERSECHAT - /* verse chat */ - int chat_flag; /* CHAT_LOGGED, CHAT_NOTLOGGED */ -#endif -} VNode; - - -/* - * Verse Session: verse client can be connected to several verse servers - * it is neccessary to store some information about each session - */ -typedef struct VerseSession { - struct VerseSession *next, *prev; - /* verse data */ - VSession *vsession; /* pointer at VSeesion (verse.h) */ - uint32 avatar; /* id of avatar */ - char *address; /* string containg IP/domain name of verse server and number of port */ - void *connection; /* no clue */ - uint8 *host_id; /* no clue */ - /* blender internals */ - short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */ - DynamicList nodes; /* list of verse nodes */ - ListBase queue; /* list of nodes waiting for sending to verse server */ - unsigned int counter; /* count of events, when connection wasn't accepted */ - /* client dependent methods */ - void (*post_connect_accept)(struct VerseSession *session); - void (*post_connect_terminated)(struct VerseSession *session); - void (*post_connect_update)(struct VerseSession *session); -} VerseSession; - -typedef struct VerseServer { - struct VerseServer *next, *prev; - char *name; /* human-readable server name */ - char *ip; /* string containing IP/domain name of verse server and number of port */ - short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */ - struct VerseSession *session; /* pointer to related session */ -} VerseServer; -/* - * list of post callback functions - */ -typedef struct PostCallbackFunction { - void (*function)(void *arg); - void *param; -} PostCallbackFunction; - -/* VerseSession->flag */ -#define VERSE_CONNECTING 1 -#define VERSE_CONNECTED 2 -#define VERSE_AUTOSUBSCRIBE 4 - -/* max VerseSession->counter value */ -#define MAX_UNCONNECTED_EVENTS 100 - -/* VNode flags */ -#define NODE_SENT 1 -#define NODE_RECEIVED 2 -#define NODE_DELTED 4 -#define NODE_OBSOLETE 8 - -#ifdef VERSECHAT -#define CHAT_NOTLOGGED 0 -#define CHAT_LOGGED 1 -#endif - -/* VLayer flags */ -#define LAYER_SENT 1 -#define LAYER_RECEIVED 2 -#define LAYER_DELETED 4 -#define LAYER_OBSOLETE 8 - -/* VLink->flag */ -#define LINK_SEND_READY 1 - -/* VObjectData->flag */ -#define POS_RECEIVE_READY 1 -#define ROT_RECEIVE_READY 2 -#define SCALE_RECEIVE_READY 4 -#define POS_SEND_READY 8 -#define ROT_SEND_READY 16 -#define SCALE_SEND_READY 32 - -/* VLayer->content */ -#define VERTEX_LAYER 0 -#define POLYGON_LAYER 1 - -/* VerseVert->flag */ -#define VERT_DELETED 1 /* vertex delete command was received from verse server */ -#define VERT_RECEIVED 2 /* VerseVert was received from verse server (is not in sending queue) */ -#define VERT_LOCKED 4 /* VerseVert is ready to send local position to verse server */ -#define VERT_POS_OBSOLETE 8 /* position of vertex was changed during sending to verse server */ -#define VERT_OBSOLETE 16 /* vertex delete command was sent to verse server; it means, that - * no information related to this vertex shoudln't be sent to verse - * until verse vertex is completely deleted ... then this vertex id - * can be reused again for new vertex */ - -/* VerseFace->flag */ -#define FACE_SEND_READY 1 /* VerseFace is ready for sending to verse server */ -#define FACE_RECEIVED 2 /* VerseFace was received from verse server */ -#define FACE_SENT 4 /* VerseFace was sent to verse server and we expect receiving from verse server */ -#define FACE_DELETED 8 /* delete command was sent to verse server */ -#define FACE_CHANGED 16 /* VerseFace was only changed not created */ -#define FACE_OBSOLETE 32 /* VerseFace was changed during sending to verse server */ - -/* Queue type */ -#define VERSE_NODE 1 -#define VERSE_LINK 2 -#define VERSE_LAYER 3 -#define VERSE_VERT 4 -#define VERSE_FACE 5 - -#define VERSE_TAG 6 -#define VERSE_TAG_GROUP 7 - -#define VERSE_VERT_UINT32 8 -#define VERSE_VERT_REAL32 9 -#define VERSE_VERT_VEC_REAL32 10 - -#define VERSE_FACE_UINT8 11 -#define VERSE_FACE_UINT32 12 -#define VERSE_FACE_REAL32 13 -#define VERSE_FACE_QUAT_UINT32 14 -#define VERSE_FACE_QUAT_REAL32 15 - -/* Verse Bitmap Layer flags */ -#define VBLAYER_SUBSCRIBED 1 - -/* function prototypes */ - -/* functions from verse_session.c */ -void set_verse_session_callbacks(void); -struct VerseSession *versesession_from_vsession(VSession *vsession); -struct VerseSession *current_verse_session(void); -struct VerseSession *create_verse_session(const char *name, const char *pass, const char *address, uint8 *expected_key); -void free_verse_session(struct VerseSession *session); -void b_verse_update(void); -void b_verse_ms_get(void); -void b_verse_connect(char *address); -void end_verse_session(struct VerseSession *session); -void end_all_verse_sessions(void); - -/* functions from verse_node.c */ -void send_verse_tag(struct VTag *vtag); -void send_verse_taggroup(struct VTagGroup *vtaggroup); -void send_verse_node(struct VNode *vnode); -void free_verse_node_data(struct VNode *vnode); -void free_verse_node(struct VNode *vnode); -struct VNode* lookup_vnode(VerseSession *session, VNodeID node_id); -struct VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id); -void set_node_callbacks(void); - -/* functions from verse_object_node.c */ -struct VLink *find_unsent_parent_vlink(struct VerseSession *session, struct VNode *vnode); -struct VLink *find_unsent_child_vlink(struct VerseSession *session, struct VNode *vnode); -struct VLink *create_verse_link(VerseSession *session, struct VNode *source, struct VNode *target, uint16 link_id, uint32 target_id, const char *label); -void send_verse_object_position(struct VNode *vnode); -void send_verse_object_rotation(struct VNode *vnode); -void send_verse_object_scale(struct VNode *vnode); -void send_verse_link(struct VLink *vlink); - -void free_object_data(struct VNode *vnode); -void set_object_callbacks(void); -struct VObjectData *create_object_data(void); - - -/* functions from verse_method.c */ -void free_verse_methodgroup(VMethodGroup *vmg); -#ifdef VERSECHAT -void send_say(const char *chan, const char *utter); -void send_login(struct VNode *vnode); -void send_logout(struct VNode *vnode); -void send_join(struct VNode *vnode, const char *chan); -void send_leave(struct VNode *vnode, const char *chan); -#endif -void set_method_callbacks(void); - -/* functions from verse_geometry_node.c */ -struct VerseFace* create_verse_face(struct VLayer *vlayer, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); -struct VerseVert* create_verse_vertex(struct VLayer *vlayer, uint32 vertex_id, real32 x, real32 y, real32 z); -struct VLayer *create_verse_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real); -struct VGeomData *create_geometry_data(void); - -void send_verse_layer(struct VLayer *vlayer); - -void send_verse_face_corner_quat_real32(struct quat_real32_item *item, short type); -void send_verse_face_corner_quat_uint32(struct quat_uint32_item *item, short type); -void send_verse_face_real32(struct real32_item *item, short type); -void send_verse_face_uint32(struct uint32_item *item, short type); -void send_verse_face_uint8(struct uint8_item *item, short type); - -void send_verse_vert_vec_real32(struct vec_real32_item *item, short type); -void send_verse_vert_real32(struct real32_item *item, short type); -void send_verse_vert_uint32(struct uint32_item *item, short type); - -void send_verse_vertex_delete(struct VerseVert *vvert); -void send_verse_vertex(struct VerseVert *vvert); -void send_verse_face_delete(struct VerseFace *vface); - -void destroy_geometry(struct VNode *vnode); - -struct VLayer* find_verse_layer_type(struct VGeomData *geom, short content); -void add_item_to_send_queue(struct ListBase *lb, void *item, short type); -void free_geom_data(struct VNode *vnode); -void set_geometry_callbacks(void); - -/* functions prototypes from verse_bitmap.c */ -void set_bitmap_callbacks(void); -void free_bitmap_layer_data(struct VBitmapLayer *vblayer); -struct VBitmapLayer *create_bitmap_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNBLayerType type); -void free_bitmap_node_data(struct VNode *vnode); -struct VBitmapData *create_bitmap_data(void); - -#endif diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h index 83b9b57b3bc..4ef63b069c2 100644 --- a/source/blender/blenkernel/BKE_writeavi.h +++ b/source/blender/blenkernel/BKE_writeavi.h @@ -37,16 +37,17 @@ extern "C" { /* generic blender movie support, could move to own module */ struct RenderData; -void start_avi(struct RenderData *rd, int rectx, int recty); +struct Scene; +void start_avi(struct Scene *scene, struct RenderData *rd, int rectx, int recty); void end_avi(void); -void append_avi(int frame, int *pixels, int rectx, int recty); +void append_avi(struct RenderData *rd, int frame, int *pixels, int rectx, int recty); void makeavistring (struct RenderData *rd, char *string); typedef struct bMovieHandle { - void (*start_movie)(struct RenderData *rd, int rectx, int recty); - void (*append_movie)(int frame, int *pixels, int rectx, int recty); + void (*start_movie)(struct Scene *scene, struct RenderData *rd, int rectx, int recty); + void (*append_movie)(struct RenderData *rd, int frame, int *pixels, int rectx, int recty); void (*end_movie)(void); - int (*get_next_frame)(void); /* can be null */ + int (*get_next_frame)(struct RenderData *rd); /* optional */ } bMovieHandle; bMovieHandle *BKE_get_movie_handle(int imtype); diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h index 02f7ba6f860..07e0e01ef7e 100644 --- a/source/blender/blenkernel/BKE_writeffmpeg.h +++ b/source/blender/blenkernel/BKE_writeffmpeg.h @@ -46,18 +46,29 @@ extern "C" { #define FFMPEG_MKV 9 #define FFMPEG_OGG 10 -#define FFMPEG_PRESET_NONE 0 -#define FFMPEG_PRESET_DVD 1 -#define FFMPEG_PRESET_SVCD 2 -#define FFMPEG_PRESET_VCD 3 -#define FFMPEG_PRESET_DV 4 -#define FFMPEG_PRESET_H264 5 +#define FFMPEG_PRESET_NONE 0 +#define FFMPEG_PRESET_DVD 1 +#define FFMPEG_PRESET_SVCD 2 +#define FFMPEG_PRESET_VCD 3 +#define FFMPEG_PRESET_DV 4 +#define FFMPEG_PRESET_H264 5 +#define FFMPEG_PRESET_THEORA 6 +#define FFMPEG_PRESET_XVID 7 +struct IDProperty; struct RenderData; +struct Scene; -extern void start_ffmpeg(struct RenderData *rd, int rectx, int recty); +extern void start_ffmpeg(struct Scene *scene, struct RenderData *rd, int rectx, int recty); extern void end_ffmpeg(void); -extern void append_ffmpeg(int frame, int *pixels, int rectx, int recty); +extern void append_ffmpeg(struct RenderData *rd, int frame, int *pixels, int rectx, int recty); + +extern void ffmpeg_set_preset(struct RenderData *rd, int preset); +extern void ffmpeg_verify_image_type(struct RenderData *rd); + +extern struct IDProperty *ffmpeg_property_add(struct RenderData *Rd, char *type, int opt_index, int parent_index); +extern int ffmpeg_property_add_string(struct RenderData *rd, const char *type, const char *str); +extern void ffmpeg_property_del(struct RenderData *rd, void *type, void *prop_); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_writeframeserver.h b/source/blender/blenkernel/BKE_writeframeserver.h index 4774906a2fa..6a38abe977f 100644 --- a/source/blender/blenkernel/BKE_writeframeserver.h +++ b/source/blender/blenkernel/BKE_writeframeserver.h @@ -33,11 +33,12 @@ extern "C" { #endif struct RenderData; +struct Scene; -extern void start_frameserver(struct RenderData *rd, int rectx, int recty); +extern void start_frameserver(struct Scene *scene, struct RenderData *rd, int rectx, int recty); extern void end_frameserver(void); -extern void append_frameserver(int frame, int *pixels, int rectx, int recty); -extern int frameserver_loop(void); +extern void append_frameserver(struct RenderData *rd, int frame, int *pixels, int rectx, int recty); +extern int frameserver_loop(struct RenderData *rd); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 3a8058b2b21..950947f0d24 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -27,22 +27,17 @@ FILE(GLOB SRC intern/*.c) SET(INC - . ../../../intern/guardedalloc ../include ../blenlib ../makesdna - ../python ../render/extern/include ../../../intern/decimation/extern + . ../../../intern/guardedalloc ../../../intern/memutil ../editors/include ../blenlib ../makesdna + ../render/extern/include ../../../intern/decimation/extern ../imbuf ../avi ../../../intern/elbeem/extern ../../../intern/opennl/extern ../../../intern/iksolver/extern ../blenloader ../quicktime - ../../../intern/bmfont ../../../extern/bullet2/src - ../nodes ../../../extern/glew/include ../gpu - ${SDL_INC} + ../../../extern/bullet2/src + ../nodes ../../../extern/glew/include ../gpu ../makesrna ../../../intern/smoke/extern + ../../../intern/bsp/extern + ../../../intern/audaspace/intern ${ZLIB_INC} - ${PYTHON_INC} ) -IF(WITH_VERSE) - ADD_DEFINITIONS(-DWITH_VERSE) - SET(INC ${INC} ${VERSE_INC}) -ENDIF(WITH_VERSE) - IF(WITH_OPENEXR) ADD_DEFINITIONS(-DWITH_OPENEXR) ENDIF(WITH_OPENEXR) @@ -60,25 +55,30 @@ IF(WITH_QUICKTIME) ADD_DEFINITIONS(-DWITH_QUICKTIME) ENDIF(WITH_QUICKTIME) +IF(WITH_SDL) + SET(INC ${INC} ${SDL_INC}) +ELSE(WITH_SDL) + ADD_DEFINITIONS(-DDISABLE_SDL) +ENDIF(WITH_SDL) + IF(WITH_FFMPEG) SET(INC ${INC} ${FFMPEG_INC}) ADD_DEFINITIONS(-DWITH_FFMPEG) ENDIF(WITH_FFMPEG) -IF(WITH_PLAYER) - ADD_SUBDIRECTORY(bad_level_call_stubs) -ENDIF(WITH_PLAYER) - -BLENDERLIB(bf_blenkernel "${SRC}" "${INC}") - -IF(WITH_VERSE) - ADD_DEPENDENCIES(bf_blenkernel mkprot verse) -ENDIF(WITH_VERSE) - -IF(WITH_INTERNATIONAL) - ADD_DEFINITIONS(-DWITH_FREETYPE2) -ENDIF(WITH_INTERNATIONAL) +IF(WITH_PYTHON) + SET(INC ${INC} ../python ${PYTHON_INC}) +ELSE(WITH_PYTHON) + ADD_DEFINITIONS(-DDISABLE_PYTHON) +ENDIF(WITH_PYTHON) IF(NOT WITH_ELBEEM) ADD_DEFINITIONS(-DDISABLE_ELBEEM) ENDIF(NOT WITH_ELBEEM) + +IF(WIN32) + SET(INC ${INC} ${PTHREADS_INC}) +ENDIF(WIN32) + +BLENDERLIB(bf_blenkernel "${SRC}" "${INC}") + diff --git a/source/blender/blenkernel/Makefile b/source/blender/blenkernel/Makefile index a5ee729b7e3..f0476bbf026 100644 --- a/source/blender/blenkernel/Makefile +++ b/source/blender/blenkernel/Makefile @@ -29,6 +29,6 @@ # Bounces make to subdirectories. SOURCEDIR = source/blender/blenkernel -DIRS = intern bad_level_call_stubs +DIRS = intern include nan_subdirs.mk diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index f68e2b70c86..6772cccbda6 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -3,14 +3,15 @@ Import ('env') sources = env.Glob('intern/*.c') -incs = '. #/intern/guardedalloc ../include ../blenlib ../makesdna' -incs += ' ../render/extern/include #/intern/decimation/extern' +incs = '. #/intern/guardedalloc #/intern/memutil ../editors/include ../blenlib ../makesdna' +incs += ' ../render/extern/include #/intern/decimation/extern ../makesrna' incs += ' ../imbuf ../avi #/intern/elbeem/extern ../nodes' incs += ' #/intern/iksolver/extern ../blenloader' incs += ' #/extern/bullet2/src' -incs += ' #/intern/bmfont' -incs += ' #/intern/opennl/extern' +incs += ' #/intern/opennl/extern #/intern/bsp/extern' incs += ' ../gpu #/extern/glew/include' +incs += ' #/intern/smoke/extern' +incs += ' #/intern/audaspace/intern' incs += ' ' + env['BF_OPENGL_INC'] incs += ' ' + env['BF_ZLIB_INC'] @@ -33,16 +34,6 @@ if env['WITH_BF_SDL']: else: defs.append('DISABLE_SDL') -if env['WITH_BF_INTERNATIONAL']: - defs.append('WITH_FREETYPE2') - -if env['WITH_BF_VERSE']: - defs.append('WITH_VERSE') - incs += ' ' + env['BF_VERSE_INCLUDE'] - -if env['WITH_BF_VERSE']: - defs.append('WITH_VERSE') - if env['WITH_BF_OPENEXR']: defs.append('WITH_OPENEXR') @@ -66,7 +57,10 @@ if env['WITH_BF_BULLET']: if env['BF_NO_ELBEEM']: defs.append('DISABLE_ELBEEM') -if env['WITH_BF_PLAYER']: - SConscript(['bad_level_call_stubs/SConscript']) +if env['WITH_BF_LCMS']: + defs.append('WITH_LCMS') + +if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'): + incs += ' ' + env['BF_PTHREADS_INC'] -env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [65, 20] ) +env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = defs, libtype=['core'], priority = [165] ) diff --git a/source/blender/blenkernel/bad_level_call_stubs/CMakeLists.txt b/source/blender/blenkernel/bad_level_call_stubs/CMakeLists.txt deleted file mode 100644 index 7574f13c92e..00000000000 --- a/source/blender/blenkernel/bad_level_call_stubs/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -# $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# The Original Code is Copyright (C) 2006, Blender Foundation -# All rights reserved. -# -# The Original Code is: all of this file. -# -# Contributor(s): Jacques Beaurain. -# -# ***** END GPL LICENSE BLOCK ***** - -FILE(GLOB SRC stubs.c) - -SET(INC - . - .. - ../../render/extern/include - ../../../intern/iksolver/extern - ../../blenlib - ../../include - ../../makesdna -) - -IF(WITH_INTERNATIONAL) - ADD_DEFINITIONS(-DWITH_FREETYPE2) -ENDIF(WITH_INTERNATIONAL) - -BLENDERLIB_NOLIST(blenkernel_blc "${SRC}" "${INC}") diff --git a/source/blender/blenkernel/bad_level_call_stubs/Makefile b/source/blender/blenkernel/bad_level_call_stubs/Makefile deleted file mode 100644 index 5268bfd8a48..00000000000 --- a/source/blender/blenkernel/bad_level_call_stubs/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -# -# $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. -# All rights reserved. -# -# The Original Code is: all of this file. -# -# Contributor(s): none yet. -# -# ***** END GPL LICENSE BLOCK ***** -# -# - -LIBNAME = blenkernel_blc -DIR = $(OCGDIR)/blender/blenkernel/$(LIBNAME) - -include nan_compile.mk - -CFLAGS += $(LEVEL_2_C_WARNINGS) -CFLAGS += $(FIX_STUBS_WARNINGS) - -CPPFLAGS += $(OGL_CPPFLAGS) -CPPFLAGS += -I../../makesdna -CPPFLAGS += -I../../include -CPPFLAGS += -I../../blenlib -CPPFLAGS += -I../../render/extern/include -CPPFLAGS += -I$(NAN_IKSOLVER)/include - -# path to our own external headerfiles -CPPFLAGS += -I.. - diff --git a/source/blender/blenkernel/bad_level_call_stubs/SConscript b/source/blender/blenkernel/bad_level_call_stubs/SConscript deleted file mode 100644 index 955a989c9f9..00000000000 --- a/source/blender/blenkernel/bad_level_call_stubs/SConscript +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/python -Import ('env') - -sources = 'stubs.c' - -incs = '. .. ../../render/extern/include' -incs += ' #/intern/iksolver/extern ../../blenlib' -incs += ' ../../include ../../makesdna' - -defs = '' -if env['WITH_BF_INTERNATIONAL']: - defs += 'WITH_FREETYPE2' - -env.BlenderLib ('blenkernel_blc', sources = Split(sources), includes=Split(incs), defines=Split(defs), libtype='player',priority=225 ) diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c deleted file mode 100644 index 1a33102f845..00000000000 --- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c +++ /dev/null @@ -1,362 +0,0 @@ -/** - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * BKE_bad_level_calls function stubs - */ - -#include <stdlib.h> - -#include "BKE_bad_level_calls.h" -#include "BLI_blenlib.h" -#include "DNA_space_types.h" -#include "DNA_texture_types.h" -#include "DNA_material_types.h" -#include "DNA_node_types.h" -#include "DNA_scene_types.h" - -#include "RE_render_ext.h" -#include "RE_shader_ext.h" -#include "RE_pipeline.h" - -int winqueue_break= 0; - -char bprogname[1]; -char btempdir[1]; - -struct IpoCurve; -struct FluidsimSettings; -struct Render; -struct RenderResult; -struct Object; -struct bPythonConstraint; -struct bConstraintOb; -struct bConstraintTarget; -struct ListBase; -struct EditFace; -struct LOD_Decimation_Info; - -char *getIpoCurveName( struct IpoCurve * icu ); -void insert_vert_icu(struct IpoCurve *icu, float x, float y, short fast); -struct IpoCurve *verify_ipocurve(struct ID *id, short a, char *b, char *d, int e, short f); -void elbeemDebugOut(char *msg); -void fluidsimSettingsFree(struct FluidsimSettings* sb); -void fluidsimSettingsCopy(struct FluidsimSettings* sb); - - -/* readfile.c */ - /* struct SpaceButs; */ -void set_rects_butspace(struct SpaceButs *buts){} - /* struct SpaceImaSel; */ -void check_imasel_copy(struct SpaceImaSel *simasel){} - /* struct ScrArea; */ -void unlink_screen(struct bScreen *sc){} -void freeAllRad(void){} -void free_editText(void){} -void free_editArmature(void){} -void free_vertexpaint(void){} - -char *getIpoCurveName( struct IpoCurve * icu ) -{ - return 0; -} - -void insert_vert_icu(struct IpoCurve *icu, float x, float y, short fast) -{ -} - - -struct IpoCurve *verify_ipocurve(struct ID *id, short a, char *b, char *d, int e, short f) -{ - return 0; -} - - -void setscreen(struct bScreen *sc){} -void force_draw_all(int header){} - /* otherwise the WHILE_SEQ doesn't work */ - /* struct Sequence; */ - -/* MAART: added "seqar = 0; totseq = 0" because the loader will crash without it. */ -void build_seqar(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq) -{ - *seqar = 0; - *totseq = 0; -} - -/* blender.c */ -void mainqenter (unsigned short event, short val){} - -void BPY_do_pyscript(ID *id, short int event){} -void BPY_clear_script(Script *script){} -void BPY_free_compiled_text(struct Text *text){} -void BPY_pydriver_update(void){} -float BPY_pydriver_eval(struct IpoDriver *driver) -{ - return 0; -} - -/* -int EXPP_dict_set_item_str(struct PyObject *dict, char *key, struct PyObject *value) -{ - return 0; -} -*/ - -void Node_SetStack(struct BPy_Node *self, struct bNodeStack **stack, int type){} -void InitNode(struct BPy_Node *self, struct bNode *node){} -void Node_SetShi(struct BPy_Node *self, struct ShadeInput *shi){} -struct BPy_NodeSockets *Node_CreateSocketLists(struct bNode *node) -{ - return 0; -} -int pytype_is_pynode(struct PyObject *pyob) -{ - return 0; -} -/* depsgraph.c: */ -struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver) -{ - return 0; -} -int BPY_button_eval(char *expr, double *value) -{ - return 0; -} - -/* PyConstraints - BPY_interface.c */ -void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets) -{ -} -void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct) -{ -} - - -/* writefile.c */ - /* struct Oops; */ -void free_oops(struct Oops *oops){} -void exit_posemode(int freedata){} -void error(char *str, ...){} -int okee(char *str, ...){return 1;} - -/* anim.c */ -ListBase editNurb; - -void waitcursor(int val){} -void allqueue(unsigned short event, short val){} -#define REDRAWVIEW3D 0x4010 -Material defmaterial; - -/* exotic.c */ -void load_editMesh(void){} -void make_editMesh(void){} -void free_editMesh(struct EditMesh *em){} -void docenter_new(void){} -int saveover(char *str){ return 0;} - -/* ipo.c */ -void copy_view3d_lock(short val){} // was a hack, to make scene layer ipo's possible - -/* library.c */ -void allspace(unsigned short event, short val){} -#define OOPS_TEST 2 - -/* mball.c */ -ListBase editelems; - -/* object.c */ -void BPY_free_scriptlink(ScriptLink *slink){} -void BPY_copy_scriptlink(ScriptLink *scriptlink){} -float *give_cursor(void){ return 0;} // become a callback or argument - - -/* packedFile.c */ -short pupmenu(char *instr){ return 0;} // will be general callback - -/* sca.c */ -#define LEFTMOUSE 0x001 // because of mouse sensor - -/* scene.c */ -#include "DNA_sequence_types.h" -void free_editing(struct Editing *ed){} // scenes and sequences problem... -void BPY_do_all_scripts (short int event, short int anim){} - -/*editmesh_lib.c*/ -void EM_select_face(struct EditFace *efa, int sel) {} -void EM_select_edge(struct EditEdge *eed, int sel) {} - -/*editmesh.c*/ -struct EditVert *addvertlist(float *vec, struct EditVert *example) { return 0;} -struct EditEdge *addedgelist(struct EditVert *v1, struct EditVert *v2, struct EditEdge *example) { return 0;} -struct EditFace *addfacelist(struct EditVert *v1, struct EditVert *v2, struct EditVert *v3, struct EditVert *v4, struct EditFace *example, struct EditFace *exampleEdges) { return 0;} -struct EditEdge *findedgelist(struct EditVert *v1, struct EditVert *v2) { return 0;} -/*edit.c*/ - -void countall(void) {} - -/* exotic.c */ -int BPY_call_importloader(char *name) -{ - return 0; -} - - -/* texture.c */ -#define FLO 128 -#define INT 96 - - -char texstr[20][12]; /* buttons.c */ - -/* editsca.c */ -void make_unique_prop_names(char *str) {} - -/* DerivedMesh.c */ -void bglBegin(int mode) {} -void bglVertex3fv(float *vec) {} -void bglVertex3f(float x, float y, float z) {} -void bglEnd(void) {} - -/* booleanops.c */ -struct DerivedMesh *NewBooleanDerivedMesh(struct DerivedMesh *dm, struct Object *ob, struct DerivedMesh *dm_select, struct Object *ob_select, - int int_op_type) { return 0; } - -/* LOD_decimation.cpp */ -int LOD_LoadMesh(struct LOD_Decimation_Info* info) { return 0;}; -int LOD_PreprocessMesh(struct LOD_Decimation_Info* info) {return 0;}; -int LOD_CollapseEdge(struct LOD_Decimation_Info* info) {return 0;}; -int LOD_FreeDecimationData(struct LOD_Decimation_Info* info) {return 0;}; - -// bobj read/write debug messages -void elbeemDebugOut(char *msg) {} -void fluidsimSettingsFree(struct FluidsimSettings* sb) {} -void fluidsimSettingsCopy(struct FluidsimSettings* sb) {} - -/*new render funcs */ -int externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta) { return 0; } -void texture_rgb_blend(float *in, float *tex, float *out, float fact, float facg, int blendtype) {} -float texture_value_blend(float tex, float out, float fact, float facg, int blendtype, int flip) { return 0; } - -void RE_FreeRenderResult(struct RenderResult *rr) {} -void RE_GetResultImage(struct Render *re, struct RenderResult *rr) {} -struct RenderResult *RE_MultilayerConvert(void *exrhandle, int rectx, int recty){return NULL;} -struct Render *RE_GetRender(const char *name) {return (struct Render *)NULL;} -struct RenderResult *RE_GetResult(Render *re) {return (struct RenderResult *)NULL;} -float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype) {return NULL;} -float RE_filter_value(int type, float x) {return 0.0f;} -struct RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) {return (struct RenderLayer *)NULL;} -void RE_Database_Free (struct Render *re) {} -void RE_FreeRender(Render *re) {} -void RE_shade_external(Render *re, ShadeInput *shi, ShadeResult *shr) {} -void RE_DataBase_GetView(Render *re, float mat[][4]) {} -struct Render *RE_NewRender(const char *name) {return (struct Render *)NULL;} -void RE_Database_Baking(struct Render *re, struct Scene *scene, int type, struct Object *actob) {}; - - -/* node_composite.c */ -void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect) {} - -int multitex_ext(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres) -{ - return 1969; -} - -/* verse */ - -void post_vertex_create(struct VerseVert *vvert) {} -void post_vertex_set_xyz(struct VerseVert *vvert) {} -void post_vertex_delete(struct VerseVert *vvert) {} -void post_vertex_free_constraint(struct VerseVert *vvert) {} -void post_polygon_create(struct VerseFace *vface) {} -void post_polygon_set_corner(struct VerseFace *vface) {} -void post_polygon_delete(struct VerseFace *vface) {} -void post_polygon_free_constraint(struct VerseFace *vface) {} -void post_polygon_set_uint8(struct VerseFace *vface) {} -void post_node_create(struct VNode *vnode) {} -void post_node_destroy(struct VNode *vnode) {} -void post_node_name_set(struct VNode *vnode) {} -void post_tag_change(struct VTag *vtag) {} -void post_taggroup_create(struct VTagGroup *vtaggroup) {} -char *verse_client_name(void) { return NULL; } -void post_transform(struct VNode *vnode) {} -void post_transform_pos(struct VNode *vnode) {} -void post_transform_rot(struct VNode *vnode) {} -void post_transform_scale(struct VNode *vnode) {} -void post_object_free_constraint(struct VNode *vnode) {} -void post_link_set(struct VLink *vlink) {} -void post_link_destroy(struct VLink *vlink) {} -void post_connect_accept(struct VerseSession *session) {} -void post_connect_terminated(struct VerseSession *session) {} -void post_connect_update(struct VerseSession *session) {} -void add_screenhandler(struct bScreen *sc, short eventcode, short val) {} -void post_bitmap_dimension_set(struct VNode *vnode) {} -void post_bitmap_layer_create(struct VBitmapLayer *vblayer) {} -void post_bitmap_layer_destroy(struct VBitmapLayer *vblayer) {} -void post_bitmap_tile_set(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys) {} -void create_meshdata_from_geom_node(struct Mesh *me, struct VNode *vnode) {} -void post_geometry_free_constraint(struct VNode *vnode) {} -void post_layer_create(struct VLayer *vlayer) {} -void post_layer_destroy(struct VLayer *vlayer) {} -void post_server_add(void) {} - -/* zbuf.c stub */ -void antialias_tagbuf(int xsize, int ysize, char *rectmove) {} - -/* imagetexture.c stub */ -void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result) {} - -void update_for_newframe(void) {} - -struct FileList; -void BIF_filelist_freelib(struct FileList* filelist) {}; - -/* edittime.c stub */ -TimeMarker *get_frame_marker(int frame){return 0;}; - -/* editseq.c */ -#include "BIF_editseq.h" // And fix the missing void there -Sequence *get_foreground_frame_seq(int frame){return 0;}; -void clear_last_seq(Sequence *seq){}; - - -/* modifier.c stub */ -void harmonic_coordinates_bind(struct MeshDeformModifierData *mmd, - float (*vertexcos)[3], int totvert, float cagemat[][4]) {} - -/* particle.c */ -void PE_free_particle_edit(struct ParticleSystem *psys) {} -void PE_get_colors(char sel[4], char nosel[4]) {} -void PE_recalc_world_cos(struct Object *ob, struct ParticleSystem *psys) {} - -/* text.c */ -void txt_copy_clipboard (struct Text *text){} - -char stipple_quarttone[1]; - -/* texture.c */ -int multitex_thread(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres, short thread, short which_output) {return 0;} - diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h index 78717393baf..47e33c0e81e 100644 --- a/source/blender/blenkernel/depsgraph_private.h +++ b/source/blender/blenkernel/depsgraph_private.h @@ -65,6 +65,7 @@ typedef struct DagNode void * first_ancestor; int ancestor_count; int lay; // accumulated layers of its relations + itself + int scelay; // layers due to being in scene int lasttime; // if lasttime != DagForest->time, this node was not evaluated yet for flushing int BFS_dist; // BFS distance int DFS_dist; // DFS distance @@ -93,6 +94,7 @@ typedef struct DagNodeQueue typedef struct DagForest { ListBase DagNode; + struct GHash *nodeHash; int numNodes; int is_acyclic; int time; // for flushing/tagging, compare with node->lasttime diff --git a/source/blender/blenkernel/intern/BME_conversions.c b/source/blender/blenkernel/intern/BME_conversions.c index 39af580969f..177bb4a136b 100644 --- a/source/blender/blenkernel/intern/BME_conversions.c +++ b/source/blender/blenkernel/intern/BME_conversions.c @@ -50,11 +50,13 @@ #include "BLI_blenlib.h" #include "BLI_editVert.h" #include "BLI_edgehash.h" -#include "BIF_editmesh.h" -#include "editmesh.h" +//XXX #include "BIF_editmesh.h" +//XXX #include "editmesh.h" #include "bmesh_private.h" -#include "BSE_edit.h" +//XXX #include "BSE_edit.h" + +/* XXX IMPORTANT: editmesh stuff doesn't belong in kernel! (ton) */ /*merge these functions*/ static void BME_DMcorners_to_loops(BME_Mesh *bm, CustomData *facedata, int index, BME_Poly *f, int numCol, int numTex){ @@ -302,7 +304,7 @@ BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em) { e->flag = eed->f & SELECT; if(eed->sharp) e->flag |= ME_SHARP; if(eed->seam) e->flag |= ME_SEAM; - if(eed->h & EM_FGON) e->flag |= ME_FGON; + //XXX if(eed->h & EM_FGON) e->flag |= ME_FGON; if(eed->h & 1) e->flag |= ME_HIDE; eed->tmp.e = (EditEdge*)e; CustomData_bmesh_copy_data(&em->edata, &bm->edata, eed->data, &e->data); @@ -343,26 +345,22 @@ BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em) { BME_model_end(bm); return bm; } -/* adds the geometry in the bmesh to G.editMesh (does not free G.editMesh) +/* adds the geometry in the bmesh to editMesh (does not free editMesh) * if td != NULL, the transdata will be mapped to the EditVert's co */ -EditMesh *BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td) { +void BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td, EditMesh *em) { BME_Vert *v1; BME_Edge *e; BME_Poly *f; BME_TransData *vtd; - EditMesh *em; EditVert *eve1, *eve2, *eve3, *eve4, **evlist; EditEdge *eed; EditFace *efa; int totvert, len, i, numTex, numCol; - em = G.editMesh; - - if (em == NULL) return NULL; - + if (em == NULL) return; CustomData_copy(&bm->vdata, &em->vdata, CD_MASK_BMESH, CD_CALLOC, 0); CustomData_copy(&bm->edata, &em->edata, CD_MASK_BMESH, CD_CALLOC, 0); @@ -378,7 +376,7 @@ EditMesh *BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td) { evlist= (EditVert **)MEM_mallocN(totvert*sizeof(void *),"evlist"); for (i=0,v1=bm->verts.first;v1;v1=v1->next,i++) { v1->tflag1 = i; - eve1 = addvertlist(v1->co,NULL); + eve1 = NULL; //XXX addvertlist(v1->co,NULL); if (td && (vtd = BME_get_transdata(td,v1))) { vtd->loc = eve1->co; } @@ -392,17 +390,17 @@ EditMesh *BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td) { /* make edges */ for (e=bm->edges.first;e;e=e->next) { - if(!(findedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1]))){ - eed= addedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1], NULL); + if(0) { //XXX if(!(findedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1]))){ + eed= NULL; //XXX addedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1], NULL); eed->crease = e->crease; eed->bweight = e->bweight; if(e->flag & ME_SEAM) eed->seam = 1; if(e->flag & ME_SHARP) eed->sharp = 1; if(e->flag & SELECT) eed->f |= SELECT; - if(e->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines! + //XXX if(e->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines! if(e->flag & ME_HIDE) eed->h |= 1; - if(G.scene->selectmode==SCE_SELECT_EDGE) - EM_select_edge(eed, eed->f & SELECT); + if(em->selectmode==SCE_SELECT_EDGE) + ; //XXX EM_select_edge(eed, eed->f & SELECT); CustomData_em_copy_data(&bm->edata, &em->edata, e->data, &eed->data); } @@ -422,15 +420,16 @@ EditMesh *BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td) { eve4= NULL; } - efa = addfacelist(eve1, eve2, eve3, eve4, NULL, NULL); + efa = NULL; //XXX addfacelist(eve1, eve2, eve3, eve4, NULL, NULL); efa->mat_nr = (unsigned char)f->mat_nr; efa->flag= f->flag & ~ME_HIDE; if(f->flag & ME_FACE_SEL) { efa->f |= SELECT; } if(f->flag & ME_HIDE) efa->h= 1; - if((G.f & G_FACESELECT) && (efa->f & SELECT)) - EM_select_face(efa, 1); /* flush down */ + // XXX flag depricated + // if((G.f & G_FACESELECT) && (efa->f & SELECT)) + //XXX EM_select_face(efa, 1); /* flush down */ CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data); BME_loops_to_corners(bm, &em->fdata, efa->data, f,numCol,numTex); } @@ -438,9 +437,6 @@ EditMesh *BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td) { MEM_freeN(evlist); - countall(); - - return em; } /* Adds the geometry found in dm to bm diff --git a/source/blender/blenkernel/intern/BME_tools.c b/source/blender/blenkernel/intern/BME_tools.c index a2cd6389e7d..32065ea5151 100644 --- a/source/blender/blenkernel/intern/BME_tools.c +++ b/source/blender/blenkernel/intern/BME_tools.c @@ -38,14 +38,13 @@ #include "DNA_listBase.h" #include "DNA_meshdata_types.h" #include "DNA_mesh_types.h" +#include "DNA_object_types.h" #include "BKE_utildefines.h" #include "BKE_bmesh.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" -#include "blendef.h" - /*split this all into a seperate bevel.c file in src*/ /* ------- Bevel code starts here -------- */ @@ -206,6 +205,7 @@ static BME_Poly *BME_split_face(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Ver } +#if 0 static void BME_data_interp_from_verts(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Vert *v, float fac) { void *src[2]; @@ -218,6 +218,7 @@ static void BME_data_interp_from_verts(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, CustomData_bmesh_interp(&bm->vdata, src, w, NULL, 2, v->data); } } +#endif static void BME_data_facevert_edgesplit(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Vert *v, BME_Edge *e1, float fac){ diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 1d0d91c4208..090f256ab9f 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -71,7 +71,6 @@ #include "BKE_material.h" #include "BKE_modifier.h" #include "BKE_mesh.h" -#include "BKE_multires.h" #include "BKE_object.h" #include "BKE_subsurf.h" #include "BKE_texture.h" @@ -81,10 +80,6 @@ #include "BLO_sys_types.h" // for intptr_t support -#ifdef WITH_VERSE -#include "BKE_verse.h" -#endif - #include "BIF_gl.h" #include "BIF_glutil.h" @@ -1391,581 +1386,16 @@ static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, Object *ob, return (DerivedMesh*) emdm; } -#ifdef WITH_VERSE - -/* verse derived mesh */ -typedef struct { - struct DerivedMesh dm; - struct VNode *vnode; - struct VLayer *vertex_layer; - struct VLayer *polygon_layer; - struct ListBase *edges; - float (*vertexCos)[3]; -} VDerivedMesh; - -/* this function set up border points of verse mesh bounding box */ -static void vDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseVert *vvert; - - if(!vdm->vertex_layer) return; - - vvert = (VerseVert*)vdm->vertex_layer->dl.lb.first; - - if(vdm->vertex_layer->dl.da.count > 0) { - while(vvert) { - DO_MINMAX(vdm->vertexCos ? vvert->cos : vvert->co, min_r, max_r); - vvert = vvert->next; - } - } - else { - min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0; - } -} - -/* this function return number of vertexes in vertex layer */ -static int vDM_getNumVerts(DerivedMesh *dm) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - - if(!vdm->vertex_layer) return 0; - else return vdm->vertex_layer->dl.da.count; -} - -/* this function return number of 'fake' edges */ -static int vDM_getNumEdges(DerivedMesh *dm) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - - return BLI_countlist(vdm->edges); -} - -/* this function returns number of polygons in polygon layer */ -static int vDM_getNumFaces(DerivedMesh *dm) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - - if(!vdm->polygon_layer) return 0; - else return vdm->polygon_layer->dl.da.count; -} - -/* this function doesn't return vertex with index of access array, - * but it return 'indexth' vertex of dynamic list */ -void vDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseVert *vvert; - int i; - - if(!vdm->vertex_layer) return; - - for(vvert = vdm->vertex_layer->dl.lb.first, i=0 ; i<index; i++) vvert = vvert->next; - - if(vvert) { - VECCOPY(vert_r->co, vvert->co); - - vert_r->no[0] = vvert->no[0] * 32767.0; - vert_r->no[1] = vvert->no[1] * 32767.0; - vert_r->no[2] = vvert->no[2] * 32767.0; - - /* TODO what to do with vert_r->flag and vert_r->mat_nr? */ - vert_r->mat_nr = 0; - vert_r->flag = 0; - } -} - -/* this function returns fake verse edge */ -void vDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseEdge *vedge; - struct VLayer *vert_vlayer = vdm->vertex_layer; - struct VerseVert *vvert; - int j; - - if(!vdm->vertex_layer || !vdm->edges) return; - - if(vdm->edges->first) { - struct VerseVert *vvert1, *vvert2; - - /* store vert indices in tmp union */ - for(vvert = vdm->vertex_layer->dl.lb.first, j = 0; vvert; vvert = vvert->next, j++) - vvert->tmp.index = j; - - for(vedge = vdm->edges->first; vedge; vedge = vedge->next) { - if(vedge->tmp.index==index) { - vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v0); - vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v1); - - if(vvert1 && vvert2) { - edge_r->v1 = vvert1->tmp.index; - edge_r->v2 = vvert2->tmp.index; - } - else { - edge_r->v1 = 0; - edge_r->v2 = 0; - } - /* not supported yet */ - edge_r->flag = 0; - edge_r->crease = 0; - edge_r->bweight = 0; - break; - } - } - } -} - -/* this function doesn't return face with index of access array, - * but it returns 'indexth' vertex of dynamic list */ -void vDM_getFace(DerivedMesh *dm, int index, MFace *face_r) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseFace *vface; - struct VerseVert *vvert; - struct VerseVert *vvert0, *vvert1, *vvert2, *vvert3; - int i; - - if(!vdm->vertex_layer || !vdm->polygon_layer) return; - - for(vface = vdm->polygon_layer->dl.lb.first, i = 0; i < index; ++i) vface = vface->next; - - face_r->mat_nr = 0; - face_r->flag = 0; - - /* goddamn, we have to search all verts to find indices */ - vvert0 = vface->vvert0; - vvert1 = vface->vvert1; - vvert2 = vface->vvert2; - vvert3 = vface->vvert3; - if(!vvert3) face_r->v4 = 0; - - for(vvert = vdm->vertex_layer->dl.lb.first, i = 0; vvert0 || vvert1 || vvert2 || vvert3; i++, vvert = vvert->next) { - if(vvert == vvert0) { - face_r->v1 = i; - vvert0 = NULL; - } - if(vvert == vvert1) { - face_r->v2 = i; - vvert1 = NULL; - } - if(vvert == vvert2) { - face_r->v3 = i; - vvert2 = NULL; - } - if(vvert == vvert3) { - face_r->v4 = i; - vvert3 = NULL; - } - } - - test_index_face(face_r, NULL, 0, vface->vvert3?4:3); -} - -/* fill array of mvert */ -void vDM_copyVertArray(DerivedMesh *dm, MVert *vert_r) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseVert *vvert; - - if(!vdm->vertex_layer) return; - - for(vvert = vdm->vertex_layer->dl.lb.first ; vvert; vvert = vvert->next, ++vert_r) { - VECCOPY(vert_r->co, vvert->co); - - vert_r->no[0] = vvert->no[0] * 32767.0; - vert_r->no[1] = vvert->no[1] * 32767.0; - vert_r->no[2] = vvert->no[2] * 32767.0; - - vert_r->mat_nr = 0; - vert_r->flag = 0; - } -} - -/* dummy function, edges arent supported in verse mesh */ -void vDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - - if(!vdm->vertex_layer || !vdm->edges) return; - - if(vdm->edges->first) { - struct VerseEdge *vedge; - struct VLayer *vert_vlayer = vdm->vertex_layer; - struct VerseVert *vvert, *vvert1, *vvert2; - int j; - - /* store vert indices in tmp union */ - for(vvert = vdm->vertex_layer->dl.lb.first, j = 0; vvert; vvert = vvert->next, ++j) - vvert->tmp.index = j; - - for(vedge = vdm->edges->first, j=0 ; vedge; vedge = vedge->next, ++edge_r, j++) { - /* create temporary edge index */ - vedge->tmp.index = j; - vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v0); - vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v1); - if(vvert1 && vvert2) { - edge_r->v1 = vvert1->tmp.index; - edge_r->v2 = vvert2->tmp.index; - } - else { - printf("error: vDM_copyEdgeArray: %d, %d\n", vedge->v0, vedge->v1); - edge_r->v1 = 0; - edge_r->v2 = 0; - } - /* not supported yet */ - edge_r->flag = 0; - edge_r->crease = 0; - edge_r->bweight = 0; - } - } -} - -/* fill array of mfaces */ -void vDM_copyFaceArray(DerivedMesh *dm, MFace *face_r) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseFace *vface; - struct VerseVert *vvert; - int i; - - if(!vdm->vertex_layer || !vdm->polygon_layer) return; - - /* store vertexes indices in tmp union */ - for(vvert = vdm->vertex_layer->dl.lb.first, i = 0; vvert; vvert = vvert->next, ++i) - vvert->tmp.index = i; - - for(vface = vdm->polygon_layer->dl.lb.first; vface; vface = vface->next, ++face_r) { - face_r->mat_nr = 0; - face_r->flag = 0; - - face_r->v1 = vface->vvert0->tmp.index; - face_r->v2 = vface->vvert1->tmp.index; - face_r->v3 = vface->vvert2->tmp.index; - if(vface->vvert3) face_r->v4 = vface->vvert3->tmp.index; - else face_r->v4 = 0; - - test_index_face(face_r, NULL, 0, vface->vvert3?4:3); - } -} - -/* return coordination of vertex with index */ -static void vDM_getVertCo(DerivedMesh *dm, int index, float co_r[3]) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseVert *vvert = NULL; - - if(!vdm->vertex_layer) return; - - vvert = BLI_dlist_find_link(&(vdm->vertex_layer->dl), index); - - if(vvert) { - VECCOPY(co_r, vdm->vertexCos ? vvert->cos : vvert->co); - } - else { - co_r[0] = co_r[1] = co_r[2] = 0.0; - } -} - -/* return array of vertex coordiantions */ -static void vDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3]) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseVert *vvert; - int i = 0; - - if(!vdm->vertex_layer) return; - - vvert = vdm->vertex_layer->dl.lb.first; - while(vvert) { - VECCOPY(cos_r[i], vdm->vertexCos ? vvert->cos : vvert->co); - i++; - vvert = vvert->next; - } -} - -/* return normal of vertex with index */ -static void vDM_getVertNo(DerivedMesh *dm, int index, float no_r[3]) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseVert *vvert = NULL; - - if(!vdm->vertex_layer) return; - - vvert = BLI_dlist_find_link(&(vdm->vertex_layer->dl), index); - if(vvert) { - VECCOPY(no_r, vvert->no); - } - else { - no_r[0] = no_r[1] = no_r[2] = 0.0; - } -} - -/* draw all VerseVertexes */ -static void vDM_drawVerts(DerivedMesh *dm) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseVert *vvert; - - if(!vdm->vertex_layer) return; - - vvert = vdm->vertex_layer->dl.lb.first; - - bglBegin(GL_POINTS); - while(vvert) { - bglVertex3fv(vdm->vertexCos ? vvert->cos : vvert->co); - vvert = vvert->next; - } - bglEnd(); -} - -/* draw all edges of VerseFaces ... it isn't optimal, because verse - * specification doesn't support edges :-( ... bother eskil ;-) - * ... some edges (most of edges) are drawn twice */ -static void vDM_drawEdges(DerivedMesh *dm, int drawLooseEdges) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseEdge *vedge; - struct VLayer *vert_vlayer = vdm->vertex_layer; - - if(vert_vlayer && vdm->edges && (BLI_countlist(vdm->edges) > 0)) { - struct VerseVert *vvert1, *vvert2; - - glBegin(GL_LINES); - for(vedge = vdm->edges->first; vedge; vedge = vedge->next) { - vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v0); - vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v1); - if(vvert1 && vvert2) { - glVertex3fv(vdm->vertexCos ? vvert1->cos : vvert1->co); - glVertex3fv(vdm->vertexCos ? vvert2->cos : vvert2->co); - } - } - glEnd(); - } -} - -/* verse spec doesn't support edges ... loose edges can't exist */ -void vDM_drawLooseEdges(DerivedMesh *dm) -{ -} - -/* draw uv edges, not supported yet */ -static void vDM_drawUVEdges(DerivedMesh *dm) -{ -} - -/* draw all VerseFaces */ -static void vDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *attribs)) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseFace *vface; - - if(!vdm->polygon_layer) return; - - vface = vdm->polygon_layer->dl.lb.first; - - glShadeModel(GL_FLAT); - while(vface) { - glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES); - glNormal3fv(vface->no); - glVertex3fv(vdm->vertexCos ? vface->vvert0->cos : vface->vvert0->co); - glVertex3fv(vdm->vertexCos ? vface->vvert1->cos : vface->vvert1->co); - glVertex3fv(vdm->vertexCos ? vface->vvert2->cos : vface->vvert2->co); - if(vface->vvert3) - glVertex3fv(vdm->vertexCos ? vface->vvert3->cos : vface->vvert3->co); - glEnd(); - vface = vface->next; - } -} - -/* this function should draw mesh with mapped texture, but it isn't supported yet */ -static void vDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr)) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseFace *vface; - - if(!vdm->polygon_layer) return; - - vface = vdm->polygon_layer->dl.lb.first; - - while(vface) { - glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES); - glVertex3fv(vdm->vertexCos ? vface->vvert0->cos : vface->vvert0->co); - glVertex3fv(vdm->vertexCos ? vface->vvert1->cos : vface->vvert1->co); - glVertex3fv(vdm->vertexCos ? vface->vvert2->cos : vface->vvert2->co); - if(vface->vvert3) - glVertex3fv(vdm->vertexCos ? vface->vvert3->cos : vface->vvert3->co); - glEnd(); - - vface = vface->next; - } -} - -/* this function should draw mesh with colored faces (weight paint, vertex - * colors, etc.), but it isn't supported yet */ -static void vDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - struct VerseFace *vface; - - if(!vdm->polygon_layer) return; - - vface = vdm->polygon_layer->dl.lb.first; - - while(vface) { - glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES); - glVertex3fv(vdm->vertexCos ? vface->vvert0->cos : vface->vvert0->co); - glVertex3fv(vdm->vertexCos ? vface->vvert1->cos : vface->vvert1->co); - glVertex3fv(vdm->vertexCos ? vface->vvert2->cos : vface->vvert2->co); - if(vface->vvert3) - glVertex3fv(vdm->vertexCos ? vface->vvert3->cos : vface->vvert3->co); - glEnd(); - - vface = vface->next; - } -} - -/**/ -static void vDM_foreachMappedVert( - DerivedMesh *dm, - void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), - void *userData) -{ -} - -/**/ -static void vDM_foreachMappedEdge( - DerivedMesh *dm, - void (*func)(void *userData, int index, float *v0co, float *v1co), - void *userData) -{ -} - -/**/ -static void vDM_foreachMappedFaceCenter( - DerivedMesh *dm, - void (*func)(void *userData, int index, float *cent, float *no), - void *userData) -{ -} - -/**/ -static void vDM_drawMappedFacesTex( - DerivedMesh *dm, - int (*setDrawParams)(void *userData, int index), - void *userData) -{ - /* not supported yet */ - vDM_drawFacesTex(dm, NULL); -} - -/**/ -static void vDM_drawMappedFaces( - DerivedMesh *dm, - int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), - void *userData, - int useColors) -{ -} - -/**/ -static void vDM_drawMappedEdges( - DerivedMesh *dm, - int (*setDrawOptions)(void *userData, int index), - void *userData) -{ -} - -/**/ -static void vDM_drawMappedEdgesInterp( - DerivedMesh *dm, - int (*setDrawOptions)(void *userData, int index), - void (*setDrawInterpOptions)(void *userData, int index, float t), - void *userData) -{ -} - -/* free all DerivedMesh data */ -static void vDM_release(DerivedMesh *dm) -{ - VDerivedMesh *vdm = (VDerivedMesh*)dm; - - if (DM_release(dm)) { - if(vdm->vertexCos) MEM_freeN(vdm->vertexCos); - MEM_freeN(vdm); - } -} - -/* create derived mesh from verse mesh ... it is used in object mode, when some other client can - * change shared data and want to see this changes in real time too */ -DerivedMesh *derivedmesh_from_versemesh(VNode *vnode, float (*vertexCos)[3]) -{ - VDerivedMesh *vdm = MEM_callocN(sizeof(*vdm), "vdm"); - - vdm->vnode = vnode; - vdm->vertex_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); - vdm->polygon_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); - vdm->edges = &((VGeomData*)vnode->data)->edges; - - /* vertex and polygon layer has to exist */ - if(vdm->vertex_layer && vdm->polygon_layer) - DM_init(&vdm->dm, vdm->vertex_layer->dl.da.count, BLI_countlist(vdm->edges), vdm->polygon_layer->dl.da.count); - else - DM_init(&vdm->dm, 0, 0, 0); - - vdm->dm.getMinMax = vDM_getMinMax; - - vdm->dm.getNumVerts = vDM_getNumVerts; - vdm->dm.getNumEdges = vDM_getNumEdges; - vdm->dm.getNumFaces = vDM_getNumFaces; - - vdm->dm.getVert = vDM_getVert; - vdm->dm.getEdge = vDM_getEdge; - vdm->dm.getFace = vDM_getFace; - vdm->dm.copyVertArray = vDM_copyVertArray; - vdm->dm.copyEdgeArray = vDM_copyEdgeArray; - vdm->dm.copyFaceArray = vDM_copyFaceArray; - - vdm->dm.foreachMappedVert = vDM_foreachMappedVert; - vdm->dm.foreachMappedEdge = vDM_foreachMappedEdge; - vdm->dm.foreachMappedFaceCenter = vDM_foreachMappedFaceCenter; - - vdm->dm.getVertCos = vDM_getVertCos; - vdm->dm.getVertCo = vDM_getVertCo; - vdm->dm.getVertNo = vDM_getVertNo; - - vdm->dm.drawVerts = vDM_drawVerts; - - vdm->dm.drawEdges = vDM_drawEdges; - vdm->dm.drawLooseEdges = vDM_drawLooseEdges; - vdm->dm.drawUVEdges = vDM_drawUVEdges; - - vdm->dm.drawFacesSolid = vDM_drawFacesSolid; - vdm->dm.drawFacesTex = vDM_drawFacesTex; - vdm->dm.drawFacesColored = vDM_drawFacesColored; - - vdm->dm.drawMappedFacesTex = vDM_drawMappedFacesTex; - vdm->dm.drawMappedFaces = vDM_drawMappedFaces; - vdm->dm.drawMappedEdges = vDM_drawMappedEdges; - vdm->dm.drawMappedEdgesInterp = vDM_drawMappedEdgesInterp; - - vdm->dm.release = vDM_release; - - vdm->vertexCos = vertexCos; - - return (DerivedMesh*) vdm; -} - -#endif - /***/ -DerivedMesh *mesh_create_derived_for_modifier(Object *ob, ModifierData *md) +DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, ModifierData *md) { Mesh *me = ob->data; ModifierTypeInfo *mti = modifierType_getInfo(md->type); DerivedMesh *dm; + md->scene= scene; + if (!(md->mode&eModifierMode_Realtime)) return NULL; if (mti->isDisabled && mti->isDisabled(md)) return NULL; @@ -1973,13 +1403,8 @@ DerivedMesh *mesh_create_derived_for_modifier(Object *ob, ModifierData *md) int numVerts; float (*deformedVerts)[3] = mesh_getVertexCos(me, &numVerts); - mti->deformVerts(md, ob, NULL, deformedVerts, numVerts); -#ifdef WITH_VERSE - if(me->vnode) dm = derivedmesh_from_versemesh(me->vnode, deformedVerts); - else dm = getMeshDerivedMesh(me, ob, deformedVerts); -#else + mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, 0, 0); dm = getMeshDerivedMesh(me, ob, deformedVerts); -#endif MEM_freeN(deformedVerts); } else { @@ -1992,53 +1417,6 @@ DerivedMesh *mesh_create_derived_for_modifier(Object *ob, ModifierData *md) return dm; } -CustomDataMask get_viewedit_datamask() -{ - CustomDataMask mask = CD_MASK_BAREMESH; - ScrArea *sa; - - /* check if we need tfaces & mcols due to face select or texture paint */ - if(FACESEL_PAINT_TEST || G.f & G_TEXTUREPAINT) - mask |= CD_MASK_MTFACE | CD_MASK_MCOL; - - if (G.curscreen==NULL) { - /* No screen, happens when saving a blendfile in background mode, - * then loading in the game engine - * just assume we need the mesh info */ - mask |= CD_MASK_MTFACE | CD_MASK_MCOL; - - if((G.fileflags & G_FILE_GAME_MAT) && - (G.fileflags & G_FILE_GAME_MAT_GLSL)) { - mask |= CD_MASK_ORCO; - } - } else { - /* check if we need tfaces & mcols due to view mode */ - for(sa = G.curscreen->areabase.first; sa; sa = sa->next) { - if(sa->spacetype == SPACE_VIEW3D) { - View3D *view = sa->spacedata.first; - if(view->drawtype == OB_SHADED) { - /* this includes normals for mesh_create_shadedColors */ - mask |= CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_NORMAL | CD_MASK_ORCO; - } - if((view->drawtype == OB_TEXTURE) || ((view->drawtype == OB_SOLID) && (view->flag2 & V3D_SOLID_TEX))) { - mask |= CD_MASK_MTFACE | CD_MASK_MCOL; - - if((G.fileflags & G_FILE_GAME_MAT) && - (G.fileflags & G_FILE_GAME_MAT_GLSL)) { - mask |= CD_MASK_ORCO; - } - } - } - } - } - - /* check if we need mcols due to vertex paint or weightpaint */ - if(G.f & G_VERTEXPAINT || G.f & G_WEIGHTPAINT) - mask |= CD_MASK_MCOL; - - return mask; -} - static float *get_editmesh_orco_verts(EditMesh *em) { EditVert *eve; @@ -2060,6 +1438,8 @@ static float *get_editmesh_orco_verts(EditMesh *em) return orco; } +/* orco custom data layer */ + static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, EditMesh *em) { DerivedMesh *dm; @@ -2111,12 +1491,102 @@ static void add_orco_dm(Object *ob, EditMesh *em, DerivedMesh *dm, DerivedMesh * DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco); } +/* weight paint colors */ + +/* Something of a hack, at the moment deal with weightpaint + * by tucking into colors during modifier eval, only in + * wpaint mode. Works ok but need to make sure recalc + * happens on enter/exit wpaint. + */ + +void weight_to_rgb(float input, float *fr, float *fg, float *fb) +{ + float blend; + + blend= ((input/2.0f)+0.5f); + + if (input<=0.25f){ // blue->cyan + *fr= 0.0f; + *fg= blend*input*4.0f; + *fb= blend; + } + else if (input<=0.50f){ // cyan->green + *fr= 0.0f; + *fg= blend; + *fb= blend*(1.0f-((input-0.25f)*4.0f)); + } + else if (input<=0.75){ // green->yellow + *fr= blend * ((input-0.50f)*4.0f); + *fg= blend; + *fb= 0.0f; + } + else if (input<=1.0){ // yellow->red + *fr= blend; + *fg= blend * (1.0f-((input-0.75f)*4.0f)); + *fb= 0.0f; + } +} + +static void calc_weightpaint_vert_color(Object *ob, ColorBand *coba, int vert, unsigned char *col) +{ + Mesh *me = ob->data; + float colf[4], input = 0.0f; + int i; + + if (me->dvert) { + for (i=0; i<me->dvert[vert].totweight; i++) + if (me->dvert[vert].dw[i].def_nr==ob->actdef-1) + input+=me->dvert[vert].dw[i].weight; + } + + CLAMP(input, 0.0f, 1.0f); + + if(coba) + do_colorband(coba, input, colf); + else + weight_to_rgb(input, colf, colf+1, colf+2); + + col[3] = (unsigned char)(colf[0] * 255.0f); + col[2] = (unsigned char)(colf[1] * 255.0f); + col[1] = (unsigned char)(colf[2] * 255.0f); + col[0] = 255; +} + +static ColorBand *stored_cb= NULL; + +void vDM_ColorBand_store(ColorBand *coba) +{ + stored_cb= coba; +} + +static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm) +{ + Mesh *me = ob->data; + MFace *mf = me->mface; + ColorBand *coba= stored_cb; /* warning, not a local var */ + unsigned char *wtcol; + int i; + + wtcol = MEM_callocN (sizeof (unsigned char) * me->totface*4*4, "weightmap"); + + memset(wtcol, 0x55, sizeof (unsigned char) * me->totface*4*4); + for (i=0; i<me->totface; i++, mf++) { + calc_weightpaint_vert_color(ob, coba, mf->v1, &wtcol[(i*4 + 0)*4]); + calc_weightpaint_vert_color(ob, coba, mf->v2, &wtcol[(i*4 + 1)*4]); + calc_weightpaint_vert_color(ob, coba, mf->v3, &wtcol[(i*4 + 2)*4]); + if (mf->v4) + calc_weightpaint_vert_color(ob, coba, mf->v4, &wtcol[(i*4 + 3)*4]); + } + + CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_ASSIGN, wtcol, dm->numFaceData); +} + /* new value for useDeform -1 (hack for the gameengine): * - apply only the modifier stack of the object, skipping the virtual modifiers, * - don't apply the key * - apply deform modifiers and input vertexco */ -static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], +static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos)[3], DerivedMesh **deform_r, DerivedMesh **final_r, int useRenderParams, int useDeform, int needMapping, CustomDataMask dataMask, int index) @@ -2147,7 +1617,7 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], *final_r = NULL; if(useDeform) { - if(useDeform > 0 && do_ob_key(ob)) /* shape key makes deform verts */ + if(useDeform > 0 && do_ob_key(scene, ob)) /* shape key makes deform verts */ deformedVerts = mesh_getVertexCos(me, &numVerts); else if(inputVertexCos) deformedVerts = inputVertexCos; @@ -2156,6 +1626,8 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], for(;md; md = md->next, curr = curr->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); + md->scene= scene; + if(!modifier_isEnabled(md, required_mode)) continue; if(useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) continue; @@ -2163,7 +1635,7 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], if(!deformedVerts) deformedVerts = mesh_getVertexCos(me, &numVerts); - mti->deformVerts(md, ob, NULL, deformedVerts, numVerts); + mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, useRenderParams, useDeform); } else { break; } @@ -2178,22 +1650,12 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], * coordinates (vpaint, etc.) */ if (deform_r) { -#ifdef WITH_VERSE - if(me->vnode) *deform_r = derivedmesh_from_versemesh(me->vnode, deformedVerts); - else { - *deform_r = CDDM_from_mesh(me, ob); - if(deformedVerts) { - CDDM_apply_vert_coords(*deform_r, deformedVerts); - CDDM_calc_normals(*deform_r); - } - } -#else *deform_r = CDDM_from_mesh(me, ob); + if(deformedVerts) { CDDM_apply_vert_coords(*deform_r, deformedVerts); CDDM_calc_normals(*deform_r); } -#endif } } else { /* default behaviour for meshes */ @@ -2210,16 +1672,11 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], dm = NULL; orcodm = NULL; -#ifdef WITH_VERSE - /* hack to make sure modifiers don't try to use mesh data from a verse - * node - */ - if(me->vnode) dm = derivedmesh_from_versemesh(me->vnode, deformedVerts); -#endif - for(;md; md = md->next, curr = curr->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); + md->scene= scene; + if(!modifier_isEnabled(md, required_mode)) continue; if(mti->type == eModifierTypeType_OnlyDeform && !useDeform) continue; if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { @@ -2259,7 +1716,7 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], } } - mti->deformVerts(md, ob, dm, deformedVerts, numVerts); + mti->deformVerts(md, ob, dm, deformedVerts, numVerts, useRenderParams, useDeform); } else { DerivedMesh *ndm; @@ -2280,10 +1737,13 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], CDDM_apply_vert_coords(dm, deformedVerts); CDDM_calc_normals(dm); } + + if(dataMask & CD_MASK_WEIGHT_MCOL) + add_weight_mcol_dm(ob, dm); } /* create an orco derivedmesh in parallel */ - mask= (CustomDataMask)curr->link; + mask= (CustomDataMask)GET_INT_FROM_POINTER(curr->link); if(mask & CD_MASK_ORCO) { if(!orcodm) orcodm= create_orco_dm(ob, me, NULL); @@ -2303,7 +1763,7 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DM_set_only_copy(dm, mask); /* add an origspace layer if needed */ - if(((CustomDataMask)curr->link) & CD_MASK_ORIGSPACE) + if(((CustomDataMask)GET_INT_FROM_POINTER(curr->link)) & CD_MASK_ORIGSPACE) if(!CustomData_has_layer(&dm->faceData, CD_ORIGSPACE)) DM_add_face_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL); @@ -2343,26 +1803,21 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], CDDM_apply_vert_coords(finaldm, deformedVerts); CDDM_calc_normals(finaldm); + + if(dataMask & CD_MASK_WEIGHT_MCOL) + add_weight_mcol_dm(ob, finaldm); } else if(dm) { finaldm = dm; } else { -#ifdef WITH_VERSE - if(me->vnode) - finaldm = derivedmesh_from_versemesh(me->vnode, deformedVerts); - else { - finaldm = CDDM_from_mesh(me, ob); - if(deformedVerts) { - CDDM_apply_vert_coords(finaldm, deformedVerts); - CDDM_calc_normals(finaldm); - } - } -#else finaldm = CDDM_from_mesh(me, ob); + if(deformedVerts) { CDDM_apply_vert_coords(finaldm, deformedVerts); CDDM_calc_normals(finaldm); } -#endif + + if(dataMask & CD_MASK_WEIGHT_MCOL) + add_weight_mcol_dm(ob, finaldm); } /* add an orco layer if needed */ @@ -2412,12 +1867,10 @@ static int editmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm) return 1; } -static void editmesh_calc_modifiers(DerivedMesh **cage_r, +static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, DerivedMesh **cage_r, DerivedMesh **final_r, CustomDataMask dataMask) { - Object *ob = G.obedit; - EditMesh *em = G.editMesh; ModifierData *md; float (*deformedVerts)[3] = NULL; CustomDataMask mask; @@ -2434,7 +1887,7 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, dm = NULL; md = ob->modifiers.first; - + /* we always want to keep original indices */ dataMask |= CD_MASK_ORIGINDEX; @@ -2444,6 +1897,8 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, for(i = 0; md; i++, md = md->next, curr = curr->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); + md->scene= scene; + if(!editmesh_modifier_is_enabled(md, dm)) continue; @@ -2505,7 +1960,7 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, } /* create an orco derivedmesh in parallel */ - mask= (CustomDataMask)curr->link; + mask= (CustomDataMask)GET_INT_FROM_POINTER(curr->link); if(mask & CD_MASK_ORCO) { if(!orcodm) orcodm= create_orco_dm(ob, ob->data, em); @@ -2522,9 +1977,9 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, } /* set the DerivedMesh to only copy needed data */ - DM_set_only_copy(dm, (CustomDataMask)curr->link); + DM_set_only_copy(dm, (CustomDataMask)GET_INT_FROM_POINTER(curr->link)); - if(((CustomDataMask)curr->link) & CD_MASK_ORIGSPACE) + if(((CustomDataMask)GET_INT_FROM_POINTER(curr->link)) & CD_MASK_ORIGSPACE) if(!CustomData_has_layer(&dm->faceData, CD_ORIGSPACE)) DM_add_face_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL); @@ -2590,96 +2045,6 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, MEM_freeN(deformedVerts); } -/***/ - - - /* Something of a hack, at the moment deal with weightpaint - * by tucking into colors during modifier eval, only in - * wpaint mode. Works ok but need to make sure recalc - * happens on enter/exit wpaint. - */ - -void weight_to_rgb(float input, float *fr, float *fg, float *fb) -{ - float blend; - - blend= ((input/2.0f)+0.5f); - - if (input<=0.25f){ // blue->cyan - *fr= 0.0f; - *fg= blend*input*4.0f; - *fb= blend; - } - else if (input<=0.50f){ // cyan->green - *fr= 0.0f; - *fg= blend; - *fb= blend*(1.0f-((input-0.25f)*4.0f)); - } - else if (input<=0.75){ // green->yellow - *fr= blend * ((input-0.50f)*4.0f); - *fg= blend; - *fb= 0.0f; - } - else if (input<=1.0){ // yellow->red - *fr= blend; - *fg= blend * (1.0f-((input-0.75f)*4.0f)); - *fb= 0.0f; - } -} -static void calc_weightpaint_vert_color(Object *ob, ColorBand *coba, int vert, unsigned char *col) -{ - Mesh *me = ob->data; - float colf[4], input = 0.0f; - int i; - - if (me->dvert) { - for (i=0; i<me->dvert[vert].totweight; i++) - if (me->dvert[vert].dw[i].def_nr==ob->actdef-1) - input+=me->dvert[vert].dw[i].weight; - } - - CLAMP(input, 0.0f, 1.0f); - - if(coba) - do_colorband(coba, input, colf); - else - weight_to_rgb(input, colf, colf+1, colf+2); - - col[3] = (unsigned char)(colf[0] * 255.0f); - col[2] = (unsigned char)(colf[1] * 255.0f); - col[1] = (unsigned char)(colf[2] * 255.0f); - col[0] = 255; -} - -static ColorBand *stored_cb= NULL; - -void vDM_ColorBand_store(ColorBand *coba) -{ - stored_cb= coba; -} - -static unsigned char *calc_weightpaint_colors(Object *ob) -{ - Mesh *me = ob->data; - MFace *mf = me->mface; - ColorBand *coba= stored_cb; /* warning, not a local var */ - unsigned char *wtcol; - int i; - - wtcol = MEM_callocN (sizeof (unsigned char) * me->totface*4*4, "weightmap"); - - memset(wtcol, 0x55, sizeof (unsigned char) * me->totface*4*4); - for (i=0; i<me->totface; i++, mf++) { - calc_weightpaint_vert_color(ob, coba, mf->v1, &wtcol[(i*4 + 0)*4]); - calc_weightpaint_vert_color(ob, coba, mf->v2, &wtcol[(i*4 + 1)*4]); - calc_weightpaint_vert_color(ob, coba, mf->v3, &wtcol[(i*4 + 2)*4]); - if (mf->v4) - calc_weightpaint_vert_color(ob, coba, mf->v4, &wtcol[(i*4 + 3)*4]); - } - - return wtcol; -} - static void clear_mesh_caches(Object *ob) { Mesh *me= ob->data; @@ -2708,64 +2073,38 @@ static void clear_mesh_caches(Object *ob) } } -static void mesh_build_data(Object *ob, CustomDataMask dataMask) +static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask) { - Mesh *me = ob->data; + Object *obact = scene->basact?scene->basact->object:NULL; + int editing = (FACESEL_PAINT_TEST)|(G.f & G_PARTICLEEDIT); + int needMapping = editing && (ob==obact); float min[3], max[3]; - + clear_mesh_caches(ob); - if(ob!=G.obedit) { - Object *obact = G.scene->basact?G.scene->basact->object:NULL; - int editing = (FACESEL_PAINT_TEST)|(G.f & G_PARTICLEEDIT); - int needMapping = editing && (ob==obact); - - if( (G.f & G_WEIGHTPAINT) && ob==obact ) { - MCol *wpcol = (MCol*)calc_weightpaint_colors(ob); - int layernum = CustomData_number_of_layers(&me->fdata, CD_MCOL); - int prevactive = CustomData_get_active_layer(&me->fdata, CD_MCOL); - int prevrender = CustomData_get_render_layer(&me->fdata, CD_MCOL); - - /* ugly hack here, we temporarily add a new active mcol layer with - weightpaint colors in it, that is then duplicated in CDDM_from_mesh */ - CustomData_add_layer(&me->fdata, CD_MCOL, CD_ASSIGN, wpcol, me->totface); - CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum); - CustomData_set_layer_render(&me->fdata, CD_MCOL, layernum); - - mesh_calc_modifiers(ob, NULL, &ob->derivedDeform, - &ob->derivedFinal, 0, 1, - needMapping, dataMask, -1); - - CustomData_free_layer_active(&me->fdata, CD_MCOL, me->totface); - CustomData_set_layer_active(&me->fdata, CD_MCOL, prevactive); - CustomData_set_layer_render(&me->fdata, CD_MCOL, prevrender); - } else { - mesh_calc_modifiers(ob, NULL, &ob->derivedDeform, - &ob->derivedFinal, G.rendering, 1, - needMapping, dataMask, -1); - } + mesh_calc_modifiers(scene, ob, NULL, &ob->derivedDeform, + &ob->derivedFinal, 0, 1, + needMapping, dataMask, -1); - INIT_MINMAX(min, max); + INIT_MINMAX(min, max); - ob->derivedFinal->getMinMax(ob->derivedFinal, min, max); + ob->derivedFinal->getMinMax(ob->derivedFinal, min, max); - if(!ob->bb) - ob->bb= MEM_callocN(sizeof(BoundBox), "bb"); - boundbox_set_from_min_max(ob->bb, min, max); + if(!ob->bb) + ob->bb= MEM_callocN(sizeof(BoundBox), "bb"); + boundbox_set_from_min_max(ob->bb, min, max); + + ob->derivedFinal->needsFree = 0; + ob->derivedDeform->needsFree = 0; + ob->lastDataMask = dataMask; - ob->derivedFinal->needsFree = 0; - ob->derivedDeform->needsFree = 0; - ob->lastDataMask = dataMask; - } } -static void editmesh_build_data(CustomDataMask dataMask) +static void editmesh_build_data(Scene *scene, Object *obedit, EditMesh *em, CustomDataMask dataMask) { float min[3], max[3]; - EditMesh *em = G.editMesh; - - clear_mesh_caches(G.obedit); + clear_mesh_caches(obedit); if (em->derivedFinal) { if (em->derivedFinal!=em->derivedCage) { @@ -2780,235 +2119,143 @@ static void editmesh_build_data(CustomDataMask dataMask) em->derivedCage = NULL; } - editmesh_calc_modifiers(&em->derivedCage, &em->derivedFinal, dataMask); + editmesh_calc_modifiers(scene, obedit, em, &em->derivedCage, &em->derivedFinal, dataMask); em->lastDataMask = dataMask; INIT_MINMAX(min, max); em->derivedFinal->getMinMax(em->derivedFinal, min, max); - if(!G.obedit->bb) - G.obedit->bb= MEM_callocN(sizeof(BoundBox), "bb"); - boundbox_set_from_min_max(G.obedit->bb, min, max); + if(!obedit->bb) + obedit->bb= MEM_callocN(sizeof(BoundBox), "bb"); + boundbox_set_from_min_max(obedit->bb, min, max); em->derivedFinal->needsFree = 0; em->derivedCage->needsFree = 0; } -void makeDerivedMesh(Object *ob, CustomDataMask dataMask) +void makeDerivedMesh(Scene *scene, Object *ob, EditMesh *em, CustomDataMask dataMask) { - if (ob==G.obedit) { - editmesh_build_data(dataMask); + if (em) { + editmesh_build_data(scene, ob, em, dataMask); } else { - mesh_build_data(ob, dataMask); + mesh_build_data(scene, ob, dataMask); } } /***/ -DerivedMesh *mesh_get_derived_final(Object *ob, CustomDataMask dataMask) +DerivedMesh *mesh_get_derived_final(Scene *scene, Object *ob, CustomDataMask dataMask) { /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ if(!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask) - mesh_build_data(ob, dataMask); + mesh_build_data(scene, ob, dataMask); return ob->derivedFinal; } -DerivedMesh *mesh_get_derived_deform(Object *ob, CustomDataMask dataMask) +DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask dataMask) { /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ if(!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask) - mesh_build_data(ob, dataMask); + mesh_build_data(scene, ob, dataMask); return ob->derivedDeform; } -/* Move to multires Pin level, returns a copy of the original vertex coords. */ -float *multires_render_pin(Object *ob, Mesh *me, int *orig_lvl) -{ - float *vert_copy= NULL; - - if(me->mr && !(me->mr->flag & MULTIRES_NO_RENDER)) { - MultiresLevel *lvl= NULL; - int i; - - /* Make sure all mesh edits are properly stored in the multires data*/ - multires_update_levels(me, 1); - - /* Copy the highest level of multires verts */ - *orig_lvl= me->mr->current; - lvl= multires_level_n(me->mr, BLI_countlist(&me->mr->levels)); - vert_copy= MEM_callocN(sizeof(float)*3*lvl->totvert, "multires vert_copy"); - for(i=0; i<lvl->totvert; ++i) - VecCopyf(&vert_copy[i*3], me->mr->verts[i].co); - - /* Goto the pin level for multires */ - me->mr->newlvl= me->mr->pinlvl; - multires_set_level(ob, me, 1); - } - - return vert_copy; -} - -/* Propagate the changes to render level - fails if mesh topology changed */ -void multires_render_final(Object *ob, Mesh *me, DerivedMesh **dm, float *vert_copy, - const int orig_lvl, CustomDataMask dataMask) -{ - if(me->mr && !(me->mr->flag & MULTIRES_NO_RENDER)) { - if((*dm)->getNumVerts(*dm) == me->totvert && - (*dm)->getNumFaces(*dm) == me->totface) { - MultiresLevel *lvl= multires_level_n(me->mr, BLI_countlist(&me->mr->levels)); - DerivedMesh *old= NULL; - MVert *vertdup= NULL; - int i; - - /* Copy the verts into the mesh */ - vertdup= (*dm)->dupVertArray(*dm); - (*dm)->release(*dm); - for(i=0; i<me->totvert; ++i) - me->mvert[i]= vertdup[i]; - /* Free vertdup after use*/ - MEM_freeN(vertdup); - /* Go to the render level */ - me->mr->newlvl= me->mr->renderlvl; - multires_set_level(ob, me, 1); - (*dm)= getMeshDerivedMesh(me, ob, NULL); - - /* Some of the data in dm is referenced externally, so make a copy */ - old= *dm; - (*dm)= CDDM_copy(old); - old->release(old); - - if(dataMask & CD_MASK_ORCO) - add_orco_dm(ob, NULL, *dm, NULL); - - /* Restore the original verts */ - me->mr->newlvl= BLI_countlist(&me->mr->levels); - multires_set_level(ob, me, 1); - for(i=0; i<lvl->totvert; ++i) - VecCopyf(me->mvert[i].co, &vert_copy[i*3]); - } - - if(vert_copy) - MEM_freeN(vert_copy); - - me->mr->newlvl= orig_lvl; - multires_set_level(ob, me, 1); - } -} - -/* Multires note - if mesh has multires enabled, mesh is first set to the Pin level, - where all modifiers are applied, then if the topology hasn't changed, the changes - from modifiers are propagated up to the Render level. */ -DerivedMesh *mesh_create_derived_render(Object *ob, CustomDataMask dataMask) +DerivedMesh *mesh_create_derived_render(Scene *scene, Object *ob, CustomDataMask dataMask) { DerivedMesh *final; - Mesh *me= get_mesh(ob); - float *vert_copy= NULL; - int orig_lvl= 0; - vert_copy= multires_render_pin(ob, me, &orig_lvl); - mesh_calc_modifiers(ob, NULL, NULL, &final, 1, 1, 0, dataMask, -1); - multires_render_final(ob, me, &final, vert_copy, orig_lvl, dataMask); + mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, -1); return final; } -DerivedMesh *mesh_create_derived_index_render(Object *ob, CustomDataMask dataMask, int index) +DerivedMesh *mesh_create_derived_index_render(Scene *scene, Object *ob, CustomDataMask dataMask, int index) { DerivedMesh *final; - Mesh *me= get_mesh(ob); - float *vert_copy= NULL; - int orig_lvl= 0; - vert_copy= multires_render_pin(ob, me, &orig_lvl); - mesh_calc_modifiers(ob, NULL, NULL, &final, 1, 1, 0, dataMask, index); - multires_render_final(ob, me, &final, vert_copy, orig_lvl, dataMask); + mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, index); return final; } -DerivedMesh *mesh_create_derived_view(Object *ob, CustomDataMask dataMask) +DerivedMesh *mesh_create_derived_view(Scene *scene, Object *ob, CustomDataMask dataMask) { DerivedMesh *final; - mesh_calc_modifiers(ob, NULL, NULL, &final, 0, 1, 0, dataMask, -1); + mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 0, 1, 0, dataMask, -1); return final; } -DerivedMesh *mesh_create_derived_no_deform(Object *ob, float (*vertCos)[3], +DerivedMesh *mesh_create_derived_no_deform(Scene *scene, Object *ob, float (*vertCos)[3], CustomDataMask dataMask) { DerivedMesh *final; - mesh_calc_modifiers(ob, vertCos, NULL, &final, 0, 0, 0, dataMask, -1); + mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, 0, 0, dataMask, -1); return final; } -DerivedMesh *mesh_create_derived_no_virtual(Object *ob, float (*vertCos)[3], +DerivedMesh *mesh_create_derived_no_virtual(Scene *scene, Object *ob, float (*vertCos)[3], CustomDataMask dataMask) { DerivedMesh *final; - mesh_calc_modifiers(ob, vertCos, NULL, &final, 0, -1, 0, dataMask, -1); + mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, -1, 0, dataMask, -1); return final; } -DerivedMesh *mesh_create_derived_no_deform_render(Object *ob, +DerivedMesh *mesh_create_derived_no_deform_render(Scene *scene, Object *ob, float (*vertCos)[3], CustomDataMask dataMask) { DerivedMesh *final; - Mesh *me= get_mesh(ob); - float *vert_copy= NULL; - int orig_lvl= 0; - vert_copy= multires_render_pin(ob, me, &orig_lvl); - mesh_calc_modifiers(ob, vertCos, NULL, &final, 1, 0, 0, dataMask, -1); - multires_render_final(ob, me, &final, vert_copy, orig_lvl, dataMask); + mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 1, 0, 0, dataMask, -1); return final; } /***/ -DerivedMesh *editmesh_get_derived_cage_and_final(DerivedMesh **final_r, +DerivedMesh *editmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, EditMesh *em, DerivedMesh **final_r, CustomDataMask dataMask) { /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - if(!G.editMesh->derivedCage || - (G.editMesh->lastDataMask & dataMask) != dataMask) - editmesh_build_data(dataMask); + if(!em->derivedCage || + (em->lastDataMask & dataMask) != dataMask) + editmesh_build_data(scene, obedit, em, dataMask); - *final_r = G.editMesh->derivedFinal; - return G.editMesh->derivedCage; + *final_r = em->derivedFinal; + return em->derivedCage; } -DerivedMesh *editmesh_get_derived_cage(CustomDataMask dataMask) +DerivedMesh *editmesh_get_derived_cage(Scene *scene, Object *obedit, EditMesh *em, CustomDataMask dataMask) { /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - if(!G.editMesh->derivedCage || - (G.editMesh->lastDataMask & dataMask) != dataMask) - editmesh_build_data(dataMask); + if(!em->derivedCage || + (em->lastDataMask & dataMask) != dataMask) + editmesh_build_data(scene, obedit, em, dataMask); - return G.editMesh->derivedCage; + return em->derivedCage; } -DerivedMesh *editmesh_get_derived_base(void) +DerivedMesh *editmesh_get_derived_base(Object *obedit, EditMesh *em) { - return getEditMeshDerivedMesh(G.editMesh, G.obedit, NULL); + return getEditMeshDerivedMesh(em, obedit, NULL); } @@ -3038,7 +2285,7 @@ static void make_vertexcosnos__mapFunc(void *userData, int index, float *co, flo /* it stores the normals as floats, but they can still be scaled as shorts (32767 = unit) */ /* in use now by vertex/weight paint and particle generating */ -float *mesh_get_mapped_verts_nors(Object *ob) +float *mesh_get_mapped_verts_nors(Scene *scene, Object *ob) { Mesh *me= ob->data; DerivedMesh *dm; @@ -3048,7 +2295,7 @@ float *mesh_get_mapped_verts_nors(Object *ob) if(ob->type!=OB_MESH || me->totvert==0) return NULL; - dm= mesh_get_derived_final(ob, CD_MASK_BAREMESH); + dm= mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); vertexcosnos= MEM_callocN(6*sizeof(float)*me->totvert, "vertexcosnos map"); if(dm->foreachMappedVert) { @@ -3070,10 +2317,8 @@ float *mesh_get_mapped_verts_nors(Object *ob) /* ********* crazyspace *************** */ -int editmesh_get_first_deform_matrices(float (**deformmats)[3][3], float (**deformcos)[3]) +int editmesh_get_first_deform_matrices(Object *ob, EditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3]) { - Object *ob = G.obedit; - EditMesh *em = G.editMesh; ModifierData *md; DerivedMesh *dm; int i, a, numleft = 0, numVerts = 0; diff --git a/source/blender/blenkernel/intern/Makefile b/source/blender/blenkernel/intern/Makefile index 75f75b0c3c5..60ffdc78726 100644 --- a/source/blender/blenkernel/intern/Makefile +++ b/source/blender/blenkernel/intern/Makefile @@ -41,8 +41,11 @@ CPPFLAGS += -I$(OPENGL_HEADERS) CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I../../../../intern/memutil +CPPFLAGS += -I$(NAN_AUDASPACE)/include # Reference to the types in makesdna and imbuf CPPFLAGS += -I../../makesdna +CPPFLAGS += -I../../makesrna CPPFLAGS += -I../../imbuf # This mod uses the BLI and BLO module CPPFLAGS += -I../../blenlib @@ -53,13 +56,11 @@ CPPFLAGS += -I../../avi CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include # we still refer to /include a bit... -CPPFLAGS += -I../../include +CPPFLAGS += -I../../editors/include # to include the render stuff: CPPFLAGS += -I../../render/extern/include -# for image stamping -CPPFLAGS += -I$(NAN_BMFONT)/include # for sound #CPPFLAGS += -I../../../kernel/gen_system CPPFLAGS += $(NAN_SDLCFLAGS) @@ -68,6 +69,8 @@ CPPFLAGS += -I$(NAN_IKSOLVER)/include CPPFLAGS += -I$(NAN_DECIMATION)/include CPPFLAGS += -I$(NAN_ELBEEM)/include CPPFLAGS += -I$(NAN_OPENNL)/include +CPPFLAGS += -I$(NAN_BSP)/include +CPPFLAGS += -I$(NAN_SMOKE)/include # path to zlib CPPFLAGS += -I$(NAN_ZLIB)/include @@ -83,17 +86,8 @@ CPPFLAGS += -I.. # path to bullet2, for cloth CPPFLAGS += -I$(NAN_BULLET2)/include - -ifeq ($(WITH_FREETYPE2), true) - CPPFLAGS += -DWITH_FREETYPE2 - CPPFLAGS += -I$(NAN_FREETYPE)/include - CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2 -endif - -ifeq ($(WITH_VERSE), true) - CPPFLAGS += -DWITH_VERSE - CPPFLAGS += -I$(NAN_VERSE)/include -endif +CPPFLAGS += -I$(NAN_FREETYPE)/include +CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2 ifeq ($(WITH_FFMPEG),true) CPPFLAGS += -DWITH_FFMPEG diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index dea8b72bbfd..f4d4eb1cc9c 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -21,6 +21,7 @@ * All rights reserved. * * Contributor(s): Full recode, Ton Roosendaal, Crete 2005 + * Full recode, Joshua Leung, 2009 * * ***** END GPL LICENSE BLOCK ***** */ @@ -31,20 +32,22 @@ #include <string.h> #include <math.h> -#include <stdlib.h> /* for NULL */ +#include <stdlib.h> +#include <stddef.h> #include "MEM_guardedalloc.h" +#include "DNA_anim_types.h" #include "DNA_action_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_curve_types.h" -#include "DNA_ipo_types.h" #include "DNA_key_types.h" #include "DNA_nla_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_anim.h" #include "BKE_armature.h" @@ -52,7 +55,7 @@ #include "BKE_constraint.h" #include "BKE_displist.h" #include "BKE_global.h" -#include "BKE_ipo.h" +#include "BKE_fcurve.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" @@ -64,7 +67,8 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" -#include "nla.h" +#include "RNA_access.h" +#include "RNA_types.h" /* *********************** NOTE ON POSE AND ACTION ********************** @@ -81,52 +85,34 @@ /* ***************** Library data level operations on action ************** */ -static void make_local_action_channels(bAction *act) +bAction *add_empty_action(const char name[]) { - bActionChannel *chan; - bConstraintChannel *conchan; - - for (chan=act->chanbase.first; chan; chan=chan->next) { - if(chan->ipo) { - if(chan->ipo->id.us==1) { - chan->ipo->id.lib= NULL; - chan->ipo->id.flag= LIB_LOCAL; - new_id(0, (ID *)chan->ipo, 0); - } - else { - chan->ipo= copy_ipo(chan->ipo); - } - } - for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) { - if(conchan->ipo) { - if(conchan->ipo->id.us==1) { - conchan->ipo->id.lib= NULL; - conchan->ipo->id.flag= LIB_LOCAL; - new_id(0, (ID *)conchan->ipo, 0); - } - else { - conchan->ipo= copy_ipo(conchan->ipo); - } - } - } - } -} + bAction *act; + + act= alloc_libblock(&G.main->action, ID_AC, name); + act->id.flag |= LIB_FAKEUSER; // XXX this is nasty for new users... maybe we don't want this anymore + act->id.us++; + + return act; +} +// does copy_fcurve... void make_local_action(bAction *act) { - Object *ob; + // Object *ob; bAction *actn; int local=0, lib=0; - if(act->id.lib==0) return; - if(act->id.us==1) { + if (act->id.lib==0) return; + if (act->id.us==1) { act->id.lib= 0; act->id.flag= LIB_LOCAL; - make_local_action_channels(act); + //make_local_action_channels(act); new_id(0, (ID *)act, 0); return; } +#if 0 // XXX old animation system ob= G.main->object.first; while(ob) { if(ob->action==act) { @@ -135,17 +121,19 @@ void make_local_action(bAction *act) } ob= ob->id.next; } +#endif if(local && lib==0) { act->id.lib= 0; act->id.flag= LIB_LOCAL; - make_local_action_channels(act); + //make_local_action_channels(act); new_id(0, (ID *)act, 0); } else if(local && lib) { actn= copy_action(act); actn->id.us= 0; +#if 0 // XXX old animation system ob= G.main->object.first; while(ob) { if(ob->action==act) { @@ -158,24 +146,20 @@ void make_local_action(bAction *act) } ob= ob->id.next; } +#endif // XXX old animation system } } void free_action (bAction *act) { - bActionChannel *chan; + /* sanity check */ + if (act == NULL) + return; - /* Free channels */ - for (chan=act->chanbase.first; chan; chan=chan->next) { - if (chan->ipo) - chan->ipo->id.us--; - free_constraint_channels(&chan->constraintChannels); - } + /* Free F-Curves */ + free_fcurves(&act->curves); - if (act->chanbase.first) - BLI_freelistN(&act->chanbase); - /* Free groups */ if (act->groups.first) BLI_freelistN(&act->groups); @@ -188,42 +172,237 @@ void free_action (bAction *act) bAction *copy_action (bAction *src) { bAction *dst = NULL; - bActionChannel *dchan, *schan; bActionGroup *dgrp, *sgrp; + FCurve *dfcu, *sfcu; - if (!src) return NULL; - + if (src == NULL) + return NULL; dst= copy_libblock(src); - duplicatelist(&(dst->chanbase), &(src->chanbase)); - duplicatelist(&(dst->groups), &(src->groups)); - duplicatelist(&(dst->markers), &(src->markers)); + /* duplicate the lists of groups and markers */ + BLI_duplicatelist(&dst->groups, &src->groups); + BLI_duplicatelist(&dst->markers, &src->markers); - for (dchan=dst->chanbase.first, schan=src->chanbase.first; dchan; dchan=dchan->next, schan=schan->next) { + /* copy F-Curves, fixing up the links as we go */ + dst->curves.first= dst->curves.last= NULL; + + for (sfcu= src->curves.first; sfcu; sfcu= sfcu->next) { + /* duplicate F-Curve */ + dfcu= copy_fcurve(sfcu); + BLI_addtail(&dst->curves, dfcu); + + /* fix group links (kindof bad list-in-list search, but this is the most reliable way) */ for (dgrp=dst->groups.first, sgrp=src->groups.first; dgrp && sgrp; dgrp=dgrp->next, sgrp=sgrp->next) { - if (dchan->grp == sgrp) { - dchan->grp= dgrp; + if (sfcu->grp == sgrp) { + dfcu->grp= dgrp; - if (dgrp->channels.first == schan) - dgrp->channels.first= dchan; - if (dgrp->channels.last == schan) - dgrp->channels.last= dchan; + if (dgrp->channels.first == sfcu) + dgrp->channels.first= dfcu; + if (dgrp->channels.last == sfcu) + dgrp->channels.last= dfcu; break; } } - - dchan->ipo = copy_ipo(dchan->ipo); - copy_constraint_channels(&dchan->constraintChannels, &schan->constraintChannels); } - dst->id.flag |= LIB_FAKEUSER; + dst->id.flag |= LIB_FAKEUSER; // XXX this is nasty for new users... maybe we don't want this anymore dst->id.us++; return dst; } +/* Get the active action-group for an Action */ +bActionGroup *get_active_actiongroup (bAction *act) +{ + bActionGroup *agrp= NULL; + + if (act && act->groups.first) { + for (agrp= act->groups.first; agrp; agrp= agrp->next) { + if (agrp->flag & AGRP_ACTIVE) + break; + } + } + + return agrp; +} + +/* Make the given Action-Group the active one */ +void set_active_action_group (bAction *act, bActionGroup *agrp, short select) +{ + bActionGroup *grp; + + /* sanity checks */ + if (act == NULL) + return; + + /* Deactive all others */ + for (grp= act->groups.first; grp; grp= grp->next) { + if ((grp==agrp) && (select)) + grp->flag |= AGRP_ACTIVE; + else + grp->flag &= ~AGRP_ACTIVE; + } +} + +/* Add given channel into (active) group + * - assumes that channel is not linked to anything anymore + * - always adds at the end of the group + */ +void action_groups_add_channel (bAction *act, bActionGroup *agrp, FCurve *fcurve) +{ + FCurve *fcu; + short done=0; + + /* sanity checks */ + if (ELEM3(NULL, act, agrp, fcurve)) + return; + + /* if no channels, just add to two lists at the same time */ + if (act->curves.first == NULL) { + fcurve->next = fcurve->prev = NULL; + + agrp->channels.first = agrp->channels.last = fcurve; + act->curves.first = act->curves.last = fcurve; + + fcurve->grp= agrp; + return; + } + + /* try to find a channel to slot this in before/after */ + for (fcu= act->curves.first; fcu; fcu= fcu->next) { + /* if channel has no group, then we have ungrouped channels, which should always occur after groups */ + if (fcu->grp == NULL) { + BLI_insertlinkbefore(&act->curves, fcu, fcurve); + + if (agrp->channels.first == NULL) + agrp->channels.first= fcurve; + agrp->channels.last= fcurve; + + done= 1; + break; + } + + /* if channel has group after current, we can now insert (otherwise we have gone too far) */ + else if (fcu->grp == agrp->next) { + BLI_insertlinkbefore(&act->curves, fcu, fcurve); + + if (agrp->channels.first == NULL) + agrp->channels.first= fcurve; + agrp->channels.last= fcurve; + + done= 1; + break; + } + + /* if channel has group we're targeting, check whether it is the last one of these */ + else if (fcu->grp == agrp) { + if ((fcu->next) && (fcu->next->grp != agrp)) { + BLI_insertlinkafter(&act->curves, fcu, fcurve); + agrp->channels.last= fcurve; + done= 1; + break; + } + else if (fcu->next == NULL) { + BLI_addtail(&act->curves, fcurve); + agrp->channels.last= fcurve; + done= 1; + break; + } + } + + /* if channel has group before target, check whether the next one is something after target */ + else if (fcu->grp == agrp->prev) { + if (fcu->next) { + if ((fcu->next->grp != fcu->grp) && (fcu->next->grp != agrp)) { + BLI_insertlinkafter(&act->curves, fcu, fcurve); + + agrp->channels.first= fcurve; + agrp->channels.last= fcurve; + + done= 1; + break; + } + } + else { + BLI_insertlinkafter(&act->curves, fcu, fcurve); + + agrp->channels.first= fcurve; + agrp->channels.last= fcurve; + + done= 1; + break; + } + } + } + + /* only if added, set channel as belonging to this group */ + if (done) { + //printf("FCurve added to group \n"); + fcurve->grp= agrp; + } + else { + printf("Error: FCurve '%s' couldn't be added to Group '%s' \n", fcurve->rna_path, agrp->name); + BLI_addtail(&act->curves, fcurve); + } +} + +/* Remove the given channel from all groups */ +void action_groups_remove_channel (bAction *act, FCurve *fcu) +{ + /* sanity checks */ + if (ELEM(NULL, act, fcu)) + return; + + /* check if any group used this directly */ + if (fcu->grp) { + bActionGroup *agrp= fcu->grp; + + if (agrp->channels.first == agrp->channels.last) { + if (agrp->channels.first == fcu) { + agrp->channels.first= NULL; + agrp->channels.last= NULL; + } + } + else if (agrp->channels.first == fcu) { + if ((fcu->next) && (fcu->next->grp==agrp)) + agrp->channels.first= fcu->next; + else + agrp->channels.first= NULL; + } + else if (agrp->channels.last == fcu) { + if ((fcu->prev) && (fcu->prev->grp==agrp)) + agrp->channels.last= fcu->prev; + else + agrp->channels.last= NULL; + } + + fcu->grp= NULL; + } + + /* now just remove from list */ + BLI_remlink(&act->curves, fcu); +} + +/* Find a group with the given name */ +bActionGroup *action_groups_find_named (bAction *act, const char name[]) +{ + bActionGroup *grp; + + /* sanity checks */ + if (ELEM3(NULL, act, act->groups.first, name) || (name[0] == 0)) + return NULL; + + /* do string comparisons */ + for (grp= act->groups.first; grp; grp= grp->next) { + if (strcmp(grp->name, name) == 0) + return grp; + } + + /* not found */ + return NULL; +} /* ************************ Pose channels *************** */ @@ -232,12 +411,13 @@ bPoseChannel *get_pose_channel(const bPose *pose, const char *name) { bPoseChannel *chan; - if(pose==NULL) return NULL; + if (pose==NULL) return NULL; for (chan=pose->chanbase.first; chan; chan=chan->next) { - if(chan->name[0] == name[0]) + if (chan->name[0] == name[0]) { if (!strcmp (chan->name, name)) return chan; + } } return NULL; @@ -249,11 +429,10 @@ bPoseChannel *verify_pose_channel(bPose* pose, const char* name) { bPoseChannel *chan; - if (!pose) { + if (pose == NULL) return NULL; - } - /* See if this channel exists */ + /* See if this channel exists */ for (chan=pose->chanbase.first; chan; chan=chan->next) { if (!strcmp (name, chan->name)) return chan; @@ -262,10 +441,10 @@ bPoseChannel *verify_pose_channel(bPose* pose, const char* name) /* If not, create it and add it */ chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel"); - strncpy (chan->name, name, 31); + strncpy(chan->name, name, 31); /* init vars to prevent math errors */ - chan->quat[0] = 1.0F; - chan->size[0] = chan->size[1] = chan->size[2] = 1.0F; + chan->quat[0] = 1.0f; + chan->size[0] = chan->size[1] = chan->size[2] = 1.0f; chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f; chan->limitmax[0]= chan->limitmax[1]= chan->limitmax[2]= 180.0f; @@ -273,14 +452,32 @@ bPoseChannel *verify_pose_channel(bPose* pose, const char* name) Mat4One(chan->constinv); - BLI_addtail (&pose->chanbase, chan); + BLI_addtail(&pose->chanbase, chan); return chan; } +/* Find the active posechannel for an object (we can't just use pose, as layer info is in armature) */ +bPoseChannel *get_active_posechannel (Object *ob) +{ + bArmature *arm= (ob) ? ob->data : NULL; + bPoseChannel *pchan; + + if ELEM3(NULL, ob, ob->pose, arm) + return NULL; + + /* find active */ + for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if ((pchan->bone) && (pchan->bone->flag & BONE_ACTIVE) && (pchan->bone->layer & arm->layer)) + return pchan; + } + + return NULL; +} + /* dst should be freed already, makes entire duplicate */ -void copy_pose(bPose **dst, bPose *src, int copycon) +void copy_pose (bPose **dst, bPose *src, int copycon) { bPose *outPose; bPoseChannel *pchan; @@ -299,7 +496,7 @@ void copy_pose(bPose **dst, bPose *src, int copycon) outPose= MEM_callocN(sizeof(bPose), "pose"); - duplicatelist(&outPose->chanbase, &src->chanbase); + BLI_duplicatelist(&outPose->chanbase, &src->chanbase); if (copycon) { for (pchan=outPose->chanbase.first; pchan; pchan=pchan->next) { @@ -363,7 +560,7 @@ void game_copy_pose(bPose **dst, bPose *src) out= MEM_dupallocN(src); out->agroups.first= out->agroups.last= NULL; - duplicatelist(&out->chanbase, &src->chanbase); + BLI_duplicatelist(&out->chanbase, &src->chanbase); /* remap pointers */ ghash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); @@ -384,6 +581,77 @@ void game_copy_pose(bPose **dst, bPose *src) *dst=out; } + +/* Only allowed for Poses with identical channels */ +void game_blend_poses(bPose *dst, bPose *src, float srcweight/*, short mode*/) +{ + short mode= ACTSTRIPMODE_BLEND; + + bPoseChannel *dchan; + const bPoseChannel *schan; + bConstraint *dcon, *scon; + float dstweight; + int i; + + switch (mode){ + case ACTSTRIPMODE_BLEND: + dstweight = 1.0F - srcweight; + break; + case ACTSTRIPMODE_ADD: + dstweight = 1.0F; + break; + default : + dstweight = 1.0F; + } + + schan= src->chanbase.first; + for (dchan = dst->chanbase.first; dchan; dchan=dchan->next, schan= schan->next){ + if (schan->flag & (POSE_ROT|POSE_LOC|POSE_SIZE)) { + /* replaced quat->matrix->quat conversion with decent quaternion interpol (ton) */ + + /* Do the transformation blend */ + if (schan->flag & POSE_ROT) { + /* quat interpolation done separate */ + if (schan->rotmode == PCHAN_ROT_QUAT) { + float dquat[4], squat[4]; + + QUATCOPY(dquat, dchan->quat); + QUATCOPY(squat, schan->quat); + if (mode==ACTSTRIPMODE_BLEND) + QuatInterpol(dchan->quat, dquat, squat, srcweight); + else { + QuatMulFac(squat, srcweight); + QuatMul(dchan->quat, dquat, squat); + } + + NormalQuat(dchan->quat); + } + } + + for (i=0; i<3; i++) { + /* blending for loc and scale are pretty self-explanatory... */ + if (schan->flag & POSE_LOC) + dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight); + if (schan->flag & POSE_SIZE) + dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight); + + /* euler-rotation interpolation done here instead... */ + // FIXME: are these results decent? + if ((schan->flag & POSE_ROT) && (schan->rotmode)) + dchan->eul[i] = (dchan->eul[i]*dstweight) + (schan->eul[i]*srcweight); + } + dchan->flag |= schan->flag; + } + for(dcon= dchan->constraints.first, scon= schan->constraints.first; dcon && scon; dcon= dcon->next, scon= scon->next) { + /* no 'add' option for constraint blending */ + dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight; + } + } + + /* this pose is now in src time */ + dst->ctime= src->ctime; +} + void game_free_pose(bPose *pose) { if (pose) { @@ -401,7 +669,9 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan VECCOPY(pchan->loc, chan->loc); VECCOPY(pchan->size, chan->size); + VECCOPY(pchan->eul, chan->eul); QUATCOPY(pchan->quat, chan->quat); + pchan->rotmode= chan->rotmode; Mat4CpyMat4(pchan->chan_mat, (float(*)[4])chan->chan_mat); Mat4CpyMat4(pchan->pose_mat, (float(*)[4])chan->pose_mat); pchan->flag= chan->flag; @@ -495,100 +765,253 @@ void framechange_poses_clear_unkeyed(void) } } -/* ************************ END Pose channels *************** */ +/* ************************** Bone Groups ************************** */ -/* ************************ Action channels *************** */ - - -bActionChannel *get_action_channel(bAction *act, const char *name) +/* Adds a new bone-group */ +void pose_add_group (Object *ob) { - bActionChannel *chan; + bPose *pose= (ob) ? ob->pose : NULL; + bActionGroup *grp; - if (!act || !name) - return NULL; + if (ELEM(NULL, ob, ob->pose)) + return; - for (chan = act->chanbase.first; chan; chan=chan->next) { - if (!strcmp (chan->name, name)) - return chan; - } + grp= MEM_callocN(sizeof(bActionGroup), "PoseGroup"); + strcpy(grp->name, "Group"); + BLI_addtail(&pose->agroups, grp); + BLI_uniquename(&pose->agroups, grp, "Group", '.', offsetof(bActionGroup, name), 32); - return NULL; + pose->active_group= BLI_countlist(&pose->agroups); } -/* returns existing channel, or adds new one. In latter case it doesnt activate it, context is required for that */ -bActionChannel *verify_action_channel(bAction *act, const char *name) +/* Remove the active bone-group */ +void pose_remove_group (Object *ob) { - bActionChannel *chan; + bPose *pose= (ob) ? ob->pose : NULL; + bActionGroup *grp = NULL; + bPoseChannel *pchan; + + /* sanity checks */ + if (ELEM(NULL, ob, pose)) + return; + if (pose->active_group <= 0) + return; - chan= get_action_channel(act, name); - if (chan == NULL) { - chan = MEM_callocN (sizeof(bActionChannel), "actionChannel"); - strncpy(chan->name, name, 31); - BLI_addtail(&act->chanbase, chan); + /* get group to remove */ + grp= BLI_findlink(&pose->agroups, pose->active_group-1); + if (grp) { + /* adjust group references (the trouble of using indices!): + * - firstly, make sure nothing references it + * - also, make sure that those after this item get corrected + */ + for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { + if (pchan->agrp_index == pose->active_group) + pchan->agrp_index= 0; + else if (pchan->agrp_index > pose->active_group) + pchan->agrp_index--; + } + + /* now, remove it from the pose */ + BLI_freelinkN(&pose->agroups, grp); + pose->active_group= 0; } - return chan; } /* ************** time ****************** */ -static bActionStrip *get_active_strip(Object *ob) +/* Check if the given action has any keyframes */ +short action_has_motion(const bAction *act) { - bActionStrip *strip; + FCurve *fcu; - if(ob->action==NULL) - return NULL; - - for (strip=ob->nlastrips.first; strip; strip=strip->next) - if(strip->flag & ACTSTRIP_ACTIVE) - break; + /* return on the first F-Curve that has some keyframes/samples defined */ + if (act) { + for (fcu= act->curves.first; fcu; fcu= fcu->next) { + if (fcu->totvert) + return 1; + } + } - if(strip && strip->act==ob->action) - return strip; - return NULL; + /* nothing found */ + return 0; } -/* non clipped mapping of strip */ -static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert) +/* Calculate the extents of given action */ +void calc_action_range(const bAction *act, float *start, float *end, int incl_hidden) { - float length, actlength, repeat, scale; + FCurve *fcu; + float min=999999999.0f, max=-999999999.0f; + short foundvert=0; + + if (act) { + for (fcu= act->curves.first; fcu; fcu= fcu->next) { + if (fcu->totvert) { + float nmin, nmax; + + /* get extents for this curve */ + calc_fcurve_range(fcu, &nmin, &nmax); + + /* compare to the running tally */ + min= MIN2(min, nmin); + max= MAX2(max, nmax); + + foundvert= 1; + } + } + } - if (strip->repeat == 0.0f) strip->repeat = 1.0f; - repeat = (strip->flag & ACTSTRIP_USESTRIDE) ? (1.0f) : (strip->repeat); + if (foundvert) { + if(min==max) max+= 1.0f; + *start= min; + *end= max; + } + else { + *start= 0.0f; + *end= 1.0f; + } +} + +/* Copy the data from the action-pose (src) into the pose */ +/* both args are assumed to be valid */ +/* exported to game engine */ +/* Note! this assumes both poses are aligned, this isnt always true when dealing with user poses */ +void extract_pose_from_pose(bPose *pose, const bPose *src) +{ + const bPoseChannel *schan; + bPoseChannel *pchan= pose->chanbase.first; + + if (pose==src) { + printf("extract_pose_from_pose source and target are the same\n"); + return; + } + + for (schan=src->chanbase.first; (schan && pchan); schan=schan->next, pchan= pchan->next) { + copy_pose_channel_data(pchan, schan); + } +} + +/* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */ +void rest_pose(bPose *pose) +{ + bPoseChannel *pchan; + int i; - if (strip->scale == 0.0f) strip->scale= 1.0f; - scale = fabs(strip->scale); /* scale must be positive (for now) */ + if (!pose) + return; - actlength = strip->actend-strip->actstart; - if (actlength == 0.0f) actlength = 1.0f; - length = repeat * scale * actlength; + memset(pose->stride_offset, 0, sizeof(pose->stride_offset)); + memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset)); - /* invert = convert action-strip time to global time */ - if (invert) - return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start; - else - return repeat*actlength*(cframe - strip->start)/length + strip->actstart; + for (pchan=pose->chanbase.first; pchan; pchan= pchan->next){ + for (i=0; i<3; i++) { + pchan->loc[i]= 0.0f; + pchan->quat[i+1]= 0.0f; + pchan->eul[i]= 0.0f; + pchan->size[i]= 1.0f; + } + pchan->quat[0]= 1.0f; + + pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); + } } -/* if the conditions match, it converts current time to strip time */ -float get_action_frame(Object *ob, float cframe) +/* both poses should be in sync */ +void copy_pose_result(bPose *to, bPose *from) { - bActionStrip *strip= get_active_strip(ob); + bPoseChannel *pchanto, *pchanfrom; - if(strip) - return get_actionstrip_frame(strip, cframe, 0); - return cframe; + if(to==NULL || from==NULL) { + printf("pose result copy error\n"); // debug temp + return; + } + + if (to==from) { + printf("copy_pose_result source and target are the same\n"); + return; + } + + + for(pchanfrom= from->chanbase.first; pchanfrom; pchanfrom= pchanfrom->next) { + pchanto= get_pose_channel(to, pchanfrom->name); + if(pchanto) { + Mat4CpyMat4(pchanto->pose_mat, pchanfrom->pose_mat); + Mat4CpyMat4(pchanto->chan_mat, pchanfrom->chan_mat); + + /* used for local constraints */ + VECCOPY(pchanto->loc, pchanfrom->loc); + QUATCOPY(pchanto->quat, pchanfrom->quat); + VECCOPY(pchanto->eul, pchanfrom->eul); + VECCOPY(pchanto->size, pchanfrom->size); + + VECCOPY(pchanto->pose_head, pchanfrom->pose_head); + VECCOPY(pchanto->pose_tail, pchanfrom->pose_tail); + pchanto->flag= pchanfrom->flag; + } + } } -/* inverted, strip time to current time */ -float get_action_frame_inv(Object *ob, float cframe) +/* For the calculation of the effects of an Action at the given frame on an object + * This is currently only used for the Action Constraint + */ +void what_does_obaction (Scene *scene, Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe) { - bActionStrip *strip= get_active_strip(ob); + bActionGroup *agrp= action_groups_find_named(act, groupname); + + /* clear workob */ + clear_workob(workob); + + /* init workob */ + Mat4CpyMat4(workob->obmat, ob->obmat); + Mat4CpyMat4(workob->parentinv, ob->parentinv); + Mat4CpyMat4(workob->constinv, ob->constinv); + workob->parent= ob->parent; + workob->track= ob->track; + + workob->trackflag= ob->trackflag; + workob->upflag= ob->upflag; - if(strip) - return get_actionstrip_frame(strip, cframe, 1); - return cframe; + workob->partype= ob->partype; + workob->par1= ob->par1; + workob->par2= ob->par2; + workob->par3= ob->par3; + + workob->constraints.first = ob->constraints.first; + workob->constraints.last = ob->constraints.last; + + workob->pose= pose; /* need to set pose too, since this is used for both types of Action Constraint */ + + strcpy(workob->parsubstr, ob->parsubstr); + strcpy(workob->id.name, "OB<ConstrWorkOb>"); /* we don't use real object name, otherwise RNA screws with the real thing */ + + /* if we're given a group to use, it's likely to be more efficient (though a bit more dangerous) */ + if (agrp) { + /* specifically evaluate this group only */ + PointerRNA id_ptr; + + /* get RNA-pointer for the workob's ID */ + RNA_id_pointer_create(&workob->id, &id_ptr); + + /* execute action for this group only */ + animsys_evaluate_action_group(&id_ptr, act, agrp, NULL, cframe); + } + else { + AnimData adt; + + /* init animdata, and attach to workob */ + memset(&adt, 0, sizeof(AnimData)); + workob->adt= &adt; + + adt.recalc= ADT_RECALC_ANIM; + adt.action= act; + + /* execute effects of Action on to workob (or it's PoseChannels) */ + BKE_animsys_evaluate_animdata(&workob->id, &adt, cframe, ADT_RECALC_ANIM); + } } +/* ********** NLA with non-poses works with ipo channels ********** */ + +#if 0 // XXX OLD ANIMATION SYSTEM (TO BE REMOVED) /* ************************ Blending with NLA *************** */ @@ -690,227 +1113,6 @@ static void blend_pose_offset_bone(bActionStrip *strip, bPose *dst, bPose *src, VecAddf(dst->cyclic_offset, dst->cyclic_offset, src->cyclic_offset); } - -/* Only allowed for Poses with identical channels */ -void blend_poses(bPose *dst, bPose *src, float srcweight, short mode) -{ - bPoseChannel *dchan; - const bPoseChannel *schan; - bConstraint *dcon, *scon; - float dquat[4], squat[4]; - float dstweight; - int i; - - switch (mode){ - case ACTSTRIPMODE_BLEND: - dstweight = 1.0F - srcweight; - break; - case ACTSTRIPMODE_ADD: - dstweight = 1.0F; - break; - default : - dstweight = 1.0F; - } - - schan= src->chanbase.first; - for (dchan = dst->chanbase.first; dchan; dchan=dchan->next, schan= schan->next){ - if (schan->flag & (POSE_ROT|POSE_LOC|POSE_SIZE)) { - /* replaced quat->matrix->quat conversion with decent quaternion interpol (ton) */ - - /* Do the transformation blend */ - if (schan->flag & POSE_ROT) { - QUATCOPY(dquat, dchan->quat); - QUATCOPY(squat, schan->quat); - if(mode==ACTSTRIPMODE_BLEND) - QuatInterpol(dchan->quat, dquat, squat, srcweight); - else { - QuatMulFac(squat, srcweight); - QuatMul(dchan->quat, dquat, squat); - } - - NormalQuat (dchan->quat); - } - - for (i=0; i<3; i++){ - if (schan->flag & POSE_LOC) - dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight); - if (schan->flag & POSE_SIZE) - dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight); - } - dchan->flag |= schan->flag; - } - for(dcon= dchan->constraints.first, scon= schan->constraints.first; dcon && scon; dcon= dcon->next, scon= scon->next) { - /* no 'add' option for constraint blending */ - dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight; - } - } - - /* this pose is now in src time */ - dst->ctime= src->ctime; -} - - -void calc_action_range(const bAction *act, float *start, float *end, int incl_hidden) -{ - const bActionChannel *chan; - const bConstraintChannel *conchan; - const IpoCurve *icu; - float min=999999999.0f, max=-999999999.0; - int foundvert=0; - - if(act) { - for (chan=act->chanbase.first; chan; chan=chan->next) { - if(incl_hidden || (chan->flag & ACHAN_HIDDEN)==0) { - if(chan->ipo) { - for (icu=chan->ipo->curve.first; icu; icu=icu->next) { - if(icu->totvert) { - min= MIN2 (min, icu->bezt[0].vec[1][0]); - max= MAX2 (max, icu->bezt[icu->totvert-1].vec[1][0]); - foundvert=1; - } - } - } - for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) { - if(conchan->ipo) { - for (icu=conchan->ipo->curve.first; icu; icu=icu->next) { - if(icu->totvert) { - min= MIN2 (min, icu->bezt[0].vec[1][0]); - max= MAX2 (max, icu->bezt[icu->totvert-1].vec[1][0]); - foundvert=1; - } - } - } - } - } - } - } - if (foundvert) { - if(min==max) max+= 1.0f; - *start= min; - *end= max; - } - else { - *start= 0.0f; - *end= 1.0f; - } -} - -/* Copy the data from the action-pose (src) into the pose */ -/* both args are assumed to be valid */ -/* exported to game engine */ -/* Note! this assumes both poses are aligned, this isnt always true when dealing with user poses */ -void extract_pose_from_pose(bPose *pose, const bPose *src) -{ - const bPoseChannel *schan; - bPoseChannel *pchan= pose->chanbase.first; - - if (pose==src) { - printf("extract_pose_from_pose source and target are the same\n"); - return; - } - - for (schan=src->chanbase.first; (schan && pchan); schan=schan->next, pchan= pchan->next) { - copy_pose_channel_data(pchan, schan); - } -} - -/* Pose should exist, can have any number of channels too (used for constraint) */ -void extract_pose_from_action(bPose *pose, bAction *act, float ctime) -{ - bActionChannel *achan; - bPoseChannel *pchan; - Ipo *ipo; - - if (!act) - return; - if (!pose) - return; - - /* Copy the data from the action into the pose */ - for (pchan= pose->chanbase.first; pchan; pchan=pchan->next) { - /* skip this pose channel if it has been tagged as having unkeyed poses */ - if ((pchan->bone) && (pchan->bone->flag & BONE_UNKEYED)) - continue; - - /* get action channel and clear pchan-transform flags */ - achan= get_action_channel(act, pchan->name); - pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); - - if (achan) { - ipo = achan->ipo; - if (ipo) { - /* Evaluates and sets the internal ipo value */ - calc_ipo(ipo, ctime); - /* This call also sets the pchan flags */ - execute_action_ipo(achan, pchan); - } - /* 0 = do all ipos, not only drivers */ - do_constraint_channels(&pchan->constraints, &achan->constraintChannels, ctime, 0); - } - } - - pose->ctime= ctime; /* used for cyclic offset matching */ -} - -/* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */ -void rest_pose(bPose *pose) -{ - bPoseChannel *pchan; - int i; - - if (!pose) - return; - - memset(pose->stride_offset, 0, sizeof(pose->stride_offset)); - memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset)); - - for (pchan=pose->chanbase.first; pchan; pchan= pchan->next){ - for (i=0; i<3; i++) { - pchan->loc[i]= 0.0f; - pchan->quat[i+1]= 0.0f; - pchan->size[i]= 1.0f; - } - pchan->quat[0]= 1.0f; - - pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); - } -} - -/* both poses should be in sync */ -void copy_pose_result(bPose *to, bPose *from) -{ - bPoseChannel *pchanto, *pchanfrom; - - if(to==NULL || from==NULL) { - printf("pose result copy error\n"); // debug temp - return; - } - - if (to==from) { - printf("copy_pose_result source and target are the same\n"); - return; - } - - - for(pchanfrom= from->chanbase.first; pchanfrom; pchanfrom= pchanfrom->next) { - pchanto= get_pose_channel(to, pchanfrom->name); - if(pchanto) { - Mat4CpyMat4(pchanto->pose_mat, pchanfrom->pose_mat); - Mat4CpyMat4(pchanto->chan_mat, pchanfrom->chan_mat); - /* used for local constraints */ - VECCOPY(pchanto->loc, pchanfrom->loc); - QUATCOPY(pchanto->quat, pchanfrom->quat); - VECCOPY(pchanto->size, pchanfrom->size); - - VECCOPY(pchanto->pose_head, pchanfrom->pose_head); - VECCOPY(pchanto->pose_tail, pchanfrom->pose_tail); - pchanto->flag= pchanfrom->flag; - } - } -} - -/* ********** NLA with non-poses works with ipo channels ********** */ - typedef struct NlaIpoChannel { struct NlaIpoChannel *next, *prev; float val; @@ -1029,7 +1231,7 @@ int execute_ipochannels(ListBase *lb) /* this now only used for repeating cycles, to enable fields and blur. */ /* the whole time control in blender needs serious thinking... */ -static float nla_time(float cfra, float unit) +static float nla_time(Scene *scene, float cfra, float unit) { extern float bluroffs; // bad construct, borrowed from object.c for now extern float fieldoffs; @@ -1038,7 +1240,7 @@ static float nla_time(float cfra, float unit) cfra+= unit*(bluroffs+fieldoffs); /* global time */ - cfra*= G.scene->r.framelen; + cfra*= scene->r.framelen; return cfra; } @@ -1192,48 +1394,9 @@ static Object *get_parent_path(Object *ob) /* ************** do the action ************ */ -/* For the calculation of the effects of an action at the given frame on an object - * This is currently only used for the action constraint - */ -void what_does_obaction (Object *ob, bAction *act, float cframe) -{ - ListBase tchanbase= {NULL, NULL}; - - clear_workob(); - Mat4CpyMat4(workob.obmat, ob->obmat); - Mat4CpyMat4(workob.parentinv, ob->parentinv); - Mat4CpyMat4(workob.constinv, ob->constinv); - workob.parent= ob->parent; - workob.track= ob->track; - - workob.trackflag= ob->trackflag; - workob.upflag= ob->upflag; - - workob.partype= ob->partype; - workob.par1= ob->par1; - workob.par2= ob->par2; - workob.par3= ob->par3; - - workob.constraints.first = ob->constraints.first; - workob.constraints.last = ob->constraints.last; - - strcpy(workob.parsubstr, ob->parsubstr); - strcpy(workob.id.name, ob->id.name); - - /* extract_ipochannels_from_action needs id's! */ - workob.action= act; - - extract_ipochannels_from_action(&tchanbase, &workob.id, act, "Object", bsystem_time(&workob, cframe, 0.0)); - - if (tchanbase.first) { - execute_ipochannels(&tchanbase); - BLI_freelistN(&tchanbase); - } -} - /* ----- nla, etc. --------- */ -static void do_nla(Object *ob, int blocktype) +static void do_nla(Scene *scene, Object *ob, int blocktype) { bPose *tpose= NULL; Key *key= NULL; @@ -1241,7 +1404,7 @@ static void do_nla(Object *ob, int blocktype) bActionStrip *strip, *striplast=NULL, *stripfirst=NULL; float striptime, frametime, length, actlength; float blendfac, stripframe; - float scene_cfra= frame_to_float(G.scene->r.cfra); + float scene_cfra= frame_to_float(scene, scene->r.cfra); int doit, dostride; if(blocktype==ID_AR) { @@ -1307,11 +1470,11 @@ static void do_nla(Object *ob, int blocktype) if (cu->flag & CU_PATH){ /* Ensure we have a valid path */ - if(cu->path==NULL || cu->path->data==NULL) makeDispListCurveTypes(parent, 0); + if(cu->path==NULL || cu->path->data==NULL) makeDispListCurveTypes(scene, parent, 0); if(cu->path) { /* Find the position on the path */ - ctime= bsystem_time(ob, scene_cfra, 0.0); + ctime= bsystem_time(scene, ob, scene_cfra, 0.0); if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) { /* correct for actions not starting on zero */ @@ -1333,7 +1496,7 @@ static void do_nla(Object *ob, int blocktype) } frametime = (striptime * actlength) + strip->actstart; - frametime= bsystem_time(ob, frametime, 0.0); + frametime= bsystem_time(scene, ob, frametime, 0.0); if(blocktype==ID_AR) { extract_pose_from_action (tpose, strip->act, frametime); @@ -1363,7 +1526,7 @@ static void do_nla(Object *ob, int blocktype) } frametime = (striptime * actlength) + strip->actstart; - frametime= nla_time(frametime, (float)strip->repeat); + frametime= nla_time(scene, frametime, (float)strip->repeat); if(blocktype==ID_AR) { extract_pose_from_action (tpose, strip->act, frametime); @@ -1384,7 +1547,7 @@ static void do_nla(Object *ob, int blocktype) frametime = actlength * (strip->repeat-(int)strip->repeat); if(frametime<=0.000001f) frametime= actlength; /* rounding errors... */ - frametime= bsystem_time(ob, frametime+strip->actstart, 0.0); + frametime= bsystem_time(scene, ob, frametime+strip->actstart, 0.0); if(blocktype==ID_AR) extract_pose_from_action (tpose, strip->act, frametime); @@ -1449,55 +1612,4 @@ static void do_nla(Object *ob, int blocktype) BLI_freelistN(&chanbase); } -void do_all_pose_actions(Object *ob) -{ - /* only to have safe calls from editor */ - if(ob==NULL) return; - if(ob->type!=OB_ARMATURE || ob->pose==NULL) return; - - if(ob->pose->flag & POSE_LOCKED) { /* no actions to execute while transform */ - if(ob->pose->flag & POSE_DO_UNLOCK) - ob->pose->flag &= ~(POSE_LOCKED|POSE_DO_UNLOCK); - } - else if(ob->action && ((ob->nlaflag & OB_NLA_OVERRIDE)==0 || ob->nlastrips.first==NULL) ) { - float cframe= (float) G.scene->r.cfra; - - cframe= get_action_frame(ob, cframe); - - extract_pose_from_action (ob->pose, ob->action, bsystem_time(ob, cframe, 0.0)); - } - else if(ob->nlastrips.first) { - do_nla(ob, ID_AR); - } - - /* clear POSE_DO_UNLOCK flags that might have slipped through (just in case) */ - ob->pose->flag &= ~POSE_DO_UNLOCK; -} - -/* called from where_is_object */ -void do_all_object_actions(Object *ob) -{ - if(ob==NULL) return; - if(ob->dup_group) return; /* prevent conflicts, might add smarter check later */ - - /* Do local action */ - if(ob->action && ((ob->nlaflag & OB_NLA_OVERRIDE)==0 || ob->nlastrips.first==NULL) ) { - ListBase tchanbase= {NULL, NULL}; - Key *key= ob_get_key(ob); - float cframe= (float) G.scene->r.cfra; - - cframe= get_action_frame(ob, cframe); - - extract_ipochannels_from_action(&tchanbase, &ob->id, ob->action, "Object", bsystem_time(ob, cframe, 0.0)); - if(key) - extract_ipochannels_from_action(&tchanbase, &key->id, ob->action, "Shape", bsystem_time(ob, cframe, 0.0)); - - if(tchanbase.first) { - execute_ipochannels(&tchanbase); - BLI_freelistN(&tchanbase); - } - } - else if(ob->nlastrips.first) { - do_nla(ob, ID_OB); - } -} +#endif // XXX OLD ANIMATION SYSTEM (TO BE REMOVED) diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index ffb7ff51b87..6c1b8eb9000 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_editVert.h" #include "BLI_arithb.h" #include "BLI_rand.h" #include "DNA_listBase.h" @@ -68,13 +69,13 @@ #include "BKE_particle.h" #include "BKE_utildefines.h" -#include "BKE_bad_level_calls.h" - #ifdef HAVE_CONFIG_H #include <config.h> #endif -static void object_duplilist_recursive(ID *id, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated); +#include "ED_mesh.h" + +static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated); void free_path(Path *path) { @@ -100,8 +101,10 @@ void calc_curvepath(Object *ob) if(ob==NULL || ob->type != OB_CURVE) return; cu= ob->data; - if(ob==G.obedit) nu= editNurb.first; - else nu= cu->nurb.first; + if(cu->editnurb) + nu= cu->editnurb->first; + else + nu= cu->nurb.first; if(cu->path) free_path(cu->path); cu->path= NULL; @@ -301,7 +304,7 @@ static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], i return dob; } -static void group_duplilist(ListBase *lb, Object *ob, int level, int animated) +static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated) { DupliObject *dob; Group *group; @@ -316,7 +319,7 @@ static void group_duplilist(ListBase *lb, Object *ob, int level, int animated) /* handles animated groups, and */ /* we need to check update for objects that are not in scene... */ - group_handle_recalc_and_update(ob, group); + group_handle_recalc_and_update(scene, ob, group); animated= animated || group_is_animated(ob, group); for(go= group->gobject.first; go; go= go->next) { @@ -337,14 +340,14 @@ static void group_duplilist(ListBase *lb, Object *ob, int level, int animated) if(go->ob->transflag & OB_DUPLI) { Mat4CpyMat4(dob->ob->obmat, dob->mat); - object_duplilist_recursive((ID *)group, go->ob, lb, ob->obmat, level+1, animated); + object_duplilist_recursive((ID *)group, scene, go->ob, lb, ob->obmat, level+1, animated); Mat4CpyMat4(dob->ob->obmat, dob->omat); } } } } -static void frames_duplilist(ListBase *lb, Object *ob, int level, int animated) +static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated) { extern int enable_cu_speed; /* object.c */ Object copyob; @@ -354,31 +357,33 @@ static void frames_duplilist(ListBase *lb, Object *ob, int level, int animated) /* simple preventing of too deep nested groups */ if(level>MAX_DUPLI_RECUR) return; - cfrao= G.scene->r.cfra; + cfrao= scene->r.cfra; if(ob->parent==NULL && ob->track==NULL && ob->ipo==NULL && ob->constraints.first==NULL) return; if(ob->transflag & OB_DUPLINOSPEED) enable_cu_speed= 0; copyob= *ob; /* store transform info */ - for(G.scene->r.cfra= ob->dupsta; G.scene->r.cfra<=ob->dupend; G.scene->r.cfra++) { + for(scene->r.cfra= ob->dupsta; scene->r.cfra<=ob->dupend; scene->r.cfra++) { ok= 1; if(ob->dupoff) { - ok= G.scene->r.cfra - ob->dupsta; + ok= scene->r.cfra - ob->dupsta; ok= ok % (ob->dupon+ob->dupoff); if(ok < ob->dupon) ok= 1; else ok= 0; } if(ok) { - do_ob_ipo(ob); - where_is_object_time(ob, (float)G.scene->r.cfra); - dob= new_dupli_object(lb, ob, ob->obmat, ob->lay, G.scene->r.cfra, OB_DUPLIFRAMES, animated); +#if 0 // XXX old animation system + do_ob_ipo(scene, ob); +#endif // XXX old animation system + where_is_object_time(scene, ob, (float)scene->r.cfra); + dob= new_dupli_object(lb, ob, ob->obmat, ob->lay, scene->r.cfra, OB_DUPLIFRAMES, animated); Mat4CpyMat4(dob->omat, copyob.obmat); } } *ob= copyob; /* restore transform info */ - G.scene->r.cfra= cfrao; + scene->r.cfra= cfrao; enable_cu_speed= 1; } @@ -389,6 +394,7 @@ struct vertexDupliData { ListBase *lb; float pmat[4][4]; float obmat[4][4]; /* Only used for dupliverts inside dupligroups, where the ob->obmat is modified */ + Scene *scene; Object *ob, *par; float (*orco)[3]; }; @@ -429,36 +435,39 @@ static void vertex_dupli__mapFunc(void *userData, int index, float *co, float *n float tmpmat[4][4]; Mat4CpyMat4(tmpmat, vdd->ob->obmat); Mat4CpyMat4(vdd->ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)vdd->id, vdd->ob, vdd->lb, obmat, vdd->level+1, vdd->animated); + object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->level+1, vdd->animated); Mat4CpyMat4(vdd->ob->obmat, tmpmat); } } -static void vertex_duplilist(ListBase *lb, ID *id, Object *par, float par_space_mat[][4], int level, int animated) +static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) { Object *ob, *ob_iter; - Mesh *me; + Mesh *me= par->data; Base *base = NULL; - float vec[3], no[3], pmat[4][4]; - int lay, totvert, a, oblay; DerivedMesh *dm; struct vertexDupliData vdd; Scene *sce = NULL; Group *group = NULL; GroupObject * go = NULL; + EditMesh *em; + float vec[3], no[3], pmat[4][4]; + int lay, totvert, a, oblay; Mat4CpyMat4(pmat, par->obmat); /* simple preventing of too deep nested groups */ if(level>MAX_DUPLI_RECUR) return; - - if(par==G.obedit) - dm= editmesh_get_derived_cage(CD_MASK_BAREMESH); - else - dm= mesh_get_derived_deform(par, CD_MASK_BAREMESH); - + + em = BKE_mesh_get_editmesh(me); + + if(em) { + dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); + BKE_mesh_end_editmesh(me, em); + } else + dm= mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH); + if(G.rendering) { - me= par->data; vdd.orco= (float(*)[3])get_mesh_orco_verts(par); transform_mesh_orco_verts(me, vdd.orco, me->totvert, 0); } @@ -488,7 +497,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ oblay = ob_iter->lay; } - if (lay & oblay && G.obedit!=ob_iter) { + if (lay & oblay && scene->obedit!=ob_iter) { ob=ob_iter->parent; while(ob) { if(ob==par) { @@ -509,13 +518,14 @@ static void vertex_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ vdd.animated= animated; vdd.lb= lb; vdd.ob= ob; + vdd.scene= scene; vdd.par= par; Mat4CpyMat4(vdd.pmat, pmat); /* mballs have a different dupli handling */ if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ - if(par==G.obedit) { + if(par==scene->obedit) { dm->foreachMappedVert(dm, vertex_dupli__mapFunc, (void*) &vdd); } else { @@ -541,13 +551,13 @@ static void vertex_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ dm->release(dm); } -static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_mat[][4], int level, int animated) +static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) { Object *ob, *ob_iter; Base *base = NULL; DupliObject *dob; DerivedMesh *dm; - Mesh *me; + Mesh *me= par->data; MTFace *mtface; MFace *mface; MVert *mvert; @@ -556,16 +566,19 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma Scene *sce = NULL; Group *group = NULL; GroupObject *go = NULL; + EditMesh *em; float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */ /* simple preventing of too deep nested groups */ if(level>MAX_DUPLI_RECUR) return; Mat4CpyMat4(pmat, par->obmat); - - if(par==G.obedit) { + + em = BKE_mesh_get_editmesh(me); + if(em) { int totvert; - dm= editmesh_get_derived_cage(CD_MASK_BAREMESH); + + dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); totface= dm->getNumFaces(dm); mface= MEM_mallocN(sizeof(MFace)*totface, "mface temp"); @@ -573,9 +586,11 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma totvert= dm->getNumVerts(dm); mvert= MEM_mallocN(sizeof(MVert)*totvert, "mvert temp"); dm->copyVertArray(dm, mvert); + + BKE_mesh_end_editmesh(me, em); } else { - dm = mesh_get_derived_deform(par, CD_MASK_BAREMESH); + dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH); totface= dm->getNumFaces(dm); mface= dm->getFaceArray(dm); @@ -583,7 +598,6 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma } if(G.rendering) { - me= (Mesh*)par->data; orco= (float(*)[3])get_mesh_orco_verts(par); transform_mesh_orco_verts(me, orco, me->totvert, 0); @@ -615,7 +629,7 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma oblay = ob_iter->lay; } - if (lay & oblay && G.obedit!=ob_iter) { + if (lay & oblay && scene->obedit!=ob_iter) { ob=ob_iter->parent; while(ob) { if(ob==par) { @@ -708,7 +722,7 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma float tmpmat[4][4]; Mat4CpyMat4(tmpmat, ob->obmat); Mat4CpyMat4(ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)id, ob, lb, ob->obmat, level+1, animated); + object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level+1, animated); Mat4CpyMat4(ob->obmat, tmpmat); } } @@ -722,7 +736,7 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma else go= go->next; /* group loop */ } - if(par==G.obedit) { + if(par==scene->obedit) { MEM_freeN(mface); MEM_freeN(mvert); } @@ -733,7 +747,7 @@ static void face_duplilist(ListBase *lb, ID *id, Object *par, float par_space_ma dm->release(dm); } -static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated) +static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated) { GroupObject *go; Object *ob=0, **oblist=0, obcopy, *obcopylist=0; @@ -764,16 +778,17 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ if(!psys_check_enabled(par, psys)) return; - ctime = bsystem_time(par, (float)G.scene->r.cfra, 0.0); + ctime = bsystem_time(scene, par, (float)scene->r.cfra, 0.0); totpart = psys->totpart; totchild = psys->totchild; BLI_srandom(31415926 + psys->seed); - lay= G.scene->lay; - if((part->draw_as == PART_DRAW_OB && part->dup_ob) || - (part->draw_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first)) { + lay= scene->lay; + if((psys->renderdata || part->draw_as==PART_DRAW_REND) && + ((part->ren_as == PART_DRAW_OB && part->dup_ob) || + (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first))) { /* if we have a hair particle system, use the path cache */ if(part->type == PART_HAIR) { @@ -787,11 +802,11 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ totpart = psys->totcached; } - psys->lattice = psys_get_lattice(par, psys); + psys->lattice = psys_get_lattice(scene, par, psys); /* gather list of objects or single object */ - if(part->draw_as==PART_DRAW_GR) { - group_handle_recalc_and_update(par, part->dup_group); + if(part->ren_as==PART_DRAW_GR) { + group_handle_recalc_and_update(scene, par, part->dup_group); for(go=part->dup_group->gobject.first; go; go=go->next) totgroup++; @@ -836,7 +851,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ size = psys_get_child_size(psys, cpa, ctime, 0); } - if(part->draw_as==PART_DRAW_GR) { + if(part->ren_as==PART_DRAW_GR) { /* for groups, pick the object based on settings */ if(part->draw&PART_DRAW_RAND_GR) b= BLI_rand() % totgroup; @@ -872,7 +887,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ else { /* first key */ state.time = ctime; - if(psys_get_particle_state(par, psys, a, &state, 0) == 0) + if(psys_get_particle_state(scene, par, psys, a, &state, 0) == 0) continue; QuatToMat4(state.rot, pamat); @@ -880,7 +895,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ pamat[3][3]= 1.0f; } - if(part->draw_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { + if(part->ren_as==PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { for(go= part->dup_group->gobject.first, b=0; go; go= go->next, b++) { Mat4MulMat4(tmat, oblist[b]->obmat, pamat); Mat4MulFloat3((float *)tmat, size*scale); @@ -897,7 +912,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ } else { /* to give ipos in object correct offset */ - where_is_object_time(ob, ctime-pa_time); + where_is_object_time(scene, ob, ctime-pa_time); Mat4CpyMat4(mat, pamat); @@ -916,7 +931,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ } /* restore objects since they were changed in where_is_object_time */ - if(part->draw_as==PART_DRAW_GR) { + if(part->ren_as==PART_DRAW_GR) { for(a=0; a<totgroup; a++) *(oblist[a])= obcopylist[a]; } @@ -931,8 +946,8 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Object *par, float par_ MEM_freeN(obcopylist); if(psys->lattice) { - end_latt_deform(); - psys->lattice = 0; + end_latt_deform(psys->lattice); + psys->lattice = NULL; } } @@ -941,7 +956,7 @@ static Object *find_family_object(Object **obar, char *family, char ch) Object *ob; int flen; - if( obar[ch] ) return obar[ch]; + if( obar[(int)ch] ) return obar[(int)ch]; flen= strlen(family); @@ -953,13 +968,13 @@ static Object *find_family_object(Object **obar, char *family, char ch) ob= ob->id.next; } - obar[ch]= ob; + obar[(int)ch]= ob; return ob; } -static void font_duplilist(ListBase *lb, Object *par, int level, int animated) +static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int level, int animated) { Object *ob, *obar[256]; Curve *cu; @@ -974,7 +989,7 @@ static void font_duplilist(ListBase *lb, Object *par, int level, int animated) /* in par the family name is stored, use this to find the other objects */ - chartransdata= text_to_curve(par, FO_DUPLI); + chartransdata= BKE_text_to_curve(scene, par, FO_DUPLI); if(chartransdata==0) return; memset(obar, 0, 256*sizeof(void *)); @@ -1008,7 +1023,7 @@ static void font_duplilist(ListBase *lb, Object *par, int level, int animated) } /* ***************************** */ -static void object_duplilist_recursive(ID *id, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated) +static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated) { if((ob->transflag & OB_DUPLI)==0) return; @@ -1027,30 +1042,30 @@ static void object_duplilist_recursive(ID *id, Object *ob, ListBase *duplilist, if(ob->transflag & OB_DUPLIPARTS) { ParticleSystem *psys = ob->particlesystem.first; for(; psys; psys=psys->next) - new_particle_duplilist(duplilist, id, ob, par_space_mat, psys, level+1, animated); + new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, psys, level+1, animated); } else if(ob->transflag & OB_DUPLIVERTS) { if(ob->type==OB_MESH) { - vertex_duplilist(duplilist, id, ob, par_space_mat, level+1, animated); + vertex_duplilist(duplilist, id, scene, ob, par_space_mat, level+1, animated); } else if(ob->type==OB_FONT) { if (GS(id->name)==ID_SCE) { /* TODO - support dupligroups */ - font_duplilist(duplilist, ob, level+1, animated); + font_duplilist(duplilist, scene, ob, level+1, animated); } } } else if(ob->transflag & OB_DUPLIFACES) { if(ob->type==OB_MESH) - face_duplilist(duplilist, id, ob, par_space_mat, level+1, animated); + face_duplilist(duplilist, id, scene, ob, par_space_mat, level+1, animated); } else if(ob->transflag & OB_DUPLIFRAMES) { if (GS(id->name)==ID_SCE) { /* TODO - support dupligroups */ - frames_duplilist(duplilist, ob, level+1, animated); + frames_duplilist(duplilist, scene, ob, level+1, animated); } } else if(ob->transflag & OB_DUPLIGROUP) { DupliObject *dob; - group_duplilist(duplilist, ob, level+1, animated); /* now recursive */ + group_duplilist(duplilist, scene, ob, level+1, animated); /* now recursive */ if (level==0) { for(dob= duplilist->first; dob; dob= dob->next) @@ -1066,7 +1081,7 @@ ListBase *object_duplilist(Scene *sce, Object *ob) { ListBase *duplilist= MEM_mallocN(sizeof(ListBase), "duplilist"); duplilist->first= duplilist->last= NULL; - object_duplilist_recursive((ID *)sce, ob, duplilist, NULL, 0, 0); + object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0); return duplilist; } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c new file mode 100644 index 00000000000..983f1ecc31c --- /dev/null +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -0,0 +1,1498 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joshua Leung (full recode) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdio.h> +#include <string.h> +#include <stddef.h> +#include <float.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_dynstr.h" + +#include "DNA_anim_types.h" + +#include "BKE_animsys.h" +#include "BKE_action.h" +#include "BKE_fcurve.h" +#include "BKE_nla.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_utildefines.h" + +#include "RNA_access.h" +#include "RNA_types.h" + +#include "nla_private.h" + +/* ***************************************** */ +/* AnimData API */ + +/* Getter/Setter -------------------------------------------- */ + +/* Internal utility to check if ID can have AnimData */ +static short id_has_animdata (ID *id) +{ + /* sanity check */ + if (id == NULL) + return 0; + + /* Only some ID-blocks have this info for now */ + // TODO: finish adding this for the other blocktypes + switch (GS(id->name)) { + /* has AnimData */ + case ID_OB: + case ID_MB: case ID_CU: + case ID_KE: + case ID_PA: + case ID_MA: case ID_TE: case ID_NT: + case ID_LA: case ID_CA: case ID_WO: + case ID_SCE: + { + return 1; + } + + /* no AnimData */ + default: + return 0; + } +} + + +/* Get AnimData from the given ID-block. In order for this to work, we assume that + * the AnimData pointer is stored immediately after the given ID-block in the struct, + * as per IdAdtTemplate. + */ +AnimData *BKE_animdata_from_id (ID *id) +{ + /* only some ID-blocks have this info for now, so we cast the + * types that do to be of type IdAdtTemplate, and extract the + * AnimData that way + */ + if (id_has_animdata(id)) { + IdAdtTemplate *iat= (IdAdtTemplate *)id; + return iat->adt; + } + else + return NULL; +} + +/* Add AnimData to the given ID-block. In order for this to work, we assume that + * the AnimData pointer is stored immediately after the given ID-block in the struct, + * as per IdAdtTemplate. Also note that + */ +AnimData *BKE_id_add_animdata (ID *id) +{ + /* Only some ID-blocks have this info for now, so we cast the + * types that do to be of type IdAdtTemplate, and add the AnimData + * to it using the template + */ + if (id_has_animdata(id)) { + IdAdtTemplate *iat= (IdAdtTemplate *)id; + + /* check if there's already AnimData, in which case, don't add */ + if (iat->adt == NULL) { + AnimData *adt; + + /* add animdata */ + adt= iat->adt= MEM_callocN(sizeof(AnimData), "AnimData"); + + /* set default settings */ + adt->act_influence= 1.0f; + } + + return iat->adt; + } + else + return NULL; +} + +/* Freeing -------------------------------------------- */ + +/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */ +void BKE_free_animdata (ID *id) +{ + /* Only some ID-blocks have this info for now, so we cast the + * types that do to be of type IdAdtTemplate + */ + if (id_has_animdata(id)) { + IdAdtTemplate *iat= (IdAdtTemplate *)id; + AnimData *adt= iat->adt; + + /* check if there's any AnimData to start with */ + if (adt) { + /* unlink action (don't free, as it's in its own list) */ + if (adt->action) + adt->action->id.us--; + /* same goes for the temporarily displaced action */ + if (adt->tmpact) + adt->tmpact->id.us--; + + /* free nla data */ + free_nladata(&adt->nla_tracks); + + /* free drivers - stored as a list of F-Curves */ + free_fcurves(&adt->drivers); + + /* free overrides */ + // TODO... + + /* free animdata now */ + MEM_freeN(adt); + iat->adt= NULL; + } + } +} + +/* Freeing -------------------------------------------- */ + +/* Make a copy of the given AnimData - to be used when copying datablocks */ +AnimData *BKE_copy_animdata (AnimData *adt) +{ + AnimData *dadt; + + /* sanity check before duplicating struct */ + if (adt == NULL) + return NULL; + dadt= MEM_dupallocN(adt); + + /* make a copy of action - at worst, user has to delete copies... */ + // XXX review this... it might not be optimal behaviour yet... + //id_us_plus((ID *)dadt->action); + dadt->action= copy_action(adt->action); + dadt->tmpact= copy_action(adt->tmpact); + + /* duplicate NLA data */ + copy_nladata(&dadt->nla_tracks, &adt->nla_tracks); + + /* duplicate drivers (F-Curves) */ + copy_fcurves(&dadt->drivers, &adt->drivers); + + /* don't copy overrides */ + dadt->overrides.first= dadt->overrides.last= NULL; + + /* return */ + return dadt; +} + +/* *********************************** */ +/* KeyingSet API */ + +/* NOTES: + * It is very likely that there will be two copies of the api - one for internal use, + * and one 'operator' based wrapper of the internal API, which should allow for access + * from Python/scripts so that riggers can automate the creation of KeyingSets for their rigs. + */ + +/* Finding Tools --------------------------- */ + +/* Find the first path that matches the given criteria */ +// TODO: do we want some method to perform partial matches too? +KS_Path *BKE_keyingset_find_destination (KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, int group_mode) +{ + KS_Path *ksp; + + /* sanity checks */ + if ELEM(NULL, ks, rna_path) + return NULL; + + /* ID is optional for relative KeyingSets, but is necessary for absolute KeyingSets */ + if (id == NULL) { + if (ks->flag & KEYINGSET_ABSOLUTE) + return NULL; + } + + /* loop over paths in the current KeyingSet, finding the first one where all settings match + * (i.e. the first one where none of the checks fail and equal 0) + */ + for (ksp= ks->paths.first; ksp; ksp= ksp->next) { + short eq_id=1, eq_path=1, eq_index=1, eq_group=1; + + /* id */ + if ((ks->flag & KEYINGSET_ABSOLUTE) && (id != ksp->id)) + eq_id= 0; + + /* path */ + if ((ksp->rna_path==0) || strcmp(rna_path, ksp->rna_path)) + eq_path= 0; + + /* index */ + if (ksp->array_index != array_index) + eq_index= 0; + + /* group */ + if (group_name) { + // FIXME: these checks need to be coded... for now, it's not too important though + } + + /* if all aspects are ok, return */ + if (eq_id && eq_path && eq_index && eq_group) + return ksp; + } + + /* none found */ + return NULL; +} + +/* Defining Tools --------------------------- */ + +/* Used to create a new 'custom' KeyingSet for the user, that will be automatically added to the stack */ +KeyingSet *BKE_keyingset_add (ListBase *list, const char name[], short flag, short keyingflag) +{ + KeyingSet *ks; + + /* allocate new KeyingSet */ + ks= MEM_callocN(sizeof(KeyingSet), "KeyingSet"); + + if (name) + BLI_snprintf(ks->name, 64, name); + else + strcpy(ks->name, "Keying Set"); + + ks->flag= flag; + ks->keyingflag= keyingflag; + + /* add KeyingSet to list */ + BLI_addtail(list, ks); + + /* make sure KeyingSet has a unique name (this helps with identification) */ + BLI_uniquename(list, ks, "Keying Set", ' ', offsetof(KeyingSet, name), 64); + + /* return new KeyingSet for further editing */ + return ks; +} + +/* Add a destination to a KeyingSet. Nothing is returned for now... + * Checks are performed to ensure that destination is appropriate for the KeyingSet in question + */ +void BKE_keyingset_add_destination (KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode) +{ + KS_Path *ksp; + + /* sanity checks */ + if ELEM(NULL, ks, rna_path) + return; + + /* ID is optional for relative KeyingSets, but is necessary for absolute KeyingSets */ + if (id == NULL) { + if (ks->flag & KEYINGSET_ABSOLUTE) + return; + } + + /* don't add if there is already a matching KS_Path in the KeyingSet */ + if (BKE_keyingset_find_destination(ks, id, group_name, rna_path, array_index, groupmode)) + return; + + /* allocate a new KeyingSet Path */ + ksp= MEM_callocN(sizeof(KS_Path), "KeyingSet Path"); + + /* just store absolute info */ + if (ks->flag & KEYINGSET_ABSOLUTE) { + ksp->id= id; + if (group_name) + BLI_snprintf(ksp->group, 64, group_name); + else + strcpy(ksp->group, ""); + } + + /* store additional info for relative paths (just in case user makes the set relative) */ + if (id) + ksp->idtype= GS(id->name); + + /* just copy path info */ + // XXX no checks are performed for templates yet + // should array index be checked too? + ksp->rna_path= BLI_strdupn(rna_path, strlen(rna_path)); + ksp->array_index= array_index; + + /* store flags */ + ksp->flag= flag; + ksp->groupmode= groupmode; + + /* add KeyingSet path to KeyingSet */ + BLI_addtail(&ks->paths, ksp); +} + + +/* Freeing Tools --------------------------- */ + +/* Free data for KeyingSet but not set itself */ +void BKE_keyingset_free (KeyingSet *ks) +{ + KS_Path *ksp, *kspn; + + /* sanity check */ + if (ks == NULL) + return; + + /* free each path as we go to avoid looping twice */ + for (ksp= ks->paths.first; ksp; ksp= kspn) { + kspn= ksp->next; + + /* free RNA-path info */ + MEM_freeN(ksp->rna_path); + + /* free path itself */ + BLI_freelinkN(&ks->paths, ksp); + } +} + +/* Free all the KeyingSets in the given list */ +void BKE_keyingsets_free (ListBase *list) +{ + KeyingSet *ks, *ksn; + + /* sanity check */ + if (list == NULL) + return; + + /* loop over KeyingSets freeing them + * - BKE_keyingset_free() doesn't free the set itself, but it frees its sub-data + */ + for (ks= list->first; ks; ks= ksn) { + ksn= ks->next; + BKE_keyingset_free(ks); + BLI_freelinkN(list, ks); + } +} + +/* ***************************************** */ +/* Evaluation Data-Setting Backend */ + +/* Retrieve string to act as RNA-path, adjusted using mapping-table if provided + * It returns whether the string needs to be freed (i.e. if it was a temp remapped one) + * // FIXME: maybe it would be faster if we didn't have to alloc/free strings like this all the time, but for now it's safer + * + * - remap: remapping table to use + * - path: original path string (as stored in F-Curve data) + * - dst: destination string to write data to + */ +short animsys_remap_path (AnimMapper *remap, char *path, char **dst) +{ + /* is there a valid remapping table to use? */ + //if (remap) { + /* find a matching entry... to use to remap */ + // ...TODO... + //} + + /* nothing suitable found, so just set dst to look at path (i.e. no alloc/free needed) */ + *dst= path; + return 0; +} + + +/* Write the given value to a setting using RNA, and return success */ +static short animsys_write_rna_setting (PointerRNA *ptr, char *path, int array_index, float value) +{ + PropertyRNA *prop; + PointerRNA new_ptr; + + /* get property to write to */ + if (RNA_path_resolve(ptr, path, &new_ptr, &prop)) + { + /* set value - only for animatable numerical values */ + if (RNA_property_animateable(&new_ptr, prop)) + { + switch (RNA_property_type(prop)) + { + case PROP_BOOLEAN: + if (RNA_property_array_length(prop)) + RNA_property_boolean_set_index(&new_ptr, prop, array_index, (int)value); + else + RNA_property_boolean_set(&new_ptr, prop, (int)value); + break; + case PROP_INT: + if (RNA_property_array_length(prop)) + RNA_property_int_set_index(&new_ptr, prop, array_index, (int)value); + else + RNA_property_int_set(&new_ptr, prop, (int)value); + break; + case PROP_FLOAT: + if (RNA_property_array_length(prop)) + RNA_property_float_set_index(&new_ptr, prop, array_index, value); + else + RNA_property_float_set(&new_ptr, prop, value); + break; + case PROP_ENUM: + RNA_property_enum_set(&new_ptr, prop, (int)value); + break; + default: + /* nothing can be done here... so it is unsuccessful? */ + return 0; + } + } + + /* successful */ + return 1; + } + else { + /* failed to get path */ + // XXX don't tag as failed yet though, as there are some legit situations (Action Constraint) + // where some channels will not exist, but shouldn't lock up Action + if (G.f & G_DEBUG) { + printf("Animato: Invalid path. ID = '%s', '%s [%d]' \n", + (ptr && ptr->id.data) ? (((ID *)ptr->id.data)->name+2) : "<No ID>", + path, array_index); + } + return 0; + } +} + +/* Simple replacement based data-setting of the FCurve using RNA */ +static short animsys_execute_fcurve (PointerRNA *ptr, AnimMapper *remap, FCurve *fcu) +{ + char *path = NULL; + short free_path=0; + short ok= 0; + + /* get path, remapped as appropriate to work in its new environment */ + free_path= animsys_remap_path(remap, fcu->rna_path, &path); + + /* write value to setting */ + if (path) + ok= animsys_write_rna_setting(ptr, path, fcu->array_index, fcu->curval); + + /* free temp path-info */ + if (free_path) + MEM_freeN(path); + + /* return whether we were successful */ + return ok; +} + +/* Evaluate all the F-Curves in the given list + * This performs a set of standard checks. If extra checks are required, separate code should be used + */ +static void animsys_evaluate_fcurves (PointerRNA *ptr, ListBase *list, AnimMapper *remap, float ctime) +{ + FCurve *fcu; + + /* calculate then execute each curve */ + for (fcu= list->first; fcu; fcu= fcu->next) + { + /* check if this F-Curve doesn't belong to a muted group */ + if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED)==0) { + /* check if this curve should be skipped */ + if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0) + { + calculate_fcurve(fcu, ctime); + animsys_execute_fcurve(ptr, remap, fcu); + } + } + } +} + +/* ***************************************** */ +/* Driver Evaluation */ + +/* Evaluate Drivers */ +static void animsys_evaluate_drivers (PointerRNA *ptr, AnimData *adt, float ctime) +{ + FCurve *fcu; + + /* drivers are stored as F-Curves, but we cannot use the standard code, as we need to check if + * the depsgraph requested that this driver be evaluated... + */ + for (fcu= adt->drivers.first; fcu; fcu= fcu->next) + { + ChannelDriver *driver= fcu->driver; + short ok= 0; + + /* check if this driver's curve should be skipped */ + if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0) + { + /* check if driver itself is tagged for recalculation */ + if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID)/*&& (driver->flag & DRIVER_FLAG_RECALC)*/) { // XXX driver recalc flag is not set yet by depsgraph! + /* evaluate this using values set already in other places */ + // NOTE: for 'layering' option later on, we should check if we should remove old value before adding new to only be done when drivers only changed + calculate_fcurve(fcu, ctime); + ok= animsys_execute_fcurve(ptr, NULL, fcu); + + /* clear recalc flag */ + driver->flag &= ~DRIVER_FLAG_RECALC; + + /* set error-flag if evaluation failed */ + if (ok == 0) + driver->flag |= DRIVER_FLAG_INVALID; + } + } + } +} + +/* ***************************************** */ +/* Actions Evaluation */ + +/* Evaluate Action Group */ +void animsys_evaluate_action_group (PointerRNA *ptr, bAction *act, bActionGroup *agrp, AnimMapper *remap, float ctime) +{ + FCurve *fcu; + + /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ + if ELEM(NULL, act, agrp) return; + if ((remap) && (remap->target != act)) remap= NULL; + + /* if group is muted, don't evaluated any of the F-Curve */ + if (agrp->flag & AGRP_MUTED) + return; + + /* calculate then execute each curve */ + for (fcu= agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu= fcu->next) + { + /* check if this curve should be skipped */ + if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0) + { + calculate_fcurve(fcu, ctime); + animsys_execute_fcurve(ptr, remap, fcu); + } + } +} + +/* Evaluate Action (F-Curve Bag) */ +void animsys_evaluate_action (PointerRNA *ptr, bAction *act, AnimMapper *remap, float ctime) +{ + /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ + if (act == NULL) return; + if ((remap) && (remap->target != act)) remap= NULL; + + /* calculate then execute each curve */ + animsys_evaluate_fcurves(ptr, &act->curves, remap, ctime); +} + +/* ***************************************** */ +/* NLA System - Evaluation */ + +/* calculate influence of strip based for given frame based on blendin/out values */ +static float nlastrip_get_influence (NlaStrip *strip, float cframe) +{ + /* sanity checks - normalise the blendin/out values? */ + strip->blendin= (float)fabs(strip->blendin); + strip->blendout= (float)fabs(strip->blendout); + + /* result depends on where frame is in respect to blendin/out values */ + if (IS_EQ(strip->blendin, 0)==0 && (cframe <= (strip->start + strip->blendin))) { + /* there is some blend-in */ + return (float)fabs(cframe - strip->start) / (strip->blendin); + } + else if (IS_EQ(strip->blendout, 0)==0 && (cframe >= (strip->end - strip->blendout))) { + /* there is some blend-out */ + return (float)fabs(strip->end - cframe) / (strip->blendout); + } + else { + /* in the middle of the strip, we should be full strength */ + return 1.0f; + } +} + +/* evaluate the evaluation time and influence for the strip, storing the results in the strip */ +static void nlastrip_evaluate_controls (NlaStrip *strip, float ctime) +{ + /* firstly, analytically generate values for influence and time (if applicable) */ + if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0) + strip->strip_time= nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL); + if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0) + strip->influence= nlastrip_get_influence(strip, ctime); + + /* now strip's evaluate F-Curves for these settings (if applicable) */ + if (strip->fcurves.first) { + PointerRNA strip_ptr; + + /* create RNA-pointer needed to set values */ + RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr); + + /* execute these settings as per normal */ + animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime); + } +} + +/* gets the strip active at the current time for a list of strips for evaluation purposes */ +NlaEvalStrip *nlastrips_ctime_get_strip (ListBase *list, ListBase *strips, short index, float ctime) +{ + NlaStrip *strip, *estrip=NULL; + NlaEvalStrip *nes; + short side= 0; + + /* loop over strips, checking if they fall within the range */ + for (strip= strips->first; strip; strip= strip->next) { + /* check if current time occurs within this strip */ + if (IN_RANGE_INCL(ctime, strip->start, strip->end)) { + /* this strip is active, so try to use it */ + estrip= strip; + side= NES_TIME_WITHIN; + break; + } + + /* if time occurred before current strip... */ + if (ctime < strip->start) { + if (strip == strips->first) { + /* before first strip - only try to use it if it extends backwards in time too */ + if (strip->extendmode == NLASTRIP_EXTEND_HOLD) + estrip= strip; + + /* side is 'before' regardless of whether there's a useful strip */ + side= NES_TIME_BEFORE; + } + else { + /* before next strip - previous strip has ended, but next hasn't begun, + * so blending mode depends on whether strip is being held or not... + * - only occurs when no transition strip added, otherwise the transition would have + * been picked up above... + */ + strip= strip->prev; + + if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) + estrip= strip; + side= NES_TIME_AFTER; + } + break; + } + + /* if time occurred after current strip... */ + if (ctime > strip->end) { + /* only if this is the last strip should we do anything, and only if that is being held */ + if (strip == strips->last) { + if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) + estrip= strip; + + side= NES_TIME_AFTER; + break; + } + + /* otherwise, skip... as the 'before' case will catch it more elegantly! */ + } + } + + /* check if a valid strip was found + * - must not be muted (i.e. will have contribution + */ + if ((estrip == NULL) || (estrip->flag & NLASTRIP_FLAG_MUTED)) + return NULL; + + /* if ctime was not within the boundaries of the strip, clamp! */ + switch (side) { + case NES_TIME_BEFORE: /* extend first frame only */ + ctime= estrip->start; + break; + case NES_TIME_AFTER: /* extend last frame only */ + ctime= estrip->end; + break; + } + + /* evaluate strip's evaluation controls + * - skip if no influence (i.e. same effect as muting the strip) + * - negative influence is not supported yet... how would that be defined? + */ + // TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... + nlastrip_evaluate_controls(estrip, ctime); + if (estrip->influence <= 0.0f) + return NULL; + + /* check if strip has valid data to evaluate, + * and/or perform any additional type-specific actions + */ + switch (estrip->type) { + case NLASTRIP_TYPE_CLIP: + /* clip must have some action to evaluate */ + if (estrip->act == NULL) + return NULL; + break; + case NLASTRIP_TYPE_TRANSITION: + /* there must be strips to transition from and to (i.e. prev and next required) */ + if (ELEM(NULL, estrip->prev, estrip->next)) + return NULL; + + /* evaluate controls for the relevant extents of the bordering strips... */ + nlastrip_evaluate_controls(estrip->prev, estrip->start); + nlastrip_evaluate_controls(estrip->next, estrip->end); + break; + } + + /* add to list of strips we need to evaluate */ + nes= MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip"); + + nes->strip= estrip; + nes->strip_mode= side; + nes->track_index= index; + nes->strip_time= estrip->strip_time; + + if (list) + BLI_addtail(list, nes); + + return nes; +} + +/* ---------------------- */ + +/* find an NlaEvalChannel that matches the given criteria + * - ptr and prop are the RNA data to find a match for + */ +static NlaEvalChannel *nlaevalchan_find_match (ListBase *channels, PointerRNA *ptr, PropertyRNA *prop, int array_index) +{ + NlaEvalChannel *nec; + + /* sanity check */ + if (channels == NULL) + return NULL; + + /* loop through existing channels, checking for a channel which affects the same property */ + for (nec= channels->first; nec; nec= nec->next) { + /* - comparing the PointerRNA's is done by comparing the pointers + * to the actual struct the property resides in, since that all the + * other data stored in PointerRNA cannot allow us to definitively + * identify the data + */ + if ((nec->ptr.data == ptr->data) && (nec->prop == prop) && (nec->index == array_index)) + return nec; + } + + /* not found */ + return NULL; +} + +/* verify that an appropriate NlaEvalChannel for this F-Curve exists */ +static NlaEvalChannel *nlaevalchan_verify (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes, FCurve *fcu, short *newChan) +{ + NlaEvalChannel *nec; + NlaStrip *strip= nes->strip; + PropertyRNA *prop; + PointerRNA new_ptr; + char *path = NULL; + short free_path=0; + + /* sanity checks */ + if (channels == NULL) + return NULL; + + /* get RNA pointer+property info from F-Curve for more convenient handling */ + /* get path, remapped as appropriate to work in its new environment */ + free_path= animsys_remap_path(strip->remap, fcu->rna_path, &path); + + /* a valid property must be available, and it must be animateable */ + if (RNA_path_resolve(ptr, path, &new_ptr, &prop) == 0) { + if (G.f & G_DEBUG) printf("NLA Strip Eval: Cannot resolve path \n"); + return NULL; + } + /* only ok if animateable */ + else if (RNA_property_animateable(&new_ptr, prop) == 0) { + if (G.f & G_DEBUG) printf("NLA Strip Eval: Property not animateable \n"); + return NULL; + } + + /* try to find a match */ + nec= nlaevalchan_find_match(channels, &new_ptr, prop, fcu->array_index); + + /* allocate a new struct for this if none found */ + if (nec == NULL) { + nec= MEM_callocN(sizeof(NlaEvalChannel), "NlaEvalChannel"); + *newChan= 1; + BLI_addtail(channels, nec); + + nec->ptr= new_ptr; + nec->prop= prop; + nec->index= fcu->array_index; + } + else + *newChan= 0; + + /* we can now return */ + return nec; +} + +/* accumulate (i.e. blend) the given value on to the channel it affects */ +static void nlaevalchan_accumulate (NlaEvalChannel *nec, NlaEvalStrip *nes, short newChan, float value) +{ + NlaStrip *strip= nes->strip; + short blendmode= strip->blendmode; + float inf= strip->influence; + + /* if channel is new, just store value regardless of blending factors, etc. */ + if (newChan) { + nec->value= value; + return; + } + + /* if this is being performed as part of transition evaluation, incorporate + * an additional weighting factor for the influence + */ + if (nes->strip_mode == NES_TIME_TRANSITION_END) + inf *= nes->strip_time; + + /* premultiply the value by the weighting factor */ + if (IS_EQ(inf, 0)) return; + value *= inf; + + /* perform blending */ + switch (blendmode) { + case NLASTRIP_MODE_ADD: + /* simply add the scaled value on to the stack */ + nec->value += value; + break; + + case NLASTRIP_MODE_SUBTRACT: + /* simply subtract the scaled value from the stack */ + nec->value -= value; + break; + + case NLASTRIP_MODE_MULTIPLY: + /* multiply the scaled value with the stack */ + nec->value *= value; + break; + + case NLASTRIP_MODE_REPLACE: + default: // TODO: do we really want to blend by default? it seems more uses might prefer add... + /* do linear interpolation + * - the influence of the accumulated data (elsewhere, that is called dstweight) + * is 1 - influence, since the strip's influence is srcweight + */ + nec->value= nec->value * (1.0f - inf) + value; + break; + } +} + +/* accumulate the results of a temporary buffer with the results of the full-buffer */ +static void nlaevalchan_buffers_accumulate (ListBase *channels, ListBase *tmp_buffer, NlaEvalStrip *nes) +{ + NlaEvalChannel *nec, *necn, *necd; + + /* optimise - abort if no channels */ + if (tmp_buffer->first == NULL) + return; + + /* accumulate results in tmp_channels buffer to the accumulation buffer */ + for (nec= tmp_buffer->first; nec; nec= necn) { + /* get pointer to next channel in case we remove the current channel from the temp-buffer */ + necn= nec->next; + + /* try to find an existing matching channel for this setting in the accumulation buffer */ + necd= nlaevalchan_find_match(channels, &nec->ptr, nec->prop, nec->index); + + /* if there was a matching channel already in the buffer, accumulate to it, + * otherwise, add the current channel to the buffer for efficiency + */ + if (necd) + nlaevalchan_accumulate(necd, nes, 0, nec->value); + else { + BLI_remlink(tmp_buffer, nec); + BLI_addtail(channels, nec); + } + } + + /* free temp-channels that haven't been assimilated into the buffer */ + BLI_freelistN(tmp_buffer); +} + +/* ---------------------- */ +/* F-Modifier stack joining/separation utilities - should we generalise these for BLI_listbase.h interface? */ + +/* Temporarily join two lists of modifiers together, storing the result in a third list */ +static void nlaeval_fmodifiers_join_stacks (ListBase *result, ListBase *list1, ListBase *list2) +{ + FModifier *fcm1, *fcm2; + + /* if list1 is invalid... */ + if ELEM(NULL, list1, list1->first) { + if (list2 && list2->first) { + result->first= list2->first; + result->last= list2->last; + } + } + /* if list 2 is invalid... */ + else if ELEM(NULL, list2, list2->first) { + result->first= list1->first; + result->last= list1->last; + } + else { + /* list1 should be added first, and list2 second, with the endpoints of these being the endpoints for result + * - the original lists must be left unchanged though, as we need that fact for restoring + */ + result->first= list1->first; + result->last= list2->last; + + fcm1= list1->last; + fcm2= list2->first; + + fcm1->next= fcm2; + fcm2->prev= fcm1; + } +} + +/* Split two temporary lists of modifiers */ +static void nlaeval_fmodifiers_split_stacks (ListBase *list1, ListBase *list2) +{ + FModifier *fcm1, *fcm2; + + /* if list1/2 is invalid... just skip */ + if ELEM(NULL, list1, list2) + return; + if ELEM(NULL, list1->first, list2->first) + return; + + /* get endpoints */ + fcm1= list1->last; + fcm2= list2->first; + + /* clear their links */ + fcm1->next= NULL; + fcm2->prev= NULL; +} + +/* ---------------------- */ + +/* evaluate action-clip strip */ +static void nlastrip_evaluate_actionclip (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) +{ + ListBase tmp_modifiers = {NULL, NULL}; + NlaStrip *strip= nes->strip; + FCurve *fcu; + float evaltime; + + /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ + nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); + + /* evaluate strip's modifiers which modify time to evaluate the base curves at */ + evaltime= evaluate_time_fmodifiers(&tmp_modifiers, NULL, 0.0f, strip->strip_time); + + /* evaluate all the F-Curves in the action, saving the relevant pointers to data that will need to be used */ + for (fcu= strip->act->curves.first; fcu; fcu= fcu->next) { + NlaEvalChannel *nec; + float value = 0.0f; + short newChan = -1; + + /* check if this curve should be skipped */ + if (fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) + continue; + if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) + continue; + + /* evaluate the F-Curve's value for the time given in the strip + * NOTE: we use the modified time here, since strip's F-Curve Modifiers are applied on top of this + */ + value= evaluate_fcurve(fcu, evaltime); + + /* apply strip's F-Curve Modifiers on this value + * NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval) + */ + evaluate_value_fmodifiers(&tmp_modifiers, fcu, &value, strip->strip_time); + + + /* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s) + * stored in this channel if it has been used already + */ + nec= nlaevalchan_verify(ptr, channels, nes, fcu, &newChan); + if (nec) + nlaevalchan_accumulate(nec, nes, newChan, value); + } + + /* unlink this strip's modifiers from the parent's modifiers again */ + nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers); +} + +/* evaluate transition strip */ +static void nlastrip_evaluate_transition (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) +{ + ListBase tmp_channels = {NULL, NULL}; + ListBase tmp_modifiers = {NULL, NULL}; + NlaEvalStrip tmp_nes; + NlaStrip *s1, *s2; + + /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ + nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &nes->strip->modifiers, modifiers); + + /* get the two strips to operate on + * - we use the endpoints of the strips directly flanking our strip + * using these as the endpoints of the transition (destination and source) + * - these should have already been determined to be valid... + * - if this strip is being played in reverse, we need to swap these endpoints + * otherwise they will be interpolated wrong + */ + if (nes->strip->flag & NLASTRIP_FLAG_REVERSE) { + s1= nes->strip->next; + s2= nes->strip->prev; + } + else { + s1= nes->strip->prev; + s2= nes->strip->next; + } + + /* prepare template for 'evaluation strip' + * - based on the transition strip's evaluation strip data + * - strip_mode is NES_TIME_TRANSITION_* based on which endpoint + * - strip_time is the 'normalised' (i.e. in-strip) time for evaluation, + * which doubles up as an additional weighting factor for the strip influences + * which allows us to appear to be 'interpolating' between the two extremes + */ + tmp_nes= *nes; + + /* evaluate these strips into a temp-buffer (tmp_channels) */ + // FIXME: modifier evalation here needs some work... + /* first strip */ + tmp_nes.strip_mode= NES_TIME_TRANSITION_START; + tmp_nes.strip= s1; + nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes); + + /* second strip */ + tmp_nes.strip_mode= NES_TIME_TRANSITION_END; + tmp_nes.strip= s2; + nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes); + + + /* assumulate temp-buffer and full-buffer, using the 'real' strip */ + nlaevalchan_buffers_accumulate(channels, &tmp_channels, nes); + + /* unlink this strip's modifiers from the parent's modifiers again */ + nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers); +} + +/* evaluate meta-strip */ +static void nlastrip_evaluate_meta (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) +{ + ListBase tmp_channels = {NULL, NULL}; + ListBase tmp_modifiers = {NULL, NULL}; + NlaStrip *strip= nes->strip; + NlaEvalStrip *tmp_nes; + float evaltime; + + /* meta-strip was calculated normally to have some time to be evaluated at + * and here we 'look inside' the meta strip, treating it as a decorated window to + * it's child strips, which get evaluated as if they were some tracks on a strip + * (but with some extra modifiers to apply). + * + * NOTE: keep this in sync with animsys_evaluate_nla() + */ + + /* join this strip's modifiers to the parent's modifiers (own modifiers first) */ + nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers); + + /* find the child-strip to evaluate */ + evaltime= (nes->strip_time * (strip->end - strip->start)) + strip->start; + tmp_nes= nlastrips_ctime_get_strip(NULL, &strip->strips, -1, evaltime); + if (tmp_nes == NULL) + return; + + /* evaluate child-strip into tmp_channels buffer before accumulating + * in the accumulation buffer + */ + nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, tmp_nes); + + /* assumulate temp-buffer and full-buffer, using the 'real' strip */ + nlaevalchan_buffers_accumulate(channels, &tmp_channels, nes); + + /* free temp eval-strip */ + MEM_freeN(tmp_nes); + + /* unlink this strip's modifiers from the parent's modifiers again */ + nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers); +} + +/* evaluates the given evaluation strip */ +void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes) +{ + NlaStrip *strip= nes->strip; + + /* to prevent potential infinite recursion problems (i.e. transition strip, beside meta strip containing a transition + * several levels deep inside it), we tag the current strip as being evaluated, and clear this when we leave + */ + // TODO: be careful with this flag, since some edit tools may be running and have set this while animplayback was running + if (strip->flag & NLASTRIP_FLAG_EDIT_TOUCHED) + return; + strip->flag |= NLASTRIP_FLAG_EDIT_TOUCHED; + + /* actions to take depend on the type of strip */ + switch (strip->type) { + case NLASTRIP_TYPE_CLIP: /* action-clip */ + nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes); + break; + case NLASTRIP_TYPE_TRANSITION: /* transition */ + nlastrip_evaluate_transition(ptr, channels, modifiers, nes); + break; + case NLASTRIP_TYPE_META: /* meta */ + nlastrip_evaluate_meta(ptr, channels, modifiers, nes); + break; + } + + /* clear temp recursion safe-check */ + strip->flag &= ~NLASTRIP_FLAG_EDIT_TOUCHED; +} + +/* write the accumulated settings to */ +void nladata_flush_channels (ListBase *channels) +{ + NlaEvalChannel *nec; + + /* sanity checks */ + if (channels == NULL) + return; + + /* for each channel with accumulated values, write its value on the property it affects */ + for (nec= channels->first; nec; nec= nec->next) { + PointerRNA *ptr= &nec->ptr; + PropertyRNA *prop= nec->prop; + int array_index= nec->index; + float value= nec->value; + + /* write values - see animsys_write_rna_setting() to sync the code */ + switch (RNA_property_type(prop)) + { + case PROP_BOOLEAN: + if (RNA_property_array_length(prop)) + RNA_property_boolean_set_index(ptr, prop, array_index, (int)value); + else + RNA_property_boolean_set(ptr, prop, (int)value); + break; + case PROP_INT: + if (RNA_property_array_length(prop)) + RNA_property_int_set_index(ptr, prop, array_index, (int)value); + else + RNA_property_int_set(ptr, prop, (int)value); + break; + case PROP_FLOAT: + if (RNA_property_array_length(prop)) + RNA_property_float_set_index(ptr, prop, array_index, value); + else + RNA_property_float_set(ptr, prop, value); + break; + case PROP_ENUM: + RNA_property_enum_set(ptr, prop, (int)value); + break; + default: + // can't do anything with other types of property.... + break; + } + } +} + +/* ---------------------- */ + +/* NLA Evaluation function (mostly for use through do_animdata) + * - All channels that will be affected are not cleared anymore. Instead, we just evaluate into + * some temp channels, where values can be accumulated in one go. + */ +static void animsys_evaluate_nla (PointerRNA *ptr, AnimData *adt, float ctime) +{ + ListBase dummy_trackslist = {NULL, NULL}; + NlaStrip dummy_strip; + + NlaTrack *nlt; + short track_index=0; + short has_strips = 0; + + ListBase estrips= {NULL, NULL}; + ListBase echannels= {NULL, NULL}; + NlaEvalStrip *nes; + + // TODO: need to zero out all channels used, otherwise we have problems with threadsafety + // and also when the user jumps between different times instead of moving sequentially... + + /* 1. get the stack of strips to evaluate at current time (influence calculated here) */ + for (nlt=adt->nla_tracks.first; nlt; nlt=nlt->next, track_index++) { + /* if tweaking is on and this strip is the tweaking track, stop on this one */ + if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED)) + break; + + /* skip if we're only considering a track tagged 'solo' */ + if ((adt->flag & ADT_NLA_SOLO_TRACK) && (nlt->flag & NLATRACK_SOLO)==0) + continue; + /* skip if track is muted */ + if (nlt->flag & NLATRACK_MUTED) + continue; + + /* if this track has strips (but maybe they won't be suitable), set has_strips + * - used for mainly for still allowing normal action evaluation... + */ + if (nlt->strips.first) + has_strips= 1; + + /* otherwise, get strip to evaluate for this channel */ + nes= nlastrips_ctime_get_strip(&estrips, &nlt->strips, track_index, ctime); + if (nes) nes->track= nlt; + } + + /* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack + * - only do this if we're not exclusively evaluating the 'solo' NLA-track + */ + if ((adt->action) && !(adt->flag & ADT_NLA_SOLO_TRACK)) { + /* if there are strips, evaluate action as per NLA rules */ + if (has_strips) { + /* make dummy NLA strip, and add that to the stack */ + memset(&dummy_strip, 0, sizeof(NlaStrip)); + dummy_trackslist.first= dummy_trackslist.last= &dummy_strip; + + dummy_strip.act= adt->action; + dummy_strip.remap= adt->remap; + + // FIXME: what happens when we want to included F-Modifier access? + calc_action_range(dummy_strip.act, &dummy_strip.actstart, &dummy_strip.actend, 1); + dummy_strip.start = dummy_strip.actstart; + dummy_strip.end = (IS_EQ(dummy_strip.actstart, dummy_strip.actend)) ? (dummy_strip.actstart + 1.0f): (dummy_strip.actend); + + dummy_strip.blendmode= adt->act_blendmode; + dummy_strip.extendmode= adt->act_extendmode; + dummy_strip.influence= adt->act_influence; + + /* add this to our list of evaluation strips */ + nlastrips_ctime_get_strip(&estrips, &dummy_trackslist, -1, ctime); + } + else { + /* special case - evaluate as if there isn't any NLA data */ + // TODO: this is really just a stop-gap measure... + animsys_evaluate_action(ptr, adt->action, adt->remap, ctime); + return; + } + } + + /* only continue if there are strips to evaluate */ + if (estrips.first == NULL) + return; + + + /* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */ + for (nes= estrips.first; nes; nes= nes->next) + nlastrip_evaluate(ptr, &echannels, NULL, nes); + + /* 3. flush effects of accumulating channels in NLA to the actual data they affect */ + nladata_flush_channels(&echannels); + + /* 4. free temporary evaluation data */ + BLI_freelistN(&estrips); + BLI_freelistN(&echannels); +} + +/* ***************************************** */ +/* Overrides System - Public API */ + +/* Clear all overides */ + +/* Add or get existing Override for given setting */ +AnimOverride *BKE_animsys_validate_override (PointerRNA *ptr, char *path, int array_index) +{ + // FIXME: need to define how to get overrides + return NULL; +} + +/* -------------------- */ + +/* Evaluate Overrides */ +static void animsys_evaluate_overrides (PointerRNA *ptr, AnimData *adt, float ctime) +{ + AnimOverride *aor; + + /* for each override, simply execute... */ + for (aor= adt->overrides.first; aor; aor= aor->next) + animsys_write_rna_setting(ptr, aor->rna_path, aor->array_index, aor->value); +} + +/* ***************************************** */ +/* Evaluation System - Public API */ + +/* Overview of how this system works: + * 1) Depsgraph sorts data as necessary, so that data is in an order that means + * that all dependences are resolved before dependants. + * 2) All normal animation is evaluated, so that drivers have some basis values to + * work with + * a. NLA stacks are done first, as the Active Actions act as 'tweaking' tracks + * which modify the effects of the NLA-stacks + * b. Active Action is evaluated as per normal, on top of the results of the NLA tracks + * + * --------------< often in a separate phase... >------------------ + * + * 3) Drivers/expressions are evaluated on top of this, in an order where dependences are + * resolved nicely. + * Note: it may be necessary to have some tools to handle the cases where some higher-level + * drivers are added and cause some problematic dependencies that didn't exist in the local levels... + * + * --------------< always executed >------------------ + * + * Maintainance of editability of settings (XXX): + * In order to ensure that settings that are animated can still be manipulated in the UI without requiring + * that keyframes are added to prevent these values from being overwritten, we use 'overrides'. + * + * Unresolved things: + * - Handling of multi-user settings (i.e. time-offset, group-instancing) -> big cache grids or nodal system? but stored where? + * - Multiple-block dependencies (i.e. drivers for settings are in both local and higher levels) -> split into separate lists? + */ + +/* Evaluation loop for evaluation animation data + * + * This assumes that the animation-data provided belongs to the ID block in question, + * and that the flags for which parts of the anim-data settings need to be recalculated + * have been set already by the depsgraph. Now, we use the recalc + */ +void BKE_animsys_evaluate_animdata (ID *id, AnimData *adt, float ctime, short recalc) +{ + PointerRNA id_ptr; + + /* sanity checks */ + if ELEM(NULL, id, adt) + return; + + /* get pointer to ID-block for RNA to use */ + RNA_id_pointer_create(id, &id_ptr); + + /* recalculate keyframe data: + * - NLA before Active Action, as Active Action behaves as 'tweaking track' + * that overrides 'rough' work in NLA + */ + // TODO: need to double check that this all works correctly + if ((recalc & ADT_RECALC_ANIM) || (adt->recalc & ADT_RECALC_ANIM)) + { + /* evaluate NLA data */ + if ((adt->nla_tracks.first) && !(adt->flag & ADT_NLA_EVAL_OFF)) + { + /* evaluate NLA-stack + * - active action is evaluated as part of the NLA stack as the last item + */ + animsys_evaluate_nla(&id_ptr, adt, ctime); + } + /* evaluate Active Action only */ + else if (adt->action) + animsys_evaluate_action(&id_ptr, adt->action, adt->remap, ctime); + + /* reset tag */ + adt->recalc &= ~ADT_RECALC_ANIM; + } + + /* recalculate drivers + * - Drivers need to be evaluated afterwards, as they can either override + * or be layered on top of existing animation data. + * - Drivers should be in the appropriate order to be evaluated without problems... + */ + if ((recalc & ADT_RECALC_DRIVERS) /*&& (adt->recalc & ADT_RECALC_DRIVERS)*/) // XXX for now, don't check yet, as depsgraph hasn't been updated + { + animsys_evaluate_drivers(&id_ptr, adt, ctime); + } + + /* always execute 'overrides' + * - Overrides allow editing, by overwriting the value(s) set from animation-data, with the + * value last set by the user (and not keyframed yet). + * - Overrides are cleared upon frame change and/or keyframing + * - It is best that we execute this everytime, so that no errors are likely to occur. + */ + animsys_evaluate_overrides(&id_ptr, adt, ctime); + + /* clear recalc flag now */ + adt->recalc= 0; +} + +/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only + * + * This will evaluate only the animation info available in the animation data-blocks + * encountered. In order to enforce the system by which some settings controlled by a + * 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a + * standard 'root') block are overridden by a larger 'user' + */ +// FIXME?: we currently go over entire 'main' database... +void BKE_animsys_evaluate_all_animation (Main *main, float ctime) +{ + ID *id; + + if (G.f & G_DEBUG) + printf("Evaluate all animation - %f \n", ctime); + + /* macro for less typing + * - only evaluate animation data for id if it has users (and not just fake ones) + * - whether animdata exists is checked for by the evaluation function, though taking + * this outside of the function may make things slightly faster? + */ +#define EVAL_ANIM_IDS(first, aflag) \ + for (id= first; id; id= id->next) { \ + AnimData *adt= BKE_animdata_from_id(id); \ + if ( (id->us > 1) || (id->us && !(id->flag & LIB_FAKEUSER)) ) \ + BKE_animsys_evaluate_animdata(id, adt, ctime, aflag); \ + } + + /* optimisation: + * when there are no actions, don't go over database and loop over heaps of datablocks, + * which should ultimately be empty, since it is not possible for now to have any animation + * without some actions, and drivers wouldn't get affected by any state changes + */ + if (main->action.first == NULL) { + if (G.f & G_DEBUG) + printf("\tNo Actions, so no animation needs to be evaluated...\n"); + + return; + } + + /* nodes */ + // TODO... + + /* textures */ + EVAL_ANIM_IDS(main->tex.first, ADT_RECALC_ANIM); + + /* lamps */ + EVAL_ANIM_IDS(main->lamp.first, ADT_RECALC_ANIM); + + /* materials */ + EVAL_ANIM_IDS(main->mat.first, ADT_RECALC_ANIM); + + /* cameras */ + EVAL_ANIM_IDS(main->camera.first, ADT_RECALC_ANIM); + + /* shapekeys */ + // TODO: we probably need the same hack as for curves (ctime-hack) + EVAL_ANIM_IDS(main->key.first, ADT_RECALC_ANIM); + + /* metaballs */ + EVAL_ANIM_IDS(main->mball.first, ADT_RECALC_ANIM); + + /* curves */ + /* we need to perform a special hack here to ensure that the ctime + * value of the curve gets set in case there's no animation for that + * - it needs to be set before animation is evaluated just so that + * animation can successfully override... + */ + for (id= main->curve.first; id; id= id->next) { + AnimData *adt= BKE_animdata_from_id(id); + Curve *cu= (Curve *)id; + + cu->ctime= ctime; + BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM); + } + + /* meshes */ + // TODO... + + /* particles */ + EVAL_ANIM_IDS(main->particle.first, ADT_RECALC_ANIM); + + /* objects */ + /* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets + * this tagged by Depsgraph on framechange + */ + EVAL_ANIM_IDS(main->object.first, /*ADT_RECALC_ANIM*/0); + + /* worlds */ + EVAL_ANIM_IDS(main->world.first, ADT_RECALC_ANIM); + + /* scenes */ + EVAL_ANIM_IDS(main->scene.first, ADT_RECALC_ANIM); +} + +/* ***************************************** */ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 1577eb4f850..7b894d79b45 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -34,7 +34,7 @@ #include "MEM_guardedalloc.h" -#include "nla.h" +//XXX #include "nla.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" @@ -66,8 +66,7 @@ #include "BKE_object.h" #include "BKE_object.h" #include "BKE_utildefines.h" - -#include "BIF_editdeform.h" +#include "BKE_sketch.h" #include "IK_solver.h" @@ -77,23 +76,23 @@ /* **************** Generic Functions, data level *************** */ -bArmature *get_armature(Object *ob) -{ - if(ob==NULL) return NULL; - if(ob->type==OB_ARMATURE) return ob->data; - else return NULL; -} - bArmature *add_armature(char *name) { bArmature *arm; arm= alloc_libblock (&G.main->armature, ID_AR, name); arm->deformflag = ARM_DEF_VGROUP|ARM_DEF_ENVELOPE; + arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */ arm->layer= 1; return arm; } +bArmature *get_armature(Object *ob) +{ + if(ob->type==OB_ARMATURE) + return (bArmature *)ob->data; + return NULL; +} void free_boneChildren(Bone *bone) { @@ -133,6 +132,20 @@ void free_armature(bArmature *arm) if (arm) { /* unlink_armature(arm);*/ free_bones(arm); + + /* free editmode data */ + if (arm->edbo) { + BLI_freelistN(arm->edbo); + + MEM_freeN(arm->edbo); + arm->edbo= NULL; + } + + /* free sketch */ + if (arm->sketch) { + freeSketch(arm->sketch); + arm->sketch = NULL; + } } } @@ -180,7 +193,7 @@ static void copy_bonechildren (Bone* newBone, Bone* oldBone) Bone *curBone, *newChildBone; /* Copy this bone's list*/ - duplicatelist (&newBone->childbase, &oldBone->childbase); + BLI_duplicatelist(&newBone->childbase, &oldBone->childbase); /* For each child in the list, update it's children*/ newChildBone=newBone->childbase.first; @@ -197,7 +210,7 @@ bArmature *copy_armature(bArmature *arm) Bone *oldBone, *newBone; newArm= copy_libblock (arm); - duplicatelist(&newArm->bonebase, &arm->bonebase); + BLI_duplicatelist(&newArm->bonebase, &arm->bonebase); /* Duplicate the childrens' lists*/ newBone=newArm->bonebase.first; @@ -364,7 +377,7 @@ void bone_flip_name (char *name, int strip_number) */ void bone_autoside_name (char *name, int strip_number, short axis, float head, float tail) { - int len; + unsigned int len; char basename[32]={""}; char extension[5]={""}; @@ -607,7 +620,7 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest) Mat3Inv(imat3, mat3); Mat3MulMat3(mat3, result, imat3); // the matrix transforming vec_roll to desired roll - roll1= atan2(mat3[2][0], mat3[2][2]); + roll1= (float)atan2(mat3[2][0], mat3[2][2]); } } else { @@ -640,7 +653,7 @@ Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest) Mat3Inv(imat3, mat3); Mat3MulMat3(mat3, imat3, result); // the matrix transforming vec_roll to desired roll - roll2= atan2(mat3[2][0], mat3[2][2]); + roll2= (float)atan2(mat3[2][0], mat3[2][2]); /* and only now negate handle */ VecMulf(h2, -hlength2); @@ -785,7 +798,7 @@ float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, fl if(l!=0.0f) { rad= a/l; - rad= rad*rad2 + (1.0-rad)*rad1; + rad= rad*rad2 + (1.0f-rad)*rad1; } else rad= rad1; } @@ -799,8 +812,8 @@ float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, fl if(rdist==0.0f || dist >= l) return 0.0f; else { - a= sqrt(dist)-rad; - return 1.0-( a*a )/( rdist*rdist ); + a= (float)sqrt(dist)-rad; + return 1.0f-( a*a )/( rdist*rdist ); } } } @@ -906,6 +919,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, int numVerts, int deformflag, float (*prevCos)[3], const char *defgrp_name) { + bArmature *arm= armOb->data; bPoseChannel *pchan, **defnrToPC = NULL; MDeformVert *dverts = NULL; bDeformGroup *dg; @@ -921,7 +935,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, int armature_def_nr = -1; int totchan; - if(armOb == G.obedit) return; + if(arm->edbo) return; Mat4Invert(obinv, target->obmat); Mat4CpyMat4(premat, target->obmat); @@ -1216,7 +1230,10 @@ void armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float outm if (pchan==NULL) return; /* get the inverse matrix of the pchan's transforms */ - LocQuatSizeToMat4(pc_trans, pchan->loc, pchan->quat, pchan->size); + if (pchan->rotmode) + LocEulSizeToMat4(pc_trans, pchan->loc, pchan->eul, pchan->size); + else + LocQuatSizeToMat4(pc_trans, pchan->loc, pchan->quat, pchan->size); Mat4Invert(inv_trans, pc_trans); /* Remove the pchan's transforms from it's pose_mat. @@ -1298,7 +1315,7 @@ void mat3_to_vec_roll(float mat[][3], float *vec, float *roll) Mat3Inv(vecmatinv, vecmat); Mat3MulMat3(rollmat, vecmatinv, mat); - *roll= atan2(rollmat[2][0], rollmat[2][2]); + *roll= (float)atan2(rollmat[2][0], rollmat[2][2]); } } @@ -1330,7 +1347,7 @@ void vec_roll_to_mat3(float *vec, float roll, float mat[][3]) float updown; /* point same direction, or opposite? */ - updown = ( Inpf (target,nor) > 0 ) ? 1.0 : -1.0; + updown = ( Inpf (target,nor) > 0 ) ? 1.0f : -1.0f; /* I think this should work ... */ bMatrix[0][0]=updown; bMatrix[0][1]=0.0; bMatrix[0][2]=0.0; @@ -1433,7 +1450,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected * so syncing things correctly needs careful attention */ BLI_freelistN(&pose->agroups); - duplicatelist(&pose->agroups, &frompose->agroups); + BLI_duplicatelist(&pose->agroups, &frompose->agroups); pose->active_group= frompose->active_group; for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { @@ -1568,7 +1585,7 @@ static void initialize_posetree(struct Object *ob, bPoseChannel *pchan_tip) PoseTree *tree; PoseTarget *target; bConstraint *con; - bKinematicConstraint *data; + bKinematicConstraint *data= NULL; int a, segcount= 0, size, newsize, *oldparent, parent; /* find IK constraint, and validate it */ @@ -1786,10 +1803,10 @@ static void execute_posetree(Object *ob, PoseTree *tree) IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]); IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]); - if(tree->stretch && (pchan->ikstretch > 0.0)) { + if(tree->stretch && (pchan->ikstretch > 0.0f)) { float ikstretch = pchan->ikstretch*pchan->ikstretch; - IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.99)); - IK_SetLimit(seg, IK_TRANS_Y, 0.001, 1e10); + IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0f-ikstretch, 0.99f)); + IK_SetLimit(seg, IK_TRANS_Y, 0.001f, 1e10); } } @@ -1855,10 +1872,10 @@ static void execute_posetree(Object *ob, PoseTree *tree) } /* do we need blending? */ - if (!resultblend && target->con->enforce!=1.0) { + if (!resultblend && target->con->enforce!=1.0f) { float q1[4], q2[4], q[4]; float fac= target->con->enforce; - float mfac= 1.0-fac; + float mfac= 1.0f-fac; pchan= tree->pchan[target->tip]; @@ -1881,13 +1898,13 @@ static void execute_posetree(Object *ob, PoseTree *tree) iktarget= iktree[target->tip]; - if(data->weight != 0.0) { + if(data->weight != 0.0f) { if(poleconstrain) IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos, - polepos, data->poleangle*M_PI/180, (poleangledata == data)); + polepos, data->poleangle*(float)M_PI/180.0f, (poleangledata == data)); IK_SolverAddGoal(solver, iktarget, goalpos, data->weight); } - if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0)) + if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0f)) if((data->flag & CONSTRAINT_IK_AUTO)==0) IK_SolverAddGoalOrientation(solver, iktarget, goalrot, data->orientweight); @@ -1897,7 +1914,7 @@ static void execute_posetree(Object *ob, PoseTree *tree) IK_Solve(solver, 0.0f, tree->iterations); if(poleangledata) - poleangledata->poleangle= IK_SolverGetPoleAngle(solver)*180/M_PI; + poleangledata->poleangle= IK_SolverGetPoleAngle(solver)*180.0f/(float)M_PI; IK_FreeSolver(solver); @@ -1914,20 +1931,20 @@ static void execute_posetree(Object *ob, PoseTree *tree) float parentstretch, stretch; pchan= tree->pchan[a]; - parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0; + parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0f; - if(tree->stretch && (pchan->ikstretch > 0.0)) { + if(tree->stretch && (pchan->ikstretch > 0.0f)) { float trans[3], length; IK_GetTranslationChange(iktree[a], trans); length= pchan->bone->length*VecLength(pchan->pose_mat[1]); - ikstretch[a]= (length == 0.0)? 1.0: (trans[1]+length)/length; + ikstretch[a]= (length == 0.0f)? 1.0f: (trans[1]+length)/length; } else - ikstretch[a] = 1.0; + ikstretch[a] = 1.0f; - stretch= (parentstretch == 0.0)? 1.0: ikstretch[a]/parentstretch; + stretch= (parentstretch == 0.0f)? 1.0f: ikstretch[a]/parentstretch; VecMulf(tree->basis_change[a][0], stretch); VecMulf(tree->basis_change[a][1], stretch); @@ -1967,22 +1984,29 @@ void chan_calc_mat(bPoseChannel *chan) float rmat[3][3]; float tmat[3][3]; + /* get scaling matrix */ SizeToMat3(chan->size, smat); - NormalQuat(chan->quat); - - QuatToMat3(chan->quat, rmat); + /* rotations may either be quats or eulers (no rotation modes for now...) */ + if (chan->rotmode) { + /* euler rotations (will cause gimble lock... no rotation order to solve that yet) */ + EulToMat3(chan->eul, rmat); + } + else { + /* quats are normalised before use to eliminate scaling issues */ + NormalQuat(chan->quat); + QuatToMat3(chan->quat, rmat); + } + /* calculate matrix of bone (as 3x3 matrix, but then copy the 4x4) */ Mat3MulMat3(tmat, rmat, smat); - Mat4CpyMat3(chan->chan_mat, tmat); /* prevent action channels breaking chains */ /* need to check for bone here, CONSTRAINT_TYPE_ACTION uses this call */ - if (chan->bone==NULL || !(chan->bone->flag & BONE_CONNECTED)) { + if ((chan->bone==NULL) || !(chan->bone->flag & BONE_CONNECTED)) { VECCOPY(chan->chan_mat[3], chan->loc); } - } /* transform from bone(b) to bone(b+1), store in chan_mat */ @@ -2021,11 +2045,11 @@ static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[][3]) // nr = t } /* NLA strip modifiers */ -static void do_strip_modifiers(Object *armob, Bone *bone, bPoseChannel *pchan) +static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseChannel *pchan) { bActionModifier *amod; bActionStrip *strip, *strip2; - float scene_cfra= G.scene->r.cfra; + float scene_cfra= (float)scene->r.cfra; int do_modif; for (strip=armob->nlastrips.first; strip; strip=strip->next) { @@ -2074,7 +2098,7 @@ static void do_strip_modifiers(Object *armob, Bone *bone, bPoseChannel *pchan) if( strcmp(pchan->name, amod->channel)==0 ) { float mat4[4][4], mat3[3][3]; - curve_deform_vector(amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis); + curve_deform_vector(scene, amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis); Mat4CpyMat4(mat4, pchan->pose_mat); Mat4MulMat34(pchan->pose_mat, mat3, mat4); @@ -2145,7 +2169,7 @@ static void do_strip_modifiers(Object *armob, Bone *bone, bPoseChannel *pchan) /* The main armature solver, does all constraints excluding IK */ /* pchan is validated, as having bone and parent pointer */ -static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime) +static void where_is_pose_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float ctime) { Bone *bone, *parbone; bPoseChannel *parchan; @@ -2215,22 +2239,19 @@ static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime) } /* do NLA strip modifiers - i.e. curve follow */ - do_strip_modifiers(ob, bone, pchan); + do_strip_modifiers(scene, ob, bone, pchan); /* Do constraints */ if (pchan->constraints.first) { bConstraintOb *cob; - /* local constraints */ - do_constraint_channels(&pchan->constraints, NULL, ctime, 0); - /* make a copy of location of PoseChannel for later */ VECCOPY(vec, pchan->pose_mat[3]); /* prepare PoseChannel for Constraint solving * - makes a copy of matrix, and creates temporary struct to use */ - cob= constraints_make_evalob(ob, pchan, CONSTRAINT_OBTYPE_BONE); + cob= constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE); /* Solve PoseChannel's Constraints */ solve_constraints(&pchan->constraints, cob, ctime); // ctime doesnt alter objects @@ -2256,22 +2277,25 @@ static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime) /* This only reads anim data from channels, and writes to channels */ /* This is the only function adding poses */ -void where_is_pose (Object *ob) +void where_is_pose (Scene *scene, Object *ob) { bArmature *arm; Bone *bone; bPoseChannel *pchan; float imat[4][4]; - float ctime= bsystem_time(ob, (float)G.scene->r.cfra, 0.0); /* not accurate... */ + float ctime; - arm = get_armature(ob); + if(ob->type!=OB_ARMATURE) return; + arm = ob->data; - if(arm==NULL) return; - if(ob->pose==NULL || (ob->pose->flag & POSE_RECALC)) + if(ELEM(NULL, arm, scene)) return; + if((ob->pose==NULL) || (ob->pose->flag & POSE_RECALC)) armature_rebuild_pose(ob, arm); + + ctime= bsystem_time(scene, ob, (float)scene->r.cfra, 0.0); /* not accurate... */ - /* In restposition we read the data from the bones */ - if(ob==G.obedit || (arm->flag & ARM_RESTPOS)) { + /* In editmode or restposition we read the data from the bones */ + if(arm->edbo || (arm->flag & ARM_RESTPOS)) { for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { bone= pchan->bone; @@ -2304,7 +2328,7 @@ void where_is_pose (Object *ob) /* 4. walk over the tree for regular solving */ for(a=0; a<tree->totchannel; a++) { if(!(tree->pchan[a]->flag & POSE_DONE)) // successive trees can set the flag - where_is_pose_bone(ob, tree->pchan[a], ctime); + where_is_pose_bone(scene, ob, tree->pchan[a], ctime); } /* 5. execute the IK solver */ execute_posetree(ob, tree); @@ -2324,7 +2348,7 @@ void where_is_pose (Object *ob) } } else if(!(pchan->flag & POSE_DONE)) { - where_is_pose_bone(ob, pchan, ctime); + where_is_pose_bone(scene, ob, pchan, ctime); } } } diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 107953138c6..2e4e5596450 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -48,12 +48,16 @@ #include "MEM_guardedalloc.h" +#include "DNA_curve_types.h" #include "DNA_listBase.h" #include "DNA_sdna_types.h" #include "DNA_userdef_types.h" #include "DNA_object_types.h" -#include "DNA_curve_types.h" +#include "DNA_mesh_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_sound_types.h" +#include "DNA_sequence_types.h" #include "BLI_blenlib.h" #include "BLI_dynstr.h" @@ -61,21 +65,24 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "DNA_mesh_types.h" -#include "DNA_screen_types.h" - +#include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_blender.h" +#include "BKE_context.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" #include "BKE_displist.h" #include "BKE_font.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_ipo.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_object.h" +#include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_sequence.h" #include "BKE_sound.h" #include "BLI_editVert.h" @@ -84,15 +91,12 @@ #include "BLO_readfile.h" #include "BLO_writefile.h" -#include "BKE_bad_level_calls.h" // for freeAllRad editNurb free_editMesh free_editText free_editArmature #include "BKE_utildefines.h" // O_BINARY FALSE -#include "BIF_mainqueue.h" // mainqenter for onload script -#include "mydevice.h" -#include "nla.h" -#include "blendef.h" Global G; UserDef U; +ListBase WMlist= {NULL, NULL}; +short ENDIAN_ORDER; char versionstr[48]= ""; @@ -168,66 +172,42 @@ void pushpop_test() /* ********** free ********** */ +/* only to be called on exit blender */ void free_blender(void) { /* samples are in a global list..., also sets G.main->sound->sample NULL */ - sound_free_all_samples(); - free_main(G.main); G.main= NULL; + BKE_spacetypes_free(); /* after free main, it uses space callbacks */ + IMB_freeImBufdata(); /* imbuf lib */ free_nodesystem(); } -void duplicatelist(ListBase *list1, ListBase *list2) /* copy from 2 to 1 */ -{ - struct Link *link1, *link2; - - list1->first= list1->last= 0; - - link2= list2->first; - while(link2) { - - link1= MEM_dupallocN(link2); - BLI_addtail(list1, link1); - - link2= link2->next; - } -} - -static EditMesh theEditMesh; - void initglobals(void) { memset(&G, 0, sizeof(Global)); - memset(&theEditMesh, 0, sizeof(theEditMesh)); - G.editMesh = &theEditMesh; - U.savetime= 1; G.main= MEM_callocN(sizeof(Main), "initglobals"); strcpy(G.ima, "//"); - G.version= BLENDER_VERSION; - - G.order= 1; - G.order= (((char*)&G.order)[0])?L_ENDIAN:B_ENDIAN; + ENDIAN_ORDER= 1; + ENDIAN_ORDER= (((char*)&ENDIAN_ORDER)[0])? L_ENDIAN: B_ENDIAN; if(BLENDER_SUBVERSION) - sprintf(versionstr, "www.blender.org %d.%d", G.version, BLENDER_SUBVERSION); + sprintf(versionstr, "www.blender.org %d.%d", BLENDER_VERSION, BLENDER_SUBVERSION); else - sprintf(versionstr, "www.blender.org %d", G.version); + sprintf(versionstr, "www.blender.org %d", BLENDER_VERSION); #ifdef _WIN32 // FULLSCREEN G.windowstate = G_WINDOWSTATE_USERDEF; #endif - clear_workob(); /* object.c */ - G.charstart = 0x0000; G.charmin = 0x0000; G.charmax = 0xffff; @@ -237,37 +217,15 @@ void initglobals(void) static void clear_global(void) { - extern short winqueue_break; /* screen.c */ +// extern short winqueue_break; /* screen.c */ - freeAllRad(); fastshade_free_render(); /* lamps hang otherwise */ free_main(G.main); /* free all lib data */ - - /* force all queues to be left */ - winqueue_break= 1; - if (G.obedit) { - freeNurblist(&editNurb); - free_editMesh(G.editMesh); - free_editText(); - free_editArmature(); - } +// free_vertexpaint(); - G.curscreen= NULL; - G.scene= NULL; G.main= NULL; - G.obedit= NULL; - G.saction= NULL; - G.buts= NULL; - G.v2d= NULL; - G.vd= NULL; - G.soops= NULL; - G.sima= NULL; - G.sipo= NULL; - - free_vertexpaint(); - G.f &= ~(G_WEIGHTPAINT + G_VERTEXPAINT + G_FACESELECT + G_PARTICLEEDIT); } @@ -292,7 +250,7 @@ static void clean_paths(Main *main) } while(scene) { - ed= scene->ed; + ed= seq_give_editing(scene, 0); if(ed) { seq= ed->seqbasep->first; while(seq) { @@ -314,7 +272,10 @@ static void clean_paths(Main *main) } } -static void setup_app_data(BlendFileData *bfd, char *filename) +/* context matching */ +/* handle no-ui case */ + +static void setup_app_data(bContext *C, BlendFileData *bfd, char *filename) { Object *ob; bScreen *curscreen= NULL; @@ -328,16 +289,19 @@ static void setup_app_data(BlendFileData *bfd, char *filename) clean_paths(bfd->main); + /* XXX here the complex windowmanager matching */ + /* no load screens? */ if(mode) { /* comes from readfile.c */ - extern void lib_link_screen_restore(Main *, Scene *); + extern void lib_link_screen_restore(Main *, bScreen *, Scene *); + SWAP(ListBase, G.main->wm, bfd->main->wm); SWAP(ListBase, G.main->screen, bfd->main->screen); SWAP(ListBase, G.main->script, bfd->main->script); /* we re-use current screen */ - curscreen= G.curscreen; + curscreen= CTX_wm_screen(C); /* but use new Scene pointer */ curscene= bfd->curscene; if(curscene==NULL) curscene= bfd->main->scene.first; @@ -345,76 +309,79 @@ static void setup_app_data(BlendFileData *bfd, char *filename) curscreen->scene= curscene; /* clear_global will free G.main, here we can still restore pointers */ - lib_link_screen_restore(bfd->main, curscene); + lib_link_screen_restore(bfd->main, curscreen, curscene); } - clear_global(); /* free Main database */ - - if(mode!='u') G.save_over = 1; + /* free G.main Main database */ + clear_global(); G.main= bfd->main; + + CTX_data_main_set(C, G.main); + if (bfd->user) { /* only here free userdef themes... */ - BLI_freelistN(&U.themes); - + BKE_userdef_free(); + U= *bfd->user; MEM_freeN(bfd->user); - } - /* samples is a global list... */ - sound_free_all_samples(); - /* case G_FILE_NO_UI or no screens in file */ if(mode) { - G.curscreen= curscreen; - G.scene= curscene; + /* leave entire context further unaltered? */ + CTX_data_scene_set(C, curscene); } else { G.winpos= bfd->winpos; G.displaymode= bfd->displaymode; G.fileflags= bfd->fileflags; - G.curscreen= bfd->curscreen; - G.scene= G.curscreen->scene; + + CTX_wm_screen_set(C, bfd->curscreen); + CTX_data_scene_set(C, bfd->curscreen->scene); + CTX_wm_area_set(C, NULL); + CTX_wm_region_set(C, NULL); + CTX_wm_menu_set(C, NULL); } + /* this can happen when active scene was lib-linked, and doesnt exist anymore */ - if(G.scene==NULL) { - G.scene= G.main->scene.first; - G.curscreen->scene= G.scene; + if(CTX_data_scene(C)==NULL) { + CTX_data_scene_set(C, bfd->main->scene.first); + CTX_wm_screen(C)->scene= CTX_data_scene(C); + curscene= CTX_data_scene(C); } /* special cases, override loaded flags: */ if (G.f & G_DEBUG) bfd->globalf |= G_DEBUG; else bfd->globalf &= ~G_DEBUG; + if (G.f & G_SWAP_EXCHANGE) bfd->globalf |= G_SWAP_EXCHANGE; + else bfd->globalf &= ~G_SWAP_EXCHANGE; if ((U.flag & USER_DONT_DOSCRIPTLINKS)) bfd->globalf &= ~G_DOSCRIPTLINKS; G.f= bfd->globalf; if (!G.background) { - setscreen(G.curscreen); + //setscreen(G.curscreen); } + // XXX temporarily here + if(G.main->versionfile < 250) + do_versions_ipos_to_animato(G.main); // XXX fixme... complicated versionpatching + /* baseflags, groups, make depsgraph, etc */ - set_scene_bg(G.scene); - - /* clear BONE_UNKEYED flags, these are not valid anymore for proxies */ - framechange_poses_clear_unkeyed(); + set_scene_bg(CTX_data_scene(C)); /* last stage of do_versions actually, that sets recalc flags for recalc poses */ for(ob= G.main->object.first; ob; ob= ob->id.next) { if(ob->type==OB_ARMATURE) - if(ob->recalc) object_handle_update(ob); + if(ob->recalc) object_handle_update(CTX_data_scene(C), ob); } /* now tag update flags, to ensure deformers get calculated on redraw */ - DAG_scene_update_flags(G.scene, G.scene->lay); + DAG_scene_update_flags(CTX_data_scene(C), CTX_data_scene(C)->lay); - if (G.f & G_DOSCRIPTLINKS) { - /* there's an onload scriptlink to execute in screenmain */ - mainqenter(ONLOAD_SCRIPT, 1); - } if (G.sce != filename) /* these are the same at times, should never copy to the same location */ strcpy(G.sce, filename); @@ -430,44 +397,36 @@ static int handle_subversion_warning(Main *main) main->minsubversionfile > BLENDER_SUBVERSION)) { char str[128]; - - /* XXX DO NOT PORT OVER TO 2.5 BRANCH! */ - if(main->minversionfile >= 250) { - sprintf(str, "You have opened a %d file, key information will get lost, like animation data. Continue?", main->minversionfile); - - if(G.background) { - printf("ERROR: cannot render %d file\n", main->versionfile); - } - return okee(str); - } - else { - sprintf(str, "File written by newer Blender binary: %d.%d , expect loss of data!", main->minversionfile, main->minsubversionfile); - error(str); - } + + sprintf(str, "File written by newer Blender binary: %d.%d , expect loss of data!", main->minversionfile, main->minsubversionfile); +// XXX error(str); } return 1; } +void BKE_userdef_free(void) +{ + + BLI_freelistN(&U.uistyles); + BLI_freelistN(&U.uifonts); + BLI_freelistN(&U.themes); + +} + /* returns: 0: no load file 1: OK 2: OK, and with new user settings */ -int BKE_read_file(char *dir, void *type_r) +int BKE_read_file(bContext *C, char *dir, void *unused, ReportList *reports) { - BlendReadError bre; BlendFileData *bfd; int retval= 1; - - if (!G.background) - waitcursor(1); - - bfd= BLO_read_from_file(dir, &bre); + + bfd= BLO_read_from_file(dir, reports); if (bfd) { if(bfd->user) retval= 2; - if (type_r) - *((BlenFileType*)type_r)= bfd->type; if(0==handle_subversion_warning(bfd->main)) { free_main(bfd->main); @@ -476,63 +435,59 @@ int BKE_read_file(char *dir, void *type_r) retval= 0; } else - setup_app_data(bfd, dir); // frees BFD - + setup_app_data(C, bfd, dir); // frees BFD } - else { - error("Loading %s failed: %s", dir, BLO_bre_as_string(bre)); - } - - if (!G.background) - waitcursor(0); - + else + BKE_reports_prependf(reports, "Loading %s failed: ", dir); + return (bfd?retval:0); } -int BKE_read_file_from_memory(char* filebuf, int filelength, void *type_r) +int BKE_read_file_from_memory(bContext *C, char* filebuf, int filelength, void *unused, ReportList *reports) { - BlendReadError bre; BlendFileData *bfd; - - if (!G.background) - waitcursor(1); - - bfd= BLO_read_from_memory(filebuf, filelength, &bre); - if (bfd) { - if (type_r) - *((BlenFileType*)type_r)= bfd->type; - - setup_app_data(bfd, "<memory2>"); - } else { - error("Loading failed: %s", BLO_bre_as_string(bre)); - } - - if (!G.background) - waitcursor(0); - + + bfd= BLO_read_from_memory(filebuf, filelength, reports); + if (bfd) + setup_app_data(C, bfd, "<memory2>"); + else + BKE_reports_prepend(reports, "Loading failed: "); + return (bfd?1:0); } /* memfile is the undo buffer */ -int BKE_read_file_from_memfile(MemFile *memfile) +int BKE_read_file_from_memfile(bContext *C, MemFile *memfile, ReportList *reports) { - BlendReadError bre; BlendFileData *bfd; - - if (!G.background) - waitcursor(1); - - bfd= BLO_read_from_memfile(G.sce, memfile, &bre); - if (bfd) { - setup_app_data(bfd, "<memory1>"); - } else { - error("Loading failed: %s", BLO_bre_as_string(bre)); + + bfd= BLO_read_from_memfile(CTX_data_main(C), G.sce, memfile, reports); + if (bfd) + setup_app_data(C, bfd, "<memory1>"); + else + BKE_reports_prepend(reports, "Loading failed: "); + + return (bfd?1:0); +} + +/* ***************** testing for break ************* */ + +static void (*blender_test_break_cb)(void)= NULL; + +void set_blender_test_break_cb(void (*func)(void) ) +{ + blender_test_break_cb= func; +} + + +int blender_test_break(void) +{ + if (!G.background) { + if (blender_test_break_cb) + blender_test_break_cb(); } - if (!G.background) - waitcursor(0); - - return (bfd?1:0); + return (G.afbreek==1); } @@ -553,7 +508,7 @@ static ListBase undobase={NULL, NULL}; static UndoElem *curundo= NULL; -static int read_undosave(UndoElem *uel) +static int read_undosave(bContext *C, UndoElem *uel) { char scestr[FILE_MAXDIR+FILE_MAXFILE]; int success=0, fileflags; @@ -563,10 +518,10 @@ static int read_undosave(UndoElem *uel) G.fileflags |= G_FILE_NO_UI; if(UNDO_DISK) - success= BKE_read_file(uel->str, NULL); + success= BKE_read_file(C, uel->str, NULL, NULL); else - success= BKE_read_file_from_memfile(&uel->memfile); - + success= BKE_read_file_from_memfile(C, &uel->memfile, NULL); + /* restore */ strcpy(G.sce, scestr); G.fileflags= fileflags; @@ -575,7 +530,7 @@ static int read_undosave(UndoElem *uel) } /* name can be a dynamic string */ -void BKE_write_undo(char *name) +void BKE_write_undo(bContext *C, char *name) { uintptr_t maxmem, totmem, memused; int nr, success; @@ -619,7 +574,7 @@ void BKE_write_undo(char *name) /* disk save version */ if(UNDO_DISK) { static int counter= 0; - char *err, tstr[FILE_MAXDIR+FILE_MAXFILE]; + char tstr[FILE_MAXDIR+FILE_MAXFILE]; char numstr[32]; /* calculate current filename */ @@ -629,18 +584,17 @@ void BKE_write_undo(char *name) sprintf(numstr, "%d.blend", counter); BLI_make_file_string("/", tstr, btempdir, numstr); - success= BLO_write_file(tstr, G.fileflags, &err); + success= BLO_write_file(CTX_data_main(C), tstr, G.fileflags, NULL); strcpy(curundo->str, tstr); } else { MemFile *prevfile=NULL; - char *err; if(curundo->prev) prevfile= &(curundo->prev->memfile); memused= MEM_get_memory_in_use(); - success= BLO_write_file_mem(prevfile, &curundo->memfile, G.fileflags, &err); + success= BLO_write_file_mem(CTX_data_main(C), prevfile, &curundo->memfile, G.fileflags, NULL); curundo->undosize= MEM_get_memory_in_use() - memused; } @@ -674,28 +628,28 @@ void BKE_write_undo(char *name) /* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation * Note, ALWAYS call sound_initialize_sounds after BKE_undo_step() */ -void BKE_undo_step(int step) +void BKE_undo_step(bContext *C, int step) { if(step==0) { - read_undosave(curundo); + read_undosave(C, curundo); } else if(step==1) { /* curundo should never be NULL, after restart or load file it should call undo_save */ - if(curundo==NULL || curundo->prev==NULL) error("No undo available"); + if(curundo==NULL || curundo->prev==NULL) ; // XXX error("No undo available"); else { if(G.f & G_DEBUG) printf("undo %s\n", curundo->name); curundo= curundo->prev; - read_undosave(curundo); + read_undosave(C, curundo); } } else { /* curundo has to remain current situation! */ - if(curundo==NULL || curundo->next==NULL) error("No redo available"); + if(curundo==NULL || curundo->next==NULL) ; // XXX error("No redo available"); else { - read_undosave(curundo->next); + read_undosave(C, curundo->next); curundo= curundo->next; if(G.f & G_DEBUG) printf("redo %s\n", curundo->name); } @@ -717,7 +671,7 @@ void BKE_reset_undo(void) } /* based on index nr it does a restore */ -void BKE_undo_number(int nr) +void BKE_undo_number(bContext *C, int nr) { UndoElem *uel; int a=1; @@ -726,9 +680,25 @@ void BKE_undo_number(int nr) if(a==nr) break; } curundo= uel; - BKE_undo_step(0); + BKE_undo_step(C, 0); +} + +/* go back to the last occurance of name in stack */ +void BKE_undo_name(bContext *C, const char *name) +{ + UndoElem *uel; + + for(uel= undobase.last; uel; uel= uel->prev) { + if(strcmp(name, uel->name)==0) + break; + } + if(uel && uel->prev) { + curundo= uel->prev; + BKE_undo_step(C, 0); + } } + char *BKE_undo_menu_string(void) { UndoElem *uel; @@ -771,7 +741,7 @@ void BKE_undo_save_quit(void) file = open(str,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666); if(file == -1) { - error("Unable to save %s, check you have permissions", str); + //XXX error("Unable to save %s, check you have permissions", str); return; } @@ -783,7 +753,7 @@ void BKE_undo_save_quit(void) close(file); - if(chunk) error("Unable to save %s, internal error", str); + if(chunk) ; //XXX error("Unable to save %s, internal error", str); else printf("Saved session recovery to %s\n", str); } diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c new file mode 100644 index 00000000000..d8926fc5753 --- /dev/null +++ b/source/blender/blenkernel/intern/boids.c @@ -0,0 +1,1524 @@ +/* boids.c + * + * + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 by Janne Karhu. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_particle_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_force.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_boid_types.h" +#include "DNA_listBase.h" + +#include "BLI_rand.h" +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_kdtree.h" +#include "BLI_kdopbvh.h" +#include "BKE_effect.h" +#include "BKE_boids.h" +#include "BKE_particle.h" +#include "BKE_utildefines.h" +#include "BKE_modifier.h" + +#include "RNA_enum_types.h" + +typedef struct BoidValues { + float max_speed, max_acc; + float max_ave, min_speed; + float personal_space, jump_speed; +} BoidValues; + +static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness); + +static int rule_none(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa) +{ + return 0; +} + +static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) +{ + BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*) rule; + BoidSettings *boids = bbd->part->boids; + ParticleEffectorCache *ec; + Object *priority_ob = NULL; + float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; + float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0); + float priority = 0.0f, len; + int ret = 0; + + /* first find out goal/predator with highest priority */ + /* if rule->ob specified use it */ + if(gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != pa->stick_ob)) { + PartDeflect *pd = gabr->ob->pd; + float vec_to_part[3]; + + if(pd && pd->forcefield == PFIELD_BOID) { + effector_find_co(bbd->scene, pa->prev_state.co, NULL, gabr->ob, pd, loc, vec, NULL, NULL); + + VecSubf(vec_to_part, pa->prev_state.co, loc); + + priority = mul * pd->f_strength * effector_falloff(pd, vec, vec_to_part); + } + else + priority = 1.0; + + priority = 1.0; + priority_ob = gabr->ob; + } + else for(ec=bbd->psys->effectors.first; ec; ec=ec->next) { + if(ec->type & PSYS_EC_EFFECTOR) { + Object *eob = ec->ob; + PartDeflect *pd = eob->pd; + + /* skip current object */ + if(rule->type == eBoidRuleType_Goal && eob == pa->stick_ob) + continue; + + if(pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f) { + float vec_to_part[3], temp; + + effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, vec, NULL, NULL); + + VecSubf(vec_to_part, pa->prev_state.co, loc); + + temp = mul * pd->f_strength * effector_falloff(pd, vec, vec_to_part); + + if(temp == 0.0f) + ; /* do nothing */ + else if(temp > priority) { + priority = temp; + priority_ob = eob; + len = VecLength(vec_to_part); + } + /* choose closest object with same priority */ + else if(temp == priority) { + float len2 = VecLength(vec_to_part); + + if(len2 < len) { + priority_ob = eob; + len = len2; + } + } + } + } + } + + /* then use that effector */ + if(priority > (rule->type==eBoidRuleType_Avoid ? gabr->fear_factor : 0.0f)) { /* with avoid, factor is "fear factor" */ + Object *eob = priority_ob; + PartDeflect *pd = eob->pd; + float vec_to_part[3]; + float surface = 0.0f; + float nor[3]; + + if(gabr->options & BRULE_GOAL_AVOID_PREDICT) { + /* estimate future location of target */ + surface = (float)effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, vec, NULL); + + VecSubf(vec_to_part, pa->prev_state.co, loc); + len = Normalize(vec_to_part); + + VecMulf(vec, len / (val->max_speed * bbd->timestep)); + VecAddf(loc, loc, vec); + VecSubf(vec_to_part, pa->prev_state.co, loc); + } + else { + surface = (float)effector_find_co(bbd->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, NULL, NULL); + + VecSubf(vec_to_part, pa->prev_state.co, loc); + len = VecLength(vec_to_part); + } + + if(rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface!=0.0f) { + if(!bbd->goal_ob || bbd->goal_priority < priority) { + bbd->goal_ob = eob; + VECCOPY(bbd->goal_co, loc); + VECCOPY(bbd->goal_nor, nor); + } + } + else if(rule->type == eBoidRuleType_Avoid && pa->boid->mode == eBoidMode_Climbing && + priority > 2.0f * gabr->fear_factor) { + /* detach from surface and try to fly away from danger */ + VECCOPY(vec_to_part, pa->r_ve); + VecMulf(vec_to_part, -1.0f); + } + + VECCOPY(bbd->wanted_co, vec_to_part); + VecMulf(bbd->wanted_co, mul); + + bbd->wanted_speed = val->max_speed * priority; + + /* with goals factor is approach velocity factor */ + if(rule->type == eBoidRuleType_Goal && boids->landing_smoothness > 0.0f) { + float len2 = 2.0f*VecLength(pa->prev_state.vel); + + surface *= pa->size * boids->height; + + if(len2 > 0.0f && len - surface < len2) { + len2 = (len - surface)/len2; + bbd->wanted_speed *= pow(len2, boids->landing_smoothness); + } + } + + ret = 1; + } + + return ret; +} + +static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) +{ + BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule; + KDTreeNearest *ptn = NULL; + ParticleEffectorCache *ec; + ParticleTarget *pt; + float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; + float co1[3], vel1[3], co2[3], vel2[3]; + float len, t, inp, t_min = 2.0f; + int n, neighbors = 0, nearest = 0; + int ret = 0; + + //check deflector objects first + if(acbr->options & BRULE_ACOLL_WITH_DEFLECTORS) { + ParticleCollision col; + BVHTreeRayHit hit; + float radius = val->personal_space * pa->size, ray_dir[3]; + + VECCOPY(col.co1, pa->prev_state.co); + VecAddf(col.co2, pa->prev_state.co, pa->prev_state.vel); + VecSubf(ray_dir, col.co2, col.co1); + VecMulf(ray_dir, acbr->look_ahead); + col.t = 0.0f; + hit.index = -1; + hit.dist = col.ray_len = VecLength(ray_dir); + + /* find out closest deflector object */ + for(ec=bbd->psys->effectors.first; ec; ec=ec->next) { + if(ec->type & PSYS_EC_DEFLECT) { + Object *eob = ec->ob; + + /* don't check with current ground object */ + if(eob == pa->stick_ob) + continue; + + col.md = ( CollisionModifierData * ) ( modifiers_findByType ( eob, eModifierType_Collision ) ); + col.ob_t = eob; + + if(col.md && col.md->bvhtree) + BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col); + } + } + /* then avoid that object */ + if(hit.index>=0) { + /* TODO: not totally happy with this part */ + t = hit.dist/col.ray_len; + + VECCOPY(bbd->wanted_co, col.nor); + + VecMulf(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size); + + bbd->wanted_speed = sqrt(t) * VecLength(pa->prev_state.vel); + + return 1; + } + } + + //check boids in own system + if(acbr->options & BRULE_ACOLL_WITH_BOIDS) + { + neighbors = BLI_kdtree_range_search(bbd->psys->tree, acbr->look_ahead * VecLength(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn); + if(neighbors > 1) for(n=1; n<neighbors; n++) { + VECCOPY(co1, pa->prev_state.co); + VECCOPY(vel1, pa->prev_state.vel); + VECCOPY(co2, (bbd->psys->particles + ptn[n].index)->prev_state.co); + VECCOPY(vel2, (bbd->psys->particles + ptn[n].index)->prev_state.vel); + + VecSubf(loc, co1, co2); + + VecSubf(vec, vel1, vel2); + + inp = Inpf(vec,vec); + + /* velocities not parallel */ + if(inp != 0.0f) { + t = -Inpf(loc, vec)/inp; + /* cpa is not too far in the future so investigate further */ + if(t > 0.0f && t < t_min) { + VECADDFAC(co1, co1, vel1, t); + VECADDFAC(co2, co2, vel2, t); + + VecSubf(vec, co2, co1); + + len = Normalize(vec); + + /* distance of cpa is close enough */ + if(len < 2.0f * val->personal_space * pa->size) { + t_min = t; + + VecMulf(vec, VecLength(vel1)); + VecMulf(vec, (2.0f - t)/2.0f); + VecSubf(bbd->wanted_co, vel1, vec); + bbd->wanted_speed = VecLength(bbd->wanted_co); + ret = 1; + } + } + } + } + } + if(ptn){ MEM_freeN(ptn); ptn=NULL; } + + /* check boids in other systems */ + for(pt=bbd->psys->targets.first; pt; pt=pt->next) { + ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt); + + if(epsys) { + neighbors = BLI_kdtree_range_search(epsys->tree, acbr->look_ahead * VecLength(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn); + if(neighbors > 0) for(n=0; n<neighbors; n++) { + VECCOPY(co1, pa->prev_state.co); + VECCOPY(vel1, pa->prev_state.vel); + VECCOPY(co2, (epsys->particles + ptn[n].index)->prev_state.co); + VECCOPY(vel2, (epsys->particles + ptn[n].index)->prev_state.vel); + + VecSubf(loc, co1, co2); + + VecSubf(vec, vel1, vel2); + + inp = Inpf(vec,vec); + + /* velocities not parallel */ + if(inp != 0.0f) { + t = -Inpf(loc, vec)/inp; + /* cpa is not too far in the future so investigate further */ + if(t > 0.0f && t < t_min) { + VECADDFAC(co1, co1, vel1, t); + VECADDFAC(co2, co2, vel2, t); + + VecSubf(vec, co2, co1); + + len = Normalize(vec); + + /* distance of cpa is close enough */ + if(len < 2.0f * val->personal_space * pa->size) { + t_min = t; + + VecMulf(vec, VecLength(vel1)); + VecMulf(vec, (2.0f - t)/2.0f); + VecSubf(bbd->wanted_co, vel1, vec); + bbd->wanted_speed = VecLength(bbd->wanted_co); + ret = 1; + } + } + } + } + + if(ptn){ MEM_freeN(ptn); ptn=NULL; } + } + } + + + if(ptn && nearest==0) + MEM_freeN(ptn); + + return ret; +} +static int rule_separate(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) +{ + KDTreeNearest *ptn = NULL; + ParticleTarget *pt; + float len = 2.0f * val->personal_space * pa->size + 1.0f; + float vec[3] = {0.0f, 0.0f, 0.0f}; + int neighbors = BLI_kdtree_range_search(bbd->psys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn); + int ret = 0; + + if(neighbors > 1 && ptn[1].dist!=0.0f) { + VecSubf(vec, pa->prev_state.co, bbd->psys->particles[ptn[1].index].state.co); + VecMulf(vec, (2.0f * val->personal_space * pa->size - ptn[1].dist) / ptn[1].dist); + VecAddf(bbd->wanted_co, bbd->wanted_co, vec); + bbd->wanted_speed = val->max_speed; + len = ptn[1].dist; + ret = 1; + } + if(ptn){ MEM_freeN(ptn); ptn=NULL; } + + /* check other boid systems */ + for(pt=bbd->psys->targets.first; pt; pt=pt->next) { + ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt); + + if(epsys) { + neighbors = BLI_kdtree_range_search(epsys->tree, 2.0f * val->personal_space * pa->size, pa->prev_state.co, NULL, &ptn); + + if(neighbors > 0 && ptn[0].dist < len) { + VecSubf(vec, pa->prev_state.co, ptn[0].co); + VecMulf(vec, (2.0f * val->personal_space * pa->size - ptn[0].dist) / ptn[1].dist); + VecAddf(bbd->wanted_co, bbd->wanted_co, vec); + bbd->wanted_speed = val->max_speed; + len = ptn[0].dist; + ret = 1; + } + + if(ptn){ MEM_freeN(ptn); ptn=NULL; } + } + } + return ret; +} +static int rule_flock(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) +{ + KDTreeNearest ptn[11]; + float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; + int neighbors = BLI_kdtree_find_n_nearest(bbd->psys->tree, 11, pa->state.co, pa->prev_state.ave, ptn); + int n; + int ret = 0; + + if(neighbors > 1) { + for(n=1; n<neighbors; n++) { + VecAddf(loc, loc, bbd->psys->particles[ptn[n].index].prev_state.co); + VecAddf(vec, vec, bbd->psys->particles[ptn[n].index].prev_state.vel); + } + + VecMulf(loc, 1.0f/((float)neighbors - 1.0f)); + VecMulf(vec, 1.0f/((float)neighbors - 1.0f)); + + VecSubf(loc, loc, pa->prev_state.co); + VecSubf(vec, vec, pa->prev_state.vel); + + VecAddf(bbd->wanted_co, bbd->wanted_co, vec); + VecAddf(bbd->wanted_co, bbd->wanted_co, loc); + bbd->wanted_speed = VecLength(bbd->wanted_co); + + ret = 1; + } + return ret; +} +static int rule_follow_leader(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) +{ + BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule; + float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; + float mul, len; + int n = (flbr->queue_size <= 1) ? bbd->psys->totpart : flbr->queue_size; + int i, ret = 0, p = pa - bbd->psys->particles; + + if(flbr->ob) { + float vec2[3], t; + + /* first check we're not blocking the leader*/ + VecSubf(vec, flbr->loc, flbr->oloc); + VecMulf(vec, 1.0f/bbd->timestep); + + VecSubf(loc, pa->prev_state.co, flbr->oloc); + + mul = Inpf(vec, vec); + + /* leader is not moving */ + if(mul < 0.01) { + len = VecLength(loc); + /* too close to leader */ + if(len < 2.0f * val->personal_space * pa->size) { + VECCOPY(bbd->wanted_co, loc); + bbd->wanted_speed = val->max_speed; + return 1; + } + } + else { + t = Inpf(loc, vec)/mul; + + /* possible blocking of leader in near future */ + if(t > 0.0f && t < 3.0f) { + VECCOPY(vec2, vec); + VecMulf(vec2, t); + + VecSubf(vec2, loc, vec2); + + len = VecLength(vec2); + + if(len < 2.0f * val->personal_space * pa->size) { + VECCOPY(bbd->wanted_co, vec2); + bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f; + return 1; + } + } + } + + /* not blocking so try to follow leader */ + if(p && flbr->options & BRULE_LEADER_IN_LINE) { + VECCOPY(vec, bbd->psys->particles[p-1].prev_state.vel); + VECCOPY(loc, bbd->psys->particles[p-1].prev_state.co); + } + else { + VECCOPY(loc, flbr->oloc); + VecSubf(vec, flbr->loc, flbr->oloc); + VecMulf(vec, 1.0/bbd->timestep); + } + + /* fac is seconds behind leader */ + VECADDFAC(loc, loc, vec, -flbr->distance); + + VecSubf(bbd->wanted_co, loc, pa->prev_state.co); + bbd->wanted_speed = VecLength(bbd->wanted_co); + + ret = 1; + } + else if(p % n) { + float vec2[3], t, t_min = 3.0f; + + /* first check we're not blocking any leaders */ + for(i = 0; i< bbd->psys->totpart; i+=n){ + VECCOPY(vec, bbd->psys->particles[i].prev_state.vel); + + VecSubf(loc, pa->prev_state.co, bbd->psys->particles[i].prev_state.co); + + mul = Inpf(vec, vec); + + /* leader is not moving */ + if(mul < 0.01) { + len = VecLength(loc); + /* too close to leader */ + if(len < 2.0f * val->personal_space * pa->size) { + VECCOPY(bbd->wanted_co, loc); + bbd->wanted_speed = val->max_speed; + return 1; + } + } + else { + t = Inpf(loc, vec)/mul; + + /* possible blocking of leader in near future */ + if(t > 0.0f && t < t_min) { + VECCOPY(vec2, vec); + VecMulf(vec2, t); + + VecSubf(vec2, loc, vec2); + + len = VecLength(vec2); + + if(len < 2.0f * val->personal_space * pa->size) { + t_min = t; + VECCOPY(bbd->wanted_co, loc); + bbd->wanted_speed = val->max_speed * (3.0f - t)/3.0f; + ret = 1; + } + } + } + } + + if(ret) return 1; + + /* not blocking so try to follow leader */ + if(flbr->options & BRULE_LEADER_IN_LINE) { + VECCOPY(vec, bbd->psys->particles[p-1].prev_state.vel); + VECCOPY(loc, bbd->psys->particles[p-1].prev_state.co); + } + else { + VECCOPY(vec, bbd->psys->particles[p - p%n].prev_state.vel); + VECCOPY(loc, bbd->psys->particles[p - p%n].prev_state.co); + } + + /* fac is seconds behind leader */ + VECADDFAC(loc, loc, vec, -flbr->distance); + + VecSubf(bbd->wanted_co, loc, pa->prev_state.co); + bbd->wanted_speed = VecLength(bbd->wanted_co); + + ret = 1; + } + + return ret; +} +static int rule_average_speed(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) +{ + BoidRuleAverageSpeed *asbr = (BoidRuleAverageSpeed*)rule; + float vec[3] = {0.0f, 0.0f, 0.0f}; + + if(asbr->wander > 0.0f) { + /* abuse pa->r_ave for wandering */ + pa->r_ave[0] += asbr->wander * (-1.0f + 2.0f * BLI_frand()); + pa->r_ave[1] += asbr->wander * (-1.0f + 2.0f * BLI_frand()); + pa->r_ave[2] += asbr->wander * (-1.0f + 2.0f * BLI_frand()); + + Normalize(pa->r_ave); + + VECCOPY(vec, pa->r_ave); + + QuatMulVecf(pa->prev_state.rot, vec); + + VECCOPY(bbd->wanted_co, pa->prev_state.ave); + + VecMulf(bbd->wanted_co, 1.1f); + + VecAddf(bbd->wanted_co, bbd->wanted_co, vec); + + /* leveling */ + if(asbr->level > 0.0f) { + Projf(vec, bbd->wanted_co, bbd->psys->part->acc); + VecMulf(vec, asbr->level); + VecSubf(bbd->wanted_co, bbd->wanted_co, vec); + } + } + else { + VECCOPY(bbd->wanted_co, pa->prev_state.ave); + + /* may happen at birth */ + if(Inp2f(bbd->wanted_co,bbd->wanted_co)==0.0f) { + bbd->wanted_co[0] = 2.0f*(0.5f - BLI_frand()); + bbd->wanted_co[1] = 2.0f*(0.5f - BLI_frand()); + bbd->wanted_co[2] = 2.0f*(0.5f - BLI_frand()); + } + + /* leveling */ + if(asbr->level > 0.0f) { + Projf(vec, bbd->wanted_co, bbd->psys->part->acc); + VecMulf(vec, asbr->level); + VecSubf(bbd->wanted_co, bbd->wanted_co, vec); + } + + } + bbd->wanted_speed = asbr->speed * val->max_speed; + + return 1; +} +static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) +{ + BoidRuleFight *fbr = (BoidRuleFight*)rule; + KDTreeNearest *ptn = NULL; + ParticleTarget *pt; + ParticleData *epars; + ParticleData *enemy_pa; + /* friends & enemies */ + float closest_enemy[3] = {0.0f,0.0f,0.0f}; + float closest_dist = fbr->distance + 1.0f; + float f_strength = 0.0f, e_strength = 0.0f; + float health = 0.0f; + int n, ret = 0; + + /* calculate own group strength */ + int neighbors = BLI_kdtree_range_search(bbd->psys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn); + for(n=0; n<neighbors; n++) + health += bbd->psys->particles[ptn[n].index].boid->health; + + f_strength += bbd->part->boids->strength * health; + + if(ptn){ MEM_freeN(ptn); ptn=NULL; } + + /* add other friendlies and calculate enemy strength and find closest enemy */ + for(pt=bbd->psys->targets.first; pt; pt=pt->next) { + ParticleSystem *epsys = psys_get_target_system(bbd->ob, pt); + if(epsys) { + epars = epsys->particles; + + neighbors = BLI_kdtree_range_search(epsys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn); + + health = 0.0f; + + for(n=0; n<neighbors; n++) { + health += epars[ptn[n].index].boid->health; + + if(n==0 && pt->mode==PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) { + VECCOPY(closest_enemy, ptn[n].co); + closest_dist = ptn[n].dist; + enemy_pa = epars + ptn[n].index; + } + } + if(pt->mode==PTARGET_MODE_ENEMY) + e_strength += epsys->part->boids->strength * health; + else if(pt->mode==PTARGET_MODE_FRIEND) + f_strength += epsys->part->boids->strength * health; + + if(ptn){ MEM_freeN(ptn); ptn=NULL; } + } + } + /* decide action if enemy presence found */ + if(e_strength > 0.0f) { + VecSubf(bbd->wanted_co, closest_enemy, pa->prev_state.co); + + /* attack if in range */ + if(closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) { + float damage = BLI_frand(); + float enemy_dir[3] = {bbd->wanted_co[0],bbd->wanted_co[1],bbd->wanted_co[2]}; + + Normalize(enemy_dir); + + /* fight mode */ + bbd->wanted_speed = 0.0f; + + /* must face enemy to fight */ + if(Inpf(pa->prev_state.ave, enemy_dir)>0.5f) { + enemy_pa->boid->health -= bbd->part->boids->strength * bbd->timestep * ((1.0f-bbd->part->boids->accuracy)*damage + bbd->part->boids->accuracy); + } + } + else { + /* approach mode */ + bbd->wanted_speed = val->max_speed; + } + + /* check if boid doesn't want to fight */ + if(pa->boid->health/bbd->part->boids->health * bbd->part->boids->aggression < e_strength / f_strength) { + /* decide to flee */ + if(closest_dist < fbr->flee_distance * fbr->distance) { + VecMulf(bbd->wanted_co, -1.0f); + bbd->wanted_speed = val->max_speed; + } + else { /* wait for better odds */ + bbd->wanted_speed = 0.0f; + } + } + + ret = 1; + } + + return ret; +} + +typedef int (*boid_rule_cb)(BoidRule *rule, BoidBrainData *data, BoidValues *val, ParticleData *pa); + +static boid_rule_cb boid_rules[] = { + rule_none, + rule_goal_avoid, + rule_goal_avoid, + rule_avoid_collision, + rule_separate, + rule_flock, + rule_follow_leader, + rule_average_speed, + rule_fight, + //rule_help, + //rule_protect, + //rule_hide, + //rule_follow_path, + //rule_follow_wall +}; + +static void set_boid_values(BoidValues *val, BoidSettings *boids, ParticleData *pa) +{ + if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing)) { + val->max_speed = boids->land_max_speed * pa->boid->health/boids->health; + val->max_acc = boids->land_max_acc * val->max_speed; + val->max_ave = boids->land_max_ave * M_PI * pa->boid->health/boids->health; + val->min_speed = 0.0f; /* no minimum speed on land */ + val->personal_space = boids->land_personal_space; + val->jump_speed = boids->land_jump_speed * pa->boid->health/boids->health; + } + else { + val->max_speed = boids->air_max_speed * pa->boid->health/boids->health; + val->max_acc = boids->air_max_acc * val->max_speed; + val->max_ave = boids->air_max_ave * M_PI * pa->boid->health/boids->health; + val->min_speed = boids->air_min_speed * boids->air_max_speed; + val->personal_space = boids->air_personal_space; + val->jump_speed = 0.0f; /* no jumping in air */ + } +} +static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *ground_co, float *ground_nor) +{ + if(pa->boid->mode == eBoidMode_Climbing) { + SurfaceModifierData *surmd = NULL; + float x[3], v[3]; + + surmd = (SurfaceModifierData *)modifiers_findByType ( pa->stick_ob, eModifierType_Surface ); + + /* take surface velocity into account */ + effector_find_co(bbd->scene, pa->state.co, surmd, NULL, NULL, x, NULL, v, NULL); + VecAddf(x, x, v); + + /* get actual position on surface */ + effector_find_co(bbd->scene, x, surmd, NULL, NULL, ground_co, ground_nor, NULL, NULL); + + return pa->stick_ob; + } + else { + float zvec[3] = {0.0f, 0.0f, 2000.0f}; + ParticleCollision col; + BVHTreeRayHit hit; + ParticleEffectorCache *ec; + float radius = 0.0f, t, ray_dir[3]; + + VECCOPY(col.co1, pa->state.co); + VECCOPY(col.co2, pa->state.co); + VecAddf(col.co1, col.co1, zvec); + VecSubf(col.co2, col.co2, zvec); + VecSubf(ray_dir, col.co2, col.co1); + col.t = 0.0f; + hit.index = -1; + hit.dist = col.ray_len = VecLength(ray_dir); + + /* find out upmost deflector object */ + for(ec=bbd->psys->effectors.first; ec; ec=ec->next) { + if(ec->type & PSYS_EC_DEFLECT) { + Object *eob = ec->ob; + + col.md = ( CollisionModifierData * ) ( modifiers_findByType ( eob, eModifierType_Collision ) ); + col.ob_t = eob; + + if(col.md && col.md->bvhtree) + BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col); + } + } + /* then use that object */ + if(hit.index>=0) { + t = hit.dist/col.ray_len; + VecLerpf(ground_co, col.co1, col.co2, t); + VECCOPY(ground_nor, col.nor); + Normalize(ground_nor); + return col.ob; + } + else { + /* default to z=0 */ + VECCOPY(ground_co, pa->state.co); + ground_co[2] = 0; + ground_nor[0] = ground_nor[1] = 0.0f; + ground_nor[2] = 1.0f; + return NULL; + } + } +} +static int boid_rule_applies(ParticleData *pa, BoidSettings *boids, BoidRule *rule) +{ + if(rule==NULL) + return 0; + + if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing) && rule->flag & BOIDRULE_ON_LAND) + return 1; + + if(pa->boid->mode==eBoidMode_InAir && rule->flag & BOIDRULE_IN_AIR) + return 1; + + return 0; +} +void boids_precalc_rules(ParticleSettings *part, float cfra) +{ + BoidState *state = part->boids->states.first; + BoidRule *rule; + for(; state; state=state->next) { + for(rule = state->rules.first; rule; rule=rule->next) { + if(rule->type==eBoidRuleType_FollowLeader) { + BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*) rule; + + if(flbr->ob && flbr->cfra != cfra) { + /* save object locations for velocity calculations */ + VECCOPY(flbr->oloc, flbr->loc); + VECCOPY(flbr->loc, flbr->ob->obmat[3]); + flbr->cfra = cfra; + } + } + } + } +} +static void boid_climb(BoidSettings *boids, ParticleData *pa, float *surface_co, float *surface_nor) +{ + float nor[3], vel[3]; + VECCOPY(nor, surface_nor); + + /* gather apparent gravity to r_ve */ + VECADDFAC(pa->r_ve, pa->r_ve, surface_nor, -1.0); + Normalize(pa->r_ve); + + /* raise boid it's size from surface */ + VecMulf(nor, pa->size * boids->height); + VecAddf(pa->state.co, surface_co, nor); + + /* remove normal component from velocity */ + Projf(vel, pa->state.vel, surface_nor); + VecSubf(pa->state.vel, pa->state.vel, vel); +} +static float boid_goal_signed_dist(float *boid_co, float *goal_co, float *goal_nor) +{ + float vec[3]; + + VecSubf(vec, boid_co, goal_co); + + return Inpf(vec, goal_nor); +} +/* wanted_co is relative to boid location */ +static int apply_boid_rule(BoidBrainData *bbd, BoidRule *rule, BoidValues *val, ParticleData *pa, float fuzziness) +{ + if(rule==NULL) + return 0; + + if(boid_rule_applies(pa, bbd->part->boids, rule)==0) + return 0; + + if(boid_rules[rule->type](rule, bbd, val, pa)==0) + return 0; + + if(fuzziness < 0.0f || VecLenCompare(bbd->wanted_co, pa->prev_state.vel, fuzziness * VecLength(pa->prev_state.vel))==0) + return 1; + else + return 0; +} +static BoidState *get_boid_state(BoidSettings *boids, ParticleData *pa) { + BoidState *state = boids->states.first; + + for(; state; state=state->next) { + if(state->id==pa->boid->state_id) + return state; + } + + /* for some reason particle isn't at a valid state */ + state = boids->states.first; + if(state) + pa->boid->state_id = state->id; + + return state; +} +//static int boid_condition_is_true(BoidCondition *cond) { +// /* TODO */ +// return 0; +//} + +/* determines the velocity the boid wants to have */ +void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa) +{ + BoidRule *rule; + BoidSettings *boids = bbd->part->boids; + BoidValues val; + BoidState *state = get_boid_state(boids, pa); + //BoidCondition *cond; + + if(pa->boid->health <= 0.0f) { + pa->alive = PARS_DYING; + return; + } + + //planned for near future + //cond = state->conditions.first; + //for(; cond; cond=cond->next) { + // if(boid_condition_is_true(cond)) { + // pa->boid->state_id = cond->state_id; + // state = get_boid_state(boids, pa); + // break; /* only first true condition is used */ + // } + //} + + bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f; + + /* create random seed for every particle & frame */ + BLI_srandom(bbd->psys->seed + p + (int)bbd->cfra + (int)(1000*pa->r_rot[0])); + + set_boid_values(&val, bbd->part->boids, pa); + + /* go through rules */ + switch(state->ruleset_type) { + case eBoidRulesetType_Fuzzy: + { + for(rule = state->rules.first; rule; rule = rule->next) { + if(apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness)) + break; /* only first nonzero rule that comes through fuzzy rule is applied */ + } + break; + } + case eBoidRulesetType_Random: + { + /* use random rule for each particle (allways same for same particle though) */ + rule = BLI_findlink(&state->rules, (int)(1000.0f * pa->r_rot[1]) % BLI_countlist(&state->rules)); + + apply_boid_rule(bbd, rule, &val, pa, -1.0); + } + case eBoidRulesetType_Average: + { + float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f; + int n = 0; + for(rule = state->rules.first; rule; rule=rule->next) { + if(apply_boid_rule(bbd, rule, &val, pa, -1.0f)) { + VecAddf(wanted_co, wanted_co, bbd->wanted_co); + wanted_speed += bbd->wanted_speed; + n++; + bbd->wanted_co[0]=bbd->wanted_co[1]=bbd->wanted_co[2]=bbd->wanted_speed=0.0f; + } + } + + if(n > 1) { + VecMulf(wanted_co, 1.0f/(float)n); + wanted_speed /= (float)n; + } + + VECCOPY(bbd->wanted_co, wanted_co); + bbd->wanted_speed = wanted_speed; + break; + } + + } + + /* decide on jumping & liftoff */ + if(pa->boid->mode == eBoidMode_OnLand) { + /* fuzziness makes boids capable of misjudgement */ + float mul = 1.0 + state->rule_fuzziness; + + if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) { + float cvel[3], dir[3]; + + VECCOPY(dir, pa->prev_state.ave); + Normalize2(dir); + + VECCOPY(cvel, bbd->wanted_co); + Normalize2(cvel); + + if(Inp2f(cvel, dir) > 0.95 / mul) + pa->boid->mode = eBoidMode_Liftoff; + } + else if(val.jump_speed > 0.0f) { + float jump_v[3]; + int jump = 0; + + /* jump to get to a location */ + if(bbd->wanted_co[2] > 0.0f) { + float cvel[3], dir[3]; + float z_v, ground_v, cur_v; + float len; + + VECCOPY(dir, pa->prev_state.ave); + Normalize2(dir); + + VECCOPY(cvel, bbd->wanted_co); + Normalize2(cvel); + + len = Vec2Length(pa->prev_state.vel); + + /* first of all, are we going in a suitable direction? */ + /* or at a suitably slow speed */ + if(Inp2f(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) { + /* try to reach goal at highest point of the parabolic path */ + cur_v = Vec2Length(pa->prev_state.vel); + z_v = sasqrt(-2.0f * bbd->part->acc[2] * bbd->wanted_co[2]); + ground_v = Vec2Length(bbd->wanted_co)*sasqrt(-0.5f * bbd->part->acc[2] / bbd->wanted_co[2]); + + len = sasqrt((ground_v-cur_v)*(ground_v-cur_v) + z_v*z_v); + + if(len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) { + jump = 1; + + len = MIN2(len, val.jump_speed); + + VECCOPY(jump_v, dir); + jump_v[2] = z_v; + VecMulf(jump_v, ground_v); + + Normalize(jump_v); + VecMulf(jump_v, len); + Vec2Addf(jump_v, jump_v, pa->prev_state.vel); + } + } + } + + /* jump to go faster */ + if(jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) { + + } + + if(jump) { + VECCOPY(pa->prev_state.vel, jump_v); + pa->boid->mode = eBoidMode_Falling; + } + } + } +} +/* tries to realize the wanted velocity taking all constraints into account */ +void boid_body(BoidBrainData *bbd, ParticleData *pa) +{ + BoidSettings *boids = bbd->part->boids; + BoidValues val; + float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3]; + float dvec[3], bvec[3]; + float new_dir[3], new_speed; + float old_dir[3], old_speed; + float wanted_dir[3]; + float q[4], mat[3][3]; /* rotation */ + float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f}; + float force[3] = {0.0f, 0.0f, 0.0f}, tvel[3] = {0.0f, 0.0f, 1.0f}; + float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep; + int p = pa - bbd->psys->particles; + + set_boid_values(&val, boids, pa); + + /* make sure there's something in new velocity, location & rotation */ + copy_particle_key(&pa->state,&pa->prev_state,0); + + if(bbd->part->flag & PART_SIZEMASS) + pa_mass*=pa->size; + + /* if boids can't fly they fall to the ground */ + if((boids->options & BOID_ALLOW_FLIGHT)==0 && ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing)==0 && bbd->part->acc[2] != 0.0f) + pa->boid->mode = eBoidMode_Falling; + + if(pa->boid->mode == eBoidMode_Falling) { + /* Falling boids are only effected by gravity. */ + acc[2] = bbd->part->acc[2]; + } + else { + /* figure out acceleration */ + float landing_level = 2.0f; + float level = landing_level + 1.0f; + float new_vel[3]; + + if(pa->boid->mode == eBoidMode_Liftoff) { + pa->boid->mode = eBoidMode_InAir; + pa->stick_ob = boid_find_ground(bbd, pa, ground_co, ground_nor); + } + else if(pa->boid->mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) { + /* auto-leveling & landing if close to ground */ + + pa->stick_ob = boid_find_ground(bbd, pa, ground_co, ground_nor); + + /* level = how many particle sizes above ground */ + level = (pa->prev_state.co[2] - ground_co[2])/(2.0f * pa->size) - 0.5; + + landing_level = - boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass; + + if(pa->prev_state.vel[2] < 0.0f) { + if(level < 1.0f) { + bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f; + bbd->wanted_speed = 0.0f; + pa->boid->mode = eBoidMode_Falling; + } + else if(level < landing_level) { + bbd->wanted_speed *= (level - 1.0f)/landing_level; + bbd->wanted_co[2] *= (level - 1.0f)/landing_level; + } + } + } + + VECCOPY(old_dir, pa->prev_state.ave); + VECCOPY(wanted_dir, bbd->wanted_co); + new_speed = Normalize(wanted_dir); + + /* first check if we have valid direction we want to go towards */ + if(new_speed == 0.0f) { + VECCOPY(new_dir, old_dir); + } + else { + float old_dir2[2], wanted_dir2[2], nor[3], angle; + Vec2Copyf(old_dir2, old_dir); + Normalize2(old_dir2); + Vec2Copyf(wanted_dir2, wanted_dir); + Normalize2(wanted_dir2); + + /* choose random direction to turn if wanted velocity */ + /* is directly behind regardless of z-coordinate */ + if(Inp2f(old_dir2, wanted_dir2) < -0.99f) { + wanted_dir[0] = 2.0f*(0.5f - BLI_frand()); + wanted_dir[1] = 2.0f*(0.5f - BLI_frand()); + wanted_dir[2] = 2.0f*(0.5f - BLI_frand()); + Normalize(wanted_dir); + } + + /* constrain direction with maximum angular velocity */ + angle = saacos(Inpf(old_dir, wanted_dir)); + angle = MIN2(angle, val.max_ave); + + Crossf(nor, old_dir, wanted_dir); + VecRotToQuat(nor, angle, q); + VECCOPY(new_dir, old_dir); + QuatMulVecf(q, new_dir); + Normalize(new_dir); + + /* save direction in case resulting velocity too small */ + VecRotToQuat(nor, angle*dtime, q); + VECCOPY(pa->state.ave, old_dir); + QuatMulVecf(q, pa->state.ave); + Normalize(pa->state.ave); + } + + /* constrain speed with maximum acceleration */ + old_speed = VecLength(pa->prev_state.vel); + + if(bbd->wanted_speed < old_speed) + new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc); + else + new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc); + + /* combine direction and speed */ + VECCOPY(new_vel, new_dir); + VecMulf(new_vel, new_speed); + + /* maintain minimum flying velocity if not landing */ + if(level >= landing_level) { + float len2 = Inp2f(new_vel,new_vel); + float root; + + len2 = MAX2(len2, val.min_speed*val.min_speed); + root = sasqrt(new_speed*new_speed - len2); + + new_vel[2] = new_vel[2] < 0.0f ? -root : root; + + Normalize2(new_vel); + Vec2Mulf(new_vel, sasqrt(len2)); + } + + /* finally constrain speed to max speed */ + new_speed = Normalize(new_vel); + VecMulf(new_vel, MIN2(new_speed, val.max_speed)); + + /* get acceleration from difference of velocities */ + VecSubf(acc, new_vel, pa->prev_state.vel); + + /* break acceleration to components */ + Projf(tan_acc, acc, pa->prev_state.ave); + VecSubf(nor_acc, acc, tan_acc); + } + + /* account for effectors */ + do_effectors(p, pa, &pa->state, bbd->scene, bbd->ob, bbd->psys, pa->state.co, force, tvel, bbd->dfra, bbd->cfra); + + if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing)) { + float length = Normalize(force); + + length = MAX2(0.0f, length - boids->land_stick_force); + + VecMulf(force, length); + } + + VecAddf(acc, acc, force); + + /* store smoothed acceleration for nice banking etc. */ + VECADDFAC(pa->boid->acc, pa->boid->acc, acc, dtime); + VecMulf(pa->boid->acc, 1.0f / (1.0f + dtime)); + + /* integrate new location & velocity */ + + /* by regarding the acceleration as a force at this stage we*/ + /* can get better control allthough it's a bit unphysical */ + VecMulf(acc, 1.0f/pa_mass); + + VECCOPY(dvec, acc); + VecMulf(dvec, dtime*dtime*0.5f); + + VECCOPY(bvec, pa->prev_state.vel); + VecMulf(bvec, dtime); + VecAddf(dvec, dvec, bvec); + VecAddf(pa->state.co, pa->state.co, dvec); + + VECADDFAC(pa->state.vel, pa->state.vel, acc, dtime); + + if(pa->boid->mode != eBoidMode_InAir) + pa->stick_ob = boid_find_ground(bbd, pa, ground_co, ground_nor); + + /* change modes, constrain movement & keep track of down vector */ + switch(pa->boid->mode) { + case eBoidMode_InAir: + { + float grav[3] = {0.0f, 0.0f, bbd->part->acc[2] < 0.0f ? -1.0f : 0.0f}; + + /* don't take forward acceleration into account (better banking) */ + if(Inpf(pa->boid->acc, pa->state.vel) > 0.0f) { + Projf(dvec, pa->boid->acc, pa->state.vel); + VecSubf(dvec, pa->boid->acc, dvec); + } + else { + VECCOPY(dvec, pa->boid->acc); + } + + /* gather apparent gravity to r_ve */ + VECADDFAC(pa->r_ve, grav, dvec, -boids->banking); + Normalize(pa->r_ve); + + /* stick boid on goal when close enough */ + if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { + pa->boid->mode = eBoidMode_Climbing; + pa->stick_ob = bbd->goal_ob; + boid_find_ground(bbd, pa, ground_co, ground_nor); + boid_climb(boids, pa, ground_co, ground_nor); + } + /* land boid when belowg ground */ + else if(boids->options & BOID_ALLOW_LAND && pa->state.co[2] <= ground_co[2] + pa->size * boids->height) { + pa->state.co[2] = ground_co[2] + pa->size * boids->height; + pa->state.vel[2] = 0.0f; + pa->boid->mode = eBoidMode_OnLand; + } + break; + } + case eBoidMode_Falling: + { + float grav[3] = {0.0f, 0.0f, bbd->part->acc[2] < 0.0f ? -1.0f : 0.0f}; + + /* gather apparent gravity to r_ve */ + VECADDFAC(pa->r_ve, pa->r_ve, grav, dtime); + Normalize(pa->r_ve); + + if(boids->options & BOID_ALLOW_LAND) { + /* stick boid on goal when close enough */ + if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { + pa->boid->mode = eBoidMode_Climbing; + pa->stick_ob = bbd->goal_ob; + boid_find_ground(bbd, pa, ground_co, ground_nor); + boid_climb(boids, pa, ground_co, ground_nor); + } + /* land boid when really near ground */ + else if(pa->state.co[2] <= ground_co[2] + 1.01 * pa->size * boids->height){ + pa->state.co[2] = ground_co[2] + pa->size * boids->height; + pa->state.vel[2] = 0.0f; + pa->boid->mode = eBoidMode_OnLand; + } + /* if we're falling, can fly and want to go upwards lets fly */ + else if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) + pa->boid->mode = eBoidMode_InAir; + } + else + pa->boid->mode = eBoidMode_InAir; + break; + } + case eBoidMode_Climbing: + { + boid_climb(boids, pa, ground_co, ground_nor); + //float nor[3]; + //VECCOPY(nor, ground_nor); + + ///* gather apparent gravity to r_ve */ + //VECADDFAC(pa->r_ve, pa->r_ve, ground_nor, -1.0); + //Normalize(pa->r_ve); + + ///* raise boid it's size from surface */ + //VecMulf(nor, pa->size * boids->height); + //VecAddf(pa->state.co, ground_co, nor); + + ///* remove normal component from velocity */ + //Projf(v, pa->state.vel, ground_nor); + //VecSubf(pa->state.vel, pa->state.vel, v); + break; + } + case eBoidMode_OnLand: + { + /* stick boid on goal when close enough */ + if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { + pa->boid->mode = eBoidMode_Climbing; + pa->stick_ob = bbd->goal_ob; + boid_find_ground(bbd, pa, ground_co, ground_nor); + boid_climb(boids, pa, ground_co, ground_nor); + } + /* ground is too far away so boid falls */ + else if(pa->state.co[2]-ground_co[2] > 1.1 * pa->size * boids->height) + pa->boid->mode = eBoidMode_Falling; + else { + /* constrain to surface */ + pa->state.co[2] = ground_co[2] + pa->size * boids->height; + pa->state.vel[2] = 0.0f; + } + + if(boids->banking > 0.0f) { + float grav[3]; + /* Don't take gravity's strength in to account, */ + /* otherwise amount of banking is hard to control. */ + VECCOPY(grav, ground_nor); + VecMulf(grav, -1.0f); + + Projf(dvec, pa->boid->acc, pa->state.vel); + VecSubf(dvec, pa->boid->acc, dvec); + + /* gather apparent gravity to r_ve */ + VECADDFAC(pa->r_ve, grav, dvec, -boids->banking); + Normalize(pa->r_ve); + } + else { + /* gather negative surface normal to r_ve */ + VECADDFAC(pa->r_ve, pa->r_ve, ground_nor, -1.0f); + Normalize(pa->r_ve); + } + break; + } + } + + /* save direction to state.ave unless the boid is falling */ + /* (boids can't effect their direction when falling) */ + if(pa->boid->mode!=eBoidMode_Falling && VecLength(pa->state.vel) > 0.1*pa->size) { + VECCOPY(pa->state.ave, pa->state.vel); + Normalize(pa->state.ave); + } + + /* apply damping */ + if(ELEM(pa->boid->mode, eBoidMode_OnLand, eBoidMode_Climbing)) + VecMulf(pa->state.vel, 1.0f - 0.2f*bbd->part->dampfac); + + /* calculate rotation matrix based on forward & down vectors */ + if(pa->boid->mode == eBoidMode_InAir) { + VECCOPY(mat[0], pa->state.ave); + + Projf(dvec, pa->r_ve, pa->state.ave); + VecSubf(mat[2], pa->r_ve, dvec); + Normalize(mat[2]); + } + else { + Projf(dvec, pa->state.ave, pa->r_ve); + VecSubf(mat[0], pa->state.ave, dvec); + Normalize(mat[0]); + + VECCOPY(mat[2], pa->r_ve); + } + VecMulf(mat[2], -1.0f); + Crossf(mat[1], mat[2], mat[0]); + + /* apply rotation */ + Mat3ToQuat_is_ok(mat, q); + QuatCopy(pa->state.rot, q); +} + +BoidRule *boid_new_rule(int type) +{ + BoidRule *rule = NULL; + if(type <= 0) + return NULL; + + switch(type) { + case eBoidRuleType_Goal: + case eBoidRuleType_Avoid: + rule = MEM_callocN(sizeof(BoidRuleGoalAvoid), "BoidRuleGoalAvoid"); + break; + case eBoidRuleType_AvoidCollision: + rule = MEM_callocN(sizeof(BoidRuleAvoidCollision), "BoidRuleAvoidCollision"); + ((BoidRuleAvoidCollision*)rule)->look_ahead = 2.0f; + break; + case eBoidRuleType_FollowLeader: + rule = MEM_callocN(sizeof(BoidRuleFollowLeader), "BoidRuleFollowLeader"); + ((BoidRuleFollowLeader*)rule)->distance = 1.0f; + break; + case eBoidRuleType_AverageSpeed: + rule = MEM_callocN(sizeof(BoidRuleAverageSpeed), "BoidRuleAverageSpeed"); + ((BoidRuleAverageSpeed*)rule)->speed = 0.5f; + break; + case eBoidRuleType_Fight: + rule = MEM_callocN(sizeof(BoidRuleFight), "BoidRuleFight"); + ((BoidRuleFight*)rule)->distance = 100.0f; + ((BoidRuleFight*)rule)->flee_distance = 100.0f; + break; + default: + rule = MEM_callocN(sizeof(BoidRule), "BoidRule"); + break; + } + + rule->type = type; + rule->flag |= BOIDRULE_IN_AIR|BOIDRULE_ON_LAND; + strcpy(rule->name, boidrule_type_items[type-1].name); + + return rule; +} +void boid_default_settings(BoidSettings *boids) +{ + boids->air_max_speed = 10.0f; + boids->air_max_acc = 0.5f; + boids->air_max_ave = 0.5f; + boids->air_personal_space = 1.0f; + + boids->land_max_speed = 5.0f; + boids->land_max_acc = 0.5f; + boids->land_max_ave = 0.5f; + boids->land_personal_space = 1.0f; + + boids->options = BOID_ALLOW_FLIGHT; + + boids->landing_smoothness = 3.0f; + boids->banking = 1.0f; + boids->height = 1.0f; + + boids->health = 1.0f; + boids->accuracy = 1.0f; + boids->aggression = 2.0f; + boids->range = 1.0f; + boids->strength = 0.1f; +} + +BoidState *boid_new_state(BoidSettings *boids) +{ + BoidState *state = MEM_callocN(sizeof(BoidState), "BoidState"); + + state->id = boids->last_state_id++; + if(state->id) + sprintf(state->name, "State %i", state->id); + else + strcpy(state->name, "State"); + + state->rule_fuzziness = 0.5; + state->volume = 1.0f; + state->channels |= ~0; + + return state; +} + +BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state) { + BoidState *staten = MEM_dupallocN(state); + + BLI_duplicatelist(&staten->rules, &state->rules); + BLI_duplicatelist(&staten->conditions, &state->conditions); + BLI_duplicatelist(&staten->actions, &state->actions); + + staten->id = boids->last_state_id++; + + return staten; +} +void boid_free_settings(BoidSettings *boids) +{ + if(boids) { + BoidState *state = boids->states.first; + + for(; state; state=state->next) { + BLI_freelistN(&state->rules); + BLI_freelistN(&state->conditions); + BLI_freelistN(&state->actions); + } + + BLI_freelistN(&boids->states); + + MEM_freeN(boids); + } +} +BoidSettings *boid_copy_settings(BoidSettings *boids) +{ + BoidSettings *nboids = NULL; + + if(boids) { + BoidState *state; + BoidState *nstate; + + nboids = MEM_dupallocN(boids); + + BLI_duplicatelist(&nboids->states, &boids->states); + + state = boids->states.first; + nstate = nboids->states.first; + for(; state; state=state->next, nstate=nstate->next) { + BLI_duplicatelist(&nstate->rules, &state->rules); + BLI_duplicatelist(&nstate->conditions, &state->conditions); + BLI_duplicatelist(&nstate->actions, &state->actions); + } + } + + return nboids; +} +BoidState *boid_get_current_state(BoidSettings *boids) +{ + BoidState *state = boids->states.first; + + for(; state; state=state->next) { + if(state->flag & BOIDSTATE_CURRENT) + break; + } + + return state; +} + diff --git a/source/blender/blenkernel/intern/booleanops.c b/source/blender/blenkernel/intern/booleanops.c new file mode 100644 index 00000000000..eb3aefe7ee6 --- /dev/null +++ b/source/blender/blenkernel/intern/booleanops.c @@ -0,0 +1,602 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * CSG operations. + */ + +#include <string.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_ghash.h" + +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "CSG_BooleanOps.h" + +#include "BKE_booleanops.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_material.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_utildefines.h" + + + +/** + * Here's the vertex iterator structure used to walk through + * the blender vertex structure. + */ + +typedef struct { + DerivedMesh *dm; + Object *ob; + int pos; +} VertexIt; + +/** + * Implementations of local vertex iterator functions. + * These describe a blender mesh to the CSG module. + */ + +static void VertexIt_Destruct(CSG_VertexIteratorDescriptor * iterator) +{ + if (iterator->it) { + // deallocate memory for iterator + MEM_freeN(iterator->it); + iterator->it = 0; + } + iterator->Done = NULL; + iterator->Fill = NULL; + iterator->Reset = NULL; + iterator->Step = NULL; + iterator->num_elements = 0; + +} + +static int VertexIt_Done(CSG_IteratorPtr it) +{ + VertexIt * iterator = (VertexIt *)it; + return(iterator->pos >= iterator->dm->getNumVerts(iterator->dm)); +} + +static void VertexIt_Fill(CSG_IteratorPtr it, CSG_IVertex *vert) +{ + VertexIt * iterator = (VertexIt *)it; + MVert *verts = iterator->dm->getVertArray(iterator->dm); + + float global_pos[3]; + + /* boolean happens in global space, transform both with obmat */ + VecMat4MulVecfl( + global_pos, + iterator->ob->obmat, + verts[iterator->pos].co + ); + + vert->position[0] = global_pos[0]; + vert->position[1] = global_pos[1]; + vert->position[2] = global_pos[2]; +} + +static void VertexIt_Step(CSG_IteratorPtr it) +{ + VertexIt * iterator = (VertexIt *)it; + iterator->pos ++; +} + +static void VertexIt_Reset(CSG_IteratorPtr it) +{ + VertexIt * iterator = (VertexIt *)it; + iterator->pos = 0; +} + +static void VertexIt_Construct(CSG_VertexIteratorDescriptor *output, DerivedMesh *dm, Object *ob) +{ + + VertexIt *it; + if (output == 0) return; + + // allocate some memory for blender iterator + it = (VertexIt *)(MEM_mallocN(sizeof(VertexIt),"Boolean_VIt")); + if (it == 0) { + return; + } + // assign blender specific variables + it->dm = dm; + it->ob = ob; // needed for obmat transformations + + it->pos = 0; + + // assign iterator function pointers. + output->Step = VertexIt_Step; + output->Fill = VertexIt_Fill; + output->Done = VertexIt_Done; + output->Reset = VertexIt_Reset; + output->num_elements = it->dm->getNumVerts(it->dm); + output->it = it; +} + +/** + * Blender Face iterator + */ + +typedef struct { + DerivedMesh *dm; + int pos; + int offset; + int flip; +} FaceIt; + +static void FaceIt_Destruct(CSG_FaceIteratorDescriptor * iterator) +{ + MEM_freeN(iterator->it); + iterator->Done = NULL; + iterator->Fill = NULL; + iterator->Reset = NULL; + iterator->Step = NULL; + iterator->num_elements = 0; +} + +static int FaceIt_Done(CSG_IteratorPtr it) +{ + // assume CSG_IteratorPtr is of the correct type. + FaceIt * iterator = (FaceIt *)it; + return(iterator->pos >= iterator->dm->getNumFaces(iterator->dm)); +} + +static void FaceIt_Fill(CSG_IteratorPtr it, CSG_IFace *face) +{ + // assume CSG_IteratorPtr is of the correct type. + FaceIt *face_it = (FaceIt *)it; + MFace *mfaces = face_it->dm->getFaceArray(face_it->dm); + MFace *mface = &mfaces[face_it->pos]; + + /* reverse face vertices if necessary */ + face->vertex_index[1] = mface->v2; + if( face_it->flip == 0 ) { + face->vertex_index[0] = mface->v1; + face->vertex_index[2] = mface->v3; + } else { + face->vertex_index[2] = mface->v1; + face->vertex_index[0] = mface->v3; + } + if (mface->v4) { + face->vertex_index[3] = mface->v4; + face->vertex_number = 4; + } else { + face->vertex_number = 3; + } + + face->orig_face = face_it->offset + face_it->pos; +} + +static void FaceIt_Step(CSG_IteratorPtr it) +{ + FaceIt * face_it = (FaceIt *)it; + face_it->pos ++; +} + +static void FaceIt_Reset(CSG_IteratorPtr it) +{ + FaceIt * face_it = (FaceIt *)it; + face_it->pos = 0; +} + +static void FaceIt_Construct( + CSG_FaceIteratorDescriptor *output, DerivedMesh *dm, int offset, Object *ob) +{ + FaceIt *it; + if (output == 0) return; + + // allocate some memory for blender iterator + it = (FaceIt *)(MEM_mallocN(sizeof(FaceIt),"Boolean_FIt")); + if (it == 0) { + return ; + } + // assign blender specific variables + it->dm = dm; + it->offset = offset; + it->pos = 0; + + /* determine if we will need to reverse order of face vertices */ + if (ob->size[0] < 0.0f) { + if (ob->size[1] < 0.0f && ob->size[2] < 0.0f) { + it->flip = 1; + } else if (ob->size[1] >= 0.0f && ob->size[2] >= 0.0f) { + it->flip = 1; + } else { + it->flip = 0; + } + } else { + if (ob->size[1] < 0.0f && ob->size[2] < 0.0f) { + it->flip = 0; + } else if (ob->size[1] >= 0.0f && ob->size[2] >= 0.0f) { + it->flip = 0; + } else { + it->flip = 1; + } + } + + // assign iterator function pointers. + output->Step = FaceIt_Step; + output->Fill = FaceIt_Fill; + output->Done = FaceIt_Done; + output->Reset = FaceIt_Reset; + output->num_elements = it->dm->getNumFaces(it->dm); + output->it = it; +} + +static Object *AddNewBlenderMesh(Scene *scene, Base *base) +{ + // This little function adds a new mesh object to the blender object list + // It uses ob to duplicate data as this seems to be easier than creating + // a new one. This new oject contains no faces nor vertices. + Mesh *old_me; + Base *basen; + Object *ob_new; + + // now create a new blender object. + // duplicating all the settings from the previous object + // to the new one. + ob_new= copy_object(base->object); + + // Ok we don't want to use the actual data from the + // last object, the above function incremented the + // number of users, so decrement it here. + old_me= ob_new->data; + old_me->id.us--; + + // Now create a new base to add into the linked list of + // vase objects. + + basen= MEM_mallocN(sizeof(Base), "duplibase"); + *basen= *base; + BLI_addhead(&scene->base, basen); /* addhead: anders oneindige lus */ + basen->object= ob_new; + basen->flag &= ~SELECT; + + // Initialize the mesh data associated with this object. + ob_new->data= add_mesh("Mesh"); + + // Finally assign the object type. + ob_new->type= OB_MESH; + + return ob_new; +} + +static void InterpCSGFace( + DerivedMesh *dm, DerivedMesh *orig_dm, int index, int orig_index, int nr, + float mapmat[][4]) +{ + float obco[3], *co[4], *orig_co[4], w[4][4]; + MFace *mface, *orig_mface; + int j; + + mface = CDDM_get_face(dm, index); + orig_mface = orig_dm->getFaceArray(orig_dm) + orig_index; + + // get the vertex coordinates from the original mesh + orig_co[0] = (orig_dm->getVertArray(orig_dm) + orig_mface->v1)->co; + orig_co[1] = (orig_dm->getVertArray(orig_dm) + orig_mface->v2)->co; + orig_co[2] = (orig_dm->getVertArray(orig_dm) + orig_mface->v3)->co; + orig_co[3] = (orig_mface->v4)? (orig_dm->getVertArray(orig_dm) + orig_mface->v4)->co: NULL; + + // get the vertex coordinates from the new derivedmesh + co[0] = CDDM_get_vert(dm, mface->v1)->co; + co[1] = CDDM_get_vert(dm, mface->v2)->co; + co[2] = CDDM_get_vert(dm, mface->v3)->co; + co[3] = (nr == 4)? CDDM_get_vert(dm, mface->v4)->co: NULL; + + for (j = 0; j < nr; j++) { + // get coordinate into the space of the original mesh + if (mapmat) + VecMat4MulVecfl(obco, mapmat, co[j]); + else + VecCopyf(obco, co[j]); + + InterpWeightsQ3Dfl(orig_co[0], orig_co[1], orig_co[2], orig_co[3], obco, w[j]); + } + + CustomData_interp(&orig_dm->faceData, &dm->faceData, &orig_index, NULL, (float*)w, 1, index); +} + +/* Iterate over the CSG Output Descriptors and create a new DerivedMesh + from them */ +static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh( + CSG_FaceIteratorDescriptor *face_it, + CSG_VertexIteratorDescriptor *vertex_it, + float parinv[][4], + float mapmat[][4], + Material **mat, + int *totmat, + DerivedMesh *dm1, + Object *ob1, + DerivedMesh *dm2, + Object *ob2) +{ + DerivedMesh *result, *orig_dm; + GHash *material_hash = NULL; + Mesh *me1= (Mesh*)ob1->data; + Mesh *me2= (Mesh*)ob2->data; + int i; + + // create a new DerivedMesh + result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements); + CustomData_merge(&dm1->faceData, &result->faceData, CD_MASK_DERIVEDMESH, + CD_DEFAULT, face_it->num_elements); + CustomData_merge(&dm2->faceData, &result->faceData, CD_MASK_DERIVEDMESH, + CD_DEFAULT, face_it->num_elements); + + // step through the vertex iterators: + for (i = 0; !vertex_it->Done(vertex_it->it); i++) { + CSG_IVertex csgvert; + MVert *mvert = CDDM_get_vert(result, i); + + // retrieve a csg vertex from the boolean module + vertex_it->Fill(vertex_it->it, &csgvert); + vertex_it->Step(vertex_it->it); + + // we have to map the vertex coordinates back in the coordinate frame + // of the resulting object, since it was computed in world space + VecMat4MulVecfl(mvert->co, parinv, csgvert.position); + } + + // a hash table to remap materials to indices + if (mat) { + material_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + *totmat = 0; + } + + // step through the face iterators + for(i = 0; !face_it->Done(face_it->it); i++) { + Mesh *orig_me; + Object *orig_ob; + Material *orig_mat; + CSG_IFace csgface; + MFace *mface; + int orig_index, mat_nr; + + // retrieve a csg face from the boolean module + face_it->Fill(face_it->it, &csgface); + face_it->Step(face_it->it); + + // find the original mesh and data + orig_ob = (csgface.orig_face < dm1->getNumFaces(dm1))? ob1: ob2; + orig_dm = (csgface.orig_face < dm1->getNumFaces(dm1))? dm1: dm2; + orig_me = (orig_ob == ob1)? me1: me2; + orig_index = (orig_ob == ob1)? csgface.orig_face: csgface.orig_face - dm1->getNumFaces(dm1); + + // copy all face layers, including mface + CustomData_copy_data(&orig_dm->faceData, &result->faceData, orig_index, i, 1); + + // set mface + mface = CDDM_get_face(result, i); + mface->v1 = csgface.vertex_index[0]; + mface->v2 = csgface.vertex_index[1]; + mface->v3 = csgface.vertex_index[2]; + mface->v4 = (csgface.vertex_number == 4)? csgface.vertex_index[3]: 0; + + // set material, based on lookup in hash table + orig_mat= give_current_material(orig_ob, mface->mat_nr+1); + + if (mat && orig_mat) { + if (!BLI_ghash_haskey(material_hash, orig_mat)) { + mat[*totmat] = orig_mat; + mat_nr = mface->mat_nr = (*totmat)++; + BLI_ghash_insert(material_hash, orig_mat, SET_INT_IN_POINTER(mat_nr)); + } + else + mface->mat_nr = GET_INT_FROM_POINTER(BLI_ghash_lookup(material_hash, orig_mat)); + } + else + mface->mat_nr = 0; + + InterpCSGFace(result, orig_dm, i, orig_index, csgface.vertex_number, + (orig_me == me2)? mapmat: NULL); + + test_index_face(mface, &result->faceData, i, csgface.vertex_number); + } + + if (material_hash) + BLI_ghash_free(material_hash, NULL, NULL); + + CDDM_calc_edges(result); + CDDM_calc_normals(result); + + return result; +} + +static void BuildMeshDescriptors( + struct DerivedMesh *dm, + struct Object *ob, + int face_offset, + struct CSG_FaceIteratorDescriptor * face_it, + struct CSG_VertexIteratorDescriptor * vertex_it) +{ + VertexIt_Construct(vertex_it,dm, ob); + FaceIt_Construct(face_it,dm,face_offset,ob); +} + +static void FreeMeshDescriptors( + struct CSG_FaceIteratorDescriptor *face_it, + struct CSG_VertexIteratorDescriptor *vertex_it) +{ + VertexIt_Destruct(vertex_it); + FaceIt_Destruct(face_it); +} + +DerivedMesh *NewBooleanDerivedMesh_intern( + DerivedMesh *dm, struct Object *ob, DerivedMesh *dm_select, struct Object *ob_select, + int int_op_type, Material **mat, int *totmat) +{ + + float inv_mat[4][4]; + float map_mat[4][4]; + + DerivedMesh *result = NULL; + + if (dm == NULL || dm_select == NULL) return 0; + if (!dm->getNumFaces(dm) || !dm_select->getNumFaces(dm_select)) return 0; + + // we map the final object back into ob's local coordinate space. For this + // we need to compute the inverse transform from global to ob (inv_mat), + // and the transform from ob to ob_select for use in interpolation (map_mat) + Mat4Invert(inv_mat, ob->obmat); + Mat4MulMat4(map_mat, ob_select->obmat, inv_mat); + Mat4Invert(inv_mat, ob_select->obmat); + + { + // interface with the boolean module: + // + // the idea is, we pass the boolean module verts and faces using the + // provided descriptors. once the boolean operation is performed, we + // get back output descriptors, from which we then build a DerivedMesh + + CSG_VertexIteratorDescriptor vd_1, vd_2; + CSG_FaceIteratorDescriptor fd_1, fd_2; + CSG_OperationType op_type; + CSG_BooleanOperation *bool_op; + + // work out the operation they chose and pick the appropriate + // enum from the csg module. + switch (int_op_type) { + case 1 : op_type = e_csg_intersection; break; + case 2 : op_type = e_csg_union; break; + case 3 : op_type = e_csg_difference; break; + case 4 : op_type = e_csg_classify; break; + default : op_type = e_csg_intersection; + } + + BuildMeshDescriptors(dm_select, ob_select, 0, &fd_1, &vd_1); + BuildMeshDescriptors(dm, ob, dm_select->getNumFaces(dm_select) , &fd_2, &vd_2); + + bool_op = CSG_NewBooleanFunction(); + + // perform the operation + if (CSG_PerformBooleanOperation(bool_op, op_type, fd_1, vd_1, fd_2, vd_2)) { + CSG_VertexIteratorDescriptor vd_o; + CSG_FaceIteratorDescriptor fd_o; + + CSG_OutputFaceDescriptor(bool_op, &fd_o); + CSG_OutputVertexDescriptor(bool_op, &vd_o); + + // iterate through results of operation and insert + // into new object + result = ConvertCSGDescriptorsToDerivedMesh( + &fd_o, &vd_o, inv_mat, map_mat, mat, totmat, dm_select, ob_select, dm, ob); + + // free up the memory + CSG_FreeVertexDescriptor(&vd_o); + CSG_FreeFaceDescriptor(&fd_o); + } +// else +// XXX error("Unknown internal error in boolean"); + + CSG_FreeBooleanOperation(bool_op); + + FreeMeshDescriptors(&fd_1, &vd_1); + FreeMeshDescriptors(&fd_2, &vd_2); + } + + return result; +} + +int NewBooleanMesh(Scene *scene, Base *base, Base *base_select, int int_op_type) +{ + Mesh *me_new; + int a, maxmat, totmat= 0; + Object *ob_new, *ob, *ob_select; + Material **mat; + DerivedMesh *result; + DerivedMesh *dm_select; + DerivedMesh *dm; + + ob= base->object; + ob_select= base_select->object; + + dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + dm_select = mesh_create_derived_view(scene, ob_select, 0); // no modifiers in editmode ?? + + maxmat= ob->totcol + ob_select->totcol; + mat= (Material**)MEM_mallocN(sizeof(Material*)*maxmat, "NewBooleanMeshMat"); + + /* put some checks in for nice user feedback */ + if (dm == NULL || dm_select == NULL) return 0; + if (!dm->getNumFaces(dm) || !dm_select->getNumFaces(dm_select)) + { + MEM_freeN(mat); + return -1; + } + + result= NewBooleanDerivedMesh_intern(dm, ob, dm_select, ob_select, int_op_type, mat, &totmat); + + if (result == NULL) { + MEM_freeN(mat); + return 0; + } + + /* create a new blender mesh object - using 'base' as a template */ + ob_new= AddNewBlenderMesh(scene, base_select); + me_new= ob_new->data; + + DM_to_mesh(result, me_new); + result->release(result); + + dm->release(dm); + dm_select->release(dm_select); + + /* add materials to object */ + for (a = 0; a < totmat; a++) + assign_material(ob_new, mat[a], a+1); + + MEM_freeN(mat); + + /* update dag */ + DAG_object_flush_update(scene, ob_new, OB_RECALC_DATA); + + return 1; +} + +DerivedMesh *NewBooleanDerivedMesh(DerivedMesh *dm, struct Object *ob, DerivedMesh *dm_select, struct Object *ob_select, + int int_op_type) +{ + return NewBooleanDerivedMesh_intern(dm, ob, dm_select, ob_select, int_op_type, NULL, NULL); +} + diff --git a/source/blender/blenkernel/intern/booleanops_mesh.c b/source/blender/blenkernel/intern/booleanops_mesh.c new file mode 100644 index 00000000000..14e32873dbd --- /dev/null +++ b/source/blender/blenkernel/intern/booleanops_mesh.c @@ -0,0 +1,293 @@ +#if 0 + +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include "CSG_BooleanOps.h" + +#include "BKE_booleanops.h" +#include "BKE_booleanops_mesh.h" +#include "MEM_guardedalloc.h" + +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_displist.h" +#include "BKE_object.h" +#include "BKE_utildefines.h" +#include "BKE_library.h" +#include "BKE_material.h" + +#include "BLI_arithb.h" + +/** + * Implementation of boolean ops mesh interface. + */ + + void +CSG_DestroyMeshDescriptor( + CSG_MeshDescriptor *mesh +){ + // Call mesh descriptors destroy function.... + mesh->m_destroy_func(mesh); +} + +// Destroy function for blender mesh internals. + +static + void +CSG_DestroyBlenderMeshInternals( + CSG_MeshDescriptor *mesh +) { + // Free face and vertex iterators. + FreeMeshDescriptors(&(mesh->m_face_iterator),&(mesh->m_vertex_iterator)); +} + + +static + void +CSG_DestroyCSGMeshInternals( + CSG_MeshDescriptor *mesh +){ + CSG_FreeVertexDescriptor(&(mesh->m_vertex_iterator)); + CSG_FreeFaceDescriptor(&(mesh->m_face_iterator)); +} + +static + int +MakeCSGMeshFromBlenderBase( + Base * base, + CSG_MeshDescriptor * output +) { + Mesh *me; + if (output == NULL || base == NULL) return 0; + + me = get_mesh(base->object); + + output->m_descriptor.user_face_vertex_data_size = 0; + output->m_descriptor.user_data_size = sizeof(FaceData); + + output->base = base; + + BuildMeshDescriptors( + base->object, + &(output->m_face_iterator), + &(output->m_vertex_iterator) + ); + + output->m_destroy_func = CSG_DestroyBlenderMeshInternals; + + return 1; +} + + int +CSG_LoadBlenderMesh( + Object * obj, + CSG_MeshDescriptor *output +){ + + Mesh *me; + if (output == NULL || obj == NULL) return 0; + + me = get_mesh(obj); + + output->m_descriptor.user_face_vertex_data_size = 0; + output->m_descriptor.user_data_size = sizeof(FaceData); + + output->base = NULL; + + BuildMeshDescriptors( + obj, + &(output->m_face_iterator), + &(output->m_vertex_iterator) + ); + + output->m_destroy_func = CSG_DestroyBlenderMeshInternals; + output->base = NULL; + + return 1; +} + + + + + int +CSG_AddMeshToBlender( + CSG_MeshDescriptor *mesh +){ + Mesh *me_new = NULL; + Object *ob_new = NULL; + float inv_mat[4][4]; + + if (mesh == NULL) return 0; + if (mesh->base == NULL) return 0; + + Mat4Invert(inv_mat,mesh->base->object->obmat); + + // Create a new blender mesh object - using 'base' as + // a template for the new object. + ob_new= AddNewBlenderMesh(mesh->base); + + me_new = ob_new->data; + + // make sure the iterators are reset. + mesh->m_face_iterator.Reset(mesh->m_face_iterator.it); + mesh->m_vertex_iterator.Reset(mesh->m_vertex_iterator.it); + + // iterate through results of operation and insert into new object + // see subsurf.c + + ConvertCSGDescriptorsToMeshObject( + ob_new, + &(mesh->m_descriptor), + &(mesh->m_face_iterator), + &(mesh->m_vertex_iterator), + inv_mat + ); + + return 1; +} + + int +CSG_PerformOp( + CSG_MeshDescriptor *mesh1, + CSG_MeshDescriptor *mesh2, + int int_op_type, + CSG_MeshDescriptor *output +){ + + CSG_OperationType op_type; + CSG_BooleanOperation * bool_op = CSG_NewBooleanFunction(); + int success = 0; + + if (bool_op == NULL) return 0; + + if ((mesh1 == NULL) || (mesh2 == NULL) || (output == NULL)) { + return 0; + } + if ((int_op_type < 1) || (int_op_type > 3)) return 0; + + switch (int_op_type) { + case 1 : op_type = e_csg_intersection; break; + case 2 : op_type = e_csg_union; break; + case 3 : op_type = e_csg_difference; break; + case 4 : op_type = e_csg_classify; break; + default : op_type = e_csg_intersection; + } + + output->m_descriptor = CSG_DescibeOperands(bool_op,mesh1->m_descriptor,mesh2->m_descriptor); + output->base = mesh1->base; + + if (output->m_descriptor.user_face_vertex_data_size) { + // Then use the only interp function supported + success = + CSG_PerformBooleanOperation( + bool_op, + op_type, + mesh1->m_face_iterator, + mesh1->m_vertex_iterator, + mesh2->m_face_iterator, + mesh2->m_vertex_iterator, + InterpFaceVertexData + ); + } else { + success = + CSG_PerformBooleanOperation( + bool_op, + op_type, + mesh1->m_face_iterator, + mesh1->m_vertex_iterator, + mesh2->m_face_iterator, + mesh2->m_vertex_iterator, + InterpNoUserData + ); + } + + if (!success) { + CSG_FreeBooleanOperation(bool_op); + bool_op = NULL; + return 0; + } + + // get the ouput mesh descriptors. + + CSG_OutputFaceDescriptor(bool_op,&(output->m_face_iterator)); + CSG_OutputVertexDescriptor(bool_op,&(output->m_vertex_iterator)); + output->m_destroy_func = CSG_DestroyCSGMeshInternals; + + return 1; +} + + int +NewBooleanMeshTest( + struct Base * base, + struct Base * base_select, + int op_type +){ + + CSG_MeshDescriptor m1,m2,output; + CSG_MeshDescriptor output2,output3; + + if (!MakeCSGMeshFromBlenderBase(base,&m1)) { + return 0; + } + + if (!MakeCSGMeshFromBlenderBase(base_select,&m2)) { + return 0; + } + + CSG_PerformOp(&m1,&m2,1,&output); + CSG_PerformOp(&m1,&m2,2,&output2); + CSG_PerformOp(&m1,&m2,3,&output3); + + if (!CSG_AddMeshToBlender(&output)) { + return 0; + } + if (!CSG_AddMeshToBlender(&output2)) { + return 0; + } + if (!CSG_AddMeshToBlender(&output3)) { + return 0; + } + + + CSG_DestroyMeshDescriptor(&m1); + CSG_DestroyMeshDescriptor(&m2); + CSG_DestroyMeshDescriptor(&output); + CSG_DestroyMeshDescriptor(&output2); + CSG_DestroyMeshDescriptor(&output3); + + return 1; +} + +#endif + diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 021f76fd2f1..5dbef017f9d 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -28,19 +28,26 @@ */ #include <math.h> +#include <string.h> #include "MEM_guardedalloc.h" #include "DNA_brush_types.h" +#include "DNA_color_types.h" #include "DNA_image_types.h" #include "DNA_texture_types.h" #include "DNA_scene_types.h" +#include "DNA_windowmanager_types.h" + +#include "RNA_access.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" #include "BKE_brush.h" +#include "BKE_colortools.h" #include "BKE_global.h" +#include "BKE_image.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_texture.h" @@ -50,6 +57,7 @@ #include "IMB_imbuf_types.h" #include "RE_render_ext.h" /* externtex */ +#include "RE_shader_ext.h" /* Datablock add/copy/free/make_local */ @@ -68,6 +76,9 @@ Brush *add_brush(char *name) brush->rate= 0.1f; brush->innerradius= 0.5f; brush->clone.alpha= 0.5; + brush->sculpt_tool = SCULPT_TOOL_DRAW; + + brush_curve_preset(brush, BRUSH_PRESET_SHARP); /* enable fake user by default */ brush->id.flag |= LIB_FAKEUSER; @@ -92,6 +103,8 @@ Brush *copy_brush(Brush *brush) } } + brushn->curve= curvemapping_copy(brush->curve); + /* enable fake user by default */ if (!(brushn->id.flag & LIB_FAKEUSER)) { brushn->id.flag |= LIB_FAKEUSER; @@ -114,6 +127,8 @@ void free_brush(Brush *brush) MEM_freeN(mtex); } } + + curvemapping_free(brush->curve); } void make_local_brush(Brush *brush) @@ -170,6 +185,19 @@ void make_local_brush(Brush *brush) /* Library Operations */ +Brush **current_brush_source(Scene *sce) +{ + if(G.f & G_SCULPTMODE) + return &sce->toolsettings->sculpt->brush; + else if(G.f & G_VERTEXPAINT) + return &sce->toolsettings->vpaint->brush; + else if(G.f & G_WEIGHTPAINT) + return &sce->toolsettings->wpaint->brush; + else if(G.f & G_TEXTUREPAINT) + return &sce->toolsettings->imapaint.brush; + return NULL; +} + int brush_set_nr(Brush **current_brush, int nr) { ID *idtest, *id; @@ -217,6 +245,68 @@ void brush_toggled_fake_user(Brush *brush) } } +void brush_curve_preset(Brush *b, BrushCurvePreset preset) +{ + CurveMap *cm = NULL; + + if(!b->curve) + b->curve = curvemapping_add(1, 0, 0, 1, 1); + + cm = b->curve->cm; + + if(cm->curve) + MEM_freeN(cm->curve); + + if(preset == BRUSH_PRESET_SHARP) + cm->totpoint= 3; + if(preset == BRUSH_PRESET_SMOOTH) + cm->totpoint= 6; + if(preset == BRUSH_PRESET_MAX) + cm->totpoint= 2; + + + cm->curve= MEM_callocN(cm->totpoint*sizeof(CurveMapPoint), "curve points"); + cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE; + + if(preset == BRUSH_PRESET_SHARP) { + cm->curve[0].x= 0; + cm->curve[0].y= 1; + cm->curve[1].x= 0.33; + cm->curve[1].y= 0.33; + cm->curve[2].x= 1; + cm->curve[2].y= 0; + } + else if(preset == BRUSH_PRESET_SMOOTH) { + cm->curve[0].x= 0; + cm->curve[0].y= 1; + cm->curve[1].x= 0.1; + cm->curve[1].y= 0.97553; + cm->curve[2].x= 0.3; + cm->curve[2].y= 0.79389; + cm->curve[3].x= 0.9; + cm->curve[3].y= 0.02447; + cm->curve[4].x= 0.7; + cm->curve[4].y= 0.20611; + cm->curve[5].x= 1; + cm->curve[5].y= 0; + } + else if(preset == BRUSH_PRESET_MAX) { + cm->curve[0].x= 0; + cm->curve[0].y= 1; + cm->curve[1].x= 1; + cm->curve[1].y= 1; + } + + curvemapping_changed(b->curve, 0); +} + +static MTex *brush_active_texture(Brush *brush) +{ + if(brush && brush->texact >= 0) + return brush->mtex[brush->texact]; + return NULL; +} + int brush_texture_set_nr(Brush *brush, int nr) { ID *idtest, *id=NULL; @@ -895,4 +985,130 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl return totpaintops; } +/* Uses the brush curve control to find a strength value between 0 and 1 */ +float brush_curve_strength(Brush *br, float p, const float len) +{ + if(p > len) p= len; + return curvemapping_evaluateF(br->curve, 0, p/len); +} + +/* TODO: should probably be unified with BrushPainter stuff? */ +unsigned int *brush_gen_texture_cache(Brush *br, int half_side) +{ + unsigned int *texcache = NULL; + MTex *mtex = br->mtex[br->texact]; + TexResult texres; + int hasrgb, ix, iy; + int side = half_side * 2; + + memset(&texres, 0, sizeof(TexResult)); + + if(mtex && mtex->tex) { + float x, y, step = 2.0 / side, co[3]; + + texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache"); + + BKE_image_get_ibuf(mtex->tex->ima, NULL); + + /*do normalized cannonical view coords for texture*/ + for (y=-1.0, iy=0; iy<side; iy++, y += step) { + for (x=-1.0, ix=0; ix<side; ix++, x += step) { + co[0]= x; + co[1]= y; + co[2]= 0.0f; + + /* This is copied from displace modifier code */ + hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 1, &texres); + + /* if the texture gave an RGB value, we assume it didn't give a valid + * intensity, so calculate one (formula from do_material_tex). + * if the texture didn't give an RGB value, copy the intensity across + */ + if(hasrgb & TEX_RGB) + texres.tin = (0.35 * texres.tr + 0.45 * + texres.tg + 0.2 * texres.tb); + + texres.tin = texres.tin * 255.0; + ((char*)texcache)[(iy*side+ix)*4] = (char)texres.tin; + ((char*)texcache)[(iy*side+ix)*4+1] = (char)texres.tin; + ((char*)texcache)[(iy*side+ix)*4+2] = (char)texres.tin; + ((char*)texcache)[(iy*side+ix)*4+3] = (char)texres.tin; + } + } + } + + return texcache; +} + +/**** Radial Control ****/ +static struct ImBuf *brush_gen_radial_control_imbuf(Brush *br) +{ + ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture"); + unsigned int *texcache; + int side = 128; + int half = side / 2; + int i, j; + + texcache = brush_gen_texture_cache(br, half); + im->rect_float = MEM_callocN(sizeof(float) * side * side, "radial control rect"); + im->x = im->y = side; + + for(i=0; i<side; ++i) { + for(j=0; j<side; ++j) { + float magn= sqrt(pow(i - half, 2) + pow(j - half, 2)); + im->rect_float[i*side + j]= brush_curve_strength(br, magn, half); + } + } + /* Modulate curve with texture */ + if(texcache) { + for(i=0; i<side; ++i) { + for(j=0; j<side; ++j) { + const int col= texcache[i*side+j]; + im->rect_float[i*side+j]*= (((char*)&col)[0]+((char*)&col)[1]+((char*)&col)[2])/3.0f/255.0f; + } + } + + MEM_freeN(texcache); + } + + return im; +} + +void brush_radial_control_invoke(wmOperator *op, Brush *br, float size_weight) +{ + int mode = RNA_int_get(op->ptr, "mode"); + float original_value= 0; + + if(mode == WM_RADIALCONTROL_SIZE) + original_value = br->size * size_weight; + else if(mode == WM_RADIALCONTROL_STRENGTH) + original_value = br->alpha; + else if(mode == WM_RADIALCONTROL_ANGLE) { + MTex *mtex = brush_active_texture(br); + if(mtex) + original_value = mtex->rot; + } + + RNA_float_set(op->ptr, "initial_value", original_value); + op->customdata = brush_gen_radial_control_imbuf(br); +} + +int brush_radial_control_exec(wmOperator *op, Brush *br, float size_weight) +{ + int mode = RNA_int_get(op->ptr, "mode"); + float new_value = RNA_float_get(op->ptr, "new_value"); + const float conv = 0.017453293; + + if(mode == WM_RADIALCONTROL_SIZE) + br->size = new_value * size_weight; + else if(mode == WM_RADIALCONTROL_STRENGTH) + br->alpha = new_value; + else if(mode == WM_RADIALCONTROL_ANGLE) { + MTex *mtex = brush_active_texture(br); + if(mtex) + mtex->rot = new_value * conv; + } + + return OPERATOR_FINISHED; +} diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 2c1b5ced614..706eece108c 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -42,6 +42,7 @@ #include "BKE_displist.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_multires.h" #include "BKE_utildefines.h" #include "BLI_arithb.h" @@ -52,6 +53,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_fluidsim.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -64,6 +66,7 @@ #include <string.h> #include <limits.h> +#include <math.h> typedef struct { DerivedMesh dm; @@ -479,10 +482,14 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us CDDerivedMesh *cddm = (CDDerivedMesh*) dm; MVert *mv = cddm->mvert; MFace *mf = cddm->mface; - MCol *mc = DM_get_face_data_layer(dm, CD_MCOL); + MCol *mc; float *nors= dm->getFaceDataArray(dm, CD_NORMAL); int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX); + mc = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL); + if(!mc) + mc = DM_get_face_data_layer(dm, CD_MCOL); + for(i = 0; i < dm->numFaceData; i++, mf++) { int drawSmooth = (mf->flag & ME_SMOOTH); @@ -885,6 +892,7 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob) { CDDerivedMesh *cddm = cdDM_create("CDDM_from_mesh dm"); DerivedMesh *dm = &cddm->dm; + CustomDataMask mask = CD_MASK_MESH & (~CD_MASK_MDISPS); int i, *index, alloctype; /* this does a referenced copy, the only new layers being ORIGINDEX, @@ -900,11 +908,11 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob) alloctype= CD_REFERENCE; - CustomData_merge(&mesh->vdata, &dm->vertData, CD_MASK_MESH, alloctype, + CustomData_merge(&mesh->vdata, &dm->vertData, mask, alloctype, mesh->totvert); - CustomData_merge(&mesh->edata, &dm->edgeData, CD_MASK_MESH, alloctype, + CustomData_merge(&mesh->edata, &dm->edgeData, mask, alloctype, mesh->totedge); - CustomData_merge(&mesh->fdata, &dm->faceData, CD_MASK_MESH, alloctype, + CustomData_merge(&mesh->fdata, &dm->faceData, mask, alloctype, mesh->totface); cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); @@ -922,12 +930,6 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob) index = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX); for(i = 0; i < mesh->totface; ++i, ++index) *index = i; - - /* works in conjunction with hack during modifier calc, where active mcol - layer with weight paint colors is temporarily added */ - if ((G.f & G_WEIGHTPAINT) && - (ob && ob==(G.scene->basact?G.scene->basact->object:NULL))) - CustomData_duplicate_referenced_layer(&dm->faceData, CD_MCOL); return dm; } @@ -1218,7 +1220,7 @@ void CDDM_calc_edges(DerivedMesh *dm) BLI_edgehashIterator_free(ehi); /* free old CustomData and assign new one */ - CustomData_free(&dm->edgeData, dm->numVertData); + CustomData_free(&dm->edgeData, dm->numEdgeData); dm->edgeData = edgeData; dm->numEdgeData = numEdges; @@ -1281,3 +1283,192 @@ MFace *CDDM_get_faces(DerivedMesh *dm) return ((CDDerivedMesh*)dm)->mface; } +/* Multires DerivedMesh, extends CDDM */ +typedef struct MultiresDM { + CDDerivedMesh cddm; + + MultiresModifierData *mmd; + + int lvl, totlvl; + float (*orco)[3]; + MVert *subco; + + ListBase *vert_face_map, *vert_edge_map; + IndexNode *vert_face_map_mem, *vert_edge_map_mem; + int *face_offsets; + + Mesh *me; + int modified; + + void (*update)(DerivedMesh*); +} MultiresDM; + +static void MultiresDM_release(DerivedMesh *dm) +{ + MultiresDM *mrdm = (MultiresDM*)dm; + int mvert_layer; + + /* Before freeing, need to update the displacement map */ + if(dm->needsFree && mrdm->modified) + mrdm->update(dm); + + /* If the MVert data is being used as the sculpt undo store, don't free it */ + mvert_layer = CustomData_get_layer_index(&dm->vertData, CD_MVERT); + if(mvert_layer != -1) { + CustomDataLayer *cd = &dm->vertData.layers[mvert_layer]; + if(cd->data == mrdm->mmd->undo_verts) + cd->flag |= CD_FLAG_NOFREE; + } + + if(DM_release(dm)) { + MEM_freeN(mrdm->subco); + MEM_freeN(mrdm->orco); + if(mrdm->vert_face_map) + MEM_freeN(mrdm->vert_face_map); + if(mrdm->vert_face_map_mem) + MEM_freeN(mrdm->vert_face_map_mem); + if(mrdm->vert_edge_map) + MEM_freeN(mrdm->vert_edge_map); + if(mrdm->vert_edge_map_mem) + MEM_freeN(mrdm->vert_edge_map_mem); + if(mrdm->face_offsets) + MEM_freeN(mrdm->face_offsets); + MEM_freeN(mrdm); + } +} + +DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, int numVerts, int numEdges, int numFaces) +{ + MultiresDM *mrdm = MEM_callocN(sizeof(MultiresDM), "MultiresDM"); + CDDerivedMesh *cddm = cdDM_create("MultiresDM CDDM"); + DerivedMesh *dm = NULL; + + mrdm->cddm = *cddm; + MEM_freeN(cddm); + dm = &mrdm->cddm.dm; + + mrdm->mmd = ms->mmd; + mrdm->me = ms->me; + + if(dm) { + MDisps *disps; + MVert *mvert; + int i; + + DM_from_template(dm, orig, numVerts, numEdges, numFaces); + CustomData_free_layers(&dm->faceData, CD_MDISPS, numFaces); + + disps = CustomData_get_layer(&orig->faceData, CD_MDISPS); + if(disps) + CustomData_add_layer(&dm->faceData, CD_MDISPS, CD_REFERENCE, disps, numFaces); + + + mvert = CustomData_get_layer(&orig->vertData, CD_MVERT); + mrdm->orco = MEM_callocN(sizeof(float) * 3 * orig->getNumVerts(orig), "multires orco"); + for(i = 0; i < orig->getNumVerts(orig); ++i) + VecCopyf(mrdm->orco[i], mvert[i].co); + } + else + DM_init(dm, numVerts, numEdges, numFaces); + + CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts); + CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges); + CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces); + + mrdm->cddm.mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); + mrdm->cddm.medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); + mrdm->cddm.mface = CustomData_get_layer(&dm->faceData, CD_MFACE); + + mrdm->lvl = ms->mmd->lvl; + mrdm->totlvl = ms->mmd->totlvl; + mrdm->subco = MEM_callocN(sizeof(MVert)*numVerts, "multires subdivided verts"); + mrdm->modified = 0; + + dm->release = MultiresDM_release; + + return dm; +} + +Mesh *MultiresDM_get_mesh(DerivedMesh *dm) +{ + return ((MultiresDM*)dm)->me; +} + +void *MultiresDM_get_orco(DerivedMesh *dm) +{ + return ((MultiresDM*)dm)->orco; + +} + +MVert *MultiresDM_get_subco(DerivedMesh *dm) +{ + return ((MultiresDM*)dm)->subco; +} + +int MultiresDM_get_totlvl(DerivedMesh *dm) +{ + return ((MultiresDM*)dm)->totlvl; +} + +int MultiresDM_get_lvl(DerivedMesh *dm) +{ + return ((MultiresDM*)dm)->lvl; +} + +void MultiresDM_set_orco(DerivedMesh *dm, float (*orco)[3]) +{ + ((MultiresDM*)dm)->orco = orco; +} + +void MultiresDM_set_update(DerivedMesh *dm, void (*update)(DerivedMesh*)) +{ + ((MultiresDM*)dm)->update = update; +} + +ListBase *MultiresDM_get_vert_face_map(DerivedMesh *dm) +{ + MultiresDM *mrdm = (MultiresDM*)dm; + + if(!mrdm->vert_face_map) + create_vert_face_map(&mrdm->vert_face_map, &mrdm->vert_face_map_mem, mrdm->me->mface, + mrdm->me->totvert, mrdm->me->totface); + + return mrdm->vert_face_map; +} + +ListBase *MultiresDM_get_vert_edge_map(DerivedMesh *dm) +{ + MultiresDM *mrdm = (MultiresDM*)dm; + + if(!mrdm->vert_edge_map) + create_vert_edge_map(&mrdm->vert_edge_map, &mrdm->vert_edge_map_mem, mrdm->me->medge, + mrdm->me->totvert, mrdm->me->totedge); + + return mrdm->vert_edge_map; +} + +int *MultiresDM_get_face_offsets(DerivedMesh *dm) +{ + MultiresDM *mrdm = (MultiresDM*)dm; + int i, accum = 0; + + if(!mrdm->face_offsets) { + int len = (int)pow(2, mrdm->lvl - 2) - 1; + int area = len * len; + int t = 1 + len * 3 + area * 3, q = t + len + area; + + mrdm->face_offsets = MEM_callocN(sizeof(int) * mrdm->me->totface, "mrdm face offsets"); + for(i = 0; i < mrdm->me->totface; ++i) { + mrdm->face_offsets[i] = accum; + + accum += (mrdm->me->mface[i].v4 ? q : t); + } + } + + return mrdm->face_offsets; +} + +void MultiresDM_mark_as_modified(DerivedMesh *dm) +{ + ((MultiresDM*)dm)->modified = 1; +} diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index af42d612870..3acaaecb1e8 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -33,6 +33,7 @@ #include "DNA_mesh_types.h" #include "DNA_object_force.h" #include "DNA_scene_types.h" +#include "DNA_particle_types.h" #include "BKE_deform.h" #include "BKE_DerivedMesh.h" @@ -42,6 +43,7 @@ #include "BKE_object.h" #include "BKE_modifier.h" #include "BKE_utildefines.h" +#include "BKE_particle.h" #include "BKE_pointcache.h" @@ -338,44 +340,6 @@ void bvhselftree_update_from_cloth(ClothModifierData *clmd, int moving) } } -int modifiers_indexInObject(Object *ob, ModifierData *md_seek); - -int cloth_read_cache(Object *ob, ClothModifierData *clmd, float framenr) -{ - PTCacheID pid; - PTCacheFile *pf; - Cloth *cloth = clmd->clothObject; - unsigned int a, ret = 1; - - if(!cloth) - return 0; - - BKE_ptcache_id_from_cloth(&pid, ob, clmd); - pf = BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, framenr); - if(pf) { - for(a = 0; a < cloth->numverts; a++) { - if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].x, 3)) { - ret = 0; - break; - } - if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].xconst, 3)) { - ret = 0; - break; - } - if(!BKE_ptcache_file_read_floats(pf, cloth->verts[a].v, 3)) { - ret = 0; - break; - } - } - - BKE_ptcache_file_close(pf); - } - else - ret = 0; - - return ret; -} - void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr) { PTCacheID pid; @@ -389,30 +353,6 @@ void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr) BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr); } -void cloth_write_cache(Object *ob, ClothModifierData *clmd, float framenr) -{ - Cloth *cloth = clmd->clothObject; - PTCacheID pid; - PTCacheFile *pf; - unsigned int a; - - if(!cloth) - return; - - BKE_ptcache_id_from_cloth(&pid, ob, clmd); - pf = BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, framenr); - if(!pf) - return; - - for(a = 0; a < cloth->numverts; a++) { - BKE_ptcache_file_write_floats(pf, cloth->verts[a].x, 3); - BKE_ptcache_file_write_floats(pf, cloth->verts[a].xconst, 3); - BKE_ptcache_file_write_floats(pf, cloth->verts[a].v, 3); - } - - BKE_ptcache_file_close(pf); -} - static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr) { PointCache *cache; @@ -479,25 +419,28 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul /************************************************ * clothModifier_do - main simulation function ************************************************/ -DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) +DerivedMesh *clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) { DerivedMesh *result; PointCache *cache; PTCacheID pid; float timescale; int framedelta, framenr, startframe, endframe; + int cache_result; - framenr= (int)G.scene->r.cfra; + clmd->scene= scene; /* nice to pass on later :) */ + framenr= (int)scene->r.cfra; cache= clmd->point_cache; result = CDDM_copy(dm); BKE_ptcache_id_from_cloth(&pid, ob, clmd); - BKE_ptcache_id_time(&pid, framenr, &startframe, &endframe, ×cale); + BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); clmd->sim_parms->timescale= timescale; if(!result) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; + cache->last_exact= 0; return dm; } @@ -509,6 +452,7 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh * if(result->getNumVerts(result) != clmd->clothObject->numverts) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; + cache->last_exact= 0; return result; } } @@ -520,6 +464,7 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh * if(BKE_ptcache_get_continue_physics()) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; + cache->last_exact= 0; /* do simulation */ if(!do_init_cloth(ob, clmd, result, framenr)) @@ -535,6 +480,7 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh * if(framenr < startframe) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; + cache->last_exact= 0; return result; } else if(framenr > endframe) { @@ -551,7 +497,9 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh * return result; /* try to read from cache */ - if(cloth_read_cache(ob, clmd, framenr)) { + cache_result = BKE_ptcache_read_cache(&pid, (float)framenr, scene->r.frs_sec); + + if(cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) { cache->flag |= PTCACHE_SIMULATION_VALID; cache->simframe= framenr; @@ -560,24 +508,38 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh * return result; } + else if(cache_result==PTCACHE_READ_OLD) { + BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_FREE); + + implicit_set_positions(clmd); + + cache->flag |= PTCACHE_SIMULATION_VALID; + } else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) { /* if baked and nothing in cache, do nothing */ cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; + cache->last_exact= 0; return result; } if(framenr == startframe) { + if(cache->flag & PTCACHE_REDO_NEEDED) { + BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); + do_init_cloth(ob, clmd, result, framenr); + } cache->flag |= PTCACHE_SIMULATION_VALID; cache->simframe= framenr; /* don't write cache on first frame, but on second frame write * cache for frame 1 and 2 */ } - else if(framedelta == 1) { + else { /* if on second frame, write cache for first frame */ - if(framenr == startframe+1) - cloth_write_cache(ob, clmd, startframe); + if(cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) + BKE_ptcache_write_cache(&pid, startframe); + + clmd->sim_parms->timescale *= framenr - cache->simframe; /* do simulation */ cache->flag |= PTCACHE_SIMULATION_VALID; @@ -586,16 +548,13 @@ DerivedMesh *clothModifier_do(ClothModifierData *clmd, Object *ob, DerivedMesh * if(!do_step_cloth(ob, clmd, result, framenr)) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; + cache->last_exact= 0; } else - cloth_write_cache(ob, clmd, framenr); + BKE_ptcache_write_cache(&pid, framenr); cloth_to_object (ob, clmd, result); } - else { - cache->flag &= ~PTCACHE_SIMULATION_VALID; - cache->simframe= 0; - } return result; } diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 0b5465ea25d..c122145c98f 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -45,7 +45,6 @@ #include "BKE_modifier.h" #include "BKE_utildefines.h" #include "BKE_DerivedMesh.h" -#include "mydevice.h" #include "Bullet-C-Api.h" @@ -592,7 +591,9 @@ CollPair* cloth_collision ( ModifierData *md1, ModifierData *md2, BVHTreeOverlap ClothModifierData *clmd = ( ClothModifierData * ) md1; CollisionModifierData *collmd = ( CollisionModifierData * ) md2; MFace *face1=NULL, *face2 = NULL; +#ifdef WITH_BULLET ClothVertex *verts1 = clmd->clothObject->verts; +#endif double distance = 0; float epsilon1 = clmd->coll_parms->epsilon; float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree ); @@ -1295,7 +1296,7 @@ int cloth_collision_moving ( ClothModifierData *clmd, CollisionModifierData *col // return all collision objects in scene // collision object will exclude self -CollisionModifierData **get_collisionobjects(Object *self, int *numcollobj) +CollisionModifierData **get_collisionobjects(Scene *scene, Object *self, int *numcollobj) { Base *base=NULL; CollisionModifierData **objs = NULL; @@ -1305,7 +1306,7 @@ CollisionModifierData **get_collisionobjects(Object *self, int *numcollobj) objs = MEM_callocN(sizeof(CollisionModifierData *)*maxobj, "CollisionObjectsArray"); // check all collision objects - for ( base = G.scene->base.first; base; base = base->next ) + for ( base = scene->base.first; base; base = base->next ) { /*Only proceed for mesh object in same layer */ if(!(base->object->type==OB_MESH && (base->lay & self->lay))) @@ -1450,7 +1451,7 @@ int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifie } // cloth - object collisions -int cloth_bvh_objcollision ( Object *ob, ClothModifierData * clmd, float step, float dt ) +int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, float dt ) { Cloth *cloth=NULL; BVHTree *cloth_bvh=NULL; @@ -1480,7 +1481,7 @@ int cloth_bvh_objcollision ( Object *ob, ClothModifierData * clmd, float step, f bvhtree_update_from_cloth ( clmd, 1 ); // 0 means STATIC, 1 means MOVING (see later in this function) bvhselftree_update_from_cloth ( clmd, 0 ); // 0 means STATIC, 1 means MOVING (see later in this function) - collobjs = get_collisionobjects(ob, &numcollobj); + collobjs = get_collisionobjects(clmd->scene, ob, &numcollobj); if(!collobjs) return 0; diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 1bc34aea9a1..26f9245abc7 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -32,6 +32,10 @@ #include <stdlib.h> #include <float.h> +#ifdef WITH_LCMS +#include <lcms.h> +#endif + #include "MEM_guardedalloc.h" #include "DNA_color_types.h" @@ -54,6 +58,91 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +/* ********************************* color transforms ********************************* */ + +/*Transform linear RGB values to nonlinear RGB values. Rec. + 709 is ITU-R Recommendation BT. 709 (1990) ``Basic + Parameter Values for the HDTV Standard for the Studio and + for International Programme Exchange'', formerly CCIR Rec. + 709.*/ +void gamma_correct_rec709(float *c, float gamma) +{ + /* Rec. 709 gamma correction. */ + const float cc = 0.018f; + + if (*c < cc) + *c *= ((1.099f * (float)powf(cc, gamma)) - 0.099f) * (1.0f/cc); + else + *c = (1.099f * (float)powf(*c, gamma)) - 0.099f; +} + +void gamma_correct(float *c, float gamma) +{ + *c = powf((*c), gamma); +} + +float srgb_to_linearrgb(float c) +{ + if (c < 0.04045f) + return (c < 0.0f)? 0.0f: c*(1.0f/12.92f); + else + return powf((c + 0.055f)*(1.0f/1.055f), 2.4f); +} + +float linearrgb_to_srgb(float c) +{ + if (c < 0.0031308f) + return (c < 0.0f)? 0.0f: c * 12.92f; + else + return 1.055f * powf(c, 1.0f/2.4f) - 0.055f; +} + +/* utility function convert an RGB triplet from sRGB to linear RGB color space */ +void color_manage_linearize(float *col_to, float *col_from) +{ + col_to[0] = srgb_to_linearrgb(col_from[0]); + col_to[1] = srgb_to_linearrgb(col_from[1]); + col_to[2] = srgb_to_linearrgb(col_from[2]); +} + +void floatbuf_to_srgb_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w) +{ + int x, y; + float *rf= rectf; + float srgb[3]; + unsigned char *rc= rectc; + + for(y=y1; y<y2; y++) { + for(x=x1; x<x2; x++, rf+=4, rc+=4) { + srgb[0]= linearrgb_to_srgb(rf[0]); + srgb[1]= linearrgb_to_srgb(rf[1]); + srgb[2]= linearrgb_to_srgb(rf[2]); + + rc[0]= FTOCHAR(srgb[0]); + rc[1]= FTOCHAR(srgb[1]); + rc[2]= FTOCHAR(srgb[2]); + rc[3]= FTOCHAR(rf[3]); + } + } +} + +void floatbuf_to_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w) +{ + int x, y; + float *rf= rectf; + unsigned char *rc= rectc; + + for(y=y1; y<y2; y++) { + for(x=x1; x<x2; x++, rf+=4, rc+=4) { + rc[0]= FTOCHAR(rf[0]); + rc[1]= FTOCHAR(rf[1]); + rc[2]= FTOCHAR(rf[2]); + rc[3]= FTOCHAR(rf[3]); + } + } +} + + /* ********************************* color curve ********************* */ /* ***************** operations on full struct ************* */ @@ -650,6 +739,38 @@ void curvemapping_evaluate_premulRGBF(CurveMapping *cumap, float *vecout, const vecout[2]= curvemap_evaluateF(cumap->cm+2, fac); } +void colorcorrection_do_ibuf(ImBuf *ibuf, const char *profile) +{ + if (ibuf->crect == NULL) + { +#ifdef WITH_LCMS + cmsHPROFILE imageProfile, proofingProfile; + cmsHTRANSFORM hTransform; + + ibuf->crect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(int), "imbuf crect"); + + imageProfile = cmsCreate_sRGBProfile(); + proofingProfile = cmsOpenProfileFromFile(profile, "r"); + + cmsErrorAction(LCMS_ERROR_SHOW); + + hTransform = cmsCreateProofingTransform(imageProfile, TYPE_RGBA_8, imageProfile, TYPE_RGBA_8, + proofingProfile, + INTENT_ABSOLUTE_COLORIMETRIC, + INTENT_ABSOLUTE_COLORIMETRIC, + cmsFLAGS_SOFTPROOFING); + + cmsDoTransform(hTransform, ibuf->rect, ibuf->crect, ibuf->x * ibuf->y); + + cmsDeleteTransform(hTransform); + cmsCloseProfile(imageProfile); + cmsCloseProfile(proofingProfile); +#else + ibuf->crect = ibuf->rect; +#endif + } +} + void curvemapping_do_ibuf(CurveMapping *cumap, ImBuf *ibuf) { diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 6b6f4a58e79..88e73a00ba7 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -31,12 +31,13 @@ #include <stddef.h> #include <string.h> #include <math.h> +#include <float.h> #include "MEM_guardedalloc.h" -#include "nla.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" +#include "BLI_editVert.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" @@ -44,6 +45,7 @@ #include "DNA_object_types.h" #include "DNA_action_types.h" #include "DNA_curve_types.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_lattice_types.h" #include "DNA_scene_types.h" @@ -65,12 +67,13 @@ #include "BKE_library.h" #include "BKE_idprop.h" #include "BKE_shrinkwrap.h" +#include "BKE_mesh.h" #ifndef DISABLE_PYTHON #include "BPY_extern.h" #endif -#include "blendef.h" +#include "ED_mesh.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -81,157 +84,6 @@ #endif -/* ******************* Constraint Channels ********************** */ -/* Constraint Channels exist in one of two places: - * - Under Action Channels in an Action (act->chanbase->achan->constraintChannels) - * - Under Object without Object-level Action yet (ob->constraintChannels) - * - * The main purpose that Constraint Channels serve is to act as a link - * between an IPO-block (which provides values to interpolate between for some settings) - */ - -/* ------------ Data Management ----------- */ - -/* Free constraint channels, and reduce the number of users of the related ipo-blocks */ -void free_constraint_channels (ListBase *chanbase) -{ - bConstraintChannel *chan; - - for (chan=chanbase->first; chan; chan=chan->next) { - if (chan->ipo) { - chan->ipo->id.us--; - } - } - - BLI_freelistN(chanbase); -} - -/* Make a copy of the constraint channels from dst to src, and also give the - * new constraint channels their own copy of the original's IPO. - */ -void copy_constraint_channels (ListBase *dst, ListBase *src) -{ - bConstraintChannel *dchan, *schan; - - dst->first = dst->last = NULL; - duplicatelist(dst, src); - - for (dchan=dst->first, schan=src->first; dchan; dchan=dchan->next, schan=schan->next) { - dchan->ipo = copy_ipo(schan->ipo); - } -} - -/* Make a copy of the constraint channels from dst to src, but make the - * new constraint channels use the same IPO-data as their twin. - */ -void clone_constraint_channels (ListBase *dst, ListBase *src) -{ - bConstraintChannel *dchan, *schan; - - dst->first = dst->last = NULL; - duplicatelist(dst, src); - - for (dchan=dst->first, schan=src->first; dchan; dchan=dchan->next, schan=schan->next) { - id_us_plus((ID *)dchan->ipo); - } -} - -/* ------------- Constraint Channel Tools ------------ */ - -/* Find the constraint channel with a given name */ -bConstraintChannel *get_constraint_channel (ListBase *list, const char name[]) -{ - bConstraintChannel *chan; - - if (list) { - for (chan = list->first; chan; chan=chan->next) { - if (!strcmp(name, chan->name)) { - return chan; - } - } - } - - return NULL; -} - -/* Find or create a new constraint channel */ -bConstraintChannel *verify_constraint_channel (ListBase *list, const char name[]) -{ - bConstraintChannel *chan; - - chan= get_constraint_channel(list, name); - - if (chan == NULL) { - chan= MEM_callocN(sizeof(bConstraintChannel), "new constraint channel"); - BLI_addtail(list, chan); - strcpy(chan->name, name); - } - - return chan; -} - -/* --------- Constraint Channel Evaluation/Execution --------- */ - -/* IPO-system call: calculate IPO-block for constraint channels, and flush that - * info onto the corresponding constraint. - */ -void do_constraint_channels (ListBase *conbase, ListBase *chanbase, float ctime, short onlydrivers) -{ - bConstraint *con; - - /* for each Constraint, calculate its Influence from the corresponding ConstraintChannel */ - for (con=conbase->first; con; con=con->next) { - Ipo *ipo= NULL; - - if (con->flag & CONSTRAINT_OWN_IPO) - ipo= con->ipo; - else { - bConstraintChannel *chan = get_constraint_channel(chanbase, con->name); - if (chan) ipo= chan->ipo; - } - - if (ipo) { - IpoCurve *icu; - - calc_ipo(ipo, ctime); - - for (icu=ipo->curve.first; icu; icu=icu->next) { - if (!onlydrivers || icu->driver) { - switch (icu->adrcode) { - case CO_ENFORCE: - { - /* Influence is clamped to 0.0f -> 1.0f range */ - con->enforce = CLAMPIS(icu->curval, 0.0f, 1.0f); - } - break; - case CO_HEADTAIL: - { - /* we need to check types of constraints that can get this here, as user - * may have created an IPO-curve for this from IPO-editor but for a constraint - * that cannot support this - */ - switch (con->type) { - /* supported constraints go here... */ - case CONSTRAINT_TYPE_LOCLIKE: - case CONSTRAINT_TYPE_TRACKTO: - case CONSTRAINT_TYPE_MINMAX: - case CONSTRAINT_TYPE_STRETCHTO: - case CONSTRAINT_TYPE_DISTLIMIT: - con->headtail = icu->curval; - break; - - default: - /* not supported */ - break; - } - } - break; - } - } - } - } - } -} /* ************************ Constraints - General Utilities *************************** */ /* These functions here don't act on any specific constraints, and are therefore should/will @@ -244,20 +96,23 @@ void do_constraint_channels (ListBase *conbase, ListBase *chanbase, float ctime, /* Find the first available, non-duplicate name for a given constraint */ void unique_constraint_name (bConstraint *con, ListBase *list) { - BLI_uniquename(list, con, "Const", offsetof(bConstraint, name), 32); + BLI_uniquename(list, con, "Const", '.', offsetof(bConstraint, name), 32); } /* ----------------- Evaluation Loop Preparation --------------- */ /* package an object/bone for use in constraint evaluation */ /* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */ -bConstraintOb *constraints_make_evalob (Object *ob, void *subdata, short datatype) +bConstraintOb *constraints_make_evalob (Scene *scene, Object *ob, void *subdata, short datatype) { bConstraintOb *cob; /* create regardless of whether we have any data! */ cob= MEM_callocN(sizeof(bConstraintOb), "bConstraintOb"); + /* for system time, part of deglobalization, code nicer later with local time (ton) */ + cob->scene= scene; + /* based on type of available data */ switch (datatype) { case CONSTRAINT_OBTYPE_OBJECT: @@ -535,9 +390,11 @@ void constraint_mat_convertspace (Object *ob, bPoseChannel *pchan, float mat[][4 /* ------------ General Target Matrix Tools ---------- */ /* function that sets the given matrix based on given vertex group in mesh */ -static void contarget_get_mesh_mat (Object *ob, char *substring, float mat[][4]) +static void contarget_get_mesh_mat (Scene *scene, Object *ob, char *substring, float mat[][4]) { DerivedMesh *dm; + Mesh *me= ob->data; + EditMesh *em = BKE_mesh_get_editmesh(me); float vec[3] = {0.0f, 0.0f, 0.0f}, tvec[3]; float normal[3] = {0.0f, 0.0f, 0.0f}, plane[3]; float imat[3][3], tmat[3][3]; @@ -552,9 +409,9 @@ static void contarget_get_mesh_mat (Object *ob, char *substring, float mat[][4]) if (dgroup < 0) return; /* get DerivedMesh */ - if ((G.obedit == ob) && (G.editMesh)) { + if (em) { /* target is in editmode, so get a special derived mesh */ - dm = CDDM_from_editmesh(G.editMesh, ob->data); + dm = CDDM_from_editmesh(em, ob->data); freeDM= 1; } else { @@ -563,7 +420,7 @@ static void contarget_get_mesh_mat (Object *ob, char *substring, float mat[][4]) * (this is more effficient + sufficient for most cases) */ if (ob->lastDataMask != CD_MASK_DERIVEDMESH) { - dm = mesh_get_derived_final(ob, CD_MASK_DERIVEDMESH); + dm = mesh_get_derived_final(scene, ob, CD_MASK_DERIVEDMESH); freeDM= 1; } else @@ -632,9 +489,11 @@ static void contarget_get_mesh_mat (Object *ob, char *substring, float mat[][4]) } } - /* free temporary DerivedMesh created */ - if (dm && freeDM) + /* free temporary DerivedMesh created (in EditMode case) */ + if (dm && freeDM) dm->release(dm); + if (em) + BKE_mesh_end_editmesh(me, em); } /* function that sets the given matrix based on given vertex group in lattice */ @@ -696,7 +555,7 @@ static void contarget_get_lattice_mat (Object *ob, char *substring, float mat[][ /* generic function to get the appropriate matrix for most target cases */ /* The cases where the target can be object data have not been implemented */ -static void constraint_target_to_mat4 (Object *ob, char *substring, float mat[][4], short from, short to, float headtail) +static void constraint_target_to_mat4 (Scene *scene, Object *ob, char *substring, float mat[][4], short from, short to, float headtail) { /* Case OBJECT */ if (!strlen(substring)) { @@ -713,7 +572,7 @@ static void constraint_target_to_mat4 (Object *ob, char *substring, float mat[][ * way as constraints can only really affect things on object/bone level. */ else if (ob->type == OB_MESH) { - contarget_get_mesh_mat(ob, substring, mat); + contarget_get_mesh_mat(scene, ob, substring, mat); constraint_mat_convertspace(ob, NULL, mat, from, to); } else if (ob->type == OB_LATTICE) { @@ -795,7 +654,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = { static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime) { if (VALID_CONS_TARGET(ct)) - constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); else if (ct) Mat4One(ct->matrix); } @@ -1210,7 +1069,7 @@ static void kinematic_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstra bKinematicConstraint *data= con->data; if (VALID_CONS_TARGET(ct)) - constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); else if (ct) { if (data->flag & CONSTRAINT_IK_AUTO) { Object *ob= cob->ob; @@ -1304,15 +1163,17 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr /* only happens on reload file, but violates depsgraph still... fix! */ if (cu->path==NULL || cu->path->data==NULL) - makeDispListCurveTypes(ct->tar, 0); + makeDispListCurveTypes(cob->scene, ct->tar, 0); if (cu->path && cu->path->data) { - curvetime= bsystem_time(ct->tar, (float)ctime, 0.0) - data->offset; + curvetime= bsystem_time(cob->scene, ct->tar, (float)ctime, 0.0) - data->offset; +#if 0 // XXX old animation system if (calc_ipo_spec(cu->ipo, CU_SPEED, &curvetime)==0) { curvetime /= cu->pathlen; CLAMP(curvetime, 0.0, 1.0); } +#endif // XXX old animation system if ( where_on_path(ct->tar, curvetime, vec, dir) ) { if (data->followflag) { @@ -1854,7 +1715,7 @@ static void pycon_copy (bConstraint *con, bConstraint *srccon) bPythonConstraint *opycon = (bPythonConstraint *)srccon->data; pycon->prop = IDP_CopyProperty(opycon->prop); - duplicatelist(&pycon->targets, &opycon->targets); + BLI_duplicatelist(&pycon->targets, &opycon->targets); } static void pycon_new_data (void *cdata) @@ -1892,13 +1753,13 @@ static void pycon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintT /* this check is to make sure curve objects get updated on file load correctly.*/ if (cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */ - makeDispListCurveTypes(ct->tar, 0); + makeDispListCurveTypes(cob->scene, ct->tar, 0); } /* firstly calculate the matrix the normal way, then let the py-function override * this matrix if it needs to do so */ - constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); /* only execute target calculation if allowed */ #ifndef DISABLE_PYTHON @@ -2005,7 +1866,7 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint Mat4One(ct->matrix); /* get the transform matrix of the target */ - constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); + constraint_target_to_mat4(cob->scene, ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space, con->headtail); /* determine where in transform range target is */ /* data->type is mapped as follows for backwards compatability: @@ -2037,28 +1898,38 @@ static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraint CLAMP(s, 0, 1); t = ( s * (data->end-data->start)) + data->start; + if (G.f & G_DEBUG) + printf("do Action Constraint %s - Ob %s Pchan %s \n", con->name, cob->ob->id.name+2, (cob->pchan)?cob->pchan->name:NULL); + /* Get the appropriate information from the action */ if (cob->type == CONSTRAINT_OBTYPE_BONE) { + Object workob; bPose *pose; bPoseChannel *pchan, *tchan; /* make a temporary pose and evaluate using that */ pose = MEM_callocN(sizeof(bPose), "pose"); + /* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set */ pchan = cob->pchan; tchan= verify_pose_channel(pose, pchan->name); - extract_pose_from_action(pose, data->act, t); - chan_calc_mat(tchan); + /* evaluate action using workob (it will only set the PoseChannel in question) */ + what_does_obaction(cob->scene, cob->ob, &workob, pose, data->act, pchan->name, t); + /* convert animation to matrices for use here */ + chan_calc_mat(tchan); Mat4CpyMat4(ct->matrix, tchan->chan_mat); /* Clean up */ free_pose(pose); } else if (cob->type == CONSTRAINT_OBTYPE_OBJECT) { + Object workob; + /* evaluate using workob */ - what_does_obaction(cob->ob, data->act, t); + // FIXME: we don't have any consistent standards on limiting effects on object... + what_does_obaction(cob->scene, cob->ob, &workob, NULL, data->act, NULL, t); object_to_mat4(&workob, ct->matrix); } else { @@ -2973,7 +2844,7 @@ static void clampto_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstrain /* only happens on reload file, but violates depsgraph still... fix! */ if (cu->path==NULL || cu->path->data==NULL) - makeDispListCurveTypes(ct->tar, 0); + makeDispListCurveTypes(cob->scene, ct->tar, 0); } /* technically, this isn't really needed for evaluation, but we don't know what else @@ -3033,44 +2904,53 @@ static void clampto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *ta float len= (curveMax[clamp_axis] - curveMin[clamp_axis]); float offset; - /* find bounding-box range where target is located */ - if (ownLoc[clamp_axis] < curveMin[clamp_axis]) { - /* bounding-box range is before */ - offset= curveMin[clamp_axis]; - - while (ownLoc[clamp_axis] < offset) - offset -= len; - - /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */ - curvetime = (ownLoc[clamp_axis] - offset) / (len); - } - else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) { - /* bounding-box range is after */ - offset= curveMax[clamp_axis]; - - while (ownLoc[clamp_axis] > offset) { - if ((offset + len) > ownLoc[clamp_axis]) - break; - else - offset += len; + /* check to make sure len is not so close to zero that it'll cause errors */ + if (IS_EQ(len, 0) == 0) { + /* find bounding-box range where target is located */ + if (ownLoc[clamp_axis] < curveMin[clamp_axis]) { + /* bounding-box range is before */ + offset= curveMin[clamp_axis]; + + while (ownLoc[clamp_axis] < offset) + offset -= len; + + /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */ + curvetime = (ownLoc[clamp_axis] - offset) / (len); + } + else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) { + /* bounding-box range is after */ + offset= curveMax[clamp_axis]; + + while (ownLoc[clamp_axis] > offset) { + if ((offset + len) > ownLoc[clamp_axis]) + break; + else + offset += len; + } + + /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */ + curvetime = (ownLoc[clamp_axis] - offset) / (len); + } + else { + /* as the location falls within bounds, just calculate */ + curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len); } - - /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */ - curvetime = (ownLoc[clamp_axis] - offset) / (len); } else { - /* as the location falls within bounds, just calculate */ - curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len); + /* as length is close to zero, curvetime by default should be 0 (i.e. the start) */ + curvetime= 0.0f; } } else { /* no cyclic, so position is clamped to within the bounding box */ if (ownLoc[clamp_axis] <= curveMin[clamp_axis]) - curvetime = 0.0; + curvetime = 0.0f; else if (ownLoc[clamp_axis] >= curveMax[clamp_axis]) - curvetime = 1.0; - else + curvetime = 1.0f; + else if ( IS_EQ((curveMax[clamp_axis] - curveMin[clamp_axis]), 0) == 0 ) curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (curveMax[clamp_axis] - curveMin[clamp_axis]); + else + curvetime = 0.0f; } /* 3. position on curve */ @@ -3148,7 +3028,7 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * if (VALID_CONS_TARGET(ct)) { float loc[3], eul[3], size[3]; float dvec[3], sval[3]; - short i; + int i; /* obtain target effect */ switch (data->from) { @@ -3195,7 +3075,7 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * switch (data->to) { case 2: /* scaling */ for (i=0; i<3; i++) - size[i]= data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i])); + size[i]= data->to_min[i] + (sval[(int)data->map[i]] * (data->to_max[i] - data->to_min[i])); break; case 1: /* rotation */ for (i=0; i<3; i++) { @@ -3205,7 +3085,7 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * tmax= data->to_max[i]; /* all values here should be in degrees */ - eul[i]= tmin + (sval[data->map[i]] * (tmax - tmin)); + eul[i]= tmin + (sval[(int)data->map[i]] * (tmax - tmin)); /* now convert final value back to radians */ eul[i] = (float)(eul[i] / 180 * M_PI); @@ -3214,7 +3094,7 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * default: /* location */ /* get new location */ for (i=0; i<3; i++) - loc[i]= (data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i]))); + loc[i]= (data->to_min[i] + (sval[(int)data->map[i]] * (data->to_max[i] - data->to_min[i]))); /* add original location back on (so that it can still be moved) */ VecAddf(loc, cob->matrix[3], loc); @@ -3281,7 +3161,7 @@ static void shrinkwrap_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr float dist; SpaceTransform transform; - DerivedMesh *target = object_get_derived_final(ct->tar, CD_MASK_BAREMESH); + DerivedMesh *target = object_get_derived_final(cob->scene, ct->tar, CD_MASK_BAREMESH); BVHTreeRayHit hit; BVHTreeNearest nearest; @@ -3402,7 +3282,7 @@ static bConstraintTypeInfo CTI_SHRINKWRAP = { /* ************************* Constraints Type-Info *************************** */ /* All of the constraints api functions use bConstraintTypeInfo structs to carry out - * and operations that involve constraint specifc code. + * and operations that involve constraint specific code. */ /* These globals only ever get directly accessed in this file */ @@ -3494,17 +3374,16 @@ void free_constraint_data (bConstraint *con) } /* Free all constraints from a constraint-stack */ -void free_constraints (ListBase *conlist) +void free_constraints (ListBase *list) { bConstraint *con; /* Free constraint data and also any extra data */ - for (con= conlist->first; con; con= con->next) { + for (con= list->first; con; con= con->next) free_constraint_data(con); - } /* Free the whole list */ - BLI_freelistN(conlist); + BLI_freelistN(list); } /* Reassign links that constraints have to other data (called during file loading?) */ @@ -3543,9 +3422,9 @@ void copy_constraints (ListBase *dst, ListBase *src) bConstraint *con, *srccon; dst->first= dst->last= NULL; - duplicatelist(dst, src); + BLI_duplicatelist(dst, src); - for (con=dst->first, srccon=src->first; con; srccon=srccon->next, con=con->next) { + for (con=dst->first, srccon=src->first; con && srccon; srccon=srccon->next, con=con->next) { bConstraintTypeInfo *cti= constraint_get_typeinfo(con); /* make a new copy of the constraint's data */ @@ -3559,6 +3438,23 @@ void copy_constraints (ListBase *dst, ListBase *src) } } +/* finds the 'active' constraint in a constraint stack */ +bConstraint *constraints_get_active (ListBase *list) +{ + bConstraint *con; + + /* search for the first constraint with the 'active' flag set */ + if (list) { + for (con= list->first; con; con= con->next) { + if (con->flag & CONSTRAINT_ACTIVE) + return con; + } + } + + /* no active constraint found */ + return NULL; +} + /* -------- Constraints and Proxies ------- */ /* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL (i.e. added to bone that's proxy-synced in this file) */ @@ -3708,7 +3604,7 @@ void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime) if (con->enforce == 0.0f) continue; /* influence of constraint - * - value should have been set from IPO's/Constraint Channels already + * - value should have been set from animation data already */ enf = con->enforce; diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c new file mode 100644 index 00000000000..d1e228f83b6 --- /dev/null +++ b/source/blender/blenkernel/intern/context.c @@ -0,0 +1,786 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation (2008). + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_ID.h" +#include "DNA_listBase.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" +#include "DNA_windowmanager_types.h" + +#include "RNA_access.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_screen.h" + +#include <string.h> + +/* struct */ + +struct bContext { + int thread; + + /* windowmanager context */ + struct { + struct wmWindowManager *manager; + struct wmWindow *window; + struct bScreen *screen; + struct ScrArea *area; + struct ARegion *region; + struct ARegion *menu; + struct bContextStore *store; + } wm; + + /* data context */ + struct { + struct Main *main; + struct Scene *scene; + + int recursion; + int py_init; /* true if python is initialized */ + } data; + + /* data evaluation */ + struct { + int render; + } eval; +}; + +/* context */ + +bContext *CTX_create() +{ + bContext *C; + + C= MEM_callocN(sizeof(bContext), "bContext"); + + return C; +} + +bContext *CTX_copy(const bContext *C) +{ + bContext *newC= MEM_dupallocN((void*)C); + + return newC; +} + +void CTX_free(bContext *C) +{ + MEM_freeN(C); +} + +/* store */ + +bContextStore *CTX_store_add(ListBase *contexts, char *name, PointerRNA *ptr) +{ + bContextStoreEntry *entry; + bContextStore *ctx, *lastctx; + + /* ensure we have a context to put the entry in, if it was already used + * we have to copy the context to ensure */ + ctx= contexts->last; + + if(!ctx || ctx->used) { + if(ctx) { + lastctx= ctx; + ctx= MEM_dupallocN(lastctx); + BLI_duplicatelist(&ctx->entries, &lastctx->entries); + } + else + ctx= MEM_callocN(sizeof(bContextStore), "bContextStore"); + + BLI_addtail(contexts, ctx); + } + + entry= MEM_callocN(sizeof(bContextStoreEntry), "bContextStoreEntry"); + BLI_strncpy(entry->name, name, sizeof(entry->name)); + entry->ptr= *ptr; + + BLI_addtail(&ctx->entries, entry); + + return ctx; +} + +void CTX_store_set(bContext *C, bContextStore *store) +{ + C->wm.store= store; +} + +bContextStore *CTX_store_copy(bContextStore *store) +{ + bContextStore *ctx; + + ctx= MEM_dupallocN(store); + BLI_duplicatelist(&ctx->entries, &store->entries); + + return ctx; +} + +void CTX_store_free(bContextStore *store) +{ + BLI_freelistN(&store->entries); + MEM_freeN(store); +} + +void CTX_store_free_list(ListBase *contexts) +{ + bContextStore *ctx; + + while((ctx= contexts->first)) { + BLI_remlink(contexts, ctx); + CTX_store_free(ctx); + } +} + +/* is python initialied? */ +int CTX_py_init_get(bContext *C) +{ + return C->data.py_init; +} +void CTX_py_init_set(bContext *C, int value) +{ + C->data.py_init= value; +} + +/* window manager context */ + +wmWindowManager *CTX_wm_manager(const bContext *C) +{ + return C->wm.manager; +} + +wmWindow *CTX_wm_window(const bContext *C) +{ + return C->wm.window; +} + +bScreen *CTX_wm_screen(const bContext *C) +{ + return C->wm.screen; +} + +ScrArea *CTX_wm_area(const bContext *C) +{ + return C->wm.area; +} + +SpaceLink *CTX_wm_space_data(const bContext *C) +{ + return (C->wm.area)? C->wm.area->spacedata.first: NULL; +} + +ARegion *CTX_wm_region(const bContext *C) +{ + return C->wm.region; +} + +void *CTX_wm_region_data(const bContext *C) +{ + return (C->wm.region)? C->wm.region->regiondata: NULL; +} + +struct ARegion *CTX_wm_menu(const bContext *C) +{ + return C->wm.menu; +} + +struct ReportList *CTX_wm_reports(const bContext *C) +{ + if (C->wm.manager) + return &(C->wm.manager->reports); + + return NULL; +} + +View3D *CTX_wm_view3d(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_VIEW3D) + return C->wm.area->spacedata.first; + return NULL; +} + +RegionView3D *CTX_wm_region_view3d(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_VIEW3D) + if(C->wm.region) + return C->wm.region->regiondata; + return NULL; +} + +struct SpaceText *CTX_wm_space_text(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_TEXT) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceConsole *CTX_wm_space_console(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_CONSOLE) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceImage *CTX_wm_space_image(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_IMAGE) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceButs *CTX_wm_space_buts(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_BUTS) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceFile *CTX_wm_space_file(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_FILE) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceSeq *CTX_wm_space_seq(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_SEQ) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceOops *CTX_wm_space_outliner(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_OUTLINER) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceNla *CTX_wm_space_nla(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_NLA) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceTime *CTX_wm_space_time(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_TIME) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceNode *CTX_wm_space_node(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_NODE) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceLogic *CTX_wm_space_logic(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_LOGIC) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceIpo *CTX_wm_space_graph(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_IPO) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceAction *CTX_wm_space_action(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_ACTION) + return C->wm.area->spacedata.first; + return NULL; +} + +struct SpaceInfo *CTX_wm_space_info(const bContext *C) +{ + if(C->wm.area && C->wm.area->spacetype==SPACE_INFO) + return C->wm.area->spacedata.first; + return NULL; +} + +void CTX_wm_manager_set(bContext *C, wmWindowManager *wm) +{ + C->wm.manager= wm; + C->wm.window= NULL; + C->wm.screen= NULL; + C->wm.area= NULL; + C->wm.region= NULL; +} + +void CTX_wm_window_set(bContext *C, wmWindow *win) +{ + C->wm.window= win; + C->wm.screen= (win)? win->screen: NULL; + C->data.scene= (C->wm.screen)? C->wm.screen->scene: NULL; + C->wm.area= NULL; + C->wm.region= NULL; +} + +void CTX_wm_screen_set(bContext *C, bScreen *screen) +{ + C->wm.screen= screen; + C->data.scene= (C->wm.screen)? C->wm.screen->scene: NULL; + C->wm.area= NULL; + C->wm.region= NULL; +} + +void CTX_wm_area_set(bContext *C, ScrArea *area) +{ + C->wm.area= area; + C->wm.region= NULL; +} + +void CTX_wm_region_set(bContext *C, ARegion *region) +{ + C->wm.region= region; +} + +void CTX_wm_menu_set(bContext *C, ARegion *menu) +{ + C->wm.menu= menu; +} + +/* data context utility functions */ + +struct bContextDataResult { + PointerRNA ptr; + ListBase list; + const char **dir; +}; + +static int ctx_data_get(bContext *C, const char *member, bContextDataResult *result) +{ + int done= 0, recursion= C->data.recursion; + + memset(result, 0, sizeof(bContextDataResult)); + + /* we check recursion to ensure that we do not get infinite + * loops requesting data from ourselfs in a context callback */ + if(!done && recursion < 1 && C->wm.store) { + bContextStoreEntry *entry; + + C->data.recursion= 1; + + for(entry=C->wm.store->entries.first; entry; entry=entry->next) { + if(strcmp(entry->name, member) == 0) { + result->ptr= entry->ptr; + done= 1; + } + } + } + if(!done && recursion < 2 && C->wm.region) { + C->data.recursion= 2; + if(C->wm.region->type && C->wm.region->type->context) + done= C->wm.region->type->context(C, member, result); + } + if(!done && recursion < 3 && C->wm.area) { + C->data.recursion= 3; + if(C->wm.area->type && C->wm.area->type->context) + done= C->wm.area->type->context(C, member, result); + } + if(!done && recursion < 4 && C->wm.screen) { + bContextDataCallback cb= C->wm.screen->context; + C->data.recursion= 4; + if(cb) + done= cb(C, member, result); + } + + C->data.recursion= recursion; + + return done; +} + +static void *ctx_data_pointer_get(const bContext *C, const char *member) +{ + bContextDataResult result; + + if(ctx_data_get((bContext*)C, member, &result)) + return result.ptr.data; + + return NULL; +} + +static int ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer) +{ + bContextDataResult result; + + if(ctx_data_get((bContext*)C, member, &result)) { + *pointer= result.ptr.data; + return 1; + } + else { + *pointer= NULL; + return 0; + } +} + +static int ctx_data_collection_get(const bContext *C, const char *member, ListBase *list) +{ + bContextDataResult result; + + if(ctx_data_get((bContext*)C, member, &result)) { + *list= result.list; + return 1; + } + + list->first= NULL; + list->last= NULL; + + return 0; +} + +PointerRNA CTX_data_pointer_get(const bContext *C, const char *member) +{ + bContextDataResult result; + + if(ctx_data_get((bContext*)C, member, &result)) + return result.ptr; + else + return PointerRNA_NULL; +} + +PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type) +{ + PointerRNA ptr = CTX_data_pointer_get(C, member); + + if(ptr.data && RNA_struct_is_a(ptr.type, type)) + return ptr; + + return PointerRNA_NULL; +} + +ListBase CTX_data_collection_get(const bContext *C, const char *member) +{ + bContextDataResult result; + + if(ctx_data_get((bContext*)C, member, &result)) { + return result.list; + } + else { + ListBase list; + memset(&list, 0, sizeof(list)); + return list; + } +} + +void CTX_data_get(const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb) +{ + bContextDataResult result; + + if(ctx_data_get((bContext*)C, member, &result)) { + *r_ptr= result.ptr; + *r_lb= result.list; + } + else { + memset(r_ptr, 0, sizeof(*r_ptr)); + memset(r_lb, 0, sizeof(*r_lb)); + } +} + +static void data_dir_add(ListBase *lb, const char *member) +{ + LinkData *link; + + if(strcmp(member, "scene") == 0) /* exception */ + return; + + for(link=lb->first; link; link=link->next) + if(strcmp(link->data, member) == 0) + return; + + link= MEM_callocN(sizeof(LinkData), "LinkData"); + link->data= (void*)member; + BLI_addtail(lb, link); +} + +ListBase CTX_data_dir_get(const bContext *C) +{ + bContextDataResult result; + ListBase lb; + int a; + + memset(&lb, 0, sizeof(lb)); + + if(C->wm.store) { + bContextStoreEntry *entry; + + for(entry=C->wm.store->entries.first; entry; entry=entry->next) + data_dir_add(&lb, entry->name); + } + if(C->wm.region && C->wm.region->type && C->wm.region->type->context) { + memset(&result, 0, sizeof(result)); + C->wm.region->type->context(C, "", &result); + + if(result.dir) + for(a=0; result.dir[a]; a++) + data_dir_add(&lb, result.dir[a]); + } + if(C->wm.area && C->wm.area->type && C->wm.area->type->context) { + memset(&result, 0, sizeof(result)); + C->wm.area->type->context(C, "", &result); + + if(result.dir) + for(a=0; result.dir[a]; a++) + data_dir_add(&lb, result.dir[a]); + } + if(C->wm.screen && C->wm.screen->context) { + bContextDataCallback cb= C->wm.screen->context; + memset(&result, 0, sizeof(result)); + cb(C, "", &result); + + if(result.dir) + for(a=0; result.dir[a]; a++) + data_dir_add(&lb, result.dir[a]); + } + + return lb; +} + +int CTX_data_equals(const char *member, const char *str) +{ + return (strcmp(member, str) == 0); +} + +int CTX_data_dir(const char *member) +{ + return (strcmp(member, "") == 0); +} + +void CTX_data_id_pointer_set(bContextDataResult *result, ID *id) +{ + RNA_id_pointer_create(id, &result->ptr); +} + +void CTX_data_pointer_set(bContextDataResult *result, ID *id, StructRNA *type, void *data) +{ + RNA_pointer_create(id, type, data, &result->ptr); +} + +void CTX_data_id_list_add(bContextDataResult *result, ID *id) +{ + CollectionPointerLink *link; + + link= MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_id_list_add"); + RNA_id_pointer_create(id, &link->ptr); + + BLI_addtail(&result->list, link); +} + +void CTX_data_list_add(bContextDataResult *result, ID *id, StructRNA *type, void *data) +{ + CollectionPointerLink *link; + + link= MEM_callocN(sizeof(CollectionPointerLink), "CTX_data_list_add"); + RNA_pointer_create(id, type, data, &link->ptr); + + BLI_addtail(&result->list, link); +} + +int ctx_data_list_count(const bContext *C, int (*func)(const bContext*, ListBase*)) +{ + ListBase list; + + if(func(C, &list)) { + int tot= BLI_countlist(&list); + BLI_freelistN(&list); + return tot; + } + else + return 0; +} + +void CTX_data_dir_set(bContextDataResult *result, const char **dir) +{ + result->dir= dir; +} + +/* data context */ + +Main *CTX_data_main(const bContext *C) +{ + Main *bmain; + + if(ctx_data_pointer_verify(C, "main", (void*)&bmain)) + return bmain; + else + return C->data.main; +} + +void CTX_data_main_set(bContext *C, Main *bmain) +{ + C->data.main= bmain; +} + +Scene *CTX_data_scene(const bContext *C) +{ + Scene *scene; + + if(ctx_data_pointer_verify(C, "scene", (void*)&scene)) + return scene; + else + return C->data.scene; +} + +void CTX_data_scene_set(bContext *C, Scene *scene) +{ + C->data.scene= scene; +} + +ToolSettings *CTX_data_tool_settings(const bContext *C) +{ + Scene *scene = CTX_data_scene(C); + + if(scene) + return scene->toolsettings; + else + return NULL; +} + +int CTX_data_selected_nodes(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selected_nodes", list); +} + +int CTX_data_selected_editable_objects(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selected_editable_objects", list); +} + +int CTX_data_selected_editable_bases(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selected_editable_bases", list); +} + +int CTX_data_selected_objects(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selected_objects", list); +} + +int CTX_data_selected_bases(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selected_bases", list); +} + +int CTX_data_visible_objects(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "visible_objects", list); +} + +int CTX_data_visible_bases(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "visible_bases", list); +} + +int CTX_data_selectable_objects(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selectable_objects", list); +} + +int CTX_data_selectable_bases(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selectable_bases", list); +} + +struct Object *CTX_data_active_object(const bContext *C) +{ + return ctx_data_pointer_get(C, "active_object"); +} + +struct Base *CTX_data_active_base(const bContext *C) +{ + return ctx_data_pointer_get(C, "active_base"); +} + +struct Object *CTX_data_edit_object(const bContext *C) +{ + return ctx_data_pointer_get(C, "edit_object"); +} + +struct Image *CTX_data_edit_image(const bContext *C) +{ + return ctx_data_pointer_get(C, "edit_image"); +} + +struct Text *CTX_data_edit_text(const bContext *C) +{ + return ctx_data_pointer_get(C, "edit_text"); +} + +struct EditBone *CTX_data_active_bone(const bContext *C) +{ + return ctx_data_pointer_get(C, "active_bone"); +} + +int CTX_data_selected_bones(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selected_bones", list); +} + +int CTX_data_selected_editable_bones(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selected_editable_bones", list); +} + +int CTX_data_visible_bones(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "visible_bones", list); +} + +int CTX_data_editable_bones(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "editable_bones", list); +} + +struct bPoseChannel *CTX_data_active_pchan(const bContext *C) +{ + return ctx_data_pointer_get(C, "active_pchan"); +} + +int CTX_data_selected_pchans(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selected_pchans", list); +} + +int CTX_data_visible_pchans(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "visible_pchans", list); +} + diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 0d6382a8d37..7dd868278f4 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -48,27 +48,26 @@ /* for dereferencing pointers */ #include "DNA_ID.h" -#include "DNA_vfont_types.h" #include "DNA_key_types.h" -#include "DNA_ipo_types.h" +#include "DNA_scene_types.h" +#include "DNA_vfont_types.h" -#include "BKE_global.h" -#include "BKE_main.h" -#include "BKE_utildefines.h" // VECCOPY -#include "BKE_object.h" -#include "BKE_mesh.h" +#include "BKE_animsys.h" +#include "BKE_anim.h" #include "BKE_curve.h" #include "BKE_displist.h" -#include "BKE_ipo.h" -#include "BKE_anim.h" -#include "BKE_library.h" +#include "BKE_font.h" +#include "BKE_global.h" #include "BKE_key.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_utildefines.h" // VECCOPY /* globals */ -extern ListBase editNurb; /* editcurve.c */ - /* local */ int cu_isectLL(float *v1, float *v2, float *v3, float *v4, short cox, short coy, @@ -86,20 +85,42 @@ void unlink_curve(Curve *cu) cu->vfont= 0; if(cu->key) cu->key->id.us--; cu->key= 0; - if(cu->ipo) cu->ipo->id.us--; - cu->ipo= 0; } +/* frees editcurve entirely */ +void BKE_free_editfont(Curve *cu) +{ + if(cu->editfont) { + EditFont *ef= cu->editfont; + + if(ef->oldstr) MEM_freeN(ef->oldstr); + if(ef->oldstrinfo) MEM_freeN(ef->oldstrinfo); + if(ef->textbuf) MEM_freeN(ef->textbuf); + if(ef->textbufinfo) MEM_freeN(ef->textbufinfo); + if(ef->copybuf) MEM_freeN(ef->copybuf); + if(ef->copybufinfo) MEM_freeN(ef->copybufinfo); + + MEM_freeN(ef); + cu->editfont= NULL; + } +} -/* niet curve zelf vrijgeven */ +/* don't free curve itself */ void free_curve(Curve *cu) { - freeNurblist(&cu->nurb); BLI_freelistN(&cu->bev); freedisplist(&cu->disp); + BKE_free_editfont(cu); + if(cu->editnurb) { + freeNurblist(cu->editnurb); + MEM_freeN(cu->editnurb); + cu->editnurb= NULL; + } + unlink_curve(cu); + BKE_free_animdata((ID *)cu); if(cu->mat) MEM_freeN(cu->mat); if(cu->str) MEM_freeN(cu->str); @@ -128,6 +149,18 @@ Curve *add_curve(char *name, int type) cu->bb= unit_boundbox(); + if(type==OB_FONT) { + cu->vfont= cu->vfontb= cu->vfonti= cu->vfontbi= get_builtin_font(); + cu->vfont->id.us+=4; + cu->str= MEM_mallocN(12, "str"); + strcpy(cu->str, "Text"); + cu->pos= 4; + cu->strinfo= MEM_callocN(12*sizeof(CharInfo), "strinfo new"); + cu->totbox= cu->actbox= 1; + cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox"); + cu->tb[0].w = cu->tb[0].h = 0.0; + } + return cu; } @@ -157,8 +190,12 @@ Curve *copy_curve(Curve *cu) cun->bev.first= cun->bev.last= 0; cun->path= 0; + cun->editnurb= NULL; + +#if 0 // XXX old animation system /* single user ipo too */ if(cun->ipo) cun->ipo= copy_ipo(cun->ipo); +#endif // XXX old animation system id_us_plus((ID *)cun->vfont); id_us_plus((ID *)cun->vfontb); @@ -1033,7 +1070,7 @@ float *make_orco_surf(Object *ob) /* NOTE: This routine is tied to the order of vertex * built by displist and as passed to the renderer. */ -float *make_orco_curve(Object *ob) +float *make_orco_curve(Scene *scene, Object *ob) { Curve *cu = ob->data; DispList *dl; @@ -1043,7 +1080,7 @@ float *make_orco_curve(Object *ob) if (!(cu->flag&CU_UV_ORCO) && cu->key && cu->key->refkey) { cp_cu_key(cu, cu->key->refkey, 0, count_curveverts(&cu->nurb)); - makeDispListCurveTypes(ob, 1); + makeDispListCurveTypes(scene, ob, 1); remakeDisp = 1; } @@ -1116,7 +1153,7 @@ float *make_orco_curve(Object *ob) } if (remakeDisp) { - makeDispListCurveTypes(ob, 0); + makeDispListCurveTypes(scene, ob, 0); } return coord_array; @@ -1125,7 +1162,7 @@ float *make_orco_curve(Object *ob) /* ***************** BEVEL ****************** */ -void makebevelcurve(Object *ob, ListBase *disp) +void makebevelcurve(Scene *scene, Object *ob, ListBase *disp) { DispList *dl, *dlnew; Curve *bevcu, *cu; @@ -1136,7 +1173,7 @@ void makebevelcurve(Object *ob, ListBase *disp) disp->first = disp->last = NULL; /* if a font object is being edited, then do nothing */ - if( ob == G.obedit && ob->type == OB_FONT ) return; +// XXX if( ob == obedit && ob->type == OB_FONT ) return; if(cu->bevobj && cu->bevobj!=ob) { if(cu->bevobj->type==OB_CURVE) { @@ -1147,7 +1184,7 @@ void makebevelcurve(Object *ob, ListBase *disp) dl= bevcu->disp.first; if(dl==0) { - makeDispListCurveTypes(cu->bevobj, 0); + makeDispListCurveTypes(scene, cu->bevobj, 0); dl= bevcu->disp.first; } while(dl) { @@ -1529,7 +1566,7 @@ void makeBevelList(Object *ob) /* STEP 1: MAKE POLYS */ BLI_freelistN(&(cu->bev)); - if(ob==G.obedit && ob->type!=OB_FONT) nu= editNurb.first; + if(cu->editnurb && ob->type!=OB_FONT) nu= cu->editnurb->first; else nu= cu->nurb.first; while(nu) { @@ -1976,7 +2013,7 @@ void makeBevelList(Object *ob) * 1: nothing, 1:auto, 2:vector, 3:aligned */ -/* mode: is not zero when IpoCurve, is 2 when forced horizontal for autohandles */ +/* mode: is not zero when FCurve, is 2 when forced horizontal for autohandles */ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) { float *p1,*p2,*p3, pt[3]; @@ -2307,18 +2344,18 @@ void autocalchandlesNurb(Nurb *nu, int flag) calchandlesNurb(nu); } -void autocalchandlesNurb_all(int flag) +void autocalchandlesNurb_all(ListBase *editnurb, int flag) { Nurb *nu; - nu= editNurb.first; + nu= editnurb->first; while(nu) { autocalchandlesNurb(nu, flag); nu= nu->next; } } -void sethandlesNurb(short code) +void sethandlesNurb(ListBase *editnurb, short code) { /* code==1: set autohandle */ /* code==2: set vectorhandle */ @@ -2331,7 +2368,7 @@ void sethandlesNurb(short code) short a, ok=0; if(code==1 || code==2) { - nu= editNurb.first; + nu= editnurb->first; while(nu) { if( (nu->type & 7)==CU_BEZIER) { bezt= nu->bezt; @@ -2355,7 +2392,7 @@ void sethandlesNurb(short code) else { /* there is 1 handle not FREE: FREE it all, else make ALIGNED */ - nu= editNurb.first; + nu= editnurb->first; if (code == 5) { ok = HD_ALIGN; } else if (code == 6) { @@ -2378,7 +2415,7 @@ void sethandlesNurb(short code) if(ok) ok= HD_FREE; else ok= HD_ALIGN; } - nu= editNurb.first; + nu= editnurb->first; while(nu) { if( (nu->type & 7)==CU_BEZIER) { bezt= nu->bezt; diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 4038ccb1ea7..705d0b66d7f 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -34,6 +34,7 @@ #include "BKE_customdata.h" #include "BKE_utildefines.h" // CLAMP +#include "BLI_arithb.h" #include "BLI_blenlib.h" #include "BLI_linklist.h" #include "BLI_mempool.h" @@ -44,6 +45,7 @@ #include "MEM_guardedalloc.h" +#include <math.h> #include <string.h> /* number of layers to add when growing a CustomData object */ @@ -378,6 +380,156 @@ static void layerDefault_origspace_face(void *data, int count) for(i = 0; i < count; i++) osf[i] = default_osf; } + +/* Adapted from sculptmode.c */ +static void mdisps_bilinear(float out[3], float (*disps)[3], int st, float u, float v) +{ + int x, y, x2, y2; + const int st_max = st - 1; + float urat, vrat, uopp; + float d[4][3], d2[2][3]; + + if(u < 0) + u = 0; + else if(u >= st) + u = st_max; + if(v < 0) + v = 0; + else if(v >= st) + v = st_max; + + x = floor(u); + y = floor(v); + x2 = x + 1; + y2 = y + 1; + + if(x2 >= st) x2 = st_max; + if(y2 >= st) y2 = st_max; + + urat = u - x; + vrat = v - y; + uopp = 1 - urat; + + VecCopyf(d[0], disps[y * st + x]); + VecCopyf(d[1], disps[y * st + x2]); + VecCopyf(d[2], disps[y2 * st + x]); + VecCopyf(d[3], disps[y2 * st + x2]); + VecMulf(d[0], uopp); + VecMulf(d[1], urat); + VecMulf(d[2], uopp); + VecMulf(d[3], urat); + + VecAddf(d2[0], d[0], d[1]); + VecAddf(d2[1], d[2], d[3]); + VecMulf(d2[0], 1 - vrat); + VecMulf(d2[1], vrat); + + VecAddf(out, d2[0], d2[1]); +} + +static void layerSwap_mdisps(void *data, int *ci) +{ + MDisps *s = data; + float (*d)[3] = NULL; + int x, y, st; + + if(!(ci[0] == 2 && ci[1] == 3 && ci[2] == 0 && ci[3] == 1)) return; + + d = MEM_callocN(sizeof(float) * 3 * s->totdisp, "mdisps swap"); + st = sqrt(s->totdisp); + + for(y = 0; y < st; ++y) { + for(x = 0; x < st; ++x) { + VecCopyf(d[(st - y - 1) * st + (st - x - 1)], s->disps[y * st + x]); + } + } + + if(s->disps) + MEM_freeN(s->disps); + s->disps = d; +} + +static void layerInterp_mdisps(void **sources, float *weights, float *sub_weights, + int count, void *dest) +{ + MDisps *d = dest; + MDisps *s = NULL; + int st, stl; + int i, x, y; + float crn[4][2]; + float (*sw)[4] = NULL; + + /* Initialize the destination */ + for(i = 0; i < d->totdisp; ++i) { + float z[3] = {0,0,0}; + VecCopyf(d->disps[i], z); + } + + /* For now, some restrictions on the input */ + if(count != 1 || !sub_weights) return; + + st = sqrt(d->totdisp); + stl = st - 1; + + sw = (void*)sub_weights; + for(i = 0; i < 4; ++i) { + crn[i][0] = 0 * sw[i][0] + stl * sw[i][1] + stl * sw[i][2] + 0 * sw[i][3]; + crn[i][1] = 0 * sw[i][0] + 0 * sw[i][1] + stl * sw[i][2] + stl * sw[i][3]; + } + + s = sources[0]; + for(y = 0; y < st; ++y) { + for(x = 0; x < st; ++x) { + /* One suspects this code could be cleaner. */ + float xl = (float)x / (st - 1); + float yl = (float)y / (st - 1); + float mid1[2] = {crn[0][0] * (1 - xl) + crn[1][0] * xl, + crn[0][1] * (1 - xl) + crn[1][1] * xl}; + float mid2[2] = {crn[3][0] * (1 - xl) + crn[2][0] * xl, + crn[3][1] * (1 - xl) + crn[2][1] * xl}; + float mid3[2] = {mid1[0] * (1 - yl) + mid2[0] * yl, + mid1[1] * (1 - yl) + mid2[1] * yl}; + + float srcdisp[3]; + + mdisps_bilinear(srcdisp, s->disps, st, mid3[0], mid3[1]); + VecCopyf(d->disps[y * st + x], srcdisp); + } + } +} + +static void layerCopy_mdisps(const void *source, void *dest, int count) +{ + int i; + const MDisps *s = source; + MDisps *d = dest; + + for(i = 0; i < count; ++i) { + if(s[i].disps) { + d[i].disps = MEM_dupallocN(s[i].disps); + d[i].totdisp = s[i].totdisp; + } + else { + d[i].disps = NULL; + d[i].totdisp = 0; + } + + } +} + +static void layerFree_mdisps(void *data, int count, int size) +{ + int i; + MDisps *d = data; + + for(i = 0; i < count; ++i) { + if(d[i].disps) + MEM_freeN(d[i].disps); + d[i].disps = NULL; + d[i].totdisp = 0; + } +} + /* --------- */ static void layerDefault_mloopcol(void *data, int count) @@ -569,27 +721,32 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(MTexPoly), "MTexPoly", 1, "Face Texture", NULL, NULL, NULL, NULL, NULL}, {sizeof(MLoopUV), "MLoopUV", 1, "UV coord", NULL, NULL, layerInterp_mloopuv, NULL, NULL}, {sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL, layerDefault_mloopcol}, - {sizeof(float)*3*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL} + {sizeof(float)*3*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps, + layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL}, + {sizeof(MCol)*4, "MCol", 4, "WeightCol", NULL, NULL, layerInterp_mcol, + layerSwap_mcol, layerDefault_mcol}, }; const char *LAYERTYPENAMES[CD_NUMTYPES] = { "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty", - "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent"}; + "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco", "CDMTexPoly", "CDMLoopUV", + "CDMloopCol", "CDTangent", "CDMDisps", "CDWeightMCol"}; const CustomDataMask CD_MASK_BAREMESH = CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE; const CustomDataMask CD_MASK_MESH = CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL | - CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR; + CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS; const CustomDataMask CD_MASK_EDITMESH = CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | - CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR; + CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS; const CustomDataMask CD_MASK_DERIVEDMESH = CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | - CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT; + CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_WEIGHT_MCOL; const CustomDataMask CD_MASK_BMESH = CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR; const CustomDataMask CD_MASK_FACECORNERS = diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 59619b25f8b..6c765b02e5d 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -33,13 +33,13 @@ #include "BLI_winstuff.h" #endif -//#include "BMF_Api.h" - #include "BLI_blenlib.h" #include "BLI_arithb.h" +#include "DNA_anim_types.h" #include "DNA_action_types.h" #include "DNA_armature_types.h" +#include "DNA_boid_types.h" #include "DNA_curve_types.h" #include "DNA_camera_types.h" #include "DNA_ID.h" @@ -54,7 +54,7 @@ #include "DNA_object_types.h" #include "DNA_object_force.h" #include "DNA_object_fluidsim.h" -#include "DNA_oops_types.h" +#include "DNA_outliner_types.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -62,6 +62,8 @@ #include "DNA_view2d_types.h" #include "DNA_view3d_types.h" +#include "BLI_ghash.h" + #include "BKE_action.h" #include "BKE_effect.h" #include "BKE_global.h" @@ -77,7 +79,6 @@ #include "BKE_scene.h" #include "MEM_guardedalloc.h" -#include "blendef.h" #ifndef DISABLE_PYTHON #include "BPY_extern.h" @@ -303,61 +304,49 @@ DagForest * dag_init() return forest; } -static void dag_add_driver_relation(Ipo *ipo, DagForest *dag, DagNode *node, int isdata) +/* isdata = object data... */ +// XXX this needs to be extended to be more flexible (so that not only objects are evaluated via depsgraph)... +static void dag_add_driver_relation(AnimData *adt, DagForest *dag, DagNode *node, int isdata) { - IpoCurve *icu; + FCurve *fcu; DagNode *node1; - for(icu= ipo->curve.first; icu; icu= icu->next) { - if(icu->driver) { - - if (icu->driver->type == IPO_DRIVER_TYPE_PYTHON) { - - if ((icu->driver->flag & IPO_DRIVER_FLAG_INVALID) || (icu->driver->name[0] == '\0')) - continue; /* empty or invalid expression */ -#ifndef DISABLE_PYTHON - else { - /* now we need refs to all objects mentioned in this - * pydriver expression, to call 'dag_add_relation' - * for each of them */ - Object **obarray = BPY_pydriver_get_objects(icu->driver); - if (obarray) { - Object *ob, **oba = obarray; - - while (*oba) { - ob = *oba; - node1 = dag_get_node(dag, ob); - if (ob->type == OB_ARMATURE) - dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Python Ipo Driver"); - else - dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB, "Python Ipo Driver"); - oba++; - } - - MEM_freeN(obarray); - } + for (fcu= adt->drivers.first; fcu; fcu= fcu->next) { + ChannelDriver *driver= fcu->driver; + DriverTarget *dtar; + + /* loop over targets, adding relationships as appropriate */ + for (dtar= driver->targets.first; dtar; dtar= dtar->next) { + if (dtar->id) { + if (GS(dtar->id->name)==ID_OB) { + Object *ob= (Object *)dtar->id; + + /* normal channel-drives-channel */ + node1 = dag_get_node(dag, dtar->id); + + /* check if bone... */ + if ((ob->type==OB_ARMATURE) && dtar->rna_path && strstr(dtar->rna_path, "pose.pose_channels[")) + dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Driver"); + /* check if ob data */ + else if (dtar->rna_path && strstr(dtar->rna_path, "data.")) + dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Driver"); + /* normal */ + else + dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB, "Driver"); } -#endif /* DISABLE_PYTHON */ - } - else if (icu->driver->ob) { - node1 = dag_get_node(dag, icu->driver->ob); - if(icu->driver->blocktype==ID_AR) - dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Ipo Driver"); - else - dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB, "Ipo Driver"); } } } } -static void dag_add_collision_field_relation(DagForest *dag, Object *ob, DagNode *node) +static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Object *ob, DagNode *node) { Base *base; DagNode *node2; // would be nice to have a list of colliders here // so for now walk all objects in scene check 'same layer rule' - for(base = G.scene->base.first; base; base= base->next) { + for(base = scene->base.first; base; base= base->next) { if((base->lay & ob->lay) && base->object->pd) { Object *ob1= base->object; if((ob1->pd->deflect || ob1->pd->forcefield) && (ob1 != ob)) { @@ -368,10 +357,9 @@ static void dag_add_collision_field_relation(DagForest *dag, Object *ob, DagNode } } -static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int mask) +static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, Object *ob, int mask) { bConstraint *con; - bConstraintChannel *conchan; DagNode * node; DagNode * node2; DagNode * node3; @@ -426,35 +414,11 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int } /* driver dependencies, nla modifiers */ - if(ob->ipo) - dag_add_driver_relation(ob->ipo, dag, node, 0); - - key= ob_get_key(ob); - if(key && key->ipo) - dag_add_driver_relation(key->ipo, dag, node, 1); - - for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next) - if(conchan->ipo) - dag_add_driver_relation(conchan->ipo, dag, node, 0); - - if(ob->action) { - bActionChannel *chan; - for (chan = ob->action->chanbase.first; chan; chan=chan->next){ - if(chan->ipo) - dag_add_driver_relation(chan->ipo, dag, node, 1); - for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) - if(conchan->ipo) - dag_add_driver_relation(conchan->ipo, dag, node, 1); - } - } +#if 0 // XXX old animation system if(ob->nlastrips.first) { bActionStrip *strip; bActionChannel *chan; for(strip= ob->nlastrips.first; strip; strip= strip->next) { - if(strip->act && strip->act!=ob->action) - for (chan = strip->act->chanbase.first; chan; chan=chan->next) - if(chan->ipo) - dag_add_driver_relation(chan->ipo, dag, node, 1); if(strip->modifiers.first) { bActionModifier *amod; for(amod= strip->modifiers.first; amod; amod= amod->next) { @@ -466,13 +430,21 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int } } } +#endif // XXX old animation system + if (ob->adt) + dag_add_driver_relation(ob->adt, dag, node, (ob->type == OB_ARMATURE)); // XXX isdata arg here doesn't give an accurate picture of situation + + key= ob_get_key(ob); + if (key && key->adt) + dag_add_driver_relation(key->adt, dag, node, 1); + if (ob->modifiers.first) { ModifierData *md; for(md=ob->modifiers.first; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (mti->updateDepgraph) mti->updateDepgraph(md, dag, ob, node); + if (mti->updateDepgraph) mti->updateDepgraph(md, dag, scene, ob, node); } } if (ob->parent) { @@ -515,11 +487,12 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA|DAG_RL_OB_OB, "Proxy"); /* inverted relation, so addtoroot shouldn't be set to zero */ } + + if (ob->type==OB_CAMERA) { Camera *cam = (Camera *)ob->data; - if (cam->ipo) { - dag_add_driver_relation(cam->ipo, dag, node, 1); - } + if (cam->adt) + dag_add_driver_relation(cam->adt, dag, node, 1); if (cam->dof_ob) { node2 = dag_get_node(dag, cam->dof_ob); dag_add_relation(dag,node2,node,DAG_RL_OB_OB, "Camera DoF"); @@ -527,10 +500,10 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int } if (ob->type==OB_LAMP) { Lamp *la = (Lamp *)ob->data; - if (la->ipo) { - dag_add_driver_relation(la->ipo, dag, node, 1); - } + if (la->adt) + dag_add_driver_relation(la->adt, dag, node, 1); } + if (ob->transflag & OB_DUPLI) { if((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) { GroupObject *go; @@ -547,10 +520,10 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int /* softbody collision */ if((ob->type==OB_MESH) || (ob->type==OB_CURVE) || (ob->type==OB_LATTICE)) if(modifiers_isSoftbodyEnabled(ob) || modifiers_isClothEnabled(ob)) - dag_add_collision_field_relation(dag, ob, node); + dag_add_collision_field_relation(dag, scene, ob, node); if (ob->type==OB_MBALL) { - Object *mom= find_basis_mball(ob); + Object *mom= find_basis_mball(scene, ob); if(mom!=ob) { node2 = dag_get_node(dag, mom); dag_add_relation(dag,node,node2,DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Metaball"); // mom depends on children! @@ -566,9 +539,8 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int node2 = dag_get_node(dag, cu->taperobj); dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Curve Taper"); } - if(cu->ipo) - dag_add_driver_relation(cu->ipo, dag, node, 1); - + if (cu->adt) + dag_add_driver_relation(cu->adt, dag, node, 1); } else if(ob->type==OB_FONT) { Curve *cu= ob->data; @@ -584,60 +556,81 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int GroupObject *go; for(; psys; psys=psys->next) { + BoidRule *rule = NULL; + BoidState *state = NULL; ParticleSettings *part= psys->part; dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation"); - if(psys->flag & PSYS_DISABLED || psys->flag & PSYS_DELETE) + if(!psys_check_enabled(ob, psys)) continue; - if(part->phystype==PART_PHYS_KEYED && psys->keyed_ob && - BLI_findlink(&psys->keyed_ob->particlesystem,psys->keyed_psys-1)) { - node2 = dag_get_node(dag, psys->keyed_ob); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Keyed Physics"); + if(ELEM(part->phystype,PART_PHYS_KEYED,PART_PHYS_BOIDS)) { + ParticleTarget *pt = psys->targets.first; + + for(; pt; pt=pt->next) { + if(pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys-1)) { + node2 = dag_get_node(dag, pt->ob); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Targets"); + } + } } - if(part->draw_as == PART_DRAW_OB && part->dup_ob) { + if(part->ren_as == PART_DRAW_OB && part->dup_ob) { node2 = dag_get_node(dag, part->dup_ob); dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualisation"); if(part->dup_ob->type == OB_MBALL) dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualisation"); } - if(part->draw_as == PART_DRAW_GR && part->dup_group) { + if(part->ren_as == PART_DRAW_GR && part->dup_group) { for(go=part->dup_group->gobject.first; go; go=go->next) { node2 = dag_get_node(dag, go->ob); dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Group Visualisation"); } } - if(psys->effectors.first) - psys_end_effectors(psys); - psys_init_effectors(ob,psys->part->eff_group,psys); + psys_end_effectors(psys); + psys_init_effectors(scene, ob, psys->part->eff_group, psys); - if(psys->effectors.first) { - for(nec= psys->effectors.first; nec; nec= nec->next) { - Object *ob1= nec->ob; + for(nec= psys->effectors.first; nec; nec= nec->next) { + Object *ob1= nec->ob; - if(nec->type & PSYS_EC_EFFECTOR) { - node2 = dag_get_node(dag, ob1); - if(ob1->pd->forcefield==PFIELD_GUIDE) - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Field"); - else - dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Particle Field"); - } - else if(nec->type & PSYS_EC_DEFLECT) { - node2 = dag_get_node(dag, ob1); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Collision"); - } - else if(nec->type & PSYS_EC_PARTICLE) { - node2 = dag_get_node(dag, ob1); - dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Field"); - } - - if(nec->type & PSYS_EC_REACTOR) { - node2 = dag_get_node(dag, ob1); - dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Reactor"); + if(nec->type & PSYS_EC_EFFECTOR) { + node2 = dag_get_node(dag, ob1); + if(ob1->pd->forcefield==PFIELD_GUIDE) + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Field"); + else + dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Particle Field"); + } + else if(nec->type & PSYS_EC_DEFLECT) { + node2 = dag_get_node(dag, ob1); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Collision"); + } + else if(nec->type & PSYS_EC_PARTICLE) { + node2 = dag_get_node(dag, ob1); + dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Field"); + } + + if(nec->type & PSYS_EC_REACTOR) { + node2 = dag_get_node(dag, ob1); + dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Reactor"); + } + } + + if(part->boids) { + for(state = part->boids->states.first; state; state=state->next) { + for(rule = state->rules.first; rule; rule=rule->next) { + Object *ruleob = NULL; + if(rule->type==eBoidRuleType_Avoid) + ruleob = ((BoidRuleGoalAvoid*)rule)->ob; + else if(rule->type==eBoidRuleType_FollowLeader) + ruleob = ((BoidRuleFollowLeader*)rule)->ob; + + if(ruleob) { + node2 = dag_get_node(dag, ruleob); + dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Boid Rule"); + } } } } @@ -708,9 +701,9 @@ struct DagForest *build_dag(struct Scene *sce, short mask) for(base = sce->base.first; base; base= base->next) { ob= base->object; - build_dag_object(dag, scenenode, ob, mask); + build_dag_object(dag, scenenode, sce, ob, mask); if(ob->proxy) - build_dag_object(dag, scenenode, ob->proxy, mask); + build_dag_object(dag, scenenode, sce, ob->proxy, mask); /* handled in next loop */ if(ob->dup_group) @@ -721,7 +714,7 @@ struct DagForest *build_dag(struct Scene *sce, short mask) for(group= G.main->group.first; group; group= group->id.next) { if(group->id.flag & LIB_DOIT) { for(go= group->gobject.first; go; go= go->next) { - build_dag_object(dag, scenenode, go->ob, mask); + build_dag_object(dag, scenenode, sce, go->ob, mask); } group->id.flag &= ~LIB_DOIT; } @@ -785,6 +778,9 @@ void free_forest(DagForest *Dag) itN = itN->next; MEM_freeN(tempN); } + + BLI_ghash_free(Dag->nodeHash, NULL, NULL); + Dag->nodeHash= NULL; Dag->DagNode.first = NULL; Dag->DagNode.last = NULL; Dag->numNodes = 0; @@ -793,13 +789,9 @@ void free_forest(DagForest *Dag) DagNode * dag_find_node (DagForest *forest,void * fob) { - DagNode *node = forest->DagNode.first; - - while (node) { - if (node->ob == fob) - return node; - node = node->next; - } + if(forest->nodeHash) + return BLI_ghash_lookup(forest->nodeHash, fob); + return NULL; } @@ -825,7 +817,12 @@ DagNode * dag_add_node (DagForest *forest, void * fob) forest->DagNode.first = node; forest->numNodes = 1; } + + if(!forest->nodeHash) + forest->nodeHash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + BLI_ghash_insert(forest->nodeHash, fob, node); } + return node; } @@ -1765,7 +1762,7 @@ static void flush_update_node(DagNode *node, unsigned int layer, int curtime) for(itA = node->child; itA; itA= itA->next) { all_layer |= itA->lay; /* the relationship is visible */ - if((itA->lay & layer) || (itA->node->ob == G.obedit)) { + if((itA->lay & layer)) { // XXX || (itA->node->ob == obedit) if(itA->node->type==ID_OB) { obc= itA->node->ob; oldflag= obc->recalc; @@ -1796,7 +1793,7 @@ static void flush_update_node(DagNode *node, unsigned int layer, int curtime) } } /* even nicer, we can clear recalc flags... */ - if((all_layer & layer)==0 && (ob != G.obedit)) { + if((all_layer & layer)==0) { // XXX && (ob != obedit)) { /* but existing displaylists or derivedmesh should be freed */ if(ob->recalc & OB_RECALC_DATA) object_free_display(ob); @@ -1810,7 +1807,7 @@ static void flush_update_node(DagNode *node, unsigned int layer, int curtime) /* could merge this in with loop above...? (ton) */ for(itA = node->child; itA; itA= itA->next) { /* the relationship is visible */ - if((itA->lay & layer) || (itA->node->ob == G.obedit)) { + if((itA->lay & layer)) { // XXX || (itA->node->ob == obedit) if(itA->node->type==ID_OB) { obc= itA->node->ob; /* child moves */ @@ -1836,17 +1833,10 @@ static void flush_update_node(DagNode *node, unsigned int layer, int curtime) /* node was checked to have lasttime != curtime , and is of type ID_OB */ static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime) { - Base *base; DagAdjList *itA; node->lasttime= curtime; - node->lay= 0; - for(base= sce->base.first; base; base= base->next) { - if(node->ob == base->object) { - node->lay= ((Object *)node->ob)->lay; - break; - } - } + node->lay= node->scelay; for(itA = node->child; itA; itA= itA->next) { if(itA->node->type==ID_OB) { @@ -1863,7 +1853,7 @@ static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime) } /* node was checked to have lasttime != curtime , and is of type ID_OB */ -static void flush_pointcache_reset(DagNode *node, int curtime, int reset) +static void flush_pointcache_reset(Scene *scene, DagNode *node, int curtime, int reset) { DagAdjList *itA; Object *ob; @@ -1876,13 +1866,13 @@ static void flush_pointcache_reset(DagNode *node, int curtime, int reset) ob= (Object*)(node->ob); if(reset || (ob->recalc & OB_RECALC)) { - if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH)) + if(BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH)) ob->recalc |= OB_RECALC_DATA; - flush_pointcache_reset(itA->node, curtime, 1); + flush_pointcache_reset(scene, itA->node, curtime, 1); } else - flush_pointcache_reset(itA->node, curtime, 0); + flush_pointcache_reset(scene, itA->node, curtime, 0); } } } @@ -1891,9 +1881,10 @@ static void flush_pointcache_reset(DagNode *node, int curtime, int reset) /* flushes all recalc flags in objects down the dependency tree */ void DAG_scene_flush_update(Scene *sce, unsigned int lay, int time) { - DagNode *firstnode; + DagNode *firstnode, *node; DagAdjList *itA; Object *ob; + Base *base; int lasttime; if(sce->theDag==NULL) { @@ -1910,6 +1901,15 @@ void DAG_scene_flush_update(Scene *sce, unsigned int lay, int time) sce->theDag->time++; // so we know which nodes were accessed lasttime= sce->theDag->time; + + for(base= sce->base.first; base; base= base->next) { + node= dag_get_node(sce->theDag, base->object); + if(node) + node->scelay= base->object->lay; + else + node->scelay= 0; + } + for(itA = firstnode->child; itA; itA= itA->next) if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB) flush_layer_node(sce, itA->node, lasttime); @@ -1930,13 +1930,13 @@ void DAG_scene_flush_update(Scene *sce, unsigned int lay, int time) ob= (Object*)(itA->node->ob); if(ob->recalc & OB_RECALC) { - if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH)) + if(BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH)) ob->recalc |= OB_RECALC_DATA; - flush_pointcache_reset(itA->node, lasttime, 1); + flush_pointcache_reset(sce, itA->node, lasttime, 1); } else - flush_pointcache_reset(itA->node, lasttime, 0); + flush_pointcache_reset(sce, itA->node, lasttime, 0); } } } @@ -1953,25 +1953,28 @@ static int object_modifiers_use_time(Object *ob) return 0; } -static int exists_channel(Object *ob, char *name) +static short animdata_use_time(AnimData *adt) { - bActionStrip *strip; + NlaTrack *nlt; - if(ob->action) - if(get_action_channel(ob->action, name)) - return 1; + if(adt==NULL) return 0; - for (strip=ob->nlastrips.first; strip; strip=strip->next) - if(get_action_channel(strip->act, name)) + /* check action - only if assigned, and it has anim curves */ + if (adt->action && adt->action->curves.first) + return 1; + + /* check NLA tracks + strips */ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + if (nlt->strips.first) return 1; + } + return 0; } static void dag_object_time_update_flags(Object *ob) { - - if(ob->ipo) ob->recalc |= OB_RECALC_OB; - else if(ob->constraints.first) { + if(ob->constraints.first) { bConstraint *con; for (con = ob->constraints.first; con; con=con->next) { bConstraintTypeInfo *cti= constraint_get_typeinfo(con); @@ -1994,21 +1997,14 @@ static void dag_object_time_update_flags(Object *ob) } } - if(ob->scriptlink.totscript) ob->recalc |= OB_RECALC_OB; - if(ob->parent) { /* motion path or bone child */ if(ob->parent->type==OB_CURVE || ob->parent->type==OB_ARMATURE) ob->recalc |= OB_RECALC_OB; } - if(ob->action || ob->nlastrips.first) { - /* since actions now are mixed, we set the recalcs on the safe side */ - ob->recalc |= OB_RECALC_OB; - if(ob->type==OB_ARMATURE) - ob->recalc |= OB_RECALC_DATA; - else if(exists_channel(ob, "Shape")) - ob->recalc |= OB_RECALC_DATA; - else if(ob->dup_group) { +#if 0 // XXX old animation system + if(ob->nlastrips.first) { + if(ob->dup_group) { bActionStrip *strip; /* this case is for groups with nla, whilst nla target has no action or nla */ for(strip= ob->nlastrips.first; strip; strip= strip->next) { @@ -2017,6 +2013,14 @@ static void dag_object_time_update_flags(Object *ob) } } } +#endif // XXX old animation system + + if(animdata_use_time(ob->adt)) { + ob->recalc |= OB_RECALC; + ob->adt->recalc |= ADT_RECALC_ANIM; + } + + if((ob->adt) && (ob->type==OB_ARMATURE)) ob->recalc |= OB_RECALC_DATA; if(object_modifiers_use_time(ob)) ob->recalc |= OB_RECALC_DATA; if((ob->pose) && (ob->pose->flag & POSE_CONSTRAINTS_TIMEDEPEND)) ob->recalc |= OB_RECALC_DATA; @@ -2079,7 +2083,6 @@ static void dag_object_time_update_flags(Object *ob) } } } - /* flag all objects that need recalc, for changes in time for example */ void DAG_scene_update_flags(Scene *scene, unsigned int lay) { @@ -2138,22 +2141,6 @@ void DAG_scene_update_flags(Scene *scene, unsigned int lay) } -/* for depgraph updating, all layers visible in a screen */ -/* this is a copy from editscreen.c... I need to think over a more proper solution for this */ -/* probably the DAG_object_flush_update() should give layer too? */ -/* or some kind of dag context... (DAG_set_layer) */ -static unsigned int dag_screen_view3d_layers(void) -{ - ScrArea *sa; - int layer= 0; - - for(sa= G.curscreen->areabase.first; sa; sa= sa->next) { - if(sa->spacetype==SPACE_VIEW3D) - layer |= ((View3D *)sa->spacedata.first)->lay; - } - return layer; -} - /* flag this object and all its relations to recalc */ /* if you need to do more objects, tag object yourself and @@ -2164,7 +2151,7 @@ void DAG_object_flush_update(Scene *sce, Object *ob, short flag) if(ob==NULL || sce->theDag==NULL) return; ob->recalc |= flag; - BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH); + BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH); /* all users of this ob->data should be checked */ /* BUT! displists for curves are still only on cu */ @@ -2179,7 +2166,7 @@ void DAG_object_flush_update(Scene *sce, Object *ob, short flag) for (obt=G.main->object.first; obt; obt= obt->id.next) { if (obt != ob && obt->data==ob->data) { obt->recalc |= OB_RECALC_DATA; - BKE_ptcache_object_reset(obt, PTCACHE_RESET_DEPSGRAPH); + BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); } } } @@ -2187,9 +2174,9 @@ void DAG_object_flush_update(Scene *sce, Object *ob, short flag) } } - if(G.curscreen) - DAG_scene_flush_update(sce, dag_screen_view3d_layers(), 0); - else +// XXX if(G.curscreen) +// DAG_scene_flush_update(sce, dag_screen_view3d_layers(), 0); +// else DAG_scene_flush_update(sce, sce->lay, 0); } @@ -2308,6 +2295,7 @@ void DAG_pose_sort(Object *ob) ListBase targets = {NULL, NULL}; bConstraintTarget *ct; +#if 0 // XXX old animation system... driver stuff to watch out for if(con->ipo) { IpoCurve *icu; for(icu= con->ipo->curve.first; icu; icu= icu->next) { @@ -2319,7 +2307,7 @@ void DAG_pose_sort(Object *ob) if(target) { node2 = dag_get_node(dag, target); dag_add_relation(dag, node2, node, 0, "Ipo Driver"); - + /* uncommented this line, results in dependencies * not being added properly for this constraint, * what is the purpose of this? - brecht */ @@ -2328,6 +2316,7 @@ void DAG_pose_sort(Object *ob) } } } +#endif // XXX old animation system... driver stuff to watch out for if (cti && cti->get_constraint_targets) { cti->get_constraint_targets(con, &targets); diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index afc769b0966..069129c15da 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -60,7 +60,6 @@ #include "BLI_editVert.h" #include "BLI_edgehash.h" -#include "BKE_bad_level_calls.h" #include "BKE_utildefines.h" #include "BKE_global.h" #include "BKE_displist.h" @@ -305,24 +304,34 @@ int surfindex_displist(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, i /* create default shade input... save cpu cycles with ugly global */ /* XXXX bad code warning: local ShadeInput initialize... */ static ShadeInput shi; -static void init_fastshade_shadeinput(void) +static void init_fastshade_shadeinput(Render *re) { memset(&shi, 0, sizeof(ShadeInput)); - shi.lay= G.scene->lay; + shi.lay= RE_GetScene(re)->lay; shi.view[2]= -1.0f; shi.passflag= SCE_PASS_COMBINED; shi.combinedflag= -1; } -static Render *fastshade_get_render(void) +static Render *fastshade_get_render(Scene *scene) { - Render *re= RE_GetRender("_Shade View_"); - if(re==NULL) { - re= RE_NewRender("_Shade View_"); - - RE_Database_Baking(re, G.scene, 0, 0); /* 0= no faces */ + // XXX 2.5: this crashes combined with previewrender + // due to global R so disabled for now +#if 0 + /* XXX ugly global still, but we can't do preview while rendering */ + if(G.rendering==0) { + + Render *re= RE_GetRender("_Shade View_"); + if(re==NULL) { + re= RE_NewRender("_Shade View_"); + + RE_Database_Baking(re, scene, 0, 0); /* 0= no faces */ + } + return re; } - return re; +#endif + + return NULL; } /* called on file reading */ @@ -463,7 +472,7 @@ static void init_fastshade_for_ob(Render *re, Object *ob, int *need_orco_r, floa RE_shade_external(re, NULL, NULL); /* initialize global here */ - init_fastshade_shadeinput(); + init_fastshade_shadeinput(re); RE_DataBase_GetView(re, tmat); Mat4MulMat4(mat, ob->obmat, tmat); @@ -516,9 +525,9 @@ static void mesh_create_shadedColors(Render *re, Object *ob, int onlyForMesh, un dataMask |= CD_MASK_ORCO; if (onlyForMesh) - dm = mesh_get_derived_deform(ob, dataMask); + dm = mesh_get_derived_deform(RE_GetScene(re), ob, dataMask); else - dm = mesh_get_derived_final(ob, dataMask); + dm = mesh_get_derived_final(RE_GetScene(re), ob, dataMask); mvert = dm->getVertArray(dm); mface = dm->getFaceArray(dm); @@ -558,6 +567,7 @@ static void mesh_create_shadedColors(Render *re, Object *ob, int onlyForMesh, un } for (i=0; i<totface; i++) { + extern Material defmaterial; /* material.c */ MFace *mf= &mface[i]; Material *ma= give_current_material(ob, mf->mat_nr+1); int j, vidx[4], nverts= mf->v4?4:3; @@ -609,26 +619,28 @@ static void mesh_create_shadedColors(Render *re, Object *ob, int onlyForMesh, un end_fastshade_for_ob(ob); } -void shadeMeshMCol(Object *ob, Mesh *me) +void shadeMeshMCol(Scene *scene, Object *ob, Mesh *me) { + Render *re= fastshade_get_render(scene); int a; char *cp; unsigned int *mcol= (unsigned int*)me->mcol; - Render *re= fastshade_get_render(); - mesh_create_shadedColors(re, ob, 1, &mcol, NULL); - me->mcol= (MCol*)mcol; - - /* swap bytes */ - for(cp= (char *)me->mcol, a= 4*me->totface; a>0; a--, cp+=4) { - SWAP(char, cp[0], cp[3]); - SWAP(char, cp[1], cp[2]); + if(re) { + mesh_create_shadedColors(re, ob, 1, &mcol, NULL); + me->mcol= (MCol*)mcol; + + /* swap bytes */ + for(cp= (char *)me->mcol, a= 4*me->totface; a>0; a--, cp+=4) { + SWAP(char, cp[0], cp[3]); + SWAP(char, cp[1], cp[2]); + } } } /* has base pointer, to check for layer */ /* called from drawobject.c */ -void shadeDispList(Base *base) +void shadeDispList(Scene *scene, Base *base) { Object *ob= base->object; DispList *dl, *dlob; @@ -640,7 +652,9 @@ void shadeDispList(Base *base) unsigned int *col1; int a, need_orco; - re= fastshade_get_render(); + re= fastshade_get_render(scene); + if(re==NULL) + return; dl = find_displist(&ob->disp, DL_VERTCOL); if (dl) { @@ -662,13 +676,15 @@ void shadeDispList(Base *base) init_fastshade_for_ob(re, ob, &need_orco, mat, imat); - if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) { + if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { /* now we need the normals */ cu= ob->data; dl= cu->disp.first; while(dl) { + extern Material defmaterial; /* material.c */ + dlob= MEM_callocN(sizeof(DispList), "displistshade"); BLI_addtail(&ob->disp, dlob); dlob->type= DL_VERTCOL; @@ -739,6 +755,7 @@ void shadeDispList(Base *base) if(dl->type==DL_INDEX4) { if(dl->nors) { + extern Material defmaterial; /* material.c */ if(dl->col1) MEM_freeN(dl->col1); col1= dl->col1= MEM_mallocN(sizeof(int)*dl->nr, "col1"); @@ -776,22 +793,22 @@ void shadeDispList(Base *base) /* frees render and shade part of displists */ /* note: dont do a shade again, until a redraw happens */ -void reshadeall_displist(void) +void reshadeall_displist(Scene *scene) { Base *base; Object *ob; fastshade_free_render(); - for(base= G.scene->base.first; base; base= base->next) { + for(base= scene->base.first; base; base= base->next) { ob= base->object; if(ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) freedisplist(&ob->disp); - if(base->lay & G.scene->lay) { + if(base->lay & scene->lay) { /* Metaballs have standard displist at the Object */ - if(ob->type==OB_MBALL) shadeDispList(base); + if(ob->type==OB_MBALL) shadeDispList(scene, base); } } } @@ -982,7 +999,7 @@ void filldisplist(ListBase *dispbase, ListBase *to) dl= dl->next; } - if(totvert && BLI_edgefill(0, (G.obedit && G.obedit->actcol)?(G.obedit->actcol-1):0)) { + if(totvert && BLI_edgefill(0, 0)) { // XXX (obedit && obedit->actcol)?(obedit->actcol-1):0)) { /* count faces */ tot= 0; @@ -1127,7 +1144,7 @@ void curve_to_filledpoly(Curve *cu, ListBase *nurb, ListBase *dispbase) - first point left, last point right - based on subdivided points in original curve, not on points in taper curve (still) */ -float calc_taper(Object *taperobj, int cur, int tot) +float calc_taper(Scene *scene, Object *taperobj, int cur, int tot) { Curve *cu; DispList *dl; @@ -1137,7 +1154,7 @@ float calc_taper(Object *taperobj, int cur, int tot) cu= taperobj->data; dl= cu->disp.first; if(dl==NULL) { - makeDispListCurveTypes(taperobj, 0); + makeDispListCurveTypes(scene, taperobj, 0); dl= cu->disp.first; } if(dl) { @@ -1170,15 +1187,15 @@ float calc_taper(Object *taperobj, int cur, int tot) return 1.0; } -void makeDispListMBall(Object *ob) +void makeDispListMBall(Scene *scene, Object *ob) { if(!ob || ob->type!=OB_MBALL) return; freedisplist(&(ob->disp)); if(ob->type==OB_MBALL) { - if(ob==find_basis_mball(ob)) { - metaball_polygonize(ob); + if(ob==find_basis_mball(scene, ob)) { + metaball_polygonize(scene, ob); tex_space_mball(ob); object_deform_mball(ob); @@ -1214,12 +1231,14 @@ static ModifierData *curve_get_tesselate_point(Object *ob, int forRender, int ed return preTesselatePoint; } -void curve_calc_modifiers_pre(Object *ob, ListBase *nurb, int forRender, float (**originalVerts_r)[3], float (**deformedVerts_r)[3], int *numVerts_r) +static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, float (**originalVerts_r)[3], float (**deformedVerts_r)[3], int *numVerts_r) { - int editmode = (!forRender && ob==G.obedit); ModifierData *md = modifiers_getVirtualModifierList(ob); - ModifierData *preTesselatePoint = curve_get_tesselate_point(ob, forRender, editmode); + ModifierData *preTesselatePoint; + Curve *cu= ob->data; + ListBase *nurb= cu->editnurb?cu->editnurb:&cu->nurb; int numVerts = 0; + int editmode = (!forRender && cu->editnurb); float (*originalVerts)[3] = NULL; float (*deformedVerts)[3] = NULL; int required_mode; @@ -1227,9 +1246,11 @@ void curve_calc_modifiers_pre(Object *ob, ListBase *nurb, int forRender, float ( if(forRender) required_mode = eModifierMode_Render; else required_mode = eModifierMode_Realtime; + preTesselatePoint = curve_get_tesselate_point(ob, forRender, editmode); + if(editmode) required_mode |= eModifierMode_Editmode; - if(ob!=G.obedit && do_ob_key(ob)) { + if(cu->editnurb==NULL && do_ob_key(scene, ob)) { deformedVerts = curve_getVertexCos(ob->data, nurb, &numVerts); originalVerts = MEM_dupallocN(deformedVerts); } @@ -1238,6 +1259,8 @@ void curve_calc_modifiers_pre(Object *ob, ListBase *nurb, int forRender, float ( for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); + md->scene= scene; + if ((md->mode & required_mode) != required_mode) continue; if (mti->isDisabled && mti->isDisabled(md)) continue; if (mti->type!=eModifierTypeType_OnlyDeform) continue; @@ -1247,7 +1270,7 @@ void curve_calc_modifiers_pre(Object *ob, ListBase *nurb, int forRender, float ( originalVerts = MEM_dupallocN(deformedVerts); } - mti->deformVerts(md, ob, NULL, deformedVerts, numVerts); + mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, forRender, editmode); if (md==preTesselatePoint) break; @@ -1263,17 +1286,21 @@ void curve_calc_modifiers_pre(Object *ob, ListBase *nurb, int forRender, float ( *numVerts_r = numVerts; } -static void curve_calc_modifiers_post(Object *ob, ListBase *nurb, ListBase *dispbase, int forRender, float (*originalVerts)[3], float (*deformedVerts)[3]) +static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispbase, int forRender, float (*originalVerts)[3], float (*deformedVerts)[3]) { - int editmode = (!forRender && ob==G.obedit); ModifierData *md = modifiers_getVirtualModifierList(ob); - ModifierData *preTesselatePoint = curve_get_tesselate_point(ob, forRender, editmode); + ModifierData *preTesselatePoint; + Curve *cu= ob->data; + ListBase *nurb= cu->editnurb?cu->editnurb:&cu->nurb; DispList *dl; int required_mode; + int editmode = (!forRender && cu->editnurb); if(forRender) required_mode = eModifierMode_Render; else required_mode = eModifierMode_Realtime; + preTesselatePoint = curve_get_tesselate_point(ob, forRender, editmode); + if(editmode) required_mode |= eModifierMode_Editmode; if (preTesselatePoint) { @@ -1283,6 +1310,8 @@ static void curve_calc_modifiers_post(Object *ob, ListBase *nurb, ListBase *disp for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); + md->scene= scene; + if ((md->mode & required_mode) != required_mode) continue; if (mti->isDisabled && mti->isDisabled(md)) continue; if (mti->type!=eModifierTypeType_OnlyDeform && mti->type!=eModifierTypeType_DeformOrConstruct) continue; @@ -1302,7 +1331,7 @@ static void curve_calc_modifiers_post(Object *ob, ListBase *nurb, ListBase *disp fp+= offs; } - mti->deformVerts(md, ob, NULL, (float(*)[3]) allverts, totvert); + mti->deformVerts(md, ob, NULL, (float(*)[3]) allverts, totvert, forRender, editmode); fp= allverts; for (dl=dispbase->first; dl; dl=dl->next) { @@ -1314,7 +1343,7 @@ static void curve_calc_modifiers_post(Object *ob, ListBase *nurb, ListBase *disp } else { for (dl=dispbase->first; dl; dl=dl->next) { - mti->deformVerts(md, ob, NULL, (float(*)[3]) dl->verts, (dl->type==DL_INDEX3)?dl->nr:dl->parts*dl->nr); + mti->deformVerts(md, ob, NULL, (float(*)[3]) dl->verts, (dl->type==DL_INDEX3)?dl->nr:dl->parts*dl->nr, forRender, editmode); } } } @@ -1356,7 +1385,7 @@ static void displist_surf_indices(DispList *dl) } -void makeDispListSurf(Object *ob, ListBase *dispbase, int forRender, int forOrco) +void makeDispListSurf(Scene *scene, Object *ob, ListBase *dispbase, int forRender, int forOrco) { ListBase *nubase; Nurb *nu; @@ -1368,15 +1397,13 @@ void makeDispListSurf(Object *ob, ListBase *dispbase, int forRender, int forOrco float (*originalVerts)[3]; float (*deformedVerts)[3]; - if(!forRender && ob==G.obedit) { - nubase= &editNurb; - } - else { + if(!forRender && cu->editnurb) + nubase= cu->editnurb; + else nubase= &cu->nurb; - } if(!forOrco) - curve_calc_modifiers_pre(ob, nubase, forRender, &originalVerts, &deformedVerts, &numVerts); + curve_calc_modifiers_pre(scene, ob, forRender, &originalVerts, &deformedVerts, &numVerts); for (nu=nubase->first; nu; nu=nu->next) { if(forRender || nu->hide==0) { @@ -1431,10 +1458,10 @@ void makeDispListSurf(Object *ob, ListBase *dispbase, int forRender, int forOrco } if(!forOrco) - curve_calc_modifiers_post(ob, nubase, dispbase, forRender, originalVerts, deformedVerts); + curve_calc_modifiers_post(scene, ob, dispbase, forRender, originalVerts, deformedVerts); } -void makeDispListCurveTypes(Object *ob, int forOrco) +void makeDispListCurveTypes(Scene *scene, Object *ob, int forOrco) { Curve *cu = ob->data; ListBase *dispbase; @@ -1447,29 +1474,33 @@ void makeDispListCurveTypes(Object *ob, int forOrco) freedisplist(dispbase); if(ob->type==OB_SURF) { - makeDispListSurf(ob, dispbase, 0, forOrco); + makeDispListSurf(scene, ob, dispbase, 0, forOrco); } - else if ELEM(ob->type, OB_CURVE, OB_FONT) { + else if (ELEM(ob->type, OB_CURVE, OB_FONT)) { ListBase dlbev; + ListBase *nubase; float (*originalVerts)[3]; float (*deformedVerts)[3]; - int obedit= (G.obedit && G.obedit->data==ob->data && G.obedit->type==OB_CURVE); - ListBase *nubase = obedit?&editNurb:&cu->nurb; int numVerts; + if(cu->editnurb) + nubase= cu->editnurb; + else + nubase= &cu->nurb; + BLI_freelistN(&(cu->bev)); if(cu->path) free_path(cu->path); cu->path= NULL; - if(ob->type==OB_FONT) text_to_curve(ob, 0); + if(ob->type==OB_FONT) BKE_text_to_curve(scene, ob, 0); - if(!forOrco) curve_calc_modifiers_pre(ob, nubase, 0, &originalVerts, &deformedVerts, &numVerts); + if(!forOrco) curve_calc_modifiers_pre(scene, ob, 0, &originalVerts, &deformedVerts, &numVerts); makeBevelList(ob); /* If curve has no bevel will return nothing */ - makebevelcurve(ob, &dlbev); + makebevelcurve(scene, ob, &dlbev); /* no bevel or extrude, and no width correction? */ if (!dlbev.first && cu->width==1.0f) { @@ -1547,7 +1578,7 @@ void makeDispListCurveTypes(Object *ob, int forOrco) if ( (cu->bevobj!=NULL) || !((cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ) fac = bevp->radius; } else { - fac = calc_taper(cu->taperobj, a, bl->nr); + fac = calc_taper(scene, cu->taperobj, a, bl->nr); } if (bevp->f1) { @@ -1592,7 +1623,7 @@ void makeDispListCurveTypes(Object *ob, int forOrco) if(cu->flag & CU_PATH) calc_curvepath(ob); - if(!forOrco) curve_calc_modifiers_post(ob, nubase, &cu->disp, 0, originalVerts, deformedVerts); + if(!forOrco) curve_calc_modifiers_post(scene, ob, &cu->disp, 0, originalVerts, deformedVerts); tex_space_curve(cu); } diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 5bc3e295272..e3c4f12184e 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -29,6 +29,8 @@ * ***** END GPL LICENSE BLOCK ***** */ +#include "BLI_storage.h" /* _LARGEFILE_SOURCE */ + #include <math.h> #include <stdlib.h> @@ -54,10 +56,11 @@ #include "BLI_jitter.h" #include "BLI_rand.h" +#include "PIL_time.h" + #include "BKE_action.h" #include "BKE_anim.h" /* needed for where_on_path */ #include "BKE_armature.h" -#include "BKE_bad_level_calls.h" #include "BKE_blender.h" #include "BKE_collision.h" #include "BKE_constraint.h" @@ -86,12 +89,29 @@ #ifndef DISABLE_ELBEEM #include "DNA_object_fluidsim.h" #include "LBM_fluidsim.h" -#include "elbeem.h" #include <zlib.h> #include <string.h> #endif // DISABLE_ELBEEM +//XXX #include "BIF_screen.h" + +PartDeflect *object_add_collision_fields(void) +{ + PartDeflect *pd; + + pd= MEM_callocN(sizeof(PartDeflect), "PartDeflect"); + + pd->pdef_sbdamp = 0.1f; + pd->pdef_sbift = 0.2f; + pd->pdef_sboft = 0.02f; + pd->seed = ((unsigned int)(ceil(PIL_check_seconds_timer()))+1) % 128; + pd->f_strength = 1.0f; + + return pd; +} + /* temporal struct, used for reading return of mesh_get_mapped_verts_nors() */ + typedef struct VeNoCo { float co[3], no[3]; } VeNoCo; @@ -137,7 +157,7 @@ void free_effects(ListBase *lb) /* -------------------------- Effectors ------------------ */ -static void add_to_effectorcache(ListBase *lb, Object *ob, Object *obsrc) +static void add_to_effectorcache(ListBase *lb, Scene *scene, Object *ob, Object *obsrc) { pEffectorCache *ec; PartDeflect *pd= ob->pd; @@ -147,7 +167,7 @@ static void add_to_effectorcache(ListBase *lb, Object *ob, Object *obsrc) Curve *cu= ob->data; if(cu->flag & CU_PATH) { if(cu->path==NULL || cu->path->data==NULL) - makeDispListCurveTypes(ob, 0); + makeDispListCurveTypes(scene, ob, 0); if(cu->path && cu->path->data) { ec= MEM_callocN(sizeof(pEffectorCache), "effector cache"); ec->ob= ob; @@ -170,7 +190,7 @@ static void add_to_effectorcache(ListBase *lb, Object *ob, Object *obsrc) } /* returns ListBase handle with objects taking part in the effecting */ -ListBase *pdInitEffectors(Object *obsrc, Group *group) +ListBase *pdInitEffectors(Scene *scene, Object *obsrc, Group *group) { static ListBase listb={NULL, NULL}; pEffectorCache *ec; @@ -182,14 +202,14 @@ ListBase *pdInitEffectors(Object *obsrc, Group *group) for(go= group->gobject.first; go; go= go->next) { if( (go->ob->lay & layer) && go->ob->pd && go->ob!=obsrc) { - add_to_effectorcache(&listb, go->ob, obsrc); + add_to_effectorcache(&listb, scene, go->ob, obsrc); } } } else { - for(base = G.scene->base.first; base; base= base->next) { + for(base = scene->base.first; base; base= base->next) { if( (base->lay & layer) && base->object->pd && base->object!=obsrc) { - add_to_effectorcache(&listb, base->object, obsrc); + add_to_effectorcache(&listb, scene, base->object, obsrc); } } } @@ -236,14 +256,14 @@ static void eff_tri_ray_hit(void *userdata, int index, const BVHTreeRay *ray, BV } // get visibility of a wind ray -static float eff_calc_visibility(Object *ob, float *co, float *dir) +static float eff_calc_visibility(Scene *scene, Object *ob, float *co, float *dir) { CollisionModifierData **collobjs = NULL; int numcollobj = 0, i; float norm[3], len = 0.0; float visibility = 1.0; - collobjs = get_collisionobjects(ob, &numcollobj); + collobjs = get_collisionobjects(scene, ob, &numcollobj); if(!collobjs) return 0; @@ -368,7 +388,7 @@ float effector_falloff(PartDeflect *pd, float *eff_velocity, float *vec_to_part) return falloff; } -void do_physical_effector(Object *ob, float *opco, short type, float force_val, float distance, float falloff, float size, float damp, float *eff_velocity, float *vec_to_part, float *velocity, float *field, int planar, struct RNG *rng, float noise_factor, float charge, float pa_size) +void do_physical_effector(Scene *scene, Object *ob, float *opco, short type, float force_val, float distance, float falloff, float size, float damp, float *eff_velocity, float *vec_to_part, float *velocity, float *field, int planar, struct RNG *rng, float noise_factor, float charge, float pa_size) { float mag_vec[3]={0,0,0}; float temp[3], temp2[3]; @@ -376,7 +396,7 @@ void do_physical_effector(Object *ob, float *opco, short type, float force_val, float noise = 0, visibility; // calculate visibility - visibility = eff_calc_visibility(ob, opco, vec_to_part); + visibility = eff_calc_visibility(scene, ob, opco, vec_to_part); if(visibility <= 0.0) return; falloff *= visibility; @@ -485,11 +505,15 @@ void do_physical_effector(Object *ob, float *opco, short type, float force_val, VecAddf(field,field,mag_vec); break; } + case PFIELD_BOID: + /* Boid field is handled completely in boids code. */ + break; } } /* -------- pdDoEffectors() -------- generic force/speed system, now used for particles and softbodies + scene = scene where it runs in, for time and stuff lb = listbase with objects that take part in effecting opco = global coord, as input force = force accumulator @@ -501,7 +525,7 @@ void do_physical_effector(Object *ob, float *opco, short type, float force_val, guide = old speed of particle */ -void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags) +void pdDoEffectors(Scene *scene, ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags) { /* Modifies the force on a particle according to its @@ -532,7 +556,7 @@ void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float pd= ob->pd; /* Get IPO force strength and fall off values here */ - where_is_object_time(ob,cur_time); + where_is_object_time(scene, ob, cur_time); /* use center of object for distance calculus */ VecSubf(vec_to_part, opco, ob->obmat[3]); @@ -545,9 +569,9 @@ void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float else { float field[3]={0,0,0}, tmp[3]; VECCOPY(field, force); - do_physical_effector(ob, opco, pd->forcefield,pd->f_strength,distance, - falloff,pd->f_dist,pd->f_damp,ob->obmat[2],vec_to_part, - speed,force,pd->flag&PFIELD_PLANAR, pd->rng, pd->f_noise, 0.0f, 0.0f); + do_physical_effector(scene, ob, opco, pd->forcefield,pd->f_strength,distance, + falloff, pd->f_dist, pd->f_damp, ob->obmat[2], vec_to_part, + speed,force, pd->flag&PFIELD_PLANAR, pd->rng, pd->f_noise, 0.0f, 0.0f); // for softbody backward compatibility if(flags & PE_WIND_AS_SPEED){ diff --git a/source/blender/blenkernel/intern/exotic.c b/source/blender/blenkernel/intern/exotic.c index 76ad0cf07c3..8827897a509 100644 --- a/source/blender/blenkernel/intern/exotic.c +++ b/source/blender/blenkernel/intern/exotic.c @@ -19,55 +19,17 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * The Original Code is: all of this file. * * Contributor(s): * - Martin DeMello * Added dxf_read_arc, dxf_read_ellipse and dxf_read_lwpolyline * Copyright (C) 2004 by Etheract Software Labs * - * ***** END GPL LICENSE BLOCK ***** - * - * eigen videoscape formaat: + * - Blender Foundation * - * - * lamp: - * 3DG2 - aantal_lampen - - type - spsi spbl - r, g, b, energy - locx, locy, locz - vecx, vecy, vecz - - - curve / nurbs: - 3DG3 - 5 of 11 (curve of surf) - aantal_nurbs - extr1 extr2 - - mat[0][0] mat[0][1] mat[0][2] mat[0][3] - mat[1][0] mat[1][1] mat[1][2] mat[1][3] - ... - - type - pntsu, pntsv - resolu, resolv - orderu, orderv - flagu, flagv - - (als type==nurb) x y z w - x y z w - ... - (als type==bez) xyz xyz xyz h1 h2 h3 - xyz xyz xyz h1 h2 h3 - ... - * - * - */ + * ***** END GPL LICENSE BLOCK *****/ +#include "BLI_storage.h" #include <ctype.h> /* isdigit, isspace */ #include <math.h> @@ -100,12 +62,12 @@ #include "DNA_view3d_types.h" #include "DNA_userdef_types.h" -#include "BKE_bad_level_calls.h" #include "BKE_utildefines.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_editVert.h" +#include "BKE_blender.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_mesh.h" @@ -114,6 +76,7 @@ #include "BKE_object.h" #include "BKE_material.h" #include "BKE_exotic.h" + /* #include "BKE_error.h" */ #include "BKE_screen.h" #include "BKE_displist.h" @@ -125,12 +88,10 @@ #include "BPY_extern.h" #endif -#include "blendef.h" - #include "zlib.h" static int is_dxf(char *str); -static void dxf_read(char *filename); +static void dxf_read(Scene *scene, char *filename); static int is_stl(char *str); static int is_stl_ascii(char *str) @@ -181,11 +142,10 @@ static int is_stl(char *str) MEM_freeN(facedata); \ fclose(fpSTL); \ sprintf(error_msg, "Problems reading face %d!", i); \ - error(error_msg); \ return; \ } \ else { \ - if (G.order==B_ENDIAN) { \ + if (ENDIAN_ORDER==B_ENDIAN) { \ SWITCH_INT(mvert->co[0]); \ SWITCH_INT(mvert->co[1]); \ SWITCH_INT(mvert->co[2]); \ @@ -235,7 +195,7 @@ static void mesh_add_normals_flags(Mesh *me) } } -static void read_stl_mesh_binary(char *str) +static void read_stl_mesh_binary(Scene *scene, char *str) { FILE *fpSTL; Object *ob; @@ -248,13 +208,13 @@ static void read_stl_mesh_binary(char *str) fpSTL= fopen(str, "rb"); if(fpSTL==NULL) { - error("Can't read file"); + //XXX error("Can't read file"); return; } fseek(fpSTL, 80, SEEK_SET); fread(&numfacets, 4*sizeof(char), 1, fpSTL); - if (G.order==B_ENDIAN) { + if (ENDIAN_ORDER==B_ENDIAN) { SWITCH_INT(numfacets); } @@ -297,7 +257,7 @@ static void read_stl_mesh_binary(char *str) fseek(fpSTL, 2, SEEK_CUR); } - ob= add_object(OB_MESH); + ob= add_object(scene, OB_MESH); me= ob->data; me->totvert = totvert; me->totface = totface; @@ -309,7 +269,7 @@ static void read_stl_mesh_binary(char *str) mesh_add_normals_flags(me); make_edges(me, 0); } - waitcursor(1); + //XXX waitcursor(1); } fclose(fpSTL); @@ -321,7 +281,6 @@ static void read_stl_mesh_binary(char *str) fclose(fpSTL); \ sprintf(error_msg, "Can't allocate storage for %d faces!", \ numtenthousand * 10000); \ - error(error_msg); \ return; \ } @@ -330,7 +289,6 @@ static void read_stl_mesh_binary(char *str) fclose(fpSTL); \ free(vertdata); \ sprintf(error_msg, "Line %d: %s", linenum, message); \ - error(message); \ return; \ } @@ -348,7 +306,7 @@ static void read_stl_mesh_binary(char *str) STLBAILOUT("Bad vertex!"); \ ++totvert; \ } -static void read_stl_mesh_ascii(char *str) +static void read_stl_mesh_ascii(Scene *scene, char *str) { FILE *fpSTL; char buffer[2048], *cp; @@ -366,7 +324,7 @@ static void read_stl_mesh_ascii(char *str) fpSTL= fopen(str, "r"); if(fpSTL==NULL) { - error("Can't read file"); + //XXX error("Can't read file"); return; } @@ -376,7 +334,7 @@ static void read_stl_mesh_ascii(char *str) */ numtenthousand = 1; vertdata = malloc(numtenthousand*3*30000*sizeof(float)); // uses realloc! - if (!vertdata) STLALLOCERROR; + if (!vertdata) { STLALLOCERROR; } linenum = 1; /* Get rid of the first line */ @@ -399,7 +357,7 @@ static void read_stl_mesh_ascii(char *str) ++numtenthousand; vertdata = realloc(vertdata, numtenthousand*3*30000*sizeof(float)); - if (!vertdata) STLALLOCERROR; + if (!vertdata) { STLALLOCERROR; } } /* Don't read normal, but check line for proper syntax anyway @@ -440,7 +398,7 @@ static void read_stl_mesh_ascii(char *str) fclose(fpSTL); /* OK, lets create our mesh */ - ob = add_object(OB_MESH); + ob = add_object(scene, OB_MESH); me = ob->data; me->totface = totface; @@ -477,7 +435,7 @@ static void read_stl_mesh_ascii(char *str) mesh_add_normals_flags(me); make_edges(me, 0); - waitcursor(1); + //XXX waitcursor(1); } #undef STLALLOCERROR @@ -485,569 +443,6 @@ static void read_stl_mesh_ascii(char *str) #undef STLREADLINE #undef STLREADVERT -static void read_videoscape_mesh(char *str) -{ - Object *ob; - Mesh *me; - MVert *mvert; - MFace *mface; - Material *ma; - FILE *fp; - float *vertdata, *vd, min[3], max[3], cent[3], ftemp; - unsigned int color[32], col; - int totcol, a, b, verts, tottria=0, totquad=0, totedge=0, poly, nr0, nr, first; - int end; - char s[50]; - - fp= fopen(str, "rb"); - if(fp==NULL) { - error("Can't read file"); - return; - } - - fscanf(fp, "%40s", s); - - fscanf(fp, "%d\n", &verts); - if(verts<=0) { - fclose(fp); - error("Read error"); - return; - } - - if(verts>MESH_MAX_VERTS) { - error("too many vertices"); - fclose(fp); - return; - } - - INIT_MINMAX(min, max); - vd= vertdata= MEM_mallocN(sizeof(float)*3*verts, "videoscapelezer"); - - for(a=0; a<verts; a++) { - fscanf(fp, "%f %f %f", vd, vd+1, vd+2); - DO_MINMAX(vd, min, max); - vd+=3; - } - - /* count faces and colors */ - for(a=0; a<32; a++) color[a]= 0; - totcol= 0; - end= 1; - while(end>0) { - end= fscanf(fp,"%d", &poly); - if(end<=0) break; - - if(poly==3) tottria++; - else if(poly==4) totquad++; - else totedge+= poly; - - for(a=0;a<poly;a++) { - end= fscanf(fp,"%d", &nr); - if(end<=0) break; - } - if(end<=0) break; - - end= fscanf(fp,"%i\n", &col); - col &= 0xF0F0F0; - for(a=0; a<totcol; a++) { - if(color[a]==col) break; - } - if(a>=totcol && totcol<32) { - color[totcol]= col; - totcol++; - } - } - - /* new object */ - ob= add_object(OB_MESH); - me= ob->data; - me->totvert= verts; - me->totface= totedge+tottria+totquad; - - me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, - NULL, me->totvert); - me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, - NULL, me->totface); - - /* colors */ - if(totcol) { - ob->mat= MEM_callocN(sizeof(void *)*totcol, "ob->mat"); - me->mat= MEM_callocN(sizeof(void *)*totcol, "me->mat"); - me->totcol= totcol; - ob->totcol= (unsigned char) me->totcol; - ob->actcol= 1; - } - - /* materials */ - for(a=0; a<totcol; a++) { - ma= G.main->mat.first; - while(ma) { - if(ma->mtex[0]==0) { - col= rgb_to_cpack(ma->r, ma->g, ma->b); - if(color[a]==col) { - me->mat[a]= ma; - ma->id.us++; - break; - } - } - ma= ma->id.next; - } - if(ma==0) { - ma= add_material("ext"); - me->mat[a]= ma; - cpack_to_rgb(color[a], cent, cent+1, cent+2); - ma->r= cent[0]; - ma->g= cent[1]; - ma->b= cent[2]; - automatname(ma); - } - } - - /* verts */ - - cent[0]= (min[0]+max[0])/2.0f; - cent[1]= (min[1]+max[1])/2.0f; - cent[2]= (min[2]+max[2])/2.0f; - VECCOPY(ob->loc, cent); - - a= me->totvert; - vd= vertdata; - mvert= me->mvert; - while(a--) { - VecSubf(mvert->co, vd, cent); - mvert++; - vd+= 3; - } - - /* faces */ - if(me->totface) { - rewind(fp); - - fscanf(fp, "%40s", s); - fscanf(fp, "%d\n", &verts); - /* fake read */ - for(a=0;a<verts;a++) { - fscanf(fp, "%f %f %f", &ftemp, &ftemp, &ftemp); - } - - a= me->totface; - mface= me->mface; - while(a--) { - end= fscanf(fp,"%d", &poly); - if(end<=0) break; - - if(poly==3 || poly==4) { - fscanf(fp,"%d", &nr); - mface->v1= MIN2(nr, me->totvert-1); - fscanf(fp,"%d", &nr); - mface->v2= MIN2(nr, me->totvert-1); - fscanf(fp,"%d", &nr); - mface->v3= MIN2(nr, me->totvert-1); - if(poly==4) { - if( fscanf(fp,"%d", &nr) <=0 ) break; - mface->v4= MIN2(nr, me->totvert-1); - } - - test_index_face(mface, NULL, 0, poly); - - mface++; - } - else { - if( fscanf(fp,"%d", &nr0) <=0) break; - first= nr0; - for(b=1; b<poly; b++) { - end= fscanf(fp,"%d", &nr); - if(end<=0) break; - nr= MIN2(nr, me->totvert-1); - mface->v1= nr; - mface->v2= nr0; - nr0= nr; - mface++; - a--; - } - mface->v1= first; - mface->v2= nr; - mface++; - if(end<=0) break; - } - end= fscanf(fp,"%i", &col); - col &= 0xF0F0F0; - if(end<=0) break; - - for(b=0; b<totcol; b++) { - if(color[b]==col) { - (mface-1)->mat_nr= b; - break; - } - } - } - } - - fclose(fp); - MEM_freeN(vertdata); - - mesh_add_normals_flags(me); - make_edges(me, 0); - - waitcursor(1); -} - -static void read_radiogour(char *str) -{ - Object *ob; - Mesh *me; - MVert *mvert; - MFace *mface; - FILE *fp; - float *vertdata, *vd, min[3], max[3], cent[3], ftemp; - unsigned int *colv, *colf, *colvertdata; - int itemp, a, b, verts, tottria=0, totquad=0, totedge=0, poly, nr0, nr, first; - int end; - char s[50]; - - fp= fopen(str, "rb"); - if(fp==NULL) { - error("Can't read file"); - return; - } - - fscanf(fp, "%40s", s); - - fscanf(fp, "%d\n", &verts); - if(verts<=0) { - fclose(fp); - error("Read error"); - return; - } - - if(verts>MESH_MAX_VERTS) { - error("too many vertices"); - fclose(fp); - return; - } - - INIT_MINMAX(min, max); - vd= vertdata= MEM_mallocN(sizeof(float)*3*verts, "videoscapelezer"); - colv= colvertdata= MEM_mallocN(verts*sizeof(float), "coldata"); - - for(a=0; a<verts; a++) { - fscanf(fp, "%f %f %f %i", vd, vd+1, vd+2, colv); - DO_MINMAX(vd, min, max); - vd+=3; - colv++; - } - - /* count faces */ - end= 1; - while(end>0) { - end= fscanf(fp,"%d", &poly); - if(end<=0) break; - - if(poly==3) tottria++; - else if(poly==4) totquad++; - else totedge+= poly; - - for(a=0;a<poly;a++) { - end= fscanf(fp,"%d", &nr); - if(end<=0) break; - } - if(end<=0) break; - - } - - if(totedge+tottria+totquad>MESH_MAX_VERTS) { - printf(" var1: %d, var2: %d, var3: %d \n", totedge, tottria, totquad); - error("too many faces"); - MEM_freeN(vertdata); - MEM_freeN(colvertdata); - fclose(fp); - return; - } - - /* new object */ - ob= add_object(OB_MESH); - me= ob->data; - me->totvert= verts; - me->totface= totedge+tottria+totquad; - me->flag= 0; - - me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, - NULL, me->totvert); - me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, - NULL, me->totface); - - /* verts */ - - cent[0]= (min[0]+max[0])/2.0f; - cent[1]= (min[1]+max[1])/2.0f; - cent[2]= (min[2]+max[2])/2.0f; - VECCOPY(ob->loc, cent); - - a= me->totvert; - vd= vertdata; - mvert= me->mvert; - while(a--) { - VecSubf(mvert->co, vd, cent); - mvert++; - vd+= 3; - } - - /* faces */ - if(me->totface) { - rewind(fp); - - fscanf(fp, "%40s", s); - fscanf(fp, "%d\n", &verts); - for(a=0;a<verts;a++) { - fscanf(fp, "%f %f %f %i", &ftemp, &ftemp, &ftemp, &itemp); - } - - a= me->totface; - mface= me->mface; - while(a--) { - end= fscanf(fp,"%d", &poly); - if(end<=0) break; - - if(poly==3 || poly==4) { - fscanf(fp,"%d", &nr); - mface->v1= MIN2(nr, me->totvert-1); - fscanf(fp,"%d", &nr); - mface->v2= MIN2(nr, me->totvert-1); - fscanf(fp,"%d", &nr); - mface->v3= MIN2(nr, me->totvert-1); - if(poly==4) { - if( fscanf(fp,"%d", &nr) <=0 ) break; - mface->v4= MIN2(nr, me->totvert-1); - } - - test_index_face(mface, NULL, 0, poly); - - mface++; - } - else { - if( fscanf(fp,"%d", &nr0) <=0) break; - first= nr0; - for(b=1; b<poly; b++) { - end= fscanf(fp,"%d", &nr); - if(end<=0) break; - nr= MIN2(nr, me->totvert-1); - mface->v1= nr; - mface->v2= nr0; - nr0= nr; - mface++; - a--; - } - mface->v1= first; - mface->v2= nr; - mface->flag= ME_SMOOTH; - - mface++; - if(end<=0) break; - } - } - - /* mcol is 4 colors per face */ - me->mcol= MEM_mallocN(4*sizeof(int)*me->totface, "mcol"); - colf= (unsigned int *)me->mcol; - - a= me->totface; - mface= me->mface; - while(a--) { - - colf[0]= colvertdata[mface->v1]; - colf[1]= colvertdata[mface->v2]; - colf[2]= colvertdata[mface->v3]; - colf[3]= colvertdata[mface->v4]; - - colf+= 4; - mface++; - } - - MEM_freeN(colvertdata); - } - - fclose(fp); - MEM_freeN(vertdata); - - mesh_add_normals_flags(me); - make_edges(me, 0); - - waitcursor(1); -} - - -static void read_videoscape_lamp(char *str) -{ - Object *ob; - Lamp *la; - FILE *fp; - float vec[3], q1[4]; - int tot, val; - char s[50]; - - fp= fopen(str, "rb"); - if(fp==NULL) { - error("Can't read file"); - return; - } - - fscanf(fp, "%40s", s); - fscanf(fp, "%d\n", &tot); - - while(tot--) { - ob= add_object(OB_LAMP); - la= ob->data; - - fscanf(fp, "%d\n", &val); - la->type= val; - if(la->type==1) la->type= LA_SPOT; - else if(la->type==2) la->type= LA_SUN; - - fscanf(fp, "%f %f\n", &la->spotsize, &la->spotblend); - - fscanf(fp, "%f %f %f %f\n", &la->r, &la->g, &la->b, &la->energy); - - fscanf(fp, "%f %f %f\n", ob->loc, ob->loc+1, ob->loc+2); - val= fscanf(fp, "%f %f %f\n", vec, vec+1, vec+2); - vectoquat(vec, 5, 2, q1); - QuatToEul(q1, ob->rot); - - if(val<=0) break; - - } - fclose(fp); -} - -static void read_videoscape_nurbs(char *str) -{ - Object *ob; - Curve *cu; - Nurb *nu; - BezTriple *bezt; - BPoint *bp; - FILE *fp; - float tmat[4][4], omat[3][3], imat[3][3], mat[3][3]; - int a, tot, type, val; - char s[50]; - - fp= fopen(str, "rb"); - if(fp==NULL) { - error("Can't read file"); - return; - } - - fscanf(fp, "%40s", s); - fscanf(fp, "%d\n", &type); - - if(type==5) ob= add_object(OB_SURF); - else ob= add_object(OB_CURVE); - cu= ob->data; - - fscanf(fp, "%d\n", &tot); - fscanf(fp, "%d %d\n", &type, &val); - - cu->ext1= 0.002f*type; - cu->ext2= 0.002f*val; - - for(a=0; a<4; a++) fscanf(fp, "%e %e %e %e\n", tmat[a], tmat[a]+1, tmat[a]+2, tmat[a]+3); - - VECCOPY(ob->loc, tmat[3]); - - Mat3CpyMat4(omat, tmat); - Mat3ToEul(omat, ob->rot); - EulToMat3(ob->rot, mat); - Mat3Inv(imat, mat); - Mat3MulMat3((float ( * )[3])tmat, imat, omat); - - while(tot--) { - nu= (Nurb*)MEM_callocN(sizeof(Nurb),"nu from exotic"); - BLI_addtail(&cu->nurb, nu); - - fscanf(fp, "%d\n", &type); - nu->type= type; - - fscanf(fp, "%d %d\n", &type, &val); - nu->pntsu= type; nu->pntsv= val; - fscanf(fp, "%d %d\n", &type, &val); - nu->resolu= type; nu->resolv= val; - fscanf(fp, "%d %d\n", &type, &val); - nu->orderu= type; nu->orderv= val; - fscanf(fp, "%d %d\n", &type, &val); - nu->flagu= type; nu->flagv= val; - - if( (nu->type & 7)==CU_BEZIER) { - a= nu->pntsu; - nu->bezt= bezt= MEM_callocN(a*sizeof(BezTriple), "bezt from exotic"); - while(a--) { - fscanf(fp, "%f %f %f ", bezt->vec[0], bezt->vec[0]+1, bezt->vec[0]+2); - Mat4MulVecfl(tmat, bezt->vec[0]); - fscanf(fp, "%f %f %f ", bezt->vec[1], bezt->vec[1]+1, bezt->vec[1]+2); - Mat4MulVecfl(tmat, bezt->vec[1]); - fscanf(fp, "%f %f %f ", bezt->vec[2], bezt->vec[2]+1, bezt->vec[2]+2); - Mat4MulVecfl(tmat, bezt->vec[2]); - fscanf(fp, "%d %d\n", &type, &val); - bezt->h1= type; - bezt->h2= val; - bezt++; - } - } - else { - a= nu->pntsu*nu->pntsv; - if(a) { - nu->bp= bp= MEM_callocN(a*sizeof(BPoint), "bp from exotic"); - while(a--) { - fscanf(fp, "%f %f %f %f\n", bp->vec, bp->vec+1, bp->vec+2, bp->vec+3); - Mat4MulVecfl(tmat, bp->vec); - bp++; - } - - val= KNOTSU(nu); - nu->knotsu= MEM_mallocN(sizeof(float)*val, "knots"); - for(a=0; a<val; a++) fscanf(fp, "%f\n", nu->knotsu+a); - - if(nu->pntsv>1) { - val= KNOTSV(nu); - nu->knotsv= MEM_mallocN(sizeof(float)*val, "knots"); - for(a=0; a<val; a++) fscanf(fp, "%f\n", nu->knotsv+a); - } - } - else { - BLI_remlink(&cu->nurb, nu); - MEM_freeN(nu); - } - } - } - fclose(fp); -} - -static void read_videoscape(char *str) -{ - int file, type; - unsigned int val; - unsigned short numlen; - char name[FILE_MAXDIR+FILE_MAXFILE], head[FILE_MAXDIR+FILE_MAXFILE], tail[FILE_MAXFILE]; - - strcpy(name, str); - - while( TRUE ) { - file= open(name, O_BINARY|O_RDONLY); - if(file<=0) break; - else { - read(file, &type, 4); - close(file); - - if(type==DDG1) read_videoscape_mesh(name); - else if(type==DDG2) read_videoscape_lamp(name); - else if(type==DDG3) read_videoscape_nurbs(name); - } - - val = BLI_stringdec(name, head, tail, &numlen); - BLI_stringenc(name, head, tail, numlen, val + 1); - - } -} - - /* ***************** INVENTOR ******************* */ @@ -1231,7 +626,7 @@ static void read_iv_index(float *data, float *baseadr, float *index, int nr, int -static void read_inventor(char *str, struct ListBase *listb) +static void read_inventor(Scene *scene, char *str, struct ListBase *listb) { struct IvNode *iv, *ivp, *ivn; char *maindata, *md, *cpa; @@ -1246,7 +641,7 @@ static void read_inventor(char *str, struct ListBase *listb) file= open(str, O_BINARY|O_RDONLY); if(file== -1) { - error("Can't read file\n"); + //XXX error("Can't read file\n"); return; } @@ -1829,7 +1224,7 @@ static void read_inventor(char *str, struct ListBase *listb) BPoint *bp; if(ivsurf==0) { - ob= add_object(OB_SURF); + ob= add_object(scene, OB_SURF); ivsurf= ob; } else ob= ivsurf; @@ -1912,7 +1307,7 @@ static void read_inventor(char *str, struct ListBase *listb) /* ************************************************************ */ -static void displist_to_mesh(DispList *dlfirst) +static void displist_to_mesh(Scene *scene, DispList *dlfirst) { Object *ob; Mesh *me; @@ -2020,24 +1415,20 @@ static void displist_to_mesh(DispList *dlfirst) return; } - if(totcol>16) { - error("Found more than 16 different colors"); - totcol= 16; - } - vec[0]= (min[0]+max[0])/2; vec[1]= (min[1]+max[1])/2; vec[2]= (min[2]+max[2])/2; - ob= add_object(OB_MESH); + ob= add_object(scene, OB_MESH); VECCOPY(ob->loc, vec); - where_is_object(ob); + where_is_object(scene, ob); me= ob->data; /* colors */ if(totcol) { ob->mat= MEM_callocN(sizeof(void *)*totcol, "ob->mat"); + ob->matbits= MEM_callocN(sizeof(char)*totcol, "ob->matbits"); me->mat= MEM_callocN(sizeof(void *)*totcol, "me->mat"); me->totcol= totcol; ob->totcol= (unsigned char) me->totcol; @@ -2087,7 +1478,7 @@ static void displist_to_mesh(DispList *dlfirst) dl= dlfirst; while(dl) { - colnr= (dl->col>15 ? 15: dl->col); + colnr= dl->col; if(colnr) colnr--; if(dl->type==DL_SURF) { @@ -2251,7 +1642,7 @@ static void displist_to_mesh(DispList *dlfirst) make_edges(me, 0); } -static void displist_to_objects(ListBase *lbase) +static void displist_to_objects(Scene *scene, ListBase *lbase) { DispList *dl, *first, *prev, *next; ListBase tempbase; @@ -2259,8 +1650,8 @@ static void displist_to_objects(ListBase *lbase) /* irst this: is still active */ if(ivsurf) { - where_is_object(ivsurf); - docenter_new(); + where_is_object(scene, ivsurf); +// XXX docenter_new(); } dl= lbase->first; @@ -2296,7 +1687,7 @@ static void displist_to_objects(ListBase *lbase) if(totvert==0) { - if(ivsurf==0) error("Found no data"); + if(ivsurf==0) {}; //XXX error("Found no data"); if(lbase->first) BLI_freelistN(lbase); return; @@ -2340,12 +1731,12 @@ static void displist_to_objects(ListBase *lbase) totvert+= vert; if(totvert > maxaantal || dl->next==0) { if(dl->next==0) { - displist_to_mesh(first); + displist_to_mesh(scene, first); } else if(dl->prev) { prev= dl->prev; prev->next= 0; - displist_to_mesh(first); + displist_to_mesh(scene, first); prev->next= dl; first= dl; totvert= 0; @@ -2360,13 +1751,13 @@ static void displist_to_objects(ListBase *lbase) curcol++; } } - else displist_to_mesh(lbase->first); + else displist_to_mesh(scene, lbase->first); freedisplist(lbase); } -int BKE_read_exotic(char *name) +int BKE_read_exotic(Scene *scene, char *name) { ListBase lbase={0, 0}; int len; @@ -2382,7 +1773,7 @@ int BKE_read_exotic(char *name) gzfile = gzopen(name,"rb"); if (NULL == gzfile ) { - error("Can't open file: %s", name); + //XXX error("Can't open file: %s", name); retval= -1; } else { gzread(gzfile, str, 31); @@ -2390,47 +1781,30 @@ int BKE_read_exotic(char *name) if ((*s0 != FORM) && (strncmp(str, "BLEN", 4) != 0) && !BLI_testextensie(name,".blend.gz")) { - waitcursor(1); - - if(*s0==GOUR) { - if(G.obedit) { - error("Unable to perform function in EditMode"); - } else { - read_radiogour(name); - retval = 1; - } - } - else if ELEM4(*s0, DDG1, DDG2, DDG3, DDG4) { - if(G.obedit) { - error("Unable to perform function in EditMode"); - } else { - read_videoscape(name); - retval = 1; - } - } - else if(strncmp(str, "#Inventor V1.0", 14)==0) { + //XXX waitcursor(1); + if(strncmp(str, "#Inventor V1.0", 14)==0) { if( strncmp(str+15, "ascii", 5)==0) { - read_inventor(name, &lbase); - displist_to_objects(&lbase); + read_inventor(scene, name, &lbase); + displist_to_objects(scene, &lbase); retval = 1; } else { - error("Can only read Inventor 1.0 ascii"); + //XXX error("Can only read Inventor 1.0 ascii"); } } else if((strncmp(str, "#VRML V1.0 asc", 14)==0)) { - read_inventor(name, &lbase); - displist_to_objects(&lbase); + read_inventor(scene, name, &lbase); + displist_to_objects(scene, &lbase); retval = 1; } else if(is_dxf(name)) { - dxf_read(name); + dxf_read(scene, name); retval = 1; } else if(is_stl(name)) { if (is_stl_ascii(name)) - read_stl_mesh_ascii(name); + read_stl_mesh_ascii(scene, name); else - read_stl_mesh_binary(name); + read_stl_mesh_binary(scene, name); retval = 1; } #ifndef DISABLE_PYTHON @@ -2439,12 +1813,12 @@ int BKE_read_exotic(char *name) if (BPY_call_importloader(name)) { retval = 1; } else { - error("Unknown file type or error, check console"); + //XXX error("Unknown file type or error, check console"); } } #endif /* DISABLE_PYTHON */ - waitcursor(0); + //XXX waitcursor(0); } } } @@ -2465,7 +1839,7 @@ static void write_vert_stl(Object *ob, MVert *verts, int index, FILE *fpSTL) VECCOPY(vert, verts[(index)].co); Mat4MulVecfl(ob->obmat, vert); - if (G.order==B_ENDIAN) { + if (ENDIAN_ORDER==B_ENDIAN) { SWITCH_INT(vert[0]); SWITCH_INT(vert[1]); SWITCH_INT(vert[2]); @@ -2502,10 +1876,10 @@ static int write_derivedmesh_stl(FILE *fpSTL, Object *ob, DerivedMesh *dm) return numfacets; } -static int write_object_stl(FILE *fpSTL, Object *ob, Mesh *me) +static int write_object_stl(FILE *fpSTL, Scene *scene, Object *ob, Mesh *me) { int numfacets = 0; - DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); + DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); numfacets += write_derivedmesh_stl(fpSTL, ob, dm); @@ -2514,7 +1888,7 @@ static int write_object_stl(FILE *fpSTL, Object *ob, Mesh *me) return numfacets; } -void write_stl(char *str) +void write_stl(Scene *scene, char *str) { Object *ob; Mesh *me; @@ -2526,21 +1900,20 @@ void write_stl(char *str) if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0; if(BLI_testextensie(str,".stl")==0) strcat(str, ".stl"); - if (!during_script()) { - if (BLI_exists(str)) - if(saveover(str)==0) - return; + if (BLI_exists(str)) { + ; //XXX if(saveover(str)==0) + //XXX return; } fpSTL= fopen(str, "wb"); if(fpSTL==NULL) { - if (!during_script()) error("Can't write file"); + //XXX error("Can't write file"); return; } strcpy(temp_dir, str); - waitcursor(1); + //XXX waitcursor(1); /* The header part of the STL */ /* First 80 characters are a title or whatever you want. @@ -2552,14 +1925,14 @@ void write_stl(char *str) fprintf(fpSTL, "Binary STL output from Blender: %-48.48s ", str); /* Write all selected mesh objects */ - base= G.scene->base.first; + base= scene->base.first; while(base) { if (base->flag & SELECT) { ob = base->object; if (ob->type == OB_MESH) { me = ob->data; if (me) - numfacets += write_object_stl(fpSTL, ob, me); + numfacets += write_object_stl(fpSTL, scene, ob, me); } } base= base->next; @@ -2570,172 +1943,14 @@ void write_stl(char *str) */ fseek(fpSTL, 80, SEEK_SET); - if (G.order==B_ENDIAN) { + if (ENDIAN_ORDER==B_ENDIAN) { SWITCH_INT(numfacets); } fwrite(&numfacets, 4*sizeof(char), 1, fpSTL); fclose(fpSTL); - waitcursor(0); -} - -static void write_videoscape_mesh(Object *ob, char *str) -{ - EditMesh *em = G.editMesh; - Mesh *me; - Material *ma; - MFace *mface; - FILE *fp; - EditVert *eve; - EditFace *evl; - unsigned int kleur[32]; - float co[3]; - int a; - intptr_t tot; - char *cp; - - if(ob && ob->type==OB_MESH); - else { - return; - } - - kleur[0]= 0x00C0C0C0; - - cp= (char *)kleur; - for(a=0; a<ob->totcol; a++, cp+=4) { - - ma= give_current_material(ob, a+1); - if(ma) { - cp[0]= (unsigned char) (255.0*ma->emit); - cp[1]= (unsigned char) (255.0*ma->b); - cp[2]= (unsigned char) (255.0*ma->g); - cp[3]= (unsigned char) (255.0*ma->r); - if(G.order==L_ENDIAN) SWITCH_INT(kleur[a]); - } - else kleur[a]= 0x00C0C0C0; - - if(a>30) break; - } - - fp= fopen(str, "wb"); - if(fp==NULL) return; - - fprintf(fp,"3DG1\n"); - - if(G.obedit) { - - fprintf(fp, "%d\n", G.totvert); - - tot= 0; - eve= em->verts.first; - while(eve) { - VECCOPY(co, eve->co); - Mat4MulVecfl(ob->obmat, co); - fprintf(fp, "%f %f %f\n", co[0], co[1], co[2] ); - eve->tmp.l = tot; - tot++; - eve= eve->next; - } - evl= em->faces.first; - while(evl) { - - if(evl->v4==0) { - fprintf(fp, "3 %ld %ld %ld 0x%x\n", - (intptr_t) evl->v1->tmp.l, - (intptr_t) evl->v2->tmp.l, - (intptr_t) evl->v3->tmp.l, - kleur[evl->mat_nr]); - } - else { - fprintf(fp, "4 %ld %ld %ld %ld 0x%x\n", - (intptr_t) evl->v1->tmp.l, - (intptr_t) evl->v2->tmp.l, - (intptr_t) evl->v3->tmp.l, - (intptr_t) evl->v4->tmp.l, - kleur[evl->mat_nr]); - } - evl= evl->next; - } - } - else { - DerivedMesh *dm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH); - - me= ob->data; - - fprintf(fp, "%d\n", me->totvert); - - mface= me->mface; - for(a=0; a<me->totvert; a++) { - dm->getVertCo(dm, a, co); - Mat4MulVecfl(ob->obmat, co); - fprintf(fp, "%f %f %f\n", co[0], co[1], co[2] ); - } - for(a=0; a<me->totface; a++, mface++) { - if(mface->v4==0) { - fprintf(fp, "3 %d %d %d 0x%x\n", mface->v1, mface->v2, mface->v3, kleur[mface->mat_nr]); - } - else { - fprintf(fp, "4 %d %d %d %d 0x%x\n", mface->v1, mface->v2, mface->v3, mface->v4, kleur[mface->mat_nr]); - } - } - - dm->release(dm); - } - - fclose(fp); - -} - - -void write_videoscape(char *str) -{ - Base *base; - int file, val, lampdone=0; - unsigned short numlen; - char head[FILE_MAXFILE], tail[FILE_MAXFILE]; - - if(BLI_testextensie(str,".trace")) str[ strlen(str)-6]= 0; - if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0; - if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0; - if(BLI_testextensie(str,".obj")==0) strcat(str, ".obj"); - - file= open(str,O_BINARY|O_RDONLY); - close(file); - if(file>-1) if(!during_script() && saveover(str)==0) return; - - strcpy(temp_dir, str); - - base= G.scene->base.first; - while(base) { - if((base->flag & SELECT) && (base->lay & G.scene->lay)) { - if(base->object->type==OB_MESH) { - write_videoscape_mesh(base->object, str); - val = BLI_stringdec(str, head, tail, &numlen); - BLI_stringenc(str, head, tail, numlen, val + 1); - } - else if(base->object->type==OB_CURVE || base->object->type==OB_SURF) { - /* write_videoscape_nurbs(base->object, str); */ - /* val = stringdec(str, head, tail, &numlen); */ - /* stringenc(str, head, tail, numlen, val + 1); */ - } - else if(lampdone==0 && base->object->type==OB_LAMP) { - /* lampdone= 1; */ - /* write_videoscape_lamps(str); */ - /* val = stringdec(str, head, tail, &numlen); */ - /* stringenc(str, head, tail, numlen, val + 1); */ - } - } - base= base->next; - } - - - /* remove when higher numbers exist */ - while(remove(str)==0) { - - val = BLI_stringdec(str, head, tail, &numlen); - BLI_stringenc(str, head, tail, numlen, val + 1); - } + //XXX waitcursor(0); } /* ******************************* WRITE VRML ***************************** */ @@ -3007,7 +2222,7 @@ static void write_object_vrml(FILE *fp, Object *ob) } -void write_vrml(char *str) +void write_vrml(Scene *scene, char *str) { Mesh *me; Material *ma; @@ -3017,22 +2232,21 @@ void write_vrml(char *str) if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0; if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0; if(BLI_testextensie(str,".wrl")==0) strcat(str, ".wrl"); - - if(!during_script() && saveover(str)==0) return; + //XXX saveover() if(saveover(str)==0) return; fp= fopen(str, "w"); - if(fp==NULL && !during_script()) { - error("Can't write file"); + if(fp==NULL) { + //XXX error("Can't write file"); return; } strcpy(temp_dir, str); - waitcursor(1); + //XXX waitcursor(1); /* FIRST: write all the datablocks */ - fprintf(fp, "#VRML V1.0 ascii\n\n# Blender V%d\n\n# 'Switch' is used as a hack, to ensure it is not part of the drawing\n\n", G.version); + fprintf(fp, "#VRML V1.0 ascii\n\n# Blender V%d\n\n# 'Switch' is used as a hack, to ensure it is not part of the drawing\n\n", BLENDER_VERSION); fprintf(fp, "Separator {\n"); fprintf(fp, "Switch {\n"); @@ -3047,7 +2261,7 @@ void write_vrml(char *str) /* only write meshes we're using in this scene */ flag_listbase_ids(&G.main->mesh, LIB_DOIT, 0); - for(base= G.scene->base.first; base; base= base->next) + for(base= scene->base.first; base; base= base->next) if(base->object->type== OB_MESH) ((ID *)base->object->data)->flag |= LIB_DOIT; @@ -3061,10 +2275,10 @@ void write_vrml(char *str) /* THEN:Hidden Objects */ fprintf(fp, "\n\t# Hidden Objects, in invisible layers\n\n"); - base= G.scene->base.first; + base= scene->base.first; while(base) { if(base->object->type== OB_MESH) { - if( (base->lay & G.scene->lay)==0 ) { + if( (base->lay & scene->lay)==0 ) { write_object_vrml(fp, base->object); } } @@ -3077,14 +2291,14 @@ void write_vrml(char *str) /* The camera */ - write_camera_vrml(fp, G.scene->camera); + write_camera_vrml(fp, scene->camera); /* THEN:The Objects */ - base= G.scene->base.first; + base= scene->base.first; while(base) { if(base->object->type== OB_MESH) { - if(base->lay & G.scene->lay) { + if(base->lay & scene->lay) { write_object_vrml(fp, base->object); } } @@ -3096,7 +2310,7 @@ void write_vrml(char *str) fclose(fp); - waitcursor(0); + //XXX waitcursor(0); } @@ -3260,7 +2474,7 @@ static void write_mesh_dxf(FILE *fp, Mesh *me) /* Write a face color */ if (me->totcol) { - ma= me->mat[mface->mat_nr]; + ma= me->mat[(int)mface->mat_nr]; if(ma) { sprintf(str,"%d",rgb_to_dxf_col(ma->r,ma->g,ma->b)); write_group(62, str); /* Color index */ @@ -3319,7 +2533,7 @@ static void write_object_dxf(FILE *fp, Object *ob, int layer) fprintf (fp, "50\n%f\n", (float) ob->rot[2]*180/M_PI); /* Can only write the Z rot */ } -void write_dxf(char *str) +void write_dxf(struct Scene *scene, char *str) { Mesh *me; Base *base; @@ -3329,21 +2543,21 @@ void write_dxf(char *str) if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0; if(BLI_testextensie(str,".dxf")==0) strcat(str, ".dxf"); - if (!during_script()) { - if (BLI_exists(str)) - if(saveover(str)==0) - return; + + if (BLI_exists(str)) { + ; //XXX if(saveover(str)==0) + // return; } fp= fopen(str, "w"); - if(fp==NULL && !during_script()) { - error("Can't write file"); + if(fp==NULL) { + //XXX error("Can't write file"); return; } strcpy(temp_dir, str); - waitcursor(1); + //XXX waitcursor(1); /* The header part of the DXF */ @@ -3360,7 +2574,7 @@ void write_dxf(char *str) /* only write meshes we're using in this scene */ flag_listbase_ids(&G.main->mesh, LIB_DOIT, 0); - for(base= G.scene->base.first; base; base= base->next) + for(base= scene->base.first; base; base= base->next) if(base->object->type== OB_MESH) ((ID *)base->object->data)->flag |= LIB_DOIT; @@ -3381,7 +2595,7 @@ void write_dxf(char *str) write_group(2, "ENTITIES"); /* Write all the mesh objects */ - base= G.scene->base.first; + base= scene->base.first; while(base) { if(base->object->type== OB_MESH) { write_object_dxf(fp, base->object, base->lay); @@ -3396,7 +2610,7 @@ void write_dxf(char *str) write_group(0, "EOF"); fclose(fp); - waitcursor(0); + //XXX waitcursor(0); } @@ -3451,12 +2665,12 @@ static int dxf_get_layer_col(char *layer) return 1; } -static int dxf_get_layer_num(char *layer) +static int dxf_get_layer_num(Scene *scene, char *layer) { int ret = 0; if (all_digits(layer) && atoi(layer)<(1<<20)) ret= atoi(layer); - if (ret == 0) ret = G.scene->lay; + if (ret == 0) ret = scene->lay; return ret; } @@ -3523,13 +2737,14 @@ static int read_groupf(char *str) return ret; } -#define id_test(id) if(id<0) {char errmsg[128];fclose(dxf_fp); if(id==-1) sprintf(errmsg, "Error inputting dxf, near line %d", dxf_line); else if(id==-2) sprintf(errmsg, "Error reading dxf, near line %d", dxf_line);error(errmsg); return;} +//XXX error() is now printf until we have a callback error +#define id_test(id) if(id<0) {char errmsg[128];fclose(dxf_fp); if(id==-1) sprintf(errmsg, "Error inputting dxf, near line %d", dxf_line); else if(id==-2) sprintf(errmsg, "Error reading dxf, near line %d", dxf_line);printf("%s", errmsg); return;} #define read_group(id,str) {id= read_groupf(str); id_test(id);} #define group_is(idtst,str) (id==idtst&&strcmp(val,str)==0) #define group_isnt(idtst,str) (id!=idtst||strcmp(val,str)!=0) -#define id_check(idtst,str) if(group_isnt(idtst,str)) { fclose(dxf_fp); error("Error parsing dxf, near line %d", dxf_line); return;} +#define id_check(idtst,str) if(group_isnt(idtst,str)) { fclose(dxf_fp); printf("Error parsing dxf, near line %d", dxf_line); return;} static int id; static char val[256]; @@ -3584,8 +2799,11 @@ static void dxf_add_mat (Object *ob, Mesh *me, float color[3], char *layer) if (!me) return; - if(ob) ob->mat= MEM_callocN(sizeof(void *)*1, "ob->mat"); - if(ob) ob->actcol= 1; + if(ob) { + ob->mat= MEM_callocN(sizeof(void *)*1, "ob->mat"); + ob->matbits= MEM_callocN(sizeof(char)*1, "ob->matbits"); + ob->actcol= 1; + } me->totcol= 1; me->mat= MEM_callocN(sizeof(void *)*1, "me->mat"); @@ -3627,22 +2845,22 @@ static float zerovec[3]= {0.0, 0.0, 0.0}; #define reset_vars cent[0]= cent[1]= cent[2]=0.0; strcpy(layname, ""); color[0]= color[1]= color[2]= -1.0 -static void dxf_get_mesh(Mesh** m, Object** o, int noob) +static void dxf_get_mesh(Scene *scene, Mesh** m, Object** o, int noob) { Mesh *me = NULL; Object *ob; if (!noob) { - *o = add_object(OB_MESH); + *o = add_object(scene, OB_MESH); ob = *o; if (strlen(entname)) new_id(&G.main->object, (ID *)ob, entname); else if (strlen(layname)) new_id(&G.main->object, (ID *)ob, layname); - if (strlen(layname)) ob->lay= dxf_get_layer_num(layname); - else ob->lay= G.scene->lay; + if (strlen(layname)) ob->lay= dxf_get_layer_num(scene, layname); + else ob->lay= scene->lay; // not nice i know... but add_object() sets active base, which needs layer setting too (ton) - G.scene->basact->lay= ob->lay; + scene->basact->lay= ob->lay; *m = ob->data; me= *m; @@ -3651,7 +2869,7 @@ static void dxf_get_mesh(Mesh** m, Object** o, int noob) } else { *o = NULL; - *m = add_mesh("Mesh"); G.totmesh++; + *m = add_mesh("Mesh"); me = *m; ob = *o; @@ -3669,7 +2887,7 @@ static void dxf_get_mesh(Mesh** m, Object** o, int noob) me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, 0); } -static void dxf_read_point(int noob) { +static void dxf_read_point(Scene *scene, int noob) { /* Blender vars */ Object *ob; Mesh *me; @@ -3698,7 +2916,7 @@ static void dxf_read_point(int noob) { read_group(id, val); } - dxf_get_mesh(&me, &ob, noob); + dxf_get_mesh(scene, &me, &ob, noob); me->totvert= 1; me->mvert= MEM_callocN(me->totvert*sizeof(MVert), "mverts"); CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert); @@ -3728,7 +2946,7 @@ static void dxf_close_line(void) linehold=NULL; } -static void dxf_read_line(int noob) { +static void dxf_read_line(Scene *scene, int noob) { /* Entity specific vars */ float epoint[3]={0.0, 0.0, 0.0}; short vspace=0; /* Whether or not coords are relative */ @@ -3778,7 +2996,7 @@ static void dxf_read_line(int noob) { dxf_close_line(); if (linemhold==NULL) { - dxf_get_mesh(&me, &ob, noob); + dxf_get_mesh(scene, &me, &ob, noob); if(ob) VECCOPY(ob->loc, cent); @@ -3840,7 +3058,7 @@ static void dxf_close_2dpoly(void) p2dhold=NULL; } -static void dxf_read_ellipse(int noob) +static void dxf_read_ellipse(Scene *scene, int noob) { /* @@ -3986,7 +3204,7 @@ static void dxf_read_ellipse(int noob) cent[2]= center[2]; #endif - dxf_get_mesh(&me, &ob, noob); + dxf_get_mesh(scene, &me, &ob, noob); strcpy(oldllay, layname); if(ob) VECCOPY(ob->loc, cent); dxf_add_mat (ob, me, color, layname); @@ -4036,7 +3254,7 @@ static void dxf_read_ellipse(int noob) } } -static void dxf_read_arc(int noob) +static void dxf_read_arc(Scene *scene, int noob) { /* Entity specific vars */ float epoint[3]={0.0, 0.0, 0.0}; @@ -4114,7 +3332,7 @@ static void dxf_read_arc(int noob) cent[1]= center[1]+dia*cos(phi); cent[2]= center[2]; - dxf_get_mesh(&me, &ob, noob); + dxf_get_mesh(scene, &me, &ob, noob); strcpy(oldllay, layname); if(ob) VECCOPY(ob->loc, cent); dxf_add_mat (ob, me, color, layname); @@ -4159,7 +3377,7 @@ static void dxf_read_arc(int noob) } } -static void dxf_read_polyline(int noob) { +static void dxf_read_polyline(Scene *scene, int noob) { /* Entity specific vars */ short vspace=0; /* Whether or not coords are relative */ int flag=0; @@ -4208,7 +3426,7 @@ static void dxf_read_polyline(int noob) { dxf_close_2dpoly(); if (p2dmhold==NULL) { - dxf_get_mesh(&me, &ob, noob); + dxf_get_mesh(scene, &me, &ob, noob); strcpy(oldplay, layname); @@ -4284,7 +3502,7 @@ static void dxf_read_polyline(int noob) { lwasp2d=1; } else if (flag&64) { - dxf_get_mesh(&me, &ob, noob); + dxf_get_mesh(scene, &me, &ob, noob); if(ob) VECCOPY(ob->loc, cent); @@ -4342,7 +3560,7 @@ static void dxf_read_polyline(int noob) { } else if (vflags & 128) { if(vids[2]==0) { - error("(PL) Error parsing dxf, not enough vertices near line %d", dxf_line); + //XXX error("(PL) Error parsing dxf, not enough vertices near line %d", dxf_line); error_exit=1; fclose(dxf_fp); @@ -4374,7 +3592,7 @@ static void dxf_read_polyline(int noob) { mface->mat_nr= 0; } else { - error("Error parsing dxf, unknown polyline information near %d", dxf_line); + //XXX error("Error parsing dxf, unknown polyline information near %d", dxf_line); error_exit=1; fclose(dxf_fp); @@ -4385,7 +3603,7 @@ static void dxf_read_polyline(int noob) { } } -static void dxf_read_lwpolyline(int noob) { +static void dxf_read_lwpolyline(Scene *scene, int noob) { /* Entity specific vars */ short vspace=0; /* Whether or not coords are relative */ int flag=0; @@ -4435,7 +3653,7 @@ static void dxf_read_lwpolyline(int noob) { if (nverts == 0) return; - dxf_get_mesh(&me, &ob, noob); + dxf_get_mesh(scene, &me, &ob, noob); strcpy(oldllay, layname); if(ob) VECCOPY(ob->loc, cent); dxf_add_mat (ob, me, color, layname); @@ -4454,14 +3672,14 @@ static void dxf_read_lwpolyline(int noob) { if (id == 10) { vert[0]= (float) atof(val); } else { - error("Error parsing dxf, expected (10, <x>) at line %d", dxf_line); + //XXX error("Error parsing dxf, expected (10, <x>) at line %d", dxf_line); } read_group(id,val); if (id == 20) { vert[1]= (float) atof(val); } else { - error("Error parsing dxf, expected (20, <y>) at line %d", dxf_line); + //XXX error("Error parsing dxf, expected (20, <y>) at line %d", dxf_line); } mvert = &me->mvert[v]; @@ -4509,7 +3727,7 @@ static void dxf_close_3dface(void) f3dhold=NULL; } -static void dxf_read_3dface(int noob) +static void dxf_read_3dface(Scene *scene, int noob) { /* Entity specific vars */ float vert2[3]={0.0, 0.0, 0.0}; @@ -4597,7 +3815,7 @@ static void dxf_read_3dface(int noob) dxf_close_3dface(); if(nverts<3) { - error("(3DF) Error parsing dxf, not enough vertices near line %d", dxf_line); + //XXX error("(3DF) Error parsing dxf, not enough vertices near line %d", dxf_line); error_exit=1; fclose(dxf_fp); @@ -4605,7 +3823,7 @@ static void dxf_read_3dface(int noob) } if (f3dmhold==NULL) { - dxf_get_mesh(&me, &ob, noob); + dxf_get_mesh(scene, &me, &ob, noob); strcpy(oldflay, layname); @@ -4672,7 +3890,7 @@ static void dxf_read_3dface(int noob) hasbumped=1; } -static void dxf_read(char *filename) +static void dxf_read(Scene *scene, char *filename) { Mesh *lastMe = G.main->mesh.last; @@ -4710,7 +3928,7 @@ static void dxf_read(char *filename) } else if (id==3) { /* Now the object def should follow */ if(strlen(entname)==0) { - error("Error parsing dxf, no mesh name near %d", dxf_line); + //XXX error("Error parsing dxf, no mesh name near %d", dxf_line); fclose(dxf_fp); return; } @@ -4720,7 +3938,7 @@ static void dxf_read(char *filename) read_group(id, val); if(group_is(0, "POLYLINE")) { - dxf_read_polyline(1); + dxf_read_polyline(scene, 1); if(error_exit) return; lwasf3d=0; lwasline=0; @@ -4728,7 +3946,7 @@ static void dxf_read(char *filename) while(group_isnt(0, "SEQEND")) read_group(id, val); } else if(group_is(0, "LWPOLYLINE")) { - dxf_read_lwpolyline(1); + dxf_read_lwpolyline(scene, 1); if(error_exit) return; lwasf3d=0; lwasline=0; @@ -4740,27 +3958,27 @@ static void dxf_read(char *filename) lwasp2d=0; lwasline=0; } else if(group_is(0, "POINT")) { - dxf_read_point(1); + dxf_read_point(scene, 1); if(error_exit) return; lwasf3d=0; lwasp2d=0; lwasline=0; } else if(group_is(0, "LINE")) { - dxf_read_line(1); + dxf_read_line(scene, 1); if(error_exit) return; lwasline=1; lwasp2d=0; lwasf3d=0; } else if(group_is(0, "3DFACE")) { - dxf_read_3dface(1); + dxf_read_3dface(scene, 1); if(error_exit) return; lwasf3d=1; lwasp2d=0; lwasline=0; } else if (group_is(0, "CIRCLE")) { - dxf_read_arc(1); + dxf_read_arc(scene, 1); } else if (group_is(0, "ELLIPSE")) { - dxf_read_ellipse(1); + dxf_read_ellipse(scene, 1); } else if (group_is(0, "ENDBLK")) { break; } @@ -4820,7 +4038,7 @@ static void dxf_read(char *filename) } if(strlen(obname)==0) { - error("Error parsing dxf, no object name near %d", dxf_line); + //XXX error("Error parsing dxf, no object name near %d", dxf_line); fclose(dxf_fp); return; } @@ -4833,7 +4051,6 @@ static void dxf_read(char *filename) ob->type= OB_MESH; ob->dt= OB_SHADED; - if(U.flag & USER_MAT_ON_OB) ob->colbits= -1; ob->trackflag= OB_POSY; ob->upflag= OB_POSZ; @@ -4844,8 +4061,6 @@ static void dxf_read(char *filename) ob->dupsta= 1; ob->dupend= 100; ob->recalc= OB_RECALC; /* needed because of weird way of adding libdata directly */ - G.totobj++; - ob->data= obdata; ((ID*)ob->data)->us++; @@ -4854,20 +4069,21 @@ static void dxf_read(char *filename) VECCOPY(ob->rot, obrot); ob->mat= MEM_callocN(sizeof(void *)*1, "ob->mat"); + ob->matbits= MEM_callocN(sizeof(char)*1, "ob->matbits"); ob->totcol= (unsigned char) ((Mesh*)ob->data)->totcol; ob->actcol= 1; - + /* note: materials are either linked to mesh or object, if both then you have to increase user counts. below line is not needed. I leave it commented out here as warning (ton) */ //for (i=0; i<ob->totcol; i++) ob->mat[i]= ((Mesh*)ob->data)->mat[i]; - if (strlen(layname)) ob->lay= dxf_get_layer_num(layname); - else ob->lay= G.scene->lay; + if (strlen(layname)) ob->lay= dxf_get_layer_num(scene, layname); + else ob->lay= scene->lay; /* link to scene */ base= MEM_callocN( sizeof(Base), "add_base"); - BLI_addhead(&G.scene->base, base); + BLI_addhead(&scene->base, base); base->lay= ob->lay; @@ -4880,7 +4096,7 @@ static void dxf_read(char *filename) lwasp2d=0; lwasline=0; } else if(group_is(0, "POLYLINE")) { - dxf_read_polyline(0); + dxf_read_polyline(scene, 0); if(error_exit) return; lwasf3d=0; lwasline=0; @@ -4888,7 +4104,7 @@ static void dxf_read(char *filename) while(group_isnt(0, "SEQEND")) read_group(id, val); } else if(group_is(0, "LWPOLYLINE")) { - dxf_read_lwpolyline(0); + dxf_read_lwpolyline(scene, 0); if(error_exit) return; lwasf3d=0; lwasline=0; @@ -4900,27 +4116,27 @@ static void dxf_read(char *filename) lwasp2d=0; lwasline=0; } else if(group_is(0, "POINT")) { - dxf_read_point(0); + dxf_read_point(scene, 0); if(error_exit) return; lwasf3d=0; lwasp2d=0; lwasline=0; } else if(group_is(0, "LINE")) { - dxf_read_line(0); + dxf_read_line(scene, 0); if(error_exit) return; lwasline=1; lwasp2d=0; lwasf3d=0; } else if(group_is(0, "3DFACE")) { - dxf_read_3dface(0); + dxf_read_3dface(scene, 0); if(error_exit) return; lwasline=0; lwasp2d=0; lwasf3d=1; } else if (group_is(0, "CIRCLE") || group_is(0, "ARC")) { - dxf_read_arc(0); + dxf_read_arc(scene, 0); } else if (group_is(0, "ELLIPSE")) { - dxf_read_ellipse(0); + dxf_read_ellipse(scene, 0); } else if(group_is(0, "ENDSEC")) { break; } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c new file mode 100644 index 00000000000..90bf08059d7 --- /dev/null +++ b/source/blender/blenkernel/intern/fcurve.c @@ -0,0 +1,1318 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joshua Leung (full recode) + * + * ***** END GPL LICENSE BLOCK ***** + */ + + +#include <math.h> +#include <stdio.h> +#include <stddef.h> +#include <string.h> +#include <float.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_noise.h" + +#include "BKE_fcurve.h" +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_idprop.h" +#include "BKE_utildefines.h" + +#include "RNA_access.h" +#include "RNA_types.h" + +#ifndef DISABLE_PYTHON +#include "BPY_extern.h" +#endif + +#define SMALL -1.0e-10 +#define SELECT 1 + +/* ************************** Data-Level Functions ************************* */ + +/* ---------------------- Freeing --------------------------- */ + +/* Frees the F-Curve itself too, so make sure BLI_remlink is called before calling this... */ +void free_fcurve (FCurve *fcu) +{ + if (fcu == NULL) + return; + + /* free curve data */ + if (fcu) { + if (fcu->bezt) MEM_freeN(fcu->bezt); + if (fcu->fpt) MEM_freeN(fcu->fpt); + } + + /* free RNA-path, as this were allocated when getting the path string */ + if (fcu->rna_path) + MEM_freeN(fcu->rna_path); + + /* free extra data - i.e. modifiers, and driver */ + fcurve_free_driver(fcu); + free_fmodifiers(&fcu->modifiers); + + /* free f-curve itself */ + MEM_freeN(fcu); +} + +/* Frees a list of F-Curves */ +void free_fcurves (ListBase *list) +{ + FCurve *fcu, *fcn; + + /* sanity check */ + if (list == NULL) + return; + + /* free data - no need to call remlink before freeing each curve, + * as we store reference to next, and freeing only touches the curve + * it's given + */ + for (fcu= list->first; fcu; fcu= fcn) { + fcn= fcu->next; + free_fcurve(fcu); + } + + /* clear pointers just in case */ + list->first= list->last= NULL; +} + +/* ---------------------- Copy --------------------------- */ + +/* duplicate an F-Curve */ +FCurve *copy_fcurve (FCurve *fcu) +{ + FCurve *fcu_d; + + /* sanity check */ + if (fcu == NULL) + return NULL; + + /* make a copy */ + fcu_d= MEM_dupallocN(fcu); + + fcu_d->next= fcu_d->prev= NULL; + fcu_d->grp= NULL; + + /* copy curve data */ + fcu_d->bezt= MEM_dupallocN(fcu_d->bezt); + fcu_d->fpt= MEM_dupallocN(fcu_d->fpt); + + /* copy rna-path */ + fcu_d->rna_path= MEM_dupallocN(fcu_d->rna_path); + + /* copy driver */ + fcu_d->driver= fcurve_copy_driver(fcu_d->driver); + + /* copy modifiers */ + copy_fmodifiers(&fcu_d->modifiers, &fcu->modifiers); + + /* return new data */ + return fcu_d; +} + +/* duplicate a list of F-Curves */ +void copy_fcurves (ListBase *dst, ListBase *src) +{ + FCurve *dfcu, *sfcu; + + /* sanity checks */ + if ELEM(NULL, dst, src) + return; + + /* clear destination list first */ + dst->first= dst->last= NULL; + + /* copy one-by-one */ + for (sfcu= src->first; sfcu; sfcu= sfcu->next) { + dfcu= copy_fcurve(sfcu); + BLI_addtail(dst, dfcu); + } +} + +/* ---------------------- Relink --------------------------- */ + +#if 0 +/* uses id->newid to match pointers with other copied data + * - called after single-user or other such + */ + if (icu->driver) + ID_NEW(icu->driver->ob); +#endif + +/* --------------------- Finding -------------------------- */ + +/* Find the F-Curve affecting the given RNA-access path + index, in the list of F-Curves provided */ +FCurve *list_find_fcurve (ListBase *list, const char rna_path[], const int array_index) +{ + FCurve *fcu; + + /* sanity checks */ + if ( ELEM(NULL, list, rna_path) || (array_index < 0) ) + return NULL; + + /* check paths of curves, then array indices... */ + for (fcu= list->first; fcu; fcu= fcu->next) { + /* simple string-compare (this assumes that they have the same root...) */ + if (fcu->rna_path && !strcmp(fcu->rna_path, rna_path)) { + /* now check indicies */ + if (fcu->array_index == array_index) + return fcu; + } + } + + /* return */ + return NULL; +} + +/* Calculate the extents of F-Curve's data */ +void calc_fcurve_bounds (FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax) +{ + float xminv=999999999.0f, xmaxv=-999999999.0f; + float yminv=999999999.0f, ymaxv=-999999999.0f; + short foundvert=0; + unsigned int i; + + if (fcu->totvert) { + if (fcu->bezt) { + /* frame range can be directly calculated from end verts */ + if (xmin || xmax) { + xminv= MIN2(xminv, fcu->bezt[0].vec[1][0]); + xmaxv= MAX2(xmaxv, fcu->bezt[fcu->totvert-1].vec[1][0]); + } + + /* only loop over keyframes to find extents for values if needed */ + if (ymin || ymax) { + BezTriple *bezt; + + for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) { + if (bezt->vec[1][1] < yminv) + yminv= bezt->vec[1][1]; + if (bezt->vec[1][1] > ymaxv) + ymaxv= bezt->vec[1][1]; + } + } + } + else if (fcu->fpt) { + /* frame range can be directly calculated from end verts */ + if (xmin || xmax) { + xminv= MIN2(xminv, fcu->fpt[0].vec[0]); + xmaxv= MAX2(xmaxv, fcu->fpt[fcu->totvert-1].vec[0]); + } + + /* only loop over keyframes to find extents for values if needed */ + if (ymin || ymax) { + FPoint *fpt; + + for (fpt=fcu->fpt, i=0; i < fcu->totvert; fpt++, i++) { + if (fpt->vec[1] < yminv) + yminv= fpt->vec[1]; + if (fpt->vec[1] > ymaxv) + ymaxv= fpt->vec[1]; + } + } + } + + foundvert=1; + } + + /* minimum sizes are 1.0f */ + if (foundvert) { + if (xminv == xmaxv) xmaxv += 1.0f; + if (yminv == ymaxv) ymaxv += 1.0f; + + if (xmin) *xmin= xminv; + if (xmax) *xmax= xmaxv; + + if (ymin) *ymin= yminv; + if (ymax) *ymax= ymaxv; + } + else { + if (xmin) *xmin= 0.0f; + if (xmax) *xmax= 0.0f; + + if (ymin) *ymin= 1.0f; + if (ymax) *ymax= 1.0f; + } +} + +/* Calculate the extents of F-Curve's keyframes */ +void calc_fcurve_range (FCurve *fcu, float *start, float *end) +{ + float min=999999999.0f, max=-999999999.0f; + short foundvert=0; + + if (fcu->totvert) { + if (fcu->bezt) { + min= MIN2(min, fcu->bezt[0].vec[1][0]); + max= MAX2(max, fcu->bezt[fcu->totvert-1].vec[1][0]); + } + else if (fcu->fpt) { + min= MIN2(min, fcu->fpt[0].vec[0]); + max= MAX2(max, fcu->fpt[fcu->totvert-1].vec[0]); + } + + foundvert=1; + } + + /* minimum length is 1 frame */ + if (foundvert) { + if (min == max) max += 1.0f; + *start= min; + *end= max; + } + else { + *start= 0.0f; + *end= 1.0f; + } +} + +/* ***************************** Keyframe Column Tools ********************************* */ + +/* add a BezTriple to a column */ +void bezt_add_to_cfra_elem (ListBase *lb, BezTriple *bezt) +{ + CfraElem *ce, *cen; + + for (ce= lb->first; ce; ce= ce->next) { + /* double key? */ + if (ce->cfra == bezt->vec[1][0]) { + if (bezt->f2 & SELECT) ce->sel= bezt->f2; + return; + } + /* should key be inserted before this column? */ + else if (ce->cfra > bezt->vec[1][0]) break; + } + + /* create a new column */ + cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); + if (ce) BLI_insertlinkbefore(lb, ce, cen); + else BLI_addtail(lb, cen); + + cen->cfra= bezt->vec[1][0]; + cen->sel= bezt->f2; +} + +/* ***************************** Samples Utilities ******************************* */ +/* Some utilities for working with FPoints (i.e. 'sampled' animation curve data, such as + * data imported from BVH/Mocap files), which are specialised for use with high density datasets, + * which BezTriples/Keyframe data are ill equipped to do. + */ + + +/* Basic sampling callback which acts as a wrapper for evaluate_fcurve() + * 'data' arg here is unneeded here... + */ +float fcurve_samplingcb_evalcurve (FCurve *fcu, void *data, float evaltime) +{ + /* assume any interference from drivers on the curve is intended... */ + return evaluate_fcurve(fcu, evaltime); +} + + +/* Main API function for creating a set of sampled curve data, given some callback function + * used to retrieve the values to store. + */ +void fcurve_store_samples (FCurve *fcu, void *data, int start, int end, FcuSampleFunc sample_cb) +{ + FPoint *fpt, *new_fpt; + int cfra; + + /* sanity checks */ + // TODO: make these tests report errors using reports not printf's + if ELEM(NULL, fcu, sample_cb) { + printf("Error: No F-Curve with F-Curve Modifiers to Bake\n"); + return; + } + if (start >= end) { + printf("Error: Frame range for Sampled F-Curve creation is inappropriate \n"); + return; + } + + /* set up sample data */ + fpt= new_fpt= MEM_callocN(sizeof(FPoint)*(end-start+1), "FPoint Samples"); + + /* use the sampling callback at 1-frame intervals from start to end frames */ + for (cfra= start; cfra <= end; cfra++, fpt++) { + fpt->vec[0]= (float)cfra; + fpt->vec[1]= sample_cb(fcu, data, (float)cfra); + } + + /* free any existing sample/keyframe data on curve */ + if (fcu->bezt) MEM_freeN(fcu->bezt); + if (fcu->fpt) MEM_freeN(fcu->fpt); + + /* store the samples */ + fcu->bezt= NULL; + fcu->fpt= new_fpt; + fcu->totvert= end - start + 1; +} + +/* ***************************** F-Curve Sanity ********************************* */ +/* The functions here are used in various parts of Blender, usually after some editing + * of keyframe data has occurred. They ensure that keyframe data is properly ordered and + * that the handles are correctly + */ + +/* This function recalculates the handles of an F-Curve + * If the BezTriples have been rearranged, sort them first before using this. + */ +void calchandles_fcurve (FCurve *fcu) +{ + BezTriple *bezt, *prev, *next; + int a= fcu->totvert; + + /* Error checking: + * - need at least two points + * - need bezier keys + * - only bezier-interpolation has handles (for now) + */ + if (ELEM(NULL, fcu, fcu->bezt) || (a < 2) /*|| ELEM(fcu->ipo, BEZT_IPO_CONST, BEZT_IPO_LIN)*/) + return; + + /* get initial pointers */ + bezt= fcu->bezt; + prev= NULL; + next= (bezt + 1); + + /* loop over all beztriples, adjusting handles */ + while (a--) { + /* clamp timing of handles to be on either side of beztriple */ + if (bezt->vec[0][0] > bezt->vec[1][0]) bezt->vec[0][0]= bezt->vec[1][0]; + if (bezt->vec[2][0] < bezt->vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0]; + + /* calculate auto-handles */ + if (fcu->flag & FCURVE_AUTO_HANDLES) + calchandleNurb(bezt, prev, next, 2); /* 2==special autohandle && keep extrema horizontal */ + else + calchandleNurb(bezt, prev, next, 1); /* 1==special autohandle */ + + /* for automatic ease in and out */ + if ((bezt->h1==HD_AUTO) && (bezt->h2==HD_AUTO)) { + /* only do this on first or last beztriple */ + if ((a == 0) || (a == fcu->totvert-1)) { + /* set both handles to have same horizontal value as keyframe */ + if (fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) { + bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1]; + } + } + } + + /* advance pointers for next iteration */ + prev= bezt; + if (a == 1) next= NULL; + else next++; + bezt++; + } +} + +/* Use when F-Curve with handles has changed + * It treats all BezTriples with the following rules: + * - PHASE 1: do types have to be altered? + * -> Auto handles: become aligned when selection status is NOT(000 || 111) + * -> Vector handles: become 'nothing' when (one half selected AND other not) + * - PHASE 2: recalculate handles +*/ +void testhandles_fcurve (FCurve *fcu) +{ + BezTriple *bezt; + unsigned int a; + + /* only beztriples have handles (bpoints don't though) */ + if ELEM(NULL, fcu, fcu->bezt) + return; + + /* loop over beztriples */ + for (a=0, bezt=fcu->bezt; a < fcu->totvert; a++, bezt++) { + short flag= 0; + + /* flag is initialised as selection status + * of beztriple control-points (labelled 0,1,2) + */ + if (bezt->f1 & SELECT) flag |= (1<<0); // == 1 + if (bezt->f2 & SELECT) flag |= (1<<1); // == 2 + if (bezt->f3 & SELECT) flag |= (1<<2); // == 4 + + /* one or two handles selected only */ + if (ELEM(flag, 0, 7)==0) { + /* auto handles become aligned */ + if (bezt->h1==HD_AUTO) + bezt->h1= HD_ALIGN; + if (bezt->h2==HD_AUTO) + bezt->h2= HD_ALIGN; + + /* vector handles become 'free' when only one half selected */ + if (bezt->h1==HD_VECT) { + /* only left half (1 or 2 or 1+2) */ + if (flag < 4) + bezt->h1= 0; + } + if (bezt->h2==HD_VECT) { + /* only right half (4 or 2+4) */ + if (flag > 3) + bezt->h2= 0; + } + } + } + + /* recalculate handles */ + calchandles_fcurve(fcu); +} + +/* This function sorts BezTriples so that they are arranged in chronological order, + * as tools working on F-Curves expect that the BezTriples are in order. + */ +void sort_time_fcurve (FCurve *fcu) +{ + short ok= 1; + + /* keep adjusting order of beztriples until nothing moves (bubble-sort) */ + while (ok) { + ok= 0; + + /* currently, will only be needed when there are beztriples */ + if (fcu->bezt) { + BezTriple *bezt; + unsigned int a; + + /* loop over ALL points to adjust position in array and recalculate handles */ + for (a=0, bezt=fcu->bezt; a < fcu->totvert; a++, bezt++) { + /* check if thee's a next beztriple which we could try to swap with current */ + if (a < (fcu->totvert-1)) { + /* swap if one is after the other (and indicate that order has changed) */ + if (bezt->vec[1][0] > (bezt+1)->vec[1][0]) { + SWAP(BezTriple, *bezt, *(bezt+1)); + ok= 1; + } + + /* if either one of both of the points exceeds crosses over the keyframe time... */ + if ( (bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0]) ) { + /* swap handles if they have switched sides for some reason */ + SWAP(float, bezt->vec[0][0], bezt->vec[2][0]); + SWAP(float, bezt->vec[0][1], bezt->vec[2][1]); + } + else { + /* clamp handles */ + if (bezt->vec[0][0] > bezt->vec[1][0]) + bezt->vec[0][0]= bezt->vec[1][0]; + if (bezt->vec[2][0] < bezt->vec[1][0]) + bezt->vec[2][0]= bezt->vec[1][0]; + } + } + } + } + } +} + +/* This function tests if any BezTriples are out of order, thus requiring a sort */ +short test_time_fcurve (FCurve *fcu) +{ + unsigned int a; + + /* sanity checks */ + if (fcu == NULL) + return 0; + + /* currently, only need to test beztriples */ + if (fcu->bezt) { + BezTriple *bezt; + + /* loop through all BezTriples, stopping when one exceeds the one after it */ + for (a=0, bezt= fcu->bezt; a < (fcu->totvert - 1); a++, bezt++) { + if (bezt->vec[1][0] > (bezt+1)->vec[1][0]) + return 1; + } + } + else if (fcu->fpt) { + FPoint *fpt; + + /* loop through all FPoints, stopping when one exceeds the one after it */ + for (a=0, fpt= fcu->fpt; a < (fcu->totvert - 1); a++, fpt++) { + if (fpt->vec[0] > (fpt+1)->vec[0]) + return 1; + } + } + + /* none need any swapping */ + return 0; +} + +/* ***************************** Drivers ********************************* */ + +/* Driver API --------------------------------- */ + +/* This frees the driver target itself */ +void driver_free_target (ChannelDriver *driver, DriverTarget *dtar) +{ + /* sanity checks */ + if (dtar == NULL) + return; + + /* free target vars */ + if (dtar->rna_path) + MEM_freeN(dtar->rna_path); + + /* remove the target from the driver */ + if (driver) + BLI_freelinkN(&driver->targets, dtar); + else + MEM_freeN(dtar); +} + +/* Add a new driver target variable */ +DriverTarget *driver_add_new_target (ChannelDriver *driver) +{ + DriverTarget *dtar; + + /* sanity checks */ + if (driver == NULL) + return NULL; + + /* make a new target */ + dtar= MEM_callocN(sizeof(DriverTarget), "DriverTarget"); + BLI_addtail(&driver->targets, dtar); + + /* give the target a 'unique' name */ + strcpy(dtar->name, "var"); + BLI_uniquename(&driver->targets, dtar, "var", '_', offsetof(DriverTarget, name), 64); + + /* return the target */ + return dtar; +} + +/* This frees the driver itself */ +void fcurve_free_driver(FCurve *fcu) +{ + ChannelDriver *driver; + DriverTarget *dtar, *dtarn; + + /* sanity checks */ + if ELEM(NULL, fcu, fcu->driver) + return; + driver= fcu->driver; + + /* free driver targets */ + for (dtar= driver->targets.first; dtar; dtar= dtarn) { + dtarn= dtar->next; + driver_free_target(driver, dtar); + } + + /* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */ + MEM_freeN(driver); + fcu->driver= NULL; +} + +/* This makes a copy of the given driver */ +ChannelDriver *fcurve_copy_driver (ChannelDriver *driver) +{ + ChannelDriver *ndriver; + DriverTarget *dtar; + + /* sanity checks */ + if (driver == NULL) + return NULL; + + /* copy all data */ + ndriver= MEM_dupallocN(driver); + + /* copy targets */ + ndriver->targets.first= ndriver->targets.last= NULL; + BLI_duplicatelist(&ndriver->targets, &driver->targets); + + for (dtar= ndriver->targets.first; dtar; dtar= dtar->next) { + /* make a copy of target's rna path if available */ + if (dtar->rna_path) + dtar->rna_path = MEM_dupallocN(dtar->rna_path); + } + + /* return the new driver */ + return ndriver; +} + +/* Driver Evaluation -------------------------- */ + +/* Helper function to obtain a value using RNA from the specified source (for evaluating drivers) */ +float driver_get_target_value (ChannelDriver *driver, DriverTarget *dtar) +{ + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + ID *id; + char *path; + int index; + float value= 0.0f; + + /* sanity check */ + if ELEM(NULL, driver, dtar) + return 0.0f; + + /* get RNA-pointer for the ID-block given in target */ + RNA_id_pointer_create(dtar->id, &id_ptr); + id= dtar->id; + path= dtar->rna_path; + index= dtar->array_index; + + /* error check for missing pointer... */ + if (id == NULL) { + printf("Error: driver doesn't have any valid target to use \n"); + if (G.f & G_DEBUG) printf("\tpath = %s [%d] \n", path, index); + driver->flag |= DRIVER_FLAG_INVALID; + return 0.0f; + } + + /* get property to read from, and get value as appropriate */ + if (RNA_path_resolve(&id_ptr, path, &ptr, &prop)) { + switch (RNA_property_type(prop)) { + case PROP_BOOLEAN: + if (RNA_property_array_length(prop)) + value= (float)RNA_property_boolean_get_index(&ptr, prop, index); + else + value= (float)RNA_property_boolean_get(&ptr, prop); + break; + case PROP_INT: + if (RNA_property_array_length(prop)) + value= (float)RNA_property_int_get_index(&ptr, prop, index); + else + value= (float)RNA_property_int_get(&ptr, prop); + break; + case PROP_FLOAT: + if (RNA_property_array_length(prop)) + value= RNA_property_float_get_index(&ptr, prop, index); + else + value= RNA_property_float_get(&ptr, prop); + break; + case PROP_ENUM: + value= (float)RNA_property_enum_get(&ptr, prop); + break; + default: + break; + } + } + else if (G.f & G_DEBUG) + printf("Driver Evaluation Error: cannot resolve target for %s -> %s \n", id->name, path); + + return value; +} + +/* Get two PoseChannels from the targets of the given Driver */ +static void driver_get_target_pchans2 (ChannelDriver *driver, bPoseChannel **pchan1, bPoseChannel **pchan2) +{ + DriverTarget *dtar; + short i = 0; + + /* before doing anything */ + *pchan1= NULL; + *pchan2= NULL; + + /* only take the first two targets */ + for (dtar= driver->targets.first; (dtar) && (i < 2); dtar=dtar->next, i++) { + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + + /* get RNA-pointer for the ID-block given in target */ + if (dtar->id) + RNA_id_pointer_create(dtar->id, &id_ptr); + else + continue; + + /* resolve path so that we have pointer to the right posechannel */ + if (RNA_path_resolve(&id_ptr, dtar->rna_path, &ptr, &prop)) { + /* is pointer valid (i.e. pointing to an actual posechannel */ + if ((ptr.type == &RNA_PoseChannel) && (ptr.data)) { + /* first or second target? */ + if (i) + *pchan1= ptr.data; + else + *pchan2= ptr.data; + } + } + } +} + +/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime" + * - "evaltime" is the frame at which F-Curve is being evaluated + * - has to return a float value + */ +static float evaluate_driver (ChannelDriver *driver, float evaltime) +{ + DriverTarget *dtar; + + /* check if driver can be evaluated */ + if (driver->flag & DRIVER_FLAG_INVALID) + return 0.0f; + + // TODO: the flags for individual targets need to be used too for more fine-grained support... + switch (driver->type) { + case DRIVER_TYPE_AVERAGE: /* average values of driver targets */ + { + /* check how many targets there are first (i.e. just one?) */ + if (driver->targets.first == driver->targets.last) { + /* just one target, so just use that */ + dtar= driver->targets.first; + return driver_get_target_value(driver, dtar); + } + else { + /* more than one target, so average the values of the targets */ + int tot = 0; + float value = 0.0f; + + /* loop through targets, adding (hopefully we don't get any overflow!) */ + for (dtar= driver->targets.first; dtar; dtar=dtar->next) { + value += driver_get_target_value(driver, dtar); + tot++; + } + + /* return the average of these */ + return (value / (float)tot); + } + } + break; + + case DRIVER_TYPE_PYTHON: /* expression */ + { +#ifndef DISABLE_PYTHON + /* check for empty or invalid expression */ + if ( (driver->expression[0] == '\0') || + (driver->flag & DRIVER_FLAG_INVALID) ) + { + return 0.0f; + } + + /* this evaluates the expression using Python,and returns its result: + * - on errors it reports, then returns 0.0f + */ + return BPY_pydriver_eval(driver); +#endif /* DISABLE_PYTHON*/ + } + break; + + + case DRIVER_TYPE_ROTDIFF: /* difference of rotations of 2 bones (should ideally be in same armature) */ + { + bPoseChannel *pchan, *pchan2; + float q1[4], q2[4], quat[4], angle; + + /* get pose channels, and check if we've got two */ + driver_get_target_pchans2(driver, &pchan, &pchan2); + if (ELEM(NULL, pchan, pchan2)) { + /* disable this driver, since it doesn't work correctly... */ + driver->flag |= DRIVER_FLAG_INVALID; + + /* check what the error was */ + if ((pchan == NULL) && (pchan2 == NULL)) + printf("Driver Evaluation Error: Rotational difference failed - first 2 targets invalid \n"); + else if (pchan == NULL) + printf("Driver Evaluation Error: Rotational difference failed - first target not valid PoseChannel \n"); + else if (pchan2 == NULL) + printf("Driver Evaluation Error: Rotational difference failed - second target not valid PoseChannel \n"); + + /* stop here... */ + return 0.0f; + } + + /* use the final posed locations */ + Mat4ToQuat(pchan->pose_mat, q1); + Mat4ToQuat(pchan2->pose_mat, q2); + + QuatInv(q1); + QuatMul(quat, q1, q2); + angle = 2.0f * (saacos(quat[0])); + angle= ABS(angle); + + return (angle > M_PI) ? (float)((2.0f * M_PI) - angle) : (float)(angle); + } + break; + + default: + { + /* special 'hack' - just use stored value + * This is currently used as the mechanism which allows animated settings to be able + * to be changed via the UI. + */ + return driver->curval; + } + } + + /* return 0.0f, as couldn't find relevant data to use */ + return 0.0f; +} + +/* ***************************** Curve Calculations ********************************* */ + +/* The total length of the handles is not allowed to be more + * than the horizontal distance between (v1-v4). + * This is to prevent curve loops. +*/ +void correct_bezpart (float *v1, float *v2, float *v3, float *v4) +{ + float h1[2], h2[2], len1, len2, len, fac; + + /* calculate handle deltas */ + h1[0]= v1[0] - v2[0]; + h1[1]= v1[1] - v2[1]; + + h2[0]= v4[0] - v3[0]; + h2[1]= v4[1] - v3[1]; + + /* calculate distances: + * - len = span of time between keyframes + * - len1 = length of handle of start key + * - len2 = length of handle of end key + */ + len= v4[0]- v1[0]; + len1= (float)fabs(h1[0]); + len2= (float)fabs(h2[0]); + + /* if the handles have no length, no need to do any corrections */ + if ((len1+len2) == 0.0f) + return; + + /* the two handles cross over each other, so force them + * apart using the proportion they overlap + */ + if ((len1+len2) > len) { + fac= len / (len1+len2); + + v2[0]= (v1[0] - fac*h1[0]); + v2[1]= (v1[1] - fac*h1[1]); + + v3[0]= (v4[0] - fac*h2[0]); + v3[1]= (v4[1] - fac*h2[1]); + } +} + +/* find root ('zero') */ +int findzero (float x, float q0, float q1, float q2, float q3, float *o) +{ + double c0, c1, c2, c3, a, b, c, p, q, d, t, phi; + int nr= 0; + + c0= q0 - x; + c1= 3.0 * (q1 - q0); + c2= 3.0 * (q0 - 2.0*q1 + q2); + c3= q3 - q0 + 3.0 * (q1 - q2); + + if (c3 != 0.0) { + a= c2/c3; + b= c1/c3; + c= c0/c3; + a= a/3; + + p= b/3 - a*a; + q= (2*a*a*a - a*b + c) / 2; + d= q*q + p*p*p; + + if (d > 0.0) { + t= sqrt(d); + o[0]= (float)(Sqrt3d(-q+t) + Sqrt3d(-q-t) - a); + + if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1; + else return 0; + } + else if (d == 0.0) { + t= Sqrt3d(-q); + o[0]= (float)(2*t - a); + + if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++; + o[nr]= (float)(-t-a); + + if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1; + else return nr; + } + else { + phi= acos(-q / sqrt(-(p*p*p))); + t= sqrt(-p); + p= cos(phi/3); + q= sqrt(3 - 3*p*p); + o[0]= (float)(2*t*p - a); + + if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++; + o[nr]= (float)(-t * (p + q) - a); + + if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) nr++; + o[nr]= (float)(-t * (p - q) - a); + + if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1; + else return nr; + } + } + else { + a=c2; + b=c1; + c=c0; + + if (a != 0.0) { + // discriminant + p= b*b - 4*a*c; + + if (p > 0) { + p= sqrt(p); + o[0]= (float)((-b-p) / (2 * a)); + + if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++; + o[nr]= (float)((-b+p)/(2*a)); + + if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1; + else return nr; + } + else if (p == 0) { + o[0]= (float)(-b / (2 * a)); + if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1; + else return 0; + } + } + else if (b != 0.0) { + o[0]= (float)(-c/b); + + if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1; + else return 0; + } + else if (c == 0.0) { + o[0]= 0.0; + return 1; + } + + return 0; + } +} + +void berekeny (float f1, float f2, float f3, float f4, float *o, int b) +{ + float t, c0, c1, c2, c3; + int a; + + c0= f1; + c1= 3.0f * (f2 - f1); + c2= 3.0f * (f1 - 2.0f*f2 + f3); + c3= f4 - f1 + 3.0f * (f2 - f3); + + for (a=0; a < b; a++) { + t= o[a]; + o[a]= c0 + t*c1 + t*t*c2 + t*t*t*c3; + } +} + +void berekenx (float *f, float *o, int b) +{ + float t, c0, c1, c2, c3; + int a; + + c0= f[0]; + c1= 3.0f * (f[3] - f[0]); + c2= 3.0f * (f[0] - 2.0f*f[3] + f[6]); + c3= f[9] - f[0] + 3.0f * (f[3] - f[6]); + + for (a=0; a < b; a++) { + t= o[a]; + o[a]= c0 + t*c1 + t*t*c2 + t*t*t*c3; + } +} + + +/* -------------------------- */ + +/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */ +static float fcurve_eval_keyframes (FCurve *fcu, BezTriple *bezts, float evaltime) +{ + BezTriple *bezt, *prevbezt, *lastbezt; + float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac; + unsigned int a; + int b; + float cvalue = 0.0f; + + /* get pointers */ + a= fcu->totvert-1; + prevbezt= bezts; + bezt= prevbezt+1; + lastbezt= prevbezt + a; + + /* evaluation time at or past endpoints? */ + if (prevbezt->vec[1][0] >= evaltime) + { + /* before or on first keyframe */ + if ( (fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (prevbezt->ipo != BEZT_IPO_CONST) && + !(fcu->flag & FCURVE_DISCRETE_VALUES) ) + { + /* linear or bezier interpolation */ + if (prevbezt->ipo==BEZT_IPO_LIN) + { + /* Use the next center point instead of our own handle for + * linear interpolated extrapolate + */ + if (fcu->totvert == 1) + cvalue= prevbezt->vec[1][1]; + else + { + bezt = prevbezt+1; + dx= prevbezt->vec[1][0] - evaltime; + fac= bezt->vec[1][0] - prevbezt->vec[1][0]; + + /* prevent division by zero */ + if (fac) { + fac= (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac; + cvalue= prevbezt->vec[1][1] - (fac * dx); + } + else + cvalue= prevbezt->vec[1][1]; + } + } + else + { + /* Use the first handle (earlier) of first BezTriple to calculate the + * gradient and thus the value of the curve at evaltime + */ + dx= prevbezt->vec[1][0] - evaltime; + fac= prevbezt->vec[1][0] - prevbezt->vec[0][0]; + + /* prevent division by zero */ + if (fac) { + fac= (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac; + cvalue= prevbezt->vec[1][1] - (fac * dx); + } + else + cvalue= prevbezt->vec[1][1]; + } + } + else + { + /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, + * so just extend first keyframe's value + */ + cvalue= prevbezt->vec[1][1]; + } + } + else if (lastbezt->vec[1][0] <= evaltime) + { + /* after or on last keyframe */ + if ( (fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (lastbezt->ipo != BEZT_IPO_CONST) && + !(fcu->flag & FCURVE_DISCRETE_VALUES) ) + { + /* linear or bezier interpolation */ + if (lastbezt->ipo==BEZT_IPO_LIN) + { + /* Use the next center point instead of our own handle for + * linear interpolated extrapolate + */ + if (fcu->totvert == 1) + cvalue= lastbezt->vec[1][1]; + else + { + prevbezt = lastbezt - 1; + dx= evaltime - lastbezt->vec[1][0]; + fac= lastbezt->vec[1][0] - prevbezt->vec[1][0]; + + /* prevent division by zero */ + if (fac) { + fac= (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac; + cvalue= lastbezt->vec[1][1] + (fac * dx); + } + else + cvalue= lastbezt->vec[1][1]; + } + } + else + { + /* Use the gradient of the second handle (later) of last BezTriple to calculate the + * gradient and thus the value of the curve at evaltime + */ + dx= evaltime - lastbezt->vec[1][0]; + fac= lastbezt->vec[2][0] - lastbezt->vec[1][0]; + + /* prevent division by zero */ + if (fac) { + fac= (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac; + cvalue= lastbezt->vec[1][1] + (fac * dx); + } + else + cvalue= lastbezt->vec[1][1]; + } + } + else + { + /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, + * so just extend last keyframe's value + */ + cvalue= lastbezt->vec[1][1]; + } + } + else + { + /* evaltime occurs somewhere in the middle of the curve */ + for (a=0; prevbezt && bezt && (a < fcu->totvert-1); a++, prevbezt=bezt, bezt++) + { + /* evaltime occurs within the interval defined by these two keyframes */ + if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) + { + /* value depends on interpolation mode */ + if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES)) + { + /* constant (evaltime not relevant, so no interpolation needed) */ + cvalue= prevbezt->vec[1][1]; + } + else if (prevbezt->ipo == BEZT_IPO_LIN) + { + /* linear - interpolate between values of the two keyframes */ + fac= bezt->vec[1][0] - prevbezt->vec[1][0]; + + /* prevent division by zero */ + if (fac) { + fac= (evaltime - prevbezt->vec[1][0]) / fac; + cvalue= prevbezt->vec[1][1] + (fac * (bezt->vec[1][1] - prevbezt->vec[1][1])); + } + else + cvalue= prevbezt->vec[1][1]; + } + else + { + /* bezier interpolation */ + /* v1,v2 are the first keyframe and its 2nd handle */ + v1[0]= prevbezt->vec[1][0]; + v1[1]= prevbezt->vec[1][1]; + v2[0]= prevbezt->vec[2][0]; + v2[1]= prevbezt->vec[2][1]; + /* v3,v4 are the last keyframe's 1st handle + the last keyframe */ + v3[0]= bezt->vec[0][0]; + v3[1]= bezt->vec[0][1]; + v4[0]= bezt->vec[1][0]; + v4[1]= bezt->vec[1][1]; + + /* adjust handles so that they don't overlap (forming a loop) */ + correct_bezpart(v1, v2, v3, v4); + + /* try to get a value for this position - if failure, try another set of points */ + b= findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl); + if (b) { + berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1); + cvalue= opl[0]; + break; + } + } + } + } + } + + /* return value */ + return cvalue; +} + +/* Calculate F-Curve value for 'evaltime' using FPoint samples */ +static float fcurve_eval_samples (FCurve *fcu, FPoint *fpts, float evaltime) +{ + FPoint *prevfpt, *lastfpt, *fpt; + float cvalue= 0.0f; + + /* get pointers */ + prevfpt= fpts; + lastfpt= prevfpt + fcu->totvert-1; + + /* evaluation time at or past endpoints? */ + if (prevfpt->vec[0] >= evaltime) { + /* before or on first sample, so just extend value */ + cvalue= prevfpt->vec[1]; + } + else if (lastfpt->vec[0] <= evaltime) { + /* after or on last sample, so just extend value */ + cvalue= lastfpt->vec[1]; + } + else { + /* find the one on the right frame (assume that these are spaced on 1-frame intervals) */ + fpt= prevfpt + (int)(evaltime - prevfpt->vec[0]); + cvalue= fpt->vec[1]; + } + + /* return value */ + return cvalue; +} + +/* ***************************** F-Curve - Evaluation ********************************* */ + +/* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime") + * Note: this is also used for drivers + */ +float evaluate_fcurve (FCurve *fcu, float evaltime) +{ + float cvalue= 0.0f; + float devaltime; + + /* if there is a driver (only if this F-Curve is acting as 'driver'), evaluate it to find value to use as "evaltime" + * since drivers essentially act as alternative input (i.e. in place of 'time') for F-Curves + * - this value will also be returned as the value of the 'curve', if there are no keyframes + */ + if (fcu->driver) { + /* evaltime now serves as input for the curve */ + evaltime= cvalue= evaluate_driver(fcu->driver, evaltime); + } + + /* evaluate modifiers which modify time to evaluate the base curve at */ + devaltime= evaluate_time_fmodifiers(&fcu->modifiers, fcu, cvalue, evaltime); + + /* evaluate curve-data + * - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying + * F-Curve modifier on the stack requested the curve to be evaluated at + */ + if (fcu->bezt) + cvalue= fcurve_eval_keyframes(fcu, fcu->bezt, devaltime); + else if (fcu->fpt) + cvalue= fcurve_eval_samples(fcu, fcu->fpt, devaltime); + + /* evaluate modifiers */ + evaluate_value_fmodifiers(&fcu->modifiers, fcu, &cvalue, evaltime); + + /* if curve can only have integral values, perform truncation (i.e. drop the decimal part) + * here so that the curve can be sampled correctly + */ + if (fcu->flag & FCURVE_INT_VALUES) + cvalue= (float)((int)cvalue); + + /* return evaluated value */ + return cvalue; +} + +/* Calculate the value of the given F-Curve at the given frame, and set its curval */ +void calculate_fcurve (FCurve *fcu, float ctime) +{ + /* only calculate + set curval (overriding the existing value) if curve has + * any data which warrants this... + */ + if ( (fcu->totvert) || (fcu->driver && !(fcu->driver->flag & DRIVER_FLAG_INVALID)) || + list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) ) + { + /* calculate and set curval (evaluates driver too if necessary) */ + fcu->curval= evaluate_fcurve(fcu, ctime); + } +} + diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c index 29c4e0f2fb5..ad9e481ffd2 100644 --- a/source/blender/blenkernel/intern/fluidsim.c +++ b/source/blender/blenkernel/intern/fluidsim.c @@ -28,11 +28,15 @@ * ***** END GPL LICENSE BLOCK ***** */ +#include "BLI_storage.h" /* _LARGEFILE_SOURCE */ + #include "MEM_guardedalloc.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_fluidsim.h" #include "DNA_object_force.h" // for pointcache +#include "DNA_object_types.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" // N_T @@ -52,7 +56,6 @@ // headers for fluidsim bobj meshes #include <stdlib.h> #include "LBM_fluidsim.h" -#include "elbeem.h" #include <zlib.h> #include <string.h> #include <stdio.h> @@ -77,12 +80,12 @@ void fluidsim_init(FluidsimModifierData *fluidmd) if(!fss) return; - fss->type = OB_FSBND_NOSLIP; + fss->type = OB_FLUIDSIM_ENABLE; fss->show_advancedoptions = 0; - fss->resolutionxyz = 50; - fss->previewresxyz = 25; - fss->realsize = 0.03; + fss->resolutionxyz = 65; + fss->previewresxyz = 45; + fss->realsize = 0.5; fss->guiDisplayMode = 2; // preview fss->renderDisplayMode = 3; // render @@ -95,7 +98,7 @@ void fluidsim_init(FluidsimModifierData *fluidmd) fss->gravy = 0.0; fss->gravz = -9.81; fss->animStart = 0.0; - fss->animEnd = 0.30; + fss->animEnd = 4.0; fss->gstar = 0.005; // used as normgstar fss->maxRefine = -1; // maxRefine is set according to resolutionxyz during bake @@ -111,15 +114,15 @@ void fluidsim_init(FluidsimModifierData *fluidmd) // no bounding box needed // todo - reuse default init from elbeem! - fss->typeFlags = 0; + fss->typeFlags = OB_FSBND_PARTSLIP; fss->domainNovecgen = 0; fss->volumeInitType = 1; // volume - fss->partSlipValue = 0.0; + fss->partSlipValue = 0.2; fss->generateTracers = 0; fss->generateParticles = 0.0; fss->surfaceSmoothing = 1.0; - fss->surfaceSubdivs = 1.0; + fss->surfaceSubdivs = 0.0; fss->particleInfSize = 0.0; fss->particleInfAlpha = 0.0; @@ -167,14 +170,14 @@ void fluidsim_free(FluidsimModifierData *fluidmd) return; } -DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) +DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Scene *scene, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) { #ifndef DISABLE_ELBEEM DerivedMesh *result = NULL; int framenr; FluidsimSettings *fss = NULL; - framenr= (int)G.scene->r.cfra; + framenr= (int)scene->r.cfra; // only handle fluidsim domains if(fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN)) @@ -396,7 +399,7 @@ static DerivedMesh *fluidsim_read_obj(char *filename) DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams) { int displaymode = 0; - int curFrame = framenr - 1 /*G.scene->r.sfra*/; /* start with 0 at start frame */ + int curFrame = framenr - 1 /*scene->r.sfra*/; /* start with 0 at start frame */ char targetDir[FILE_MAXFILE+FILE_MAXDIR], targetFile[FILE_MAXFILE+FILE_MAXDIR]; FluidsimSettings *fss = fluidmd->fss; DerivedMesh *dm = NULL; @@ -598,7 +601,7 @@ void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4], // file handling //------------------------------------------------------------------------------- -void initElbeemMesh(struct Object *ob, +void initElbeemMesh(struct Scene *scene, struct Object *ob, int *numVertices, float **vertices, int *numTriangles, int **triangles, int useGlobalCoords, int modifierIndex) @@ -610,7 +613,7 @@ void initElbeemMesh(struct Object *ob, float *verts; int *tris; - dm = mesh_create_derived_index_render(ob, CD_MASK_BAREMESH, modifierIndex); + dm = mesh_create_derived_index_render(scene, ob, CD_MASK_BAREMESH, modifierIndex); //dm = mesh_create_derived_no_deform(ob,NULL); mvert = dm->getVertArray(dm); @@ -656,5 +659,20 @@ void initElbeemMesh(struct Object *ob, dm->release(dm); } +void fluid_estimate_memory(Object *ob, FluidsimSettings *fss, char *value) +{ + Mesh *mesh; + + value[0]= '\0'; + + if(ob->type == OB_MESH) { + /* use mesh bounding box and object scaling */ + mesh= ob->data; + + fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize); + elbeemEstimateMemreq(fss->resolutionxyz, fss->bbSize[0],fss->bbSize[1],fss->bbSize[2], fss->maxRefine, value); + } +} + #endif // DISABLE_ELBEEM diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c new file mode 100644 index 00000000000..64558d0b456 --- /dev/null +++ b/source/blender/blenkernel/intern/fmodifier.c @@ -0,0 +1,1197 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + * + * Contributor(s): Joshua Leung (full recode) + * + * ***** END GPL LICENSE BLOCK ***** + */ + + +#include <math.h> +#include <stdio.h> +#include <stddef.h> +#include <string.h> +#include <float.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_noise.h" + +#include "BKE_fcurve.h" +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_idprop.h" +#include "BKE_utildefines.h" + +#include "RNA_access.h" +#include "RNA_types.h" + +#ifndef DISABLE_PYTHON +#include "BPY_extern.h" /* for BPY_pydriver_eval() */ +#endif + +#define SMALL -1.0e-10 +#define SELECT 1 + +/* ******************************** F-Modifiers ********************************* */ + +/* Info ------------------------------- */ + +/* F-Modifiers are modifiers which operate on F-Curves. However, they can also be defined + * on NLA-Strips to affect all of the F-Curves referenced by the NLA-Strip. + */ + +/* Template --------------------------- */ + +/* Each modifier defines a set of functions, which will be called at the appropriate + * times. In addition to this, each modifier should have a type-info struct, where + * its functions are attached for use. + */ + +/* Template for type-info data: + * - make a copy of this when creating new modifiers, and just change the functions + * pointed to as necessary + * - although the naming of functions doesn't matter, it would help for code + * readability, to follow the same naming convention as is presented here + * - any functions that a constraint doesn't need to define, don't define + * for such cases, just use NULL + * - these should be defined after all the functions have been defined, so that + * forward-definitions/prototypes don't need to be used! + * - keep this copy #if-def'd so that future constraints can get based off this + */ +#if 0 +static FModifierTypeInfo FMI_MODNAME = { + FMODIFIER_TYPE_MODNAME, /* type */ + sizeof(FMod_ModName), /* size */ + FMI_TYPE_SOME_ACTION, /* action type */ + FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */ + "Modifier Name", /* name */ + "FMod_ModName", /* struct name */ + fcm_modname_free, /* free data */ + fcm_modname_relink, /* relink data */ + fcm_modname_copy, /* copy data */ + fcm_modname_new_data, /* new data */ + fcm_modname_verify, /* verify */ + fcm_modname_time, /* evaluate time */ + fcm_modname_evaluate /* evaluate */ +}; +#endif + +/* Generator F-Curve Modifier --------------------------- */ + +/* Generators available: + * 1) simple polynomial generator: + * - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n]) + * - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1])) + */ + +static void fcm_generator_free (FModifier *fcm) +{ + FMod_Generator *data= (FMod_Generator *)fcm->data; + + /* free polynomial coefficients array */ + if (data->coefficients) + MEM_freeN(data->coefficients); +} + +static void fcm_generator_copy (FModifier *fcm, FModifier *src) +{ + FMod_Generator *gen= (FMod_Generator *)fcm->data; + FMod_Generator *ogen= (FMod_Generator *)src->data; + + /* copy coefficients array? */ + if (ogen->coefficients) + gen->coefficients= MEM_dupallocN(ogen->coefficients); +} + +static void fcm_generator_new_data (void *mdata) +{ + FMod_Generator *data= (FMod_Generator *)mdata; + float *cp; + + /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */ + data->poly_order= 1; + data->arraysize= 2; + cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs"); + cp[0] = 0; // y-offset + cp[1] = 1; // gradient +} + +static void fcm_generator_verify (FModifier *fcm) +{ + FMod_Generator *data= (FMod_Generator *)fcm->data; + + /* requirements depend on mode */ + switch (data->mode) { + case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */ + { + /* arraysize needs to be order+1, so resize if not */ + if (data->arraysize != (data->poly_order+1)) { + float *nc; + + /* make new coefficients array, and copy over as much data as can fit */ + nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs"); + + if (data->coefficients) { + if (data->arraysize > (data->poly_order+1)) + memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order+1)); + else + memcpy(nc, data->coefficients, sizeof(float)*data->arraysize); + + /* free the old data */ + MEM_freeN(data->coefficients); + } + + /* set the new data */ + data->coefficients= nc; + data->arraysize= data->poly_order+1; + } + } + break; + + case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */ + { + /* arraysize needs to be 2*order, so resize if not */ + if (data->arraysize != (data->poly_order * 2)) { + float *nc; + + /* make new coefficients array, and copy over as much data as can fit */ + nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs"); + + if (data->coefficients) { + if (data->arraysize > (data->poly_order * 2)) + memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2)); + else + memcpy(nc, data->coefficients, sizeof(float)*data->arraysize); + + /* free the old data */ + MEM_freeN(data->coefficients); + } + + /* set the new data */ + data->coefficients= nc; + data->arraysize= data->poly_order * 2; + } + } + break; + } +} + +static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime) +{ + FMod_Generator *data= (FMod_Generator *)fcm->data; + + /* behaviour depends on mode + * NOTE: the data in its default state is fine too + */ + switch (data->mode) { + case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */ + { + /* we overwrite cvalue with the sum of the polynomial */ + float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers"); + float value= 0.0f; + unsigned int i; + + /* for each x^n, precalculate value based on previous one first... this should be + * faster that calling pow() for each entry + */ + for (i=0; i < data->arraysize; i++) { + /* first entry is x^0 = 1, otherwise, calculate based on previous */ + if (i) + powers[i]= powers[i-1] * evaltime; + else + powers[0]= 1; + } + + /* for each coefficient, add to value, which we'll write to *cvalue in one go */ + for (i=0; i < data->arraysize; i++) + value += data->coefficients[i] * powers[i]; + + /* only if something changed, write *cvalue in one go */ + if (data->poly_order) { + if (data->flag & FCM_GENERATOR_ADDITIVE) + *cvalue += value; + else + *cvalue= value; + } + + /* cleanup */ + if (powers) + MEM_freeN(powers); + } + break; + + case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */ + { + float value= 1.0f, *cp=NULL; + unsigned int i; + + /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */ + for (cp=data->coefficients, i=0; (cp) && (i < data->poly_order); cp+=2, i++) + value *= (cp[0]*evaltime + cp[1]); + + /* only if something changed, write *cvalue in one go */ + if (data->poly_order) { + if (data->flag & FCM_GENERATOR_ADDITIVE) + *cvalue += value; + else + *cvalue= value; + } + } + break; + } +} + +static FModifierTypeInfo FMI_GENERATOR = { + FMODIFIER_TYPE_GENERATOR, /* type */ + sizeof(FMod_Generator), /* size */ + FMI_TYPE_GENERATE_CURVE, /* action type */ + FMI_REQUIRES_NOTHING, /* requirements */ + "Generator", /* name */ + "FMod_Generator", /* struct name */ + fcm_generator_free, /* free data */ + fcm_generator_copy, /* copy data */ + fcm_generator_new_data, /* new data */ + fcm_generator_verify, /* verify */ + NULL, /* evaluate time */ + fcm_generator_evaluate /* evaluate */ +}; + +/* Built-In Function Generator F-Curve Modifier --------------------------- */ + +/* This uses the general equation for equations: + * y = amplitude * fn(phase_multiplier*x + phase_offset) + y_offset + * + * where amplitude, phase_multiplier/offset, y_offset are user-defined coefficients, + * x is the evaluation 'time', and 'y' is the resultant value + * + * Functions available are + * sin, cos, tan, sinc (normalised sin), natural log, square root + */ + +static void fcm_fn_generator_new_data (void *mdata) +{ + FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)mdata; + + /* set amplitude and phase multiplier to 1.0f so that something is generated */ + data->amplitude= 1.0f; + data->phase_multiplier= 1.0f; +} + +/* Unary 'normalised sine' function + * y = sin(PI + x) / (PI * x), + * except for x = 0 when y = 1. + */ +static double sinc (double x) +{ + if (fabs(x) < 0.0001) + return 1.0; + else + return sin(M_PI * x) / (M_PI * x); +} + +static void fcm_fn_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime) +{ + FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)fcm->data; + double arg= data->phase_multiplier*evaltime + data->phase_offset; + double (*fn)(double v) = NULL; + + /* get function pointer to the func to use: + * WARNING: must perform special argument validation hereto guard against crashes + */ + switch (data->type) + { + /* simple ones */ + case FCM_GENERATOR_FN_SIN: /* sine wave */ + fn= sin; + break; + case FCM_GENERATOR_FN_COS: /* cosine wave */ + fn= cos; + break; + case FCM_GENERATOR_FN_SINC: /* normalised sine wave */ + fn= sinc; + break; + + /* validation required */ + case FCM_GENERATOR_FN_TAN: /* tangent wave */ + { + /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */ + if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0) { + if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) + *cvalue = 0.0f; /* no value possible here */ + } + else + fn= tan; + } + break; + case FCM_GENERATOR_FN_LN: /* natural log */ + { + /* check that value is greater than 1? */ + if (arg > 1.0f) { + fn= log; + } + else { + if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) + *cvalue = 0.0f; /* no value possible here */ + } + } + break; + case FCM_GENERATOR_FN_SQRT: /* square root */ + { + /* no negative numbers */ + if (arg > 0.0f) { + fn= sqrt; + } + else { + if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0) + *cvalue = 0.0f; /* no value possible here */ + } + } + break; + + default: + printf("Invalid Function-Generator for F-Modifier - %d \n", data->type); + } + + /* execute function callback to set value if appropriate */ + if (fn) { + float value= (float)(data->amplitude*fn(arg) + data->value_offset); + + if (data->flag & FCM_GENERATOR_ADDITIVE) + *cvalue += value; + else + *cvalue= value; + } +} + +static FModifierTypeInfo FMI_FN_GENERATOR = { + FMODIFIER_TYPE_FN_GENERATOR, /* type */ + sizeof(FMod_FunctionGenerator), /* size */ + FMI_TYPE_GENERATE_CURVE, /* action type */ + FMI_REQUIRES_NOTHING, /* requirements */ + "Built-In Function", /* name */ + "FMod_FunctionGenerator", /* struct name */ + NULL, /* free data */ + NULL, /* copy data */ + fcm_fn_generator_new_data, /* new data */ + NULL, /* verify */ + NULL, /* evaluate time */ + fcm_fn_generator_evaluate /* evaluate */ +}; + +/* Envelope F-Curve Modifier --------------------------- */ + +static void fcm_envelope_free (FModifier *fcm) +{ + FMod_Envelope *env= (FMod_Envelope *)fcm->data; + + /* free envelope data array */ + if (env->data) + MEM_freeN(env->data); +} + +static void fcm_envelope_copy (FModifier *fcm, FModifier *src) +{ + FMod_Envelope *env= (FMod_Envelope *)fcm->data; + FMod_Envelope *oenv= (FMod_Envelope *)src->data; + + /* copy envelope data array */ + if (oenv->data) + env->data= MEM_dupallocN(oenv->data); +} + +static void fcm_envelope_new_data (void *mdata) +{ + FMod_Envelope *env= (FMod_Envelope *)mdata; + + /* set default min/max ranges */ + env->min= -1.0f; + env->max= 1.0f; +} + +static void fcm_envelope_verify (FModifier *fcm) +{ + FMod_Envelope *env= (FMod_Envelope *)fcm->data; + + /* if the are points, perform bubble-sort on them, as user may have changed the order */ + if (env->data) { + // XXX todo... + } +} + +static void fcm_envelope_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime) +{ + FMod_Envelope *env= (FMod_Envelope *)fcm->data; + FCM_EnvelopeData *fed, *prevfed, *lastfed; + float min=0.0f, max=0.0f, fac=0.0f; + int a; + + /* get pointers */ + if (env->data == NULL) return; + prevfed= env->data; + fed= prevfed + 1; + lastfed= prevfed + (env->totvert-1); + + /* get min/max values for envelope at evaluation time (relative to mid-value) */ + if (prevfed->time >= evaltime) { + /* before or on first sample, so just extend value */ + min= prevfed->min; + max= prevfed->max; + } + else if (lastfed->time <= evaltime) { + /* after or on last sample, so just extend value */ + min= lastfed->min; + max= lastfed->max; + } + else { + /* evaltime occurs somewhere between segments */ + // TODO: implement binary search for this to make it faster? + for (a=0; prevfed && fed && (a < env->totvert-1); a++, prevfed=fed, fed++) { + /* evaltime occurs within the interval defined by these two envelope points */ + if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) { + float afac, bfac, diff; + + diff= fed->time - prevfed->time; + afac= (evaltime - prevfed->time) / diff; + bfac= (fed->time - evaltime) / diff; + + min= bfac*prevfed->min + afac*fed->min; + max= bfac*prevfed->max + afac*fed->max; + + break; + } + } + } + + /* adjust *cvalue + * - fac is the ratio of how the current y-value corresponds to the reference range + * - thus, the new value is found by mapping the old range to the new! + */ + fac= (*cvalue - (env->midval + env->min)) / (env->max - env->min); + *cvalue= min + fac*(max - min); +} + +static FModifierTypeInfo FMI_ENVELOPE = { + FMODIFIER_TYPE_ENVELOPE, /* type */ + sizeof(FMod_Envelope), /* size */ + FMI_TYPE_REPLACE_VALUES, /* action type */ + 0, /* requirements */ + "Envelope", /* name */ + "FMod_Envelope", /* struct name */ + fcm_envelope_free, /* free data */ + fcm_envelope_copy, /* copy data */ + fcm_envelope_new_data, /* new data */ + fcm_envelope_verify, /* verify */ + NULL, /* evaluate time */ + fcm_envelope_evaluate /* evaluate */ +}; + +/* Cycles F-Curve Modifier --------------------------- */ + +/* This modifier changes evaltime to something that exists within the curve's frame-range, + * then re-evaluates modifier stack up to this point using the new time. This re-entrant behaviour + * is very likely to be more time-consuming than the original approach... (which was tighly integrated into + * the calculation code...). + * + * NOTE: this needs to be at the start of the stack to be of use, as it needs to know the extents of the keyframes/sample-data + * Possible TODO - store length of cycle information that can be initialised from the extents of the keyframes/sample-data, and adjusted + * as appropriate + */ + +/* temp data used during evaluation */ +typedef struct tFCMED_Cycles { + float cycyofs; /* y-offset to apply */ +} tFCMED_Cycles; + +static void fcm_cycles_new_data (void *mdata) +{ + FMod_Cycles *data= (FMod_Cycles *)mdata; + + /* turn on cycles by default */ + data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC; +} + +static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime) +{ + FMod_Cycles *data= (FMod_Cycles *)fcm->data; + float prevkey[2], lastkey[2], cycyofs=0.0f; + short side=0, mode=0; + int cycles=0; + + /* check if modifier is first in stack, otherwise disable ourself... */ + // FIXME... + if (fcm->prev) { + fcm->flag |= FMODIFIER_FLAG_DISABLED; + return evaltime; + } + + /* calculate new evaltime due to cyclic interpolation */ + if (fcu && fcu->bezt) { + BezTriple *prevbezt= fcu->bezt; + BezTriple *lastbezt= prevbezt + fcu->totvert-1; + + prevkey[0]= prevbezt->vec[1][0]; + prevkey[1]= prevbezt->vec[1][1]; + + lastkey[0]= lastbezt->vec[1][0]; + lastkey[1]= lastbezt->vec[1][1]; + } + else if (fcu && fcu->fpt) { + FPoint *prevfpt= fcu->fpt; + FPoint *lastfpt= prevfpt + fcu->totvert-1; + + prevkey[0]= prevfpt->vec[0]; + prevkey[1]= prevfpt->vec[1]; + + lastkey[0]= lastfpt->vec[0]; + lastkey[1]= lastfpt->vec[1]; + } + else + return evaltime; + + /* check if modifier will do anything + * 1) if in data range, definitely don't do anything + * 2) if before first frame or after last frame, make sure some cycling is in use + */ + if (evaltime < prevkey[0]) { + if (data->before_mode) { + side= -1; + mode= data->before_mode; + cycles= data->before_cycles; + } + } + else if (evaltime > lastkey[0]) { + if (data->after_mode) { + side= 1; + mode= data->after_mode; + cycles= data->after_cycles; + } + } + if ELEM(0, side, mode) + return evaltime; + + /* find relative place within a cycle */ + { + float cycdx=0, cycdy=0, ofs=0; + float cycle= 0; + + /* ofs is start frame of cycle */ + ofs= prevkey[0]; + + /* calculate period and amplitude (total height) of a cycle */ + cycdx= lastkey[0] - prevkey[0]; + cycdy= lastkey[1] - prevkey[1]; + + /* check if cycle is infinitely small, to be point of being impossible to use */ + if (cycdx == 0) + return evaltime; + + /* calculate the 'number' of the cycle */ + cycle= ((float)side * (evaltime - ofs) / cycdx); + + /* check that cyclic is still enabled for the specified time */ + if (cycles == 0) { + /* catch this case so that we don't exit when we have cycles=0 + * as this indicates infinite cycles... + */ + } + else if (cycle > (cycles+1)) { + /* we are too far away from range to evaluate + * TODO: but we should still hold last value... + */ + return evaltime; + } + + /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */ + if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) { + cycyofs = (float)floor((evaltime - ofs) / cycdx); + cycyofs *= cycdy; + } + + /* calculate where in the cycle we are (overwrite evaltime to reflect this) */ + if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle) % 2)) { + /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse + * - for 'before' extrapolation, we need to flip in a different way, otherwise values past + * then end of the curve get referenced (result of fmod will be negative, and with different phase) + */ + if (side < 0) + evaltime= (float)(prevkey[0] - fmod(evaltime-ofs, cycdx)); + else + evaltime= (float)(lastkey[0] - fmod(evaltime-ofs, cycdx)); + } + else { + /* the cycle is played normally... */ + evaltime= (float)(fmod(evaltime-ofs, cycdx) + ofs); + } + if (evaltime < ofs) evaltime += cycdx; + } + + /* store temp data if needed */ + if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) { + tFCMED_Cycles *edata; + + /* for now, this is just a float, but we could get more stuff... */ + fcm->edata= edata= MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles"); + edata->cycyofs= cycyofs; + } + + /* return the new frame to evaluate */ + return evaltime; +} + +static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime) +{ + tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata; + + /* use temp data */ + if (edata) { + /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */ + *cvalue += edata->cycyofs; + + /* free temp data */ + MEM_freeN(edata); + fcm->edata= NULL; + } +} + +static FModifierTypeInfo FMI_CYCLES = { + FMODIFIER_TYPE_CYCLES, /* type */ + sizeof(FMod_Cycles), /* size */ + FMI_TYPE_EXTRAPOLATION, /* action type */ + FMI_REQUIRES_ORIGINAL_DATA, /* requirements */ + "Cycles", /* name */ + "FMod_Cycles", /* struct name */ + NULL, /* free data */ + NULL, /* copy data */ + fcm_cycles_new_data, /* new data */ + NULL /*fcm_cycles_verify*/, /* verify */ + fcm_cycles_time, /* evaluate time */ + fcm_cycles_evaluate /* evaluate */ +}; + +/* Noise F-Curve Modifier --------------------------- */ + +static void fcm_noise_new_data (void *mdata) +{ + FMod_Noise *data= (FMod_Noise *)mdata; + + /* defaults */ + data->size= 1.0f; + data->strength= 1.0f; + data->phase= 1.0f; + data->depth = 0; + data->modification = FCM_NOISE_MODIF_REPLACE; +} + +static void fcm_noise_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime) +{ + FMod_Noise *data= (FMod_Noise *)fcm->data; + float noise; + + noise = BLI_turbulence(data->size, evaltime, data->phase, 0.f, data->depth); + + switch (data->modification) { + case FCM_NOISE_MODIF_ADD: + *cvalue= *cvalue + noise * data->strength; + break; + case FCM_NOISE_MODIF_SUBTRACT: + *cvalue= *cvalue - noise * data->strength; + break; + case FCM_NOISE_MODIF_MULTIPLY: + *cvalue= *cvalue * noise * data->strength; + break; + case FCM_NOISE_MODIF_REPLACE: + default: + *cvalue= *cvalue + (noise - 0.5f) * data->strength; + break; + } +} + +static FModifierTypeInfo FMI_NOISE = { + FMODIFIER_TYPE_NOISE, /* type */ + sizeof(FMod_Noise), /* size */ + FMI_TYPE_REPLACE_VALUES, /* action type */ + 0, /* requirements */ + "Noise", /* name */ + "FMod_Noise", /* struct name */ + NULL, /* free data */ + NULL, /* copy data */ + fcm_noise_new_data, /* new data */ + NULL /*fcm_noise_verify*/, /* verify */ + NULL, /* evaluate time */ + fcm_noise_evaluate /* evaluate */ +}; + +/* Filter F-Curve Modifier --------------------------- */ + +#if 0 // XXX not yet implemented +static FModifierTypeInfo FMI_FILTER = { + FMODIFIER_TYPE_FILTER, /* type */ + sizeof(FMod_Filter), /* size */ + FMI_TYPE_REPLACE_VALUES, /* action type */ + 0, /* requirements */ + "Filter", /* name */ + "FMod_Filter", /* struct name */ + NULL, /* free data */ + NULL, /* copy data */ + NULL, /* new data */ + NULL /*fcm_filter_verify*/, /* verify */ + NULL, /* evlauate time */ + fcm_filter_evaluate /* evaluate */ +}; +#endif // XXX not yet implemented + + +/* Python F-Curve Modifier --------------------------- */ + +static void fcm_python_free (FModifier *fcm) +{ + FMod_Python *data= (FMod_Python *)fcm->data; + + /* id-properties */ + IDP_FreeProperty(data->prop); + MEM_freeN(data->prop); +} + +static void fcm_python_new_data (void *mdata) +{ + FMod_Python *data= (FMod_Python *)mdata; + + /* everything should be set correctly by calloc, except for the prop->type constant.*/ + data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps"); + data->prop->type = IDP_GROUP; +} + +static void fcm_python_copy (FModifier *fcm, FModifier *src) +{ + FMod_Python *pymod = (FMod_Python *)fcm->data; + FMod_Python *opymod = (FMod_Python *)src->data; + + pymod->prop = IDP_CopyProperty(opymod->prop); +} + +static void fcm_python_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime) +{ +#ifndef DISABLE_PYTHON + //FMod_Python *data= (FMod_Python *)fcm->data; + + /* FIXME... need to implement this modifier... + * It will need it execute a script using the custom properties + */ +#endif /* DISABLE_PYTHON */ +} + +static FModifierTypeInfo FMI_PYTHON = { + FMODIFIER_TYPE_PYTHON, /* type */ + sizeof(FMod_Python), /* size */ + FMI_TYPE_GENERATE_CURVE, /* action type */ + FMI_REQUIRES_RUNTIME_CHECK, /* requirements */ + "Python", /* name */ + "FMod_Python", /* struct name */ + fcm_python_free, /* free data */ + fcm_python_copy, /* copy data */ + fcm_python_new_data, /* new data */ + NULL /*fcm_python_verify*/, /* verify */ + NULL /*fcm_python_time*/, /* evaluate time */ + fcm_python_evaluate /* evaluate */ +}; + + +/* Limits F-Curve Modifier --------------------------- */ + +static float fcm_limits_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime) +{ + FMod_Limits *data= (FMod_Limits *)fcm->data; + + /* check for the time limits */ + if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin)) + return data->rect.xmin; + if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax)) + return data->rect.xmax; + + /* modifier doesn't change time */ + return evaltime; +} + +static void fcm_limits_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime) +{ + FMod_Limits *data= (FMod_Limits *)fcm->data; + + /* value limits now */ + if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin)) + *cvalue= data->rect.ymin; + if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax)) + *cvalue= data->rect.ymax; +} + +static FModifierTypeInfo FMI_LIMITS = { + FMODIFIER_TYPE_LIMITS, /* type */ + sizeof(FMod_Limits), /* size */ + FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */ + FMI_REQUIRES_RUNTIME_CHECK, /* requirements */ + "Limits", /* name */ + "FMod_Limits", /* struct name */ + NULL, /* free data */ + NULL, /* copy data */ + NULL, /* new data */ + NULL, /* verify */ + fcm_limits_time, /* evaluate time */ + fcm_limits_evaluate /* evaluate */ +}; + +/* F-Curve Modifier API --------------------------- */ +/* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out + * and operations that involve F-Curve modifier specific code. + */ + +/* These globals only ever get directly accessed in this file */ +static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES]; +static short FMI_INIT= 1; /* when non-zero, the list needs to be updated */ + +/* This function only gets called when FMI_INIT is non-zero */ +static void fmods_init_typeinfo () +{ + fmodifiersTypeInfo[0]= NULL; /* 'Null' F-Curve Modifier */ + fmodifiersTypeInfo[1]= &FMI_GENERATOR; /* Generator F-Curve Modifier */ + fmodifiersTypeInfo[2]= &FMI_FN_GENERATOR; /* Built-In Function Generator F-Curve Modifier */ + fmodifiersTypeInfo[3]= &FMI_ENVELOPE; /* Envelope F-Curve Modifier */ + fmodifiersTypeInfo[4]= &FMI_CYCLES; /* Cycles F-Curve Modifier */ + fmodifiersTypeInfo[5]= &FMI_NOISE; /* Apply-Noise F-Curve Modifier */ + fmodifiersTypeInfo[6]= NULL/*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented + fmodifiersTypeInfo[7]= &FMI_PYTHON; /* Custom Python F-Curve Modifier */ + fmodifiersTypeInfo[8]= &FMI_LIMITS; /* Limits F-Curve Modifier */ +} + +/* This function should be used for getting the appropriate type-info when only + * a F-Curve modifier type is known + */ +FModifierTypeInfo *get_fmodifier_typeinfo (int type) +{ + /* initialise the type-info list? */ + if (FMI_INIT) { + fmods_init_typeinfo(); + FMI_INIT = 0; + } + + /* only return for valid types */ + if ( (type >= FMODIFIER_TYPE_NULL) && + (type <= FMODIFIER_NUM_TYPES ) ) + { + /* there shouldn't be any segfaults here... */ + return fmodifiersTypeInfo[type]; + } + else { + printf("No valid F-Curve Modifier type-info data available. Type = %i \n", type); + } + + return NULL; +} + +/* This function should always be used to get the appropriate type-info, as it + * has checks which prevent segfaults in some weird cases. + */ +FModifierTypeInfo *fmodifier_get_typeinfo (FModifier *fcm) +{ + /* only return typeinfo for valid modifiers */ + if (fcm) + return get_fmodifier_typeinfo(fcm->type); + else + return NULL; +} + +/* API --------------------------- */ + +/* Add a new F-Curve Modifier to the given F-Curve of a certain type */ +FModifier *add_fmodifier (ListBase *modifiers, int type) +{ + FModifierTypeInfo *fmi= get_fmodifier_typeinfo(type); + FModifier *fcm; + + /* sanity checks */ + if ELEM(NULL, modifiers, fmi) + return NULL; + + /* special checks for whether modifier can be added */ + if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) { + /* cycles modifier must be first in stack, so for now, don't add if it can't be */ + // TODO: perhaps there is some better way, but for now, + printf("Error: Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack. \n"); + return NULL; + } + + /* add modifier itself */ + fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier"); + fcm->type = type; + fcm->flag = FMODIFIER_FLAG_EXPANDED; + BLI_addtail(modifiers, fcm); + + /* add modifier's data */ + fcm->data= MEM_callocN(fmi->size, fmi->structName); + + /* init custom settings if necessary */ + if (fmi->new_data) + fmi->new_data(fcm->data); + + /* return modifier for further editing */ + return fcm; +} + +/* Duplicate all of the F-Modifiers in the Modifier stacks */ +void copy_fmodifiers (ListBase *dst, ListBase *src) +{ + FModifier *fcm, *srcfcm; + + if ELEM(NULL, dst, src) + return; + + dst->first= dst->last= NULL; + BLI_duplicatelist(dst, src); + + for (fcm=dst->first, srcfcm=src->first; fcm && srcfcm; srcfcm=srcfcm->next, fcm=fcm->next) { + FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); + + /* make a new copy of the F-Modifier's data */ + fcm->data = MEM_dupallocN(fcm->data); + + /* only do specific constraints if required */ + if (fmi && fmi->copy_data) + fmi->copy_data(fcm, srcfcm); + } +} + +/* Remove and free the given F-Modifier from the given stack */ +void remove_fmodifier (ListBase *modifiers, FModifier *fcm) +{ + FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); + + /* sanity check */ + if (fcm == NULL) + return; + + /* free modifier's special data (stored inside fcm->data) */ + if (fcm->data) { + if (fmi && fmi->free_data) + fmi->free_data(fcm); + + /* free modifier's data (fcm->data) */ + MEM_freeN(fcm->data); + } + + /* remove modifier from stack */ + if (modifiers) + BLI_freelinkN(modifiers, fcm); + else { + // XXX this case can probably be removed some day, as it shouldn't happen... + printf("remove_fmodifier() - no modifier stack given \n"); + MEM_freeN(fcm); + } +} + +/* Remove all of a given F-Curve's modifiers */ +void free_fmodifiers (ListBase *modifiers) +{ + FModifier *fcm, *fmn; + + /* sanity check */ + if (modifiers == NULL) + return; + + /* free each modifier in order - modifier is unlinked from list and freed */ + for (fcm= modifiers->first; fcm; fcm= fmn) { + fmn= fcm->next; + remove_fmodifier(modifiers, fcm); + } +} + +/* Find the active F-Modifier */ +FModifier *find_active_fmodifier (ListBase *modifiers) +{ + FModifier *fcm; + + /* sanity checks */ + if ELEM(NULL, modifiers, modifiers->first) + return NULL; + + /* loop over modifiers until 'active' one is found */ + for (fcm= modifiers->first; fcm; fcm= fcm->next) { + if (fcm->flag & FMODIFIER_FLAG_ACTIVE) + return fcm; + } + + /* no modifier is active */ + return NULL; +} + +/* Set the active F-Modifier */ +void set_active_fmodifier (ListBase *modifiers, FModifier *fcm) +{ + FModifier *fm; + + /* sanity checks */ + if ELEM(NULL, modifiers, modifiers->first) + return; + + /* deactivate all, and set current one active */ + for (fm= modifiers->first; fm; fm= fm->next) + fm->flag &= ~FMODIFIER_FLAG_ACTIVE; + + /* make given modifier active */ + if (fcm) + fcm->flag |= FMODIFIER_FLAG_ACTIVE; +} + +/* Do we have any modifiers which match certain criteria + * - mtype - type of modifier (if 0, doesn't matter) + * - acttype - type of action to perform (if -1, doesn't matter) + */ +short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype) +{ + FModifier *fcm; + + /* if there are no specific filtering criteria, just skip */ + if ((mtype == 0) && (acttype == 0)) + return (modifiers && modifiers->first); + + /* sanity checks */ + if ELEM(NULL, modifiers, modifiers->first) + return 0; + + /* find the first mdifier fitting these criteria */ + for (fcm= modifiers->first; fcm; fcm= fcm->next) { + FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); + short mOk=1, aOk=1; /* by default 1, so that when only one test, won't fail */ + + /* check if applicable ones are fullfilled */ + if (mtype) + mOk= (fcm->type == mtype); + if (acttype > -1) + aOk= (fmi->acttype == acttype); + + /* if both are ok, we've found a hit */ + if (mOk && aOk) + return 1; + } + + /* no matches */ + return 0; +} + +/* Evaluation API --------------------------- */ + +/* evaluate time modifications imposed by some F-Curve Modifiers + * - this step acts as an optimisation to prevent the F-Curve stack being evaluated + * several times by modifiers requesting the time be modified, as the final result + * would have required using the modified time + * - modifiers only ever recieve the unmodified time, as subsequent modifiers should be + * working on the 'global' result of the modified curve, not some localised segment, + * so nevaltime gets set to whatever the last time-modifying modifier likes... + * - we start from the end of the stack, as only the last one matters for now + */ +float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime) +{ + FModifier *fcm; + float m_evaltime= evaltime; + + /* sanity checks */ + if ELEM(NULL, modifiers, modifiers->last) + return evaltime; + + /* find the first modifier from end of stack that modifies time, and calculate the time the modifier + * would calculate time at + */ + for (fcm= modifiers->last; fcm; fcm= fcm->prev) { + FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); + + /* only evaluate if there's a callback for this */ + // TODO: implement the 'influence' control feature... + if (fmi && fmi->evaluate_modifier_time) { + if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) + m_evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime); + break; + } + } + + /* return the modified evaltime */ + return m_evaltime; +} + +/* Evalautes the given set of F-Curve Modifiers using the given data + * Should only be called after evaluate_time_fmodifiers() has been called... + */ +void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, float evaltime) +{ + FModifier *fcm; + + /* sanity checks */ + if ELEM(NULL, modifiers, modifiers->first) + return; + + /* evaluate modifiers */ + for (fcm= modifiers->first; fcm; fcm= fcm->next) { + FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); + + /* only evaluate if there's a callback for this */ + // TODO: implement the 'influence' control feature... + if (fmi && fmi->evaluate_modifier) { + if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) + fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime); + } + } +} + +/* ---------- */ + +/* Bake modifiers for given F-Curve to curve sample data, in the frame range defined + * by start and end (inclusive). + */ +void fcurve_bake_modifiers (FCurve *fcu, int start, int end) +{ + ChannelDriver *driver; + + /* sanity checks */ + // TODO: make these tests report errors using reports not printf's + if ELEM(NULL, fcu, fcu->modifiers.first) { + printf("Error: No F-Curve with F-Curve Modifiers to Bake\n"); + return; + } + + /* temporarily, disable driver while we sample, so that they don't influence the outcome */ + driver= fcu->driver; + fcu->driver= NULL; + + /* bake the modifiers, by sampling the curve at each frame */ + fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve); + + /* free the modifiers now */ + free_fmodifiers(&fcu->modifiers); + + /* restore driver */ + fcu->driver= driver; +} diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 45b52f5af8e..70901778585 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -53,7 +53,6 @@ #include "DNA_scene_types.h" #include "BKE_utildefines.h" -#include "BKE_bad_level_calls.h" #include "BKE_packedFile.h" @@ -66,9 +65,7 @@ #include "BKE_curve.h" #include "BKE_displist.h" -#define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name) - -struct SelBox *selboxes= NULL; +static ListBase ttfdata= {NULL, NULL}; /* UTF-8 <-> wchar transformations */ void @@ -270,22 +267,46 @@ static PackedFile *get_builtin_packedfile(void) } } -static VFontData *vfont_get_data(VFont *vfont) +void free_ttfont(void) +{ + struct TmpFont *tf; + + tf= ttfdata.first; + while(tf) { + freePackedFile(tf->pf); + tf->pf= NULL; + tf->vfont= NULL; + tf= tf->next; + } + BLI_freelistN(&ttfdata); +} + +struct TmpFont *vfont_find_tmpfont(VFont *vfont) { struct TmpFont *tmpfnt = NULL; - PackedFile *tpf; if(vfont==NULL) return NULL; // Try finding the font from font list - tmpfnt = G.ttfdata.first; - + tmpfnt = ttfdata.first; while(tmpfnt) { if(tmpfnt->vfont == vfont) break; tmpfnt = tmpfnt->next; } + return tmpfnt; +} + +static VFontData *vfont_get_data(VFont *vfont) +{ + struct TmpFont *tmpfnt = NULL; + PackedFile *tpf; + + if(vfont==NULL) return NULL; + + // Try finding the font from font list + tmpfnt = vfont_find_tmpfont(vfont); // And then set the data if (!vfont->data) { @@ -309,20 +330,20 @@ static VFontData *vfont_get_data(VFont *vfont) tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font"); tmpfnt->pf= tpf; tmpfnt->vfont= vfont; - BLI_addtail(&G.ttfdata, tmpfnt); + BLI_addtail(&ttfdata, tmpfnt); } } else { - pf= newPackedFile(vfont->name); + pf= newPackedFile(NULL, vfont->name); if(!tmpfnt) { - tpf= newPackedFile(vfont->name); + tpf= newPackedFile(NULL, vfont->name); // Add temporary packed file to globals tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font"); tmpfnt->pf= tpf; tmpfnt->vfont= vfont; - BLI_addtail(&G.ttfdata, tmpfnt); + BLI_addtail(&ttfdata, tmpfnt); } } if(!pf) { @@ -334,11 +355,7 @@ static VFontData *vfont_get_data(VFont *vfont) } if (pf) { -#ifdef WITH_FREETYPE2 vfont->data= BLI_vfontdata_from_freetypefont(pf); -#else - vfont->data= BLI_vfontdata_from_psfont(pf); -#endif if (pf != vfont->packedfile) { freePackedFile(pf); } @@ -368,23 +385,16 @@ VFont *load_vfont(char *name) strcpy(dir, name); BLI_splitdirstring(dir, filename); - pf= newPackedFile(name); - tpf= newPackedFile(name); + pf= newPackedFile(NULL, name); + tpf= newPackedFile(NULL, name); is_builtin= 0; } if (pf) { VFontData *vfd; - - waitcursor(1); -#ifdef WITH_FREETYPE2 vfd= BLI_vfontdata_from_freetypefont(pf); -#else - vfd= BLI_vfontdata_from_psfont(pf); -#endif - if (vfd) { vfont = alloc_libblock(&G.main->vfont, ID_VF, filename); vfont->data = vfd; @@ -402,7 +412,7 @@ VFont *load_vfont(char *name) tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font"); tmpfnt->pf= tpf; tmpfnt->vfont= vfont; - BLI_addtail(&G.ttfdata, tmpfnt); + BLI_addtail(&ttfdata, tmpfnt); } } @@ -411,7 +421,7 @@ VFont *load_vfont(char *name) freePackedFile(pf); } - waitcursor(0); + //XXX waitcursor(0); } return vfont; @@ -431,6 +441,17 @@ static VFont *which_vfont(Curve *cu, CharInfo *info) } } +VFont *get_builtin_font(void) +{ + VFont *vf; + + for (vf= G.main->vfont.first; vf; vf= vf->id.next) + if (BLI_streq(vf->name, "<builtin>")) + return vf; + + return load_vfont("<builtin>"); +} + static void build_underline(Curve *cu, float x1, float y1, float x2, float y2, int charidx, short mat_nr) { Nurb *nu2; @@ -599,13 +620,11 @@ static void buildchar(Curve *cu, unsigned long character, CharInfo *info, float } } -int getselection(int *start, int *end) +int BKE_font_getselection(Object *ob, int *start, int *end) { - Curve *cu; - - if (G.obedit==NULL || G.obedit->type != OB_FONT) return 0; + Curve *cu= ob->data; - cu= G.obedit->data; + if (cu->editfont==NULL || ob->type != OB_FONT) return 0; if (cu->selstart == 0) return 0; if (cu->selstart <= cu->selend) { @@ -620,30 +639,23 @@ int getselection(int *start, int *end) } } -struct chartrans *text_to_curve(Object *ob, int mode) +struct chartrans *BKE_text_to_curve(Scene *scene, Object *ob, int mode) { VFont *vfont, *oldvfont; VFontData *vfd= NULL; - Curve *cu, *cucu; - struct chartrans *chartransdata=NULL, *ct; - float distfac, tabfac, ctime, dtime, tvec[4], vec[4], rotvec[3], minx, maxx, miny, maxy; - float cmat[3][3], timeofs, si, co, sizefac; - float *f, maxlen=0, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4; - int i, slen, oldflag, j; - short cnr=0, lnr=0, wsnr= 0; - wchar_t *mem, *tmp, ascii; - int outta; - float vecyo[3], curofs; - CharInfo *info; - float wsfac; - float ulwidth, uloverlap; + Curve *cu; + CharInfo *info, *custrinfo; TextBox *tb; + VChar *che; + struct chartrans *chartransdata=NULL, *ct; + float *f, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4; + float twidth, maxlen= 0; + int i, slen, j; int curbox; int selstart, selend; - SelBox *sb= NULL; /* to please gcc */ - VChar *che; - float twidth; int utf8len; + short cnr=0, lnr=0, wsnr= 0; + wchar_t *mem, *tmp, ascii; /* renark: do calculations including the trailing '\0' of a string because the cursor can be at that location */ @@ -653,9 +665,9 @@ struct chartrans *text_to_curve(Object *ob, int mode) // Set font data cu= (Curve *) ob->data; vfont= cu->vfont; - - if(cu->str == 0) return 0; - if(vfont == 0) return 0; + + if(cu->str == NULL) return 0; + if(vfont == NULL) return 0; // Create unicode string utf8len = utf8slen(cu->str); @@ -666,19 +678,23 @@ struct chartrans *text_to_curve(Object *ob, int mode) // Count the wchar_t string length slen = wcslen(mem); - if (cu->ulheight == 0.0) cu->ulheight = 0.05; - if (cu->strinfo==NULL) { /* old file */ - cu->strinfo = MEM_callocN((slen+1) * sizeof(CharInfo), "strinfo compat"); - } - if (cu->tb==NULL) { + if (cu->ulheight == 0.0) + cu->ulheight = 0.05; + + if (cu->strinfo==NULL) /* old file */ + cu->strinfo = MEM_callocN((slen+4) * sizeof(CharInfo), "strinfo compat"); + + custrinfo= cu->strinfo; + if (cu->editfont) + custrinfo= cu->editfont->textbufinfo; + + if (cu->tb==NULL) cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "TextBox compat"); - } vfd= vfont_get_data(vfont); /* The VFont Data can not be found */ - if(!vfd) - { + if(!vfd) { if(mem) MEM_freeN(mem); return 0; @@ -704,12 +720,12 @@ struct chartrans *text_to_curve(Object *ob, int mode) oldvfont = NULL; - for (i=0; i<slen; i++) cu->strinfo[i].flag &= ~CU_WRAP; + for (i=0; i<slen; i++) custrinfo[i].flag &= ~CU_WRAP; - if (selboxes) MEM_freeN(selboxes); - selboxes = NULL; - if (getselection(&selstart, &selend)) - selboxes = MEM_callocN((selend-selstart+1)*sizeof(SelBox), "font selboxes"); + if (cu->selboxes) MEM_freeN(cu->selboxes); + cu->selboxes = NULL; + if (BKE_font_getselection(ob, &selstart, &selend)) + cu->selboxes = MEM_callocN((selend-selstart+1)*sizeof(SelBox), "font selboxes"); tb = &(cu->tb[0]); curbox= 0; @@ -718,40 +734,37 @@ struct chartrans *text_to_curve(Object *ob, int mode) // Characters in the list che = vfd->characters.first; ascii = mem[i]; - info = &(cu->strinfo[i]); + info = &(custrinfo[i]); vfont = which_vfont(cu, info); if(vfont==NULL) break; // Find the character - while(che) - { + while(che) { if(che->index == ascii) break; che = che->next; } -#ifdef WITH_FREETYPE2 - // The character wasn't in the current curve base so load it - // But if the font is <builtin> then do not try loading since whole font is in the memory already - if(che == NULL && strcmp(vfont->name, "<builtin>")) - { + /* + * The character wasn't in the current curve base so load it + * But if the font is <builtin> then do not try loading since + * whole font is in the memory already + */ + if(che == NULL && strcmp(vfont->name, "<builtin>")) { BLI_vfontchar_from_freetypefont(vfont, ascii); } - // Try getting the character again from the list + /* Try getting the character again from the list */ che = vfd->characters.first; - while(che) - { + while(che) { if(che->index == ascii) break; che = che->next; } -#endif /* No VFont found */ - if (vfont==0) - { + if (vfont==0) { if(mem) MEM_freeN(mem); MEM_freeN(chartransdata); @@ -764,8 +777,7 @@ struct chartrans *text_to_curve(Object *ob, int mode) } /* VFont Data for VFont couldn't be found */ - if (!vfd) - { + if (!vfd) { if(mem) MEM_freeN(mem); MEM_freeN(chartransdata); @@ -774,13 +786,9 @@ struct chartrans *text_to_curve(Object *ob, int mode) // The character wasn't found, propably ascii = 0, then the width shall be 0 as well if(!che) - { twidth = 0; - } else - { twidth = che->width; - } // Calculate positions if((tb->w != 0.0) && (ct->dobreak==0) && ((xof-(tb->x/cu->fsize)+twidth)*cu->fsize) > tb->w) { @@ -794,13 +802,13 @@ struct chartrans *text_to_curve(Object *ob, int mode) i = j-1; xof = ct->xof; ct[1].dobreak = 1; - cu->strinfo[i+1].flag |= CU_WRAP; + custrinfo[i+1].flag |= CU_WRAP; goto makebreak; } if (chartransdata[j].dobreak) { // fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]); ct->dobreak= 1; - cu->strinfo[i+1].flag |= CU_WRAP; + custrinfo[i+1].flag |= CU_WRAP; ct -= 1; cnr -= 1; i--; @@ -843,6 +851,8 @@ struct chartrans *text_to_curve(Object *ob, int mode) wsnr= 0; } else if(ascii==9) { /* TAB */ + float tabfac; + ct->xof= xof; ct->yof= yof; ct->linenr= lnr; @@ -853,13 +863,16 @@ struct chartrans *text_to_curve(Object *ob, int mode) xof= cu->xof+tabfac; } else { + SelBox *sb= NULL; + float wsfac; + ct->xof= xof; ct->yof= yof; ct->linenr= lnr; ct->charnr= cnr++; - if (selboxes && (i>=selstart) && (i<=selend)) { - sb = &(selboxes[i-selstart]); + if (cu->selboxes && (i>=selstart) && (i<=selend)) { + sb = &(cu->selboxes[i-selstart]); sb->y = yof*cu->fsize-linedist*cu->fsize*0.1; sb->h = linedist*cu->fsize; sb->w = xof*cu->fsize; @@ -868,25 +881,23 @@ struct chartrans *text_to_curve(Object *ob, int mode) if (ascii==32) { wsfac = cu->wordspace; wsnr++; - } else wsfac = 1.0; + } + else wsfac = 1.0; + // Set the width of the character if(!che) - { twidth = 0; - } - else - { + else twidth = che->width; - } + xof += (twidth*wsfac*(1.0+(info->kern/40.0)) ) + xtrax; - if (selboxes && (i>=selstart) && (i<=selend)) sb->w = (xof*cu->fsize) - sb->w; + if (sb) + sb->w = (xof*cu->fsize) - sb->w; } ct++; } - - cu->lines= 1; ct= chartransdata; tmp = mem; @@ -928,9 +939,9 @@ struct chartrans *text_to_curve(Object *ob, int mode) // } ct++; } - } else if((cu->spacemode==CU_JUSTIFY) && - (cu->tb[0].w != 0.0)) { - curofs= 0; + } + else if((cu->spacemode==CU_JUSTIFY) && (cu->tb[0].w != 0.0)) { + float curofs= 0.0f; for (i=0; i<=slen; i++) { for (j=i; (mem[j]) && (mem[j]!='\n') && (mem[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++); @@ -947,14 +958,17 @@ struct chartrans *text_to_curve(Object *ob, int mode) /* TEXT ON CURVE */ if(cu->textoncurve) { - cucu= cu->textoncurve->data; + Curve *cucu= cu->textoncurve->data; + int oldflag= cucu->flag; - oldflag= cucu->flag; cucu->flag |= (CU_PATH+CU_FOLLOW); - if(cucu->path==NULL) makeDispListCurveTypes(cu->textoncurve, 0); + if(cucu->path==NULL) makeDispListCurveTypes(scene, cu->textoncurve, 0); if(cucu->path) { - float imat[4][4], imat3[3][3]; + float distfac, imat[4][4], imat3[3][3], cmat[3][3]; + float minx, maxx, miny, maxy; + float timeofs, sizefac; + Mat4Invert(imat, ob->obmat); Mat3CpyMat4(imat3, imat); @@ -999,27 +1013,24 @@ struct chartrans *text_to_curve(Object *ob, int mode) ct= chartransdata; for (i=0; i<=slen; i++, ct++) { + float ctime, dtime, vec[4], tvec[4], rotvec[3]; + float si, co; /* rotate around center character */ ascii = mem[i]; // Find the character che = vfd->characters.first; - while(che) - { + while(che) { if(che->index == ascii) break; che = che->next; } if(che) - { twidth = che->width; - } else - { twidth = 0; - } dtime= distfac*0.35f*twidth; /* why not 0.5? */ dtime= distfac*0.5f*twidth; /* why not 0.5? */ @@ -1049,12 +1060,12 @@ struct chartrans *text_to_curve(Object *ob, int mode) } } - if (selboxes) { + if (cu->selboxes) { ct= chartransdata; for (i=0; i<=selend; i++, ct++) { if (i>=selstart) { - selboxes[i-selstart].x = ct->xof*cu->fsize; - selboxes[i-selstart].y = ct->yof*cu->fsize; + cu->selboxes[i-selstart].x = ct->xof*cu->fsize; + cu->selboxes[i-selstart].y = ct->yof*cu->fsize; } } } @@ -1090,12 +1101,14 @@ struct chartrans *text_to_curve(Object *ob, int mode) } /* cursor first */ - if(ob==G.obedit) { + if(cu->editfont) { + float si, co; + ct= chartransdata+cu->pos; si= (float)sin(ct->rot); co= (float)cos(ct->rot); - f= G.textcurs[0]; + f= cu->editfont->textcurs[0]; f[0]= cu->fsize*(-0.1f*co + ct->xof); f[1]= cu->fsize*(0.1f*si + ct->yof); @@ -1125,57 +1138,60 @@ struct chartrans *text_to_curve(Object *ob, int mode) if(mode==0) { /* make nurbdata */ unsigned long cha; - + freeNurblist(&cu->nurb); ct= chartransdata; if (cu->sepchar==0) { - for (i= 0; i<slen; i++) { - cha = (uintptr_t) mem[i]; - info = &(cu->strinfo[i]); - if (info->mat_nr > (ob->totcol)) { - /* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */ - info->mat_nr = 0; - } + for (i= 0; i<slen; i++) { + cha = (uintptr_t) mem[i]; + info = &(custrinfo[i]); + if (info->mat_nr > (ob->totcol)) { + /* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */ + info->mat_nr = 0; + } // We do not want to see any character for \n or \r if(cha != '\n' && cha != '\r') buildchar(cu, cha, info, ct->xof, ct->yof, ct->rot, i); + if ((info->flag & CU_UNDERLINE) && (cu->textoncurve == NULL) && (cha != '\n') && (cha != '\r')) { - uloverlap = 0; + float ulwidth, uloverlap= 0.0f; + if ( (i<(slen-1)) && (mem[i+1] != '\n') && (mem[i+1] != '\r') && - ((mem[i+1] != ' ') || (cu->strinfo[i+1].flag & CU_UNDERLINE)) && ((cu->strinfo[i+1].flag & CU_WRAP)==0) - ) { + ((mem[i+1] != ' ') || (custrinfo[i+1].flag & CU_UNDERLINE)) && ((custrinfo[i+1].flag & CU_WRAP)==0) + ) { uloverlap = xtrax + 0.1; } // Find the character, the characters has to be in the memory already // since character checking has been done earlier already. che = vfd->characters.first; - while(che) - { + while(che) { if(che->index == cha) break; che = che->next; } - + if(!che) twidth =0; else twidth=che->width; ulwidth = cu->fsize * ((twidth* (1.0+(info->kern/40.0)))+uloverlap); build_underline(cu, ct->xof*cu->fsize, ct->yof*cu->fsize + (cu->ulpos-0.05)*cu->fsize, - ct->xof*cu->fsize + ulwidth, - ct->yof*cu->fsize + (cu->ulpos-0.05)*cu->fsize - cu->ulheight*cu->fsize, - i, info->mat_nr); + ct->xof*cu->fsize + ulwidth, + ct->yof*cu->fsize + (cu->ulpos-0.05)*cu->fsize - cu->ulheight*cu->fsize, + i, info->mat_nr); } - ct++; - } + ct++; + } } else { - outta = 0; - for (i= 0; (i<slen) && (outta==0); i++) { - ascii = mem[i]; - info = &(cu->strinfo[i]); + int outta = 0; + for (i= 0; (i<slen) && (outta==0); i++) { + ascii = mem[i]; + info = &(custrinfo[i]); if (cu->sepchar == (i+1)) { + float vecyo[3]; + mem[0] = ascii; mem[1] = 0; - cu->strinfo[0]= *info; + custrinfo[0]= *info; cu->pos = 1; cu->len = 1; vecyo[0] = ct->xof; @@ -1186,10 +1202,10 @@ struct chartrans *text_to_curve(Object *ob, int mode) outta = 1; cu->sepchar = 0; } - ct++; + ct++; + } } } - } if(mode==FO_DUPLI) { MEM_freeN(mem); diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c new file mode 100644 index 00000000000..dd8f44c71d5 --- /dev/null +++ b/source/blender/blenkernel/intern/gpencil.c @@ -0,0 +1,516 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2008, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "DNA_listBase.h" +#include "DNA_gpencil_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_userdef_types.h" +#include "DNA_vec_types.h" + +#include "BKE_blender.h" +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_gpencil.h" +#include "BKE_image.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_utildefines.h" + + +/* ************************************************** */ +/* GENERAL STUFF */ + +/* --------- Memory Management ------------ */ + +/* Free strokes belonging to a gp-frame */ +void free_gpencil_strokes (bGPDframe *gpf) +{ + bGPDstroke *gps, *gpsn; + + /* error checking */ + if (gpf == NULL) return; + + /* free strokes */ + for (gps= gpf->strokes.first; gps; gps= gpsn) { + gpsn= gps->next; + + /* free stroke memory arrays, then stroke itself */ + if (gps->points) MEM_freeN(gps->points); + BLI_freelinkN(&gpf->strokes, gps); + } +} + +/* Free all of a gp-layer's frames */ +void free_gpencil_frames (bGPDlayer *gpl) +{ + bGPDframe *gpf, *gpfn; + + /* error checking */ + if (gpl == NULL) return; + + /* free frames */ + for (gpf= gpl->frames.first; gpf; gpf= gpfn) { + gpfn= gpf->next; + + /* free strokes and their associated memory */ + free_gpencil_strokes(gpf); + BLI_freelinkN(&gpl->frames, gpf); + } +} + +/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */ +void free_gpencil_layers (ListBase *list) +{ + bGPDlayer *gpl, *gpln; + + /* error checking */ + if (list == NULL) return; + + /* delete layers*/ + for (gpl= list->first; gpl; gpl= gpln) { + gpln= gpl->next; + + /* free layers and their data */ + free_gpencil_frames(gpl); + BLI_freelinkN(list, gpl); + } +} + +/* Free all of GPencil datablock's related data, but not the block itself */ +void free_gpencil_data (bGPdata *gpd) +{ + /* free layers */ + free_gpencil_layers(&gpd->layers); +} + +/* -------- Container Creation ---------- */ + +/* add a new gp-frame to the given layer */ +bGPDframe *gpencil_frame_addnew (bGPDlayer *gpl, int cframe) +{ + bGPDframe *gpf, *gf; + short state=0; + + /* error checking */ + if ((gpl == NULL) || (cframe <= 0)) + return NULL; + + /* allocate memory for this frame */ + gpf= MEM_callocN(sizeof(bGPDframe), "bGPDframe"); + gpf->framenum= cframe; + + /* find appropriate place to add frame */ + if (gpl->frames.first) { + for (gf= gpl->frames.first; gf; gf= gf->next) { + /* check if frame matches one that is supposed to be added */ + if (gf->framenum == cframe) { + state= -1; + break; + } + + /* if current frame has already exceeded the frame to add, add before */ + if (gf->framenum > cframe) { + BLI_insertlinkbefore(&gpl->frames, gf, gpf); + state= 1; + break; + } + } + } + + /* check whether frame was added successfully */ + if (state == -1) { + MEM_freeN(gpf); + printf("Error: frame (%d) existed already for this layer \n", cframe); + } + else if (state == 0) { + /* add to end then! */ + BLI_addtail(&gpl->frames, gpf); + } + + /* return frame */ + return gpf; +} + +/* add a new gp-layer and make it the active layer */ +bGPDlayer *gpencil_layer_addnew (bGPdata *gpd) +{ + bGPDlayer *gpl; + + /* check that list is ok */ + if (gpd == NULL) + return NULL; + + /* allocate memory for frame and add to end of list */ + gpl= MEM_callocN(sizeof(bGPDlayer), "bGPDlayer"); + + /* add to datablock */ + BLI_addtail(&gpd->layers, gpl); + + /* set basic settings */ + gpl->color[3]= 0.9f; + gpl->thickness = 3; + + /* auto-name */ + sprintf(gpl->info, "GP_Layer"); + BLI_uniquename(&gpd->layers, gpl, "GP_Layer", '.', offsetof(bGPDlayer, info[0]), 128); + + /* make this one the active one */ + gpencil_layer_setactive(gpd, gpl); + + /* return layer */ + return gpl; +} + +/* add a new gp-datablock */ +bGPdata *gpencil_data_addnew (char name[]) +{ + bGPdata *gpd; + + /* allocate memory for a new block */ + gpd= alloc_libblock(&G.main->gpencil, ID_GD, name); + + /* initial settings */ + gpd->flag = (GP_DATA_DISPINFO|GP_DATA_EXPAND); + + return gpd; +} + +/* -------- Data Duplication ---------- */ + +/* make a copy of a given gpencil frame */ +bGPDframe *gpencil_frame_duplicate (bGPDframe *src) +{ + bGPDstroke *gps, *gpsd; + bGPDframe *dst; + + /* error checking */ + if (src == NULL) + return NULL; + + /* make a copy of the source frame */ + dst= MEM_dupallocN(src); + dst->prev= dst->next= NULL; + + /* copy strokes */ + dst->strokes.first = dst->strokes.last= NULL; + for (gps= src->strokes.first; gps; gps= gps->next) { + /* make copy of source stroke, then adjust pointer to points too */ + gpsd= MEM_dupallocN(gps); + gpsd->points= MEM_dupallocN(gps->points); + + BLI_addtail(&dst->strokes, gpsd); + } + + /* return new frame */ + return dst; +} + +/* make a copy of a given gpencil layer */ +bGPDlayer *gpencil_layer_duplicate (bGPDlayer *src) +{ + bGPDframe *gpf, *gpfd; + bGPDlayer *dst; + + /* error checking */ + if (src == NULL) + return NULL; + + /* make a copy of source layer */ + dst= MEM_dupallocN(src); + dst->prev= dst->next= NULL; + + /* copy frames */ + dst->frames.first= dst->frames.last= NULL; + for (gpf= src->frames.first; gpf; gpf= gpf->next) { + /* make a copy of source frame */ + gpfd= gpencil_frame_duplicate(gpf); + BLI_addtail(&dst->frames, gpfd); + + /* if source frame was the current layer's 'active' frame, reassign that too */ + if (gpf == dst->actframe) + dst->actframe= gpfd; + } + + /* return new layer */ + return dst; +} + +/* make a copy of a given gpencil datablock */ +bGPdata *gpencil_data_duplicate (bGPdata *src) +{ + bGPDlayer *gpl, *gpld; + bGPdata *dst; + + /* error checking */ + if (src == NULL) + return NULL; + + /* make a copy of the base-data */ + dst= MEM_dupallocN(src); + + /* copy layers */ + dst->layers.first= dst->layers.last= NULL; + for (gpl= src->layers.first; gpl; gpl= gpl->next) { + /* make a copy of source layer and its data */ + gpld= gpencil_layer_duplicate(gpl); + BLI_addtail(&dst->layers, gpld); + } + + /* return new */ + return dst; +} + +/* -------- GP-Frame API ---------- */ + +/* delete the last stroke of the given frame */ +void gpencil_frame_delete_laststroke (bGPDlayer *gpl, bGPDframe *gpf) +{ + bGPDstroke *gps= (gpf) ? gpf->strokes.last : NULL; + int cfra = 1; // XXX FIXME!!! + + /* error checking */ + if (ELEM(NULL, gpf, gps)) + return; + + /* free the stroke and its data */ + MEM_freeN(gps->points); + BLI_freelinkN(&gpf->strokes, gps); + + /* if frame has no strokes after this, delete it */ + if (gpf->strokes.first == NULL) { + gpencil_layer_delframe(gpl, gpf); + gpencil_layer_getframe(gpl, cfra, 0); + } +} + +/* -------- GP-Layer API ---------- */ + +/* get the appropriate gp-frame from a given layer + * - this sets the layer's actframe var (if allowed to) + * - extension beyond range (if first gp-frame is after all frame in interest and cannot add) + */ +bGPDframe *gpencil_layer_getframe (bGPDlayer *gpl, int cframe, short addnew) +{ + bGPDframe *gpf = NULL; + short found = 0; + + /* error checking */ + if (gpl == NULL) return NULL; + if (cframe <= 0) cframe = 1; + + /* check if there is already an active frame */ + if (gpl->actframe) { + gpf= gpl->actframe; + + /* do not allow any changes to layer's active frame if layer is locked */ + if (gpl->flag & GP_LAYER_LOCKED) + return gpf; + /* do not allow any changes to actframe if frame has painting tag attached to it */ + if (gpf->flag & GP_FRAME_PAINT) + return gpf; + + /* try to find matching frame */ + if (gpf->framenum < cframe) { + for (; gpf; gpf= gpf->next) { + if (gpf->framenum == cframe) { + found= 1; + break; + } + else if ((gpf->next) && (gpf->next->framenum > cframe)) { + found= 1; + break; + } + } + + /* set the appropriate frame */ + if (addnew) { + if ((found) && (gpf->framenum == cframe)) + gpl->actframe= gpf; + else + gpl->actframe= gpencil_frame_addnew(gpl, cframe); + } + else if (found) + gpl->actframe= gpf; + else + gpl->actframe= gpl->frames.last; + } + else { + for (; gpf; gpf= gpf->prev) { + if (gpf->framenum <= cframe) { + found= 1; + break; + } + } + + /* set the appropriate frame */ + if (addnew) { + if ((found) && (gpf->framenum == cframe)) + gpl->actframe= gpf; + else + gpl->actframe= gpencil_frame_addnew(gpl, cframe); + } + else if (found) + gpl->actframe= gpf; + else + gpl->actframe= gpl->frames.first; + } + } + else if (gpl->frames.first) { + /* check which of the ends to start checking from */ + const int first= ((bGPDframe *)(gpl->frames.first))->framenum; + const int last= ((bGPDframe *)(gpl->frames.last))->framenum; + + if (abs(cframe-first) > abs(cframe-last)) { + /* find gp-frame which is less than or equal to cframe */ + for (gpf= gpl->frames.last; gpf; gpf= gpf->prev) { + if (gpf->framenum <= cframe) { + found= 1; + break; + } + } + } + else { + /* find gp-frame which is less than or equal to cframe */ + for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { + if (gpf->framenum <= cframe) { + found= 1; + break; + } + } + } + + /* set the appropriate frame */ + if (addnew) { + if ((found) && (gpf->framenum == cframe)) + gpl->actframe= gpf; + else + gpl->actframe= gpencil_frame_addnew(gpl, cframe); + } + else if (found) + gpl->actframe= gpf; + else { + /* unresolved errogenous situation! */ + printf("Error: cannot find appropriate gp-frame \n"); + /* gpl->actframe should still be NULL */ + } + } + else { + /* currently no frames (add if allowed to) */ + if (addnew) + gpl->actframe= gpencil_frame_addnew(gpl, cframe); + else { + /* don't do anything... this may be when no frames yet! */ + /* gpl->actframe should still be NULL */ + } + } + + /* return */ + return gpl->actframe; +} + +/* delete the given frame from a layer */ +void gpencil_layer_delframe (bGPDlayer *gpl, bGPDframe *gpf) +{ + /* error checking */ + if (ELEM(NULL, gpl, gpf)) + return; + + /* free the frame and its data */ + free_gpencil_strokes(gpf); + BLI_freelinkN(&gpl->frames, gpf); + gpl->actframe = NULL; +} + +/* get the active gp-layer for editing */ +bGPDlayer *gpencil_layer_getactive (bGPdata *gpd) +{ + bGPDlayer *gpl; + + /* error checking */ + if (ELEM(NULL, gpd, gpd->layers.first)) + return NULL; + + /* loop over layers until found (assume only one active) */ + for (gpl=gpd->layers.first; gpl; gpl=gpl->next) { + if (gpl->flag & GP_LAYER_ACTIVE) + return gpl; + } + + /* no active layer found */ + return NULL; +} + +/* set the active gp-layer */ +void gpencil_layer_setactive (bGPdata *gpd, bGPDlayer *active) +{ + bGPDlayer *gpl; + + /* error checking */ + if (ELEM3(NULL, gpd, gpd->layers.first, active)) + return; + + /* loop over layers deactivating all */ + for (gpl=gpd->layers.first; gpl; gpl=gpl->next) + gpl->flag &= ~GP_LAYER_ACTIVE; + + /* set as active one */ + active->flag |= GP_LAYER_ACTIVE; +} + +/* delete the active gp-layer */ +void gpencil_layer_delactive (bGPdata *gpd) +{ + bGPDlayer *gpl= gpencil_layer_getactive(gpd); + + /* error checking */ + if (ELEM(NULL, gpd, gpl)) + return; + + /* free layer */ + free_gpencil_frames(gpl); + BLI_freelinkN(&gpd->layers, gpl); +} + +/* ************************************************** */ diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 0d2f86bb151..6fffbd794ef 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -280,7 +280,7 @@ static void group_replaces_nla(Object *parent, Object *target, char mode) you can draw everything, leaves tags in objects to signal it needs further updating */ /* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */ -void group_handle_recalc_and_update(Object *parent, Group *group) +void group_handle_recalc_and_update(Scene *scene, Object *parent, Group *group) { GroupObject *go; @@ -289,8 +289,8 @@ void group_handle_recalc_and_update(Object *parent, Group *group) int cfrao; /* switch to local time */ - cfrao= G.scene->r.cfra; - G.scene->r.cfra -= (int)give_timeoffset(parent); + cfrao= scene->r.cfra; + scene->r.cfra -= (int)give_timeoffset(parent); /* we need a DAG per group... */ for(go= group->gobject.first; go; go= go->next) { @@ -298,7 +298,7 @@ void group_handle_recalc_and_update(Object *parent, Group *group) go->ob->recalc= go->recalc; group_replaces_nla(parent, go->ob, 's'); - object_handle_update(go->ob); + object_handle_update(scene, go->ob); group_replaces_nla(parent, go->ob, 'e'); /* leave recalc tags in case group members are in normal scene */ @@ -307,14 +307,14 @@ void group_handle_recalc_and_update(Object *parent, Group *group) } /* restore */ - G.scene->r.cfra= cfrao; + scene->r.cfra= cfrao; } else { /* only do existing tags, as set by regular depsgraph */ for(go= group->gobject.first; go; go= go->next) { if(go->ob) { if(go->ob->recalc) { - object_handle_update(go->ob); + object_handle_update(scene, go->ob); } } } diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 79ecbf09f55..54366aadd92 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -25,6 +25,10 @@ * ***** END GPL LICENSE BLOCK ***** */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + #include "DNA_listBase.h" #include "DNA_ID.h" @@ -37,10 +41,6 @@ #include "MEM_guardedalloc.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - #define BSTR_EQ(a, b) (*(a) == *(b) && !strcmp(a, b)) /* IDPropertyTemplate is a union in DNA_ID.h */ @@ -58,8 +58,153 @@ static char idp_size_table[] = { sizeof(double) }; +/* ------------Property Array Type ----------- */ +#define GETPROP(prop, i) (((IDProperty*)(prop)->data.pointer)+(i)) + +/* --------- property array type -------------*/ + +/*note: as a start to move away from the stupid IDP_New function, this type + has it's own allocation function.*/ +IDProperty *IDP_NewIDPArray(const char *name) +{ + IDProperty *prop = MEM_callocN(sizeof(IDProperty), "IDProperty prop array"); + prop->type = IDP_IDPARRAY; + prop->len = 0; + BLI_strncpy(prop->name, name, MAX_IDPROP_NAME); + + return prop; +} + +IDProperty *IDP_CopyIDPArray(IDProperty *array) +{ + IDProperty *narray = MEM_dupallocN(array), *tmp; + int i; + + narray->data.pointer = MEM_dupallocN(array->data.pointer); + for (i=0; i<narray->len; i++) { + /*ok, the copy functions always allocate a new structure, + which doesn't work here. instead, simply copy the + contents of the new structure into the array cell, + then free it. this makes for more maintainable + code than simply reimplementing the copy functions + in this loop.*/ + tmp = IDP_CopyProperty(GETPROP(narray, i)); + memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty)); + MEM_freeN(tmp); + } + + return narray; +} + +void IDP_FreeIDPArray(IDProperty *prop) +{ + int i; + + for (i=0; i<prop->len; i++) + IDP_FreeProperty(GETPROP(prop, i)); + + if(prop->data.pointer) + MEM_freeN(prop->data.pointer); +} + +/*shallow copies item*/ +void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item) +{ + IDProperty *old = GETPROP(prop, index); + if (index >= prop->len || index < 0) return; + if (item != old) IDP_FreeProperty(old); + + memcpy(GETPROP(prop, index), item, sizeof(IDProperty)); +} + +IDProperty *IDP_GetIndexArray(IDProperty *prop, int index) +{ + return GETPROP(prop, index); +} + +IDProperty *IDP_AppendArray(IDProperty *prop, IDProperty *item) +{ + IDP_ResizeIDPArray(prop, prop->len+1); + IDP_SetIndexArray(prop, prop->len-1, item); + return item; +} + +void IDP_ResizeIDPArray(IDProperty *prop, int newlen) +{ + void *newarr; + int newsize=newlen; + + /*first check if the array buffer size has room*/ + /*if newlen is 200 chars less then totallen, reallocate anyway*/ + if (newlen <= prop->totallen && prop->totallen - newlen < 200) { + int i; + + for(i=newlen; i<prop->len; i++) + IDP_FreeProperty(GETPROP(prop, i)); + + prop->len = newlen; + return; + } + + /* - Note: This code comes from python, here's the corrusponding comment. - */ + /* This over-allocates proportional to the list size, making room + * for additional growth. The over-allocation is mild, but is + * enough to give linear-time amortized behavior over a long + * sequence of appends() in the presence of a poorly-performing + * system realloc(). + * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... + */ + newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; + + newarr = MEM_callocN(sizeof(IDProperty)*newsize, "idproperty array resized"); + if (newlen >= prop->len) { + /* newlen is bigger*/ + memcpy(newarr, prop->data.pointer, prop->len*sizeof(IDProperty)); + } + else { + int i; + /* newlen is smaller*/ + for (i=newlen; i<prop->len; i++) { + IDP_FreeProperty(GETPROP(prop, i)); + } + memcpy(newarr, prop->data.pointer, newlen*prop->len*sizeof(IDProperty)); + } -/* ----------- Array Type ----------- */ + if(prop->data.pointer) + MEM_freeN(prop->data.pointer); + prop->data.pointer = newarr; + prop->len = newlen; + prop->totallen = newsize; +} + +/* ----------- Numerical Array Type ----------- */ +static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) +{ + if(prop->subtype != IDP_GROUP) + return; + + if(newlen >= prop->len) { + /* bigger */ + IDProperty **array= newarr; + IDPropertyTemplate val; + int a; + + for(a=prop->len; a<newlen; a++) { + val.i = 0; /* silence MSVC warning about uninitialized var when debugging */ + array[a]= IDP_New(IDP_GROUP, val, "IDP_ResizeArray group"); + } + } + else { + /* smaller */ + IDProperty **array= prop->data.pointer; + int a; + + for(a=newlen; a<prop->len; a++) { + IDP_FreeProperty(array[a]); + MEM_freeN(array[a]); + } + } +} /*this function works for strings too!*/ void IDP_ResizeArray(IDProperty *prop, int newlen) @@ -70,6 +215,7 @@ void IDP_ResizeArray(IDProperty *prop, int newlen) /*first check if the array buffer size has room*/ /*if newlen is 200 chars less then totallen, reallocate anyway*/ if (newlen <= prop->totallen && prop->totallen - newlen < 200) { + idp_resize_group_array(prop, newlen, prop->data.pointer); prop->len = newlen; return; } @@ -84,11 +230,17 @@ void IDP_ResizeArray(IDProperty *prop, int newlen) */ newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; - newarr = MEM_callocN(idp_size_table[prop->type]*newsize, "idproperty array resized"); - /*newlen is bigger*/ - if (newlen >= prop->len) memcpy(newarr, prop->data.pointer, prop->len*idp_size_table[prop->type]); - /*newlen is smaller*/ - else memcpy(newarr, prop->data.pointer, newlen*prop->len*idp_size_table[prop->type]); + newarr = MEM_callocN(idp_size_table[(int)prop->subtype]*newsize, "idproperty array resized"); + if (newlen >= prop->len) { + /* newlen is bigger*/ + memcpy(newarr, prop->data.pointer, prop->len*idp_size_table[(int)prop->subtype]); + idp_resize_group_array(prop, newlen, newarr); + } + else { + /* newlen is smaller*/ + idp_resize_group_array(prop, newlen, newarr); + memcpy(newarr, prop->data.pointer, newlen*prop->len*idp_size_table[(int)prop->subtype]); + } MEM_freeN(prop->data.pointer); prop->data.pointer = newarr; @@ -96,10 +248,12 @@ void IDP_ResizeArray(IDProperty *prop, int newlen) prop->totallen = newsize; } - void IDP_FreeArray(IDProperty *prop) +void IDP_FreeArray(IDProperty *prop) { - if (prop->data.pointer) + if (prop->data.pointer) { + idp_resize_group_array(prop, 0, NULL); MEM_freeN(prop->data.pointer); + } } @@ -107,7 +261,7 @@ void IDP_ResizeArray(IDProperty *prop, int newlen) { IDProperty *newp = MEM_callocN(sizeof(IDProperty), "IDProperty array dup"); - strncpy(newp->name, prop->name, MAX_IDPROP_NAME); + BLI_strncpy(newp->name, prop->name, MAX_IDPROP_NAME); newp->type = prop->type; newp->flag = prop->flag; newp->data.val = prop->data.val; @@ -120,7 +274,17 @@ IDProperty *IDP_CopyArray(IDProperty *prop) { IDProperty *newp = idp_generic_copy(prop); - if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer); + if (prop->data.pointer) { + newp->data.pointer = MEM_dupallocN(prop->data.pointer); + + if(prop->type == IDP_GROUP) { + IDProperty **array= newp->data.pointer; + int a; + + for(a=0; a<prop->len; a++) + array[a]= IDP_CopyProperty(array[a]); + } + } newp->len = prop->len; newp->subtype = prop->subtype; newp->totallen = prop->totallen; @@ -187,7 +351,8 @@ void IDP_ConcatString(IDProperty *str1, IDProperty *append) void IDP_FreeString(IDProperty *prop) { - MEM_freeN(prop->data.pointer); + if(prop->data.pointer) + MEM_freeN(prop->data.pointer); } @@ -341,6 +506,7 @@ IDProperty *IDP_CopyProperty(IDProperty *prop) case IDP_GROUP: return IDP_CopyGroup(prop); case IDP_STRING: return IDP_CopyString(prop); case IDP_ARRAY: return IDP_CopyArray(prop); + case IDP_IDPARRAY: return IDP_CopyIDPArray(prop); default: return idp_generic_copy(prop); } } @@ -361,7 +527,61 @@ IDProperty *IDP_GetProperties(ID *id, int create_if_needed) } } -IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name) +int IDP_EqualsProperties(IDProperty *prop1, IDProperty *prop2) +{ + if(prop1 == NULL && prop2 == NULL) + return 1; + else if(prop1 == NULL || prop2 == NULL) + return 0; + else if(prop1->type != prop2->type) + return 0; + + if(prop1->type == IDP_INT) + return (IDP_Int(prop1) == IDP_Int(prop2)); + else if(prop1->type == IDP_FLOAT) + return (IDP_Float(prop1) == IDP_Float(prop2)); + else if(prop1->type == IDP_DOUBLE) + return (IDP_Double(prop1) == IDP_Double(prop2)); + else if(prop1->type == IDP_STRING) + return BSTR_EQ(IDP_String(prop1), IDP_String(prop2)); + else if(prop1->type == IDP_ARRAY) { + if(prop1->len == prop2->len && prop1->subtype == prop2->subtype) + return memcmp(IDP_Array(prop1), IDP_Array(prop2), idp_size_table[(int)prop1->subtype]*prop1->len); + else + return 0; + } + else if(prop1->type == IDP_GROUP) { + IDProperty *link1, *link2; + + if(BLI_countlist(&prop1->data.group) != BLI_countlist(&prop2->data.group)) + return 0; + + for(link1=prop1->data.group.first; link1; link1=link1->next) { + link2= IDP_GetPropertyFromGroup(prop2, link1->name); + + if(!IDP_EqualsProperties(link1, link2)) + return 0; + } + + return 1; + } + else if(prop1->type == IDP_IDPARRAY) { + IDProperty *array1= IDP_IDPArray(prop1); + IDProperty *array2= IDP_IDPArray(prop2); + int i; + + if(prop1->len != prop2->len) + return 0; + + for(i=0; i<prop1->len; i++) + if(!IDP_EqualsProperties(&array1[i], &array2[i])) + return 0; + } + + return 1; +} + +IDProperty *IDP_New(int type, IDPropertyTemplate val, const char *name) { IDProperty *prop=NULL; @@ -381,11 +601,12 @@ IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name) case IDP_ARRAY: { /*for now, we only support float and int and double arrays*/ - if (val.array.type == IDP_FLOAT || val.array.type == IDP_INT || val.array.type == IDP_DOUBLE) { + if (val.array.type == IDP_FLOAT || val.array.type == IDP_INT || val.array.type == IDP_DOUBLE || val.array.type == IDP_GROUP) { prop = MEM_callocN(sizeof(IDProperty), "IDProperty array"); - prop->len = prop->totallen = val.array.len; prop->subtype = val.array.type; - prop->data.pointer = MEM_callocN(idp_size_table[val.array.type]*val.array.len, "id property array"); + if (val.array.len) + prop->data.pointer = MEM_callocN(idp_size_table[val.array.type]*val.array.len, "id property array"); + prop->len = prop->totallen = val.array.len; break; } else { return NULL; @@ -423,7 +644,7 @@ IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name) } prop->type = type; - strncpy(prop->name, name, MAX_IDPROP_NAME); + BLI_strncpy(prop->name, name, MAX_IDPROP_NAME); /*security null byte*/ prop->name[MAX_IDPROP_NAME-1] = 0; @@ -446,6 +667,9 @@ void IDP_FreeProperty(IDProperty *prop) case IDP_GROUP: IDP_FreeGroup(prop); break; + case IDP_IDPARRAY: + IDP_FreeIDPArray(prop); + break; } } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 444c7c080ea..62af05fbc9a 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -21,9 +21,7 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * The Original Code is: all of this file. - * - * Contributor(s): Blender Foundation, 2006 + * Contributor(s): Blender Foundation, 2006, full recode * * ***** END GPL LICENSE BLOCK ***** */ @@ -55,6 +53,7 @@ #include "DNA_camera_types.h" #include "DNA_sequence_types.h" #include "DNA_texture_types.h" +#include "DNA_sequence_types.h" #include "DNA_userdef_types.h" #include "BLI_arithb.h" @@ -72,18 +71,12 @@ #include "BKE_texture.h" #include "BKE_utildefines.h" -#include "BIF_editseq.h" +//XXX #include "BIF_editseq.h" #include "PIL_time.h" #include "RE_pipeline.h" -/* for stamp drawing to an image */ -#include "BMF_Api.h" - -#include "blendef.h" -#include "BSE_time.h" - #include "GPU_extensions.h" #include "GPU_draw.h" @@ -95,6 +88,7 @@ /* quick lookup: supports 1 million frames, thousand passes */ #define IMA_MAKE_INDEX(frame, index) ((frame)<<10)+index #define IMA_INDEX_FRAME(index) (index>>10) +#define IMA_INDEX_PASS(index) (index & ~1023) /* ******** IMAGE PROCESSING ************* */ @@ -259,6 +253,10 @@ void free_image(Image *ima) if (ima->preview) { BKE_previewimg_free(&ima->preview); } + if (ima->render_text) { + MEM_freeN(ima->render_text); + ima->render_text= NULL; + } } /* only image block itself */ @@ -336,10 +334,42 @@ static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame) } } +/* empty image block, of similar type and filename */ +Image *BKE_image_copy(Image *ima) +{ + Image *new= image_alloc(ima->id.name+2, ima->source, ima->type); + + BLI_strncpy(new->name, ima->name, sizeof(ima->name)); + + new->gen_x= ima->gen_x; + new->gen_y= ima->gen_y; + new->gen_type= ima->gen_type; + + return new; +} + +void BKE_image_merge(Image *dest, Image *source) +{ + ImBuf *ibuf; + + /* sanity check */ + if(dest && source && dest!=source) { + + while((ibuf= source->ibufs.first)) { + BLI_remlink(&source->ibufs, ibuf); + image_assign_ibuf(dest, ibuf, IMA_INDEX_PASS(ibuf->index), IMA_INDEX_FRAME(ibuf->index)); + } + + free_libblock(&G.main->image, source); + } +} + + /* checks if image was already loaded, then returns same image */ /* otherwise creates new. */ /* does not load ibuf itself */ -Image *BKE_add_image_file(const char *name) +/* pass on optional frame for #name images */ +Image *BKE_add_image_file(const char *name, int frame) { Image *ima; int file, len; @@ -355,7 +385,7 @@ Image *BKE_add_image_file(const char *name) BLI_strncpy(str, name, sizeof(str)); BLI_convertstringcode(str, G.sce); - BLI_convertstringframe(str, G.scene->r.cfra); /* TODO - should this realy be here? */ + BLI_convertstringframe(str, frame); /* exists? */ file= open(str, O_BINARY|O_RDONLY); @@ -367,7 +397,7 @@ Image *BKE_add_image_file(const char *name) if(ima->source!=IMA_SRC_VIEWER && ima->source!=IMA_SRC_GENERATED) { BLI_strncpy(strtest, ima->name, sizeof(ima->name)); BLI_convertstringcode(strtest, G.sce); - BLI_convertstringframe(strtest, G.scene->r.cfra); /* TODO - should this be here? */ + BLI_convertstringframe(strtest, frame); if( strcmp(strtest, str)==0 ) { if(ima->anim==NULL || ima->id.us==0) { @@ -418,7 +448,7 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, sho rect= (unsigned char*)ibuf->rect; } - strcpy(ibuf->name, "Untitled"); + strcpy(ibuf->name, "//Untitled"); ibuf->userflags |= IB_BITMAPDIRTY; if (uvtestgrid) { @@ -426,19 +456,19 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, sho * easy to tweak like this, speed isn't really that much of an issue in this situation... */ /* checkers */ - for(y=0; y<ibuf->y; y++) { - dark = pow(-1, floor(y / checkerwidth)); + for(y=0; y<height; y++) { + dark = powf(-1.0f, floorf(y / checkerwidth)); - for(x=0; x<ibuf->x; x++) { + for(x=0; x<width; x++) { if (x % checkerwidth == 0) dark *= -1; if (floatbuf) { if (dark > 0) { - rect_float[0] = rect_float[1] = rect_float[2] = 0.25; - rect_float[3] = 1.0; + rect_float[0] = rect_float[1] = rect_float[2] = 0.25f; + rect_float[3] = 1.0f; } else { - rect_float[0] = rect_float[1] = rect_float[2] = 0.58; - rect_float[3] = 1.0; + rect_float[0] = rect_float[1] = rect_float[2] = 0.58f; + rect_float[3] = 1.0f; } rect_float+=4; } @@ -459,11 +489,11 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, sho if (floatbuf) rect_float= (float*)ibuf->rect_float; else rect= (unsigned char*)ibuf->rect; - for(y=0; y<ibuf->y; y++) { - hoffs = 0.125 * floor(y / checkerwidth); + for(y=0; y<height; y++) { + hoffs = 0.125f * floorf(y / checkerwidth); - for(x=0; x<ibuf->x; x++) { - h = 0.125 * floor(x / checkerwidth); + for(x=0; x<width; x++) { + h = 0.125f * floorf(x / checkerwidth); if ((fabs((x % checkerwidth) - (checkerwidth / 2)) < 4) && (fabs((y % checkerwidth) - (checkerwidth / 2)) < 4)) { @@ -471,19 +501,19 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, sho if ((fabs((x % checkerwidth) - (checkerwidth / 2)) < 1) || (fabs((y % checkerwidth) - (checkerwidth / 2)) < 1)) { - hue = fmod(fabs(h-hoffs), 1.0); + hue = fmodf(fabs(h-hoffs), 1.0f); hsv_to_rgb(hue, s, v, &r, &g, &b); if (floatbuf) { rect_float[0]= r; rect_float[1]= g; rect_float[2]= b; - rect_float[3]= 1.0; + rect_float[3]= 1.0f; } else { - rect[0]= (char)(r * 255.0); - rect[1]= (char)(g * 255.0); - rect[2]= (char)(b * 255.0); + rect[0]= (char)(r * 255.0f); + rect[1]= (char)(g * 255.0f); + rect[2]= (char)(b * 255.0f); rect[3]= 255; } } @@ -496,8 +526,15 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, sho } } } else { /* blank image */ - for(y=0; y<ibuf->y; y++) { - for(x=0; x<ibuf->x; x++) { + char ccol[4]; + + ccol[0]= (char)(color[0]*255.0f); + ccol[1]= (char)(color[1]*255.0f); + ccol[2]= (char)(color[2]*255.0f); + ccol[3]= (char)(color[3]*255.0f); + + for(y=0; y<height; y++) { + for(x=0; x<width; x++) { if (floatbuf) { rect_float[0]= color[0]; rect_float[1]= color[1]; @@ -506,10 +543,10 @@ static ImBuf *add_ibuf_size(int width, int height, char *name, int floatbuf, sho rect_float+=4; } else { - rect[0]= (char)(color[0] * 255.0); - rect[1]= (char)(color[1] * 255.0); - rect[2]= (char)(color[2] * 255.0); - rect[3]= (char)(color[3] * 255.0); + rect[0]= ccol[0]; + rect[1]= ccol[1]; + rect[2]= ccol[2]; + rect[3]= ccol[3]; rect+=4; } } @@ -585,6 +622,7 @@ void tag_image_time(Image *ima) ima->lastused = (int)PIL_check_seconds_timer(); } +#if 0 static void tag_all_images_time() { Image *ima; @@ -597,6 +635,7 @@ static void tag_all_images_time() } } } +#endif void free_old_images() { @@ -828,17 +867,20 @@ int BKE_imtype_is_movie(int imtype) case R_AVICODEC: case R_QUICKTIME: case R_FFMPEG: + case R_H264: + case R_THEORA: + case R_XVID: case R_FRAMESERVER: return 1; } return 0; } -void BKE_add_image_extension(char *string, int imtype) +void BKE_add_image_extension(Scene *scene, char *string, int imtype) { char *extension=""; - if(G.scene->r.imtype== R_IRIS) { + if(imtype== R_IRIS) { if(!BLI_testextensie(string, ".rgb")) extension= ".rgb"; } @@ -850,7 +892,7 @@ void BKE_add_image_extension(char *string, int imtype) if(!BLI_testextensie(string, ".hdr")) extension= ".hdr"; } - else if(imtype==R_PNG || imtype==R_FFMPEG) { + else if (ELEM5(imtype, R_PNG, R_FFMPEG, R_H264, R_THEORA, R_XVID)) { if(!BLI_testextensie(string, ".png")) extension= ".png"; } @@ -917,7 +959,7 @@ typedef struct StampData { char strip[64]; } StampData; -static void stampdata(StampData *stamp_data, int do_prefix) +static void stampdata(Scene *scene, StampData *stamp_data, int do_prefix) { char text[256]; @@ -928,7 +970,7 @@ static void stampdata(StampData *stamp_data, int do_prefix) char sdate[9]; #endif /* WIN32 */ - if (G.scene->r.stamp & R_STAMP_FILENAME) { + if (scene->r.stamp & R_STAMP_FILENAME) { if (G.relbase_valid) { if (do_prefix) sprintf(stamp_data->file, "File %s", G.sce); else sprintf(stamp_data->file, "%s", G.sce); @@ -941,14 +983,14 @@ static void stampdata(StampData *stamp_data, int do_prefix) stamp_data->file[0] = '\0'; } - if (G.scene->r.stamp & R_STAMP_NOTE) { + if (scene->r.stamp & R_STAMP_NOTE) { /* Never do prefix for Note */ - sprintf(stamp_data->note, "%s", G.scene->r.stamp_udata); + sprintf(stamp_data->note, "%s", scene->r.stamp_udata); } else { stamp_data->note[0] = '\0'; } - if (G.scene->r.stamp & R_STAMP_DATE) { + if (scene->r.stamp & R_STAMP_DATE) { #ifdef WIN32 _strdate (sdate); sprintf (text, "%s", sdate); @@ -963,8 +1005,8 @@ static void stampdata(StampData *stamp_data, int do_prefix) stamp_data->date[0] = '\0'; } - if (G.scene->r.stamp & R_STAMP_MARKER) { - TimeMarker *marker = get_frame_marker(CFRA); + if (scene->r.stamp & R_STAMP_MARKER) { + TimeMarker *marker = NULL; // XXX get_frame_marker(scene->r.cfra); if (marker) strcpy(text, marker->name); else strcpy(text, "<none>"); @@ -975,11 +1017,11 @@ static void stampdata(StampData *stamp_data, int do_prefix) stamp_data->marker[0] = '\0'; } - if (G.scene->r.stamp & R_STAMP_TIME) { + if (scene->r.stamp & R_STAMP_TIME) { int h, m, s, f; h= m= s= f= 0; - f = (int)(G.scene->r.cfra % G.scene->r.frs_sec); - s = (int)(G.scene->r.cfra / G.scene->r.frs_sec); + f = (int)(scene->r.cfra % scene->r.frs_sec); + s = (int)(scene->r.cfra / scene->r.frs_sec); if (s) { m = (int)(s / 60); @@ -991,7 +1033,7 @@ static void stampdata(StampData *stamp_data, int do_prefix) } } - if (G.scene->r.frs_sec < 100) + if (scene->r.frs_sec < 100) sprintf (text, "%02d:%02d:%02d.%02d", h, m, s, f); else sprintf (text, "%02d:%02d:%02d.%03d", h, m, s, f); @@ -1002,17 +1044,17 @@ static void stampdata(StampData *stamp_data, int do_prefix) stamp_data->time[0] = '\0'; } - if (G.scene->r.stamp & R_STAMP_FRAME) { + if (scene->r.stamp & R_STAMP_FRAME) { char format[32]; - if (do_prefix) sprintf(format, "Frame %%0%di\n", 1 + (int) log10(G.scene->r.efra)); - else sprintf(format, "%%0%di\n", 1 + (int) log10(G.scene->r.efra)); - sprintf (stamp_data->frame, format, G.scene->r.cfra); + if (do_prefix) sprintf(format, "Frame %%0%di\n", 1 + (int) log10(scene->r.efra)); + else sprintf(format, "%%0%di\n", 1 + (int) log10(scene->r.efra)); + sprintf (stamp_data->frame, format, scene->r.cfra); } else { stamp_data->frame[0] = '\0'; } - if (G.scene->r.stamp & R_STAMP_CAMERA) { - if (G.scene->camera) strcpy(text, ((Camera *) G.scene->camera)->id.name+2); + if (scene->r.stamp & R_STAMP_CAMERA) { + if (scene->camera) strcpy(text, ((Camera *) scene->camera)->id.name+2); else strcpy(text, "<none>"); if (do_prefix) sprintf(stamp_data->camera, "Camera %s", text); @@ -1021,15 +1063,15 @@ static void stampdata(StampData *stamp_data, int do_prefix) stamp_data->camera[0] = '\0'; } - if (G.scene->r.stamp & R_STAMP_SCENE) { - if (do_prefix) sprintf(stamp_data->scene, "Scene %s", G.scene->id.name+2); - else sprintf(stamp_data->scene, "%s", G.scene->id.name+2); + if (scene->r.stamp & R_STAMP_SCENE) { + if (do_prefix) sprintf(stamp_data->scene, "Scene %s", scene->id.name+2); + else sprintf(stamp_data->scene, "%s", scene->id.name+2); } else { stamp_data->scene[0] = '\0'; } - if (G.scene->r.stamp & R_STAMP_SEQSTRIP) { - Sequence *seq = get_foreground_frame_seq(CFRA); + if (scene->r.stamp & R_STAMP_SEQSTRIP) { + Sequence *seq= NULL; //XXX = get_foreground_frame_seq(scene->r.cfra); if (seq) strcpy(text, seq->name+2); else strcpy(text, "<none>"); @@ -1041,8 +1083,11 @@ static void stampdata(StampData *stamp_data, int do_prefix) } } -void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height, int channels) +void BKE_stamp_buf(Scene *scene, unsigned char *rect, float *rectf, int width, int height, int channels) { +#if 0 +// XXX +// This go back when BLF_draw_buffer is implemented - Diego struct StampData stamp_data; int x=1,y=1; @@ -1054,9 +1099,9 @@ void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height, int if (!rect && !rectf) return; - stampdata(&stamp_data, 1); + stampdata(scene, &stamp_data, 1); - switch (G.scene->r.stamp_font_id) { + switch (scene->r.stamp_font_id) { case 1: /* tiny */ font = BMF_GetFont(BMF_kHelveticaBold8); break; @@ -1088,24 +1133,24 @@ void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height, int if (stamp_data.file[0]) { /* Top left corner */ text_width = BMF_GetStringWidth(font, stamp_data.file); - buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); - BMF_DrawStringBuf(font, stamp_data.file, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height, channels); + buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.file, x+(text_pad/2), y, scene->r.fg_stamp, rect, rectf, width, height, channels); y -= font_height+2; /* Top and bottom 1 pix padding each */ } /* Top left corner, below File */ if (stamp_data.note[0]) { text_width = BMF_GetStringWidth(font, stamp_data.note); - buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); - BMF_DrawStringBuf(font, stamp_data.note, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height, channels); + buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.note, x+(text_pad/2), y, scene->r.fg_stamp, rect, rectf, width, height, channels); y -= font_height+2; /* Top and bottom 1 pix padding each */ } /* Top left corner, below File (or Note) */ if (stamp_data.date[0]) { text_width = BMF_GetStringWidth(font, stamp_data.date); - buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); - BMF_DrawStringBuf(font, stamp_data.date, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height, channels); + buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.date, x+(text_pad/2), y, scene->r.fg_stamp, rect, rectf, width, height, channels); } /* Bottom left corner, leaving space for timing */ @@ -1113,8 +1158,8 @@ void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height, int x = 1; y = font_height+2+1; /* 2 for padding in TIME|FRAME fields below and 1 for padding in this one */ text_width = BMF_GetStringWidth(font, stamp_data.marker); - buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); - BMF_DrawStringBuf(font, stamp_data.marker, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height, channels); + buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.marker, x+(text_pad/2), y, scene->r.fg_stamp, rect, rectf, width, height, channels); } /* Left bottom corner */ @@ -1122,8 +1167,8 @@ void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height, int x = 1; y = 1; text_width = BMF_GetStringWidth(font, stamp_data.time); - buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); - BMF_DrawStringBuf(font, stamp_data.time, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height, channels); + buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.time, x+(text_pad/2), y, scene->r.fg_stamp, rect, rectf, width, height, channels); x += text_width+text_pad+2; /* Both sides have 1 pix additional padding each */ } @@ -1132,8 +1177,8 @@ void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height, int /* Left bottom corner (after SMPTE if exists) */ if (!stamp_data.time[0]) x = 1; y = 1; - buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); - BMF_DrawStringBuf(font, stamp_data.frame, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height, channels); + buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.frame, x+(text_pad/2), y, scene->r.fg_stamp, rect, rectf, width, height, channels); } if (stamp_data.camera[0]) { @@ -1141,8 +1186,8 @@ void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height, int /* Center of bottom edge */ x = (width/2) - (BMF_GetStringWidth(font, stamp_data.camera)/2); y = 1; - buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); - BMF_DrawStringBuf(font, stamp_data.camera, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height, channels); + buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.camera, x+(text_pad/2), y, scene->r.fg_stamp, rect, rectf, width, height, channels); } if (stamp_data.scene[0]) { @@ -1150,8 +1195,8 @@ void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height, int /* Bottom right corner */ x = width - (text_width+1+text_pad); y = 1; - buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); - BMF_DrawStringBuf(font, stamp_data.scene, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height, channels); + buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.scene, x+(text_pad/2), y, scene->r.fg_stamp, rect, rectf, width, height, channels); } if (stamp_data.strip[0]) { @@ -1159,20 +1204,20 @@ void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height, int /* Top right corner */ x = width - (text_width+1+text_pad); y = height - font_height - 1; - buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); - BMF_DrawStringBuf(font, stamp_data.strip, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height, channels); + buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1); + BMF_DrawStringBuf(font, stamp_data.strip, x+(text_pad/2), y, scene->r.fg_stamp, rect, rectf, width, height, channels); } - +#endif // 0 XXX } -void BKE_stamp_info(struct ImBuf *ibuf) +void BKE_stamp_info(Scene *scene, struct ImBuf *ibuf) { struct StampData stamp_data; if (!ibuf) return; /* fill all the data values, no prefix */ - stampdata(&stamp_data, 0); + stampdata(scene, &stamp_data, 0); if (stamp_data.file[0]) IMB_imginfo_change_field (ibuf, "File", stamp_data.file); if (stamp_data.note[0]) IMB_imginfo_change_field (ibuf, "Note", stamp_data.note); @@ -1185,7 +1230,7 @@ void BKE_stamp_info(struct ImBuf *ibuf) if (stamp_data.strip[0]) IMB_imginfo_change_field (ibuf, "Strip", stamp_data.strip); } -int BKE_write_ibuf(ImBuf *ibuf, char *name, int imtype, int subimtype, int quality) +int BKE_write_ibuf(Scene *scene, ImBuf *ibuf, char *name, int imtype, int subimtype, int quality) { int ok; @@ -1195,7 +1240,7 @@ int BKE_write_ibuf(ImBuf *ibuf, char *name, int imtype, int subimtype, int quali else if ((imtype==R_RADHDR)) { ibuf->ftype= RADHDR; } - else if (imtype==R_PNG || imtype==R_FFMPEG) { + else if (ELEM5(imtype, R_PNG, R_FFMPEG, R_H264, R_THEORA, R_XVID)) { ibuf->ftype= PNG; } #ifdef WITH_DDS @@ -1270,8 +1315,8 @@ int BKE_write_ibuf(ImBuf *ibuf, char *name, int imtype, int subimtype, int quali BLI_make_existing_file(name); - if(G.scene->r.scemode & R_STAMP_INFO) - BKE_stamp_info(ibuf); + if(scene->r.stamp & R_STAMP_ALL) + BKE_stamp_info(scene, ibuf); ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat); if (ok == 0) { @@ -1282,7 +1327,7 @@ int BKE_write_ibuf(ImBuf *ibuf, char *name, int imtype, int subimtype, int quali } -void BKE_makepicstring(char *string, char *base, int frame, int imtype) +void BKE_makepicstring(struct Scene *scene, char *string, char *base, int frame, int imtype) { if (string==NULL) return; @@ -1295,8 +1340,8 @@ void BKE_makepicstring(char *string, char *base, int frame, int imtype) BLI_convertstringcode(string, G.sce); BLI_convertstringframe(string, frame); - if(G.scene->r.scemode & R_EXTENSION) - BKE_add_image_extension(string, imtype); + if(scene->r.scemode & R_EXTENSION) + BKE_add_image_extension(scene, string, imtype); } @@ -1400,7 +1445,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal) /* try to repack file */ if(ima->packedfile) { PackedFile *pf; - pf = newPackedFile(ima->name); + pf = newPackedFile(NULL, ima->name); if (pf) { freePackedFile(ima->packedfile); ima->packedfile = pf; @@ -1467,12 +1512,12 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser) return rpass; } -RenderResult *BKE_image_get_renderresult(Image *ima) +RenderResult *BKE_image_get_renderresult(struct Scene *scene, Image *ima) { if(ima->rr) return ima->rr; if(ima->type==IMA_TYPE_R_RESULT) - return RE_GetResult(RE_GetRender(G.scene->id.name)); + return RE_GetResult(RE_GetRender(scene->id.name)); return NULL; } @@ -1719,7 +1764,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) /* make packed file for autopack */ if ((ima->packedfile == NULL) && (G.fileflags & G_AUTOPACK)) - ima->packedfile = newPackedFile(str); + ima->packedfile = newPackedFile(NULL, str); } if(ima->flag & IMA_DO_PREMUL) @@ -1775,11 +1820,30 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser) /* showing RGBA result itself (from compo/sequence) or like exr, using layers etc */ +/* always returns a single ibuf, also during render progress */ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser) { - RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name)); + Render *re= NULL; + RenderResult *rr= NULL; - if(rr) { + if(iuser && iuser->scene) { + re= RE_GetRender(iuser->scene->id.name); + rr= RE_GetResult(re); + } + if(rr==NULL) return NULL; + + if(RE_RenderInProgress(re)) { + ImBuf *ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0); + + /* make ibuf if needed, and initialize it */ + /* this only gets called when mutex locked */ + if(ibuf==NULL) { + ibuf= IMB_allocImBuf(rr->rectx, rr->recty, 32, IB_rect, 0); + image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + } + return ibuf; + } + else { RenderResult rres; float *rectf; unsigned int *rect; @@ -1791,10 +1855,10 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser) pass= (iuser)? iuser->pass: 0; /* this gives active layer, composite or seqence result */ - RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres); + RE_GetResultImage(RE_GetRender(iuser->scene->id.name), &rres); rect= (unsigned int *)rres.rect32; rectf= rres.rectf; - dither= G.scene->r.dither_intensity; + dither= iuser->scene->r.dither_intensity; /* get compo/seq result by default */ if(rr->rectf && layer==0); @@ -1969,7 +2033,7 @@ ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser) else if(ima->source==IMA_SRC_FILE) { if(ima->type==IMA_TYPE_IMAGE) - ibuf= image_load_image_file(ima, iuser, G.scene->r.cfra); /* cfra only for '#', this global is OK */ + ibuf= image_load_image_file(ima, iuser, frame); /* cfra only for '#', this global is OK */ /* no else; on load the ima type can change */ if(ima->type==IMA_TYPE_MULTILAYER) /* keeps render result, stores ibufs in listbase, allows saving */ @@ -1978,17 +2042,12 @@ ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser) } else if(ima->source == IMA_SRC_GENERATED) { /* generated is: ibuf is allocated dynamically */ - if(ima->type==IMA_TYPE_VERSE) { - /* todo */ - } - else { /* always fall back to IMA_TYPE_UV_TEST */ - /* UV testgrid or black or solid etc */ - if(ima->gen_x==0) ima->gen_x= 256; - if(ima->gen_y==0) ima->gen_y= 256; - ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, 0, ima->gen_type, color); - image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); - ima->ok= IMA_OK_LOADED; - } + /* UV testgrid or black or solid etc */ + if(ima->gen_x==0) ima->gen_x= 256; + if(ima->gen_y==0) ima->gen_y= 256; + ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, 0, ima->gen_type, color); + image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); + ima->ok= IMA_OK_LOADED; } else if(ima->source == IMA_SRC_VIEWER) { if(ima->type==IMA_TYPE_R_RESULT) { diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index 93e35a4db06..fc5213d5532 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -1393,7 +1393,7 @@ float calculateVertexWindForce(float wind[3], float vertexnormal[3]) return (INPR(wind, vertexnormal)); } -void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVector *lV, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, ListBase *effectors, float time, fmatrix3x3 *M) +static void cloth_calc_force(ClothModifierData *clmd, float frame, lfVector *lF, lfVector *lX, lfVector *lV, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, ListBase *effectors, float time, fmatrix3x3 *M) { /* Collect forces and derivatives: F,dFdX,dFdV */ Cloth *cloth = clmd->clothObject; @@ -1442,7 +1442,7 @@ void cloth_calc_force(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVec { float speed[3] = {0.0f, 0.0f,0.0f}; - pdDoEffectors(effectors, lX[i], winvec[i], speed, (float)G.scene->r.cfra, 0.0f, 0); + pdDoEffectors(clmd->scene, effectors, lX[i], winvec[i], speed, frame, 0.0f, 0); } for(i = 0; i < cloth->numfaces; i++) @@ -1570,8 +1570,8 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase while(step < tf) { // calculate forces - effectors= pdInitEffectors(ob,NULL); - cloth_calc_force(clmd, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step, id->M); + effectors= pdInitEffectors(clmd->scene, ob, NULL); + cloth_calc_force(clmd, frame, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step, id->M); if(effectors) pdEndEffectors(effectors); // calculate new velocity @@ -1600,6 +1600,10 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase if(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) { + float temp = clmd->sim_parms->stepsPerFrame; + /* not too nice hack, but collisions need this correction -jahka */ + clmd->sim_parms->stepsPerFrame /= clmd->sim_parms->timescale; + // collisions // itstart(); @@ -1614,7 +1618,7 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase // call collision function // TODO: check if "step" or "step+dt" is correct - dg - result = cloth_bvh_objcollision(ob, clmd, step, dt); + result = cloth_bvh_objcollision(ob, clmd, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale); // correct velocity again, just to be sure we had to change it due to adaptive collisions for(i = 0; i < numverts; i++) @@ -1637,6 +1641,9 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase } } + /* restore original stepsPerFrame */ + clmd->sim_parms->stepsPerFrame = temp; + // X = Xnew; cp_lfvector(id->X, id->Xnew, numverts); @@ -1648,13 +1655,12 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase cp_lfvector(id->V, id->Vnew, numverts); // calculate - effectors= pdInitEffectors(ob,NULL); - cloth_calc_force(clmd, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step+dt, id->M); + effectors= pdInitEffectors(clmd->scene, ob, NULL); + cloth_calc_force(clmd, frame, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step+dt, id->M); if(effectors) pdEndEffectors(effectors); simulate_implicit_euler(id->Vnew, id->X, id->V, id->F, id->dFdV, id->dFdX, dt / 2.0f, id->A, id->B, id->dV, id->S, id->z, id->olddV, id->P, id->Pinv, id->M, id->bigI); } - } else { diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 0077cf95262..a72f26f6157 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -23,14 +23,23 @@ * * The Original Code is: all of this file. * - * Contributor(s): 2008, Joshua Leung (IPO System cleanup) + * Contributor(s): 2008,2009 Joshua Leung (IPO System cleanup, Animation System Recode) * * ***** END GPL LICENSE BLOCK ***** */ +/* NOTE: + * + * This file is no longer used to provide tools for the depreceated IPO system. Instead, it + * is only used to house the conversion code to the new system. + * + * -- Joshua Leung, Jan 2009 + */ + #include <math.h> #include <stdio.h> #include <string.h> +#include <stddef.h> #ifdef HAVE_CONFIG_H #include <config.h> @@ -38,8 +47,10 @@ #include "MEM_guardedalloc.h" +#include "DNA_anim_types.h" #include "DNA_action_types.h" #include "DNA_armature_types.h" +#include "DNA_constraint_types.h" #include "DNA_curve_types.h" #include "DNA_camera_types.h" #include "DNA_lamp_types.h" @@ -47,6 +58,7 @@ #include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" +#include "DNA_nla_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" #include "DNA_particle_types.h" @@ -59,2826 +71,1801 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" +#include "BLI_dynstr.h" -#include "BKE_bad_level_calls.h" #include "BKE_utildefines.h" +#include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_blender.h" #include "BKE_curve.h" #include "BKE_constraint.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_ipo.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_nla.h" #include "BKE_object.h" -#ifndef DISABLE_PYTHON -#include "BPY_extern.h" /* for BPY_pydriver_eval() */ -#endif - -#define SMALL -1.0e-10 - -/* ***************************** Adrcode Blocktype Defines ********************************* */ - -/* This array concept was meant to make sure that defines such as OB_LOC_X - don't have to be enumerated, also for backward compatibility, future changes, - and to enable it all can be accessed with a for-next loop. - - This should whole adrcode system should eventually be replaced by a proper Data API -*/ - - -int co_ar[CO_TOTIPO]= { - CO_ENFORCE, CO_HEADTAIL -}; - -int ob_ar[OB_TOTIPO]= { - OB_LOC_X, OB_LOC_Y, OB_LOC_Z, OB_DLOC_X, OB_DLOC_Y, OB_DLOC_Z, - OB_ROT_X, OB_ROT_Y, OB_ROT_Z, OB_DROT_X, OB_DROT_Y, OB_DROT_Z, - OB_SIZE_X, OB_SIZE_Y, OB_SIZE_Z, OB_DSIZE_X, OB_DSIZE_Y, OB_DSIZE_Z, - OB_LAY, OB_TIME, OB_COL_R, OB_COL_G, OB_COL_B, OB_COL_A, - OB_PD_FSTR, OB_PD_FFALL, OB_PD_SDAMP, OB_PD_RDAMP, OB_PD_PERM, OB_PD_FMAXD -}; - -int ac_ar[AC_TOTIPO]= { - AC_LOC_X, AC_LOC_Y, AC_LOC_Z, - AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z, - AC_SIZE_X, AC_SIZE_Y, AC_SIZE_Z -}; -int ma_ar[MA_TOTIPO]= { - MA_COL_R, MA_COL_G, MA_COL_B, - MA_SPEC_R, MA_SPEC_G, MA_SPEC_B, - MA_MIR_R, MA_MIR_G, MA_MIR_B, - MA_REF, MA_ALPHA, MA_EMIT, MA_AMB, - MA_SPEC, MA_HARD, MA_SPTR, MA_IOR, - MA_MODE, MA_HASIZE, MA_TRANSLU, MA_RAYM, - MA_FRESMIR, MA_FRESMIRI, MA_FRESTRA, MA_FRESTRAI, MA_ADD, - - MA_MAP1+MAP_OFS_X, MA_MAP1+MAP_OFS_Y, MA_MAP1+MAP_OFS_Z, - MA_MAP1+MAP_SIZE_X, MA_MAP1+MAP_SIZE_Y, MA_MAP1+MAP_SIZE_Z, - MA_MAP1+MAP_R, MA_MAP1+MAP_G, MA_MAP1+MAP_B, - MA_MAP1+MAP_DVAR, MA_MAP1+MAP_COLF, MA_MAP1+MAP_NORF, MA_MAP1+MAP_VARF, MA_MAP1+MAP_DISP -}; -int te_ar[TE_TOTIPO] ={ - - TE_NSIZE, TE_NDEPTH, TE_NTYPE, TE_TURB, - - TE_VNW1, TE_VNW2, TE_VNW3, TE_VNW4, - TE_VNMEXP, TE_VN_COLT, TE_VN_DISTM, - - TE_ISCA, TE_DISTA, - - TE_MG_TYP, TE_MGH, TE_MG_LAC, TE_MG_OCT, TE_MG_OFF, TE_MG_GAIN, - - TE_N_BAS1, TE_N_BAS2, - - TE_COL_R, TE_COL_G, TE_COL_B, TE_BRIGHT, TE_CONTRA -}; +/* *************************************************** */ +/* Old-Data Freeing Tools */ -int seq_ar[SEQ_TOTIPO]= { - SEQ_FAC1 -}; - -int cu_ar[CU_TOTIPO]= { - CU_SPEED -}; - -int wo_ar[WO_TOTIPO]= { - WO_HOR_R, WO_HOR_G, WO_HOR_B, WO_ZEN_R, WO_ZEN_G, WO_ZEN_B, - WO_EXPOS, WO_MISI, WO_MISTDI, WO_MISTSTA, WO_MISTHI, - WO_STAR_R, WO_STAR_G, WO_STAR_B, WO_STARDIST, WO_STARSIZE, - - MA_MAP1+MAP_OFS_X, MA_MAP1+MAP_OFS_Y, MA_MAP1+MAP_OFS_Z, - MA_MAP1+MAP_SIZE_X, MA_MAP1+MAP_SIZE_Y, MA_MAP1+MAP_SIZE_Z, - MA_MAP1+MAP_R, MA_MAP1+MAP_G, MA_MAP1+MAP_B, - MA_MAP1+MAP_DVAR, MA_MAP1+MAP_COLF, MA_MAP1+MAP_NORF, MA_MAP1+MAP_VARF -}; - -int la_ar[LA_TOTIPO]= { - LA_ENERGY, LA_COL_R, LA_COL_G, LA_COL_B, - LA_DIST, LA_SPOTSI, LA_SPOTBL, - LA_QUAD1, LA_QUAD2, LA_HALOINT, - - MA_MAP1+MAP_OFS_X, MA_MAP1+MAP_OFS_Y, MA_MAP1+MAP_OFS_Z, - MA_MAP1+MAP_SIZE_X, MA_MAP1+MAP_SIZE_Y, MA_MAP1+MAP_SIZE_Z, - MA_MAP1+MAP_R, MA_MAP1+MAP_G, MA_MAP1+MAP_B, - MA_MAP1+MAP_DVAR, MA_MAP1+MAP_COLF -}; - -/* yafray: aperture & focal distance curves added */ -/* qdn: FDIST now available to Blender as well for defocus node */ -int cam_ar[CAM_TOTIPO]= { - CAM_LENS, CAM_STA, CAM_END, CAM_YF_APERT, CAM_YF_FDIST, CAM_SHIFT_X, CAM_SHIFT_Y -}; - -int snd_ar[SND_TOTIPO]= { - SND_VOLUME, SND_PITCH, SND_PANNING, SND_ATTEN -}; - -int fluidsim_ar[FLUIDSIM_TOTIPO]= { - FLUIDSIM_VISC, FLUIDSIM_TIME, - FLUIDSIM_GRAV_X , FLUIDSIM_GRAV_Y , FLUIDSIM_GRAV_Z , - FLUIDSIM_VEL_X , FLUIDSIM_VEL_Y , FLUIDSIM_VEL_Z , - FLUIDSIM_ACTIVE, - FLUIDSIM_ATTR_FORCE_STR, FLUIDSIM_ATTR_FORCE_RADIUS, - FLUIDSIM_VEL_FORCE_STR, FLUIDSIM_VEL_FORCE_RADIUS, -}; - -int part_ar[PART_TOTIPO]= { - PART_EMIT_FREQ, PART_EMIT_LIFE, PART_EMIT_VEL, PART_EMIT_AVE, PART_EMIT_SIZE, - PART_AVE, PART_SIZE, PART_DRAG, PART_BROWN, PART_DAMP, PART_LENGTH, PART_CLUMP, - PART_GRAV_X, PART_GRAV_Y, PART_GRAV_Z, PART_KINK_AMP, PART_KINK_FREQ, PART_KINK_SHAPE, - PART_BB_TILT, PART_PD_FSTR, PART_PD_FFALL, PART_PD_FMAXD, PART_PD2_FSTR, PART_PD2_FFALL, PART_PD2_FMAXD -}; - -/* ************************** Data-Level Functions ************************* */ - -/* ---------------------- Freeing --------------------------- */ - -/* frees the ipo curve itself too */ -void free_ipo_curve (IpoCurve *icu) -{ - if (icu == NULL) - return; - - if (icu->bezt) - MEM_freeN(icu->bezt); - if (icu->driver) - MEM_freeN(icu->driver); - - MEM_freeN(icu); -} - -/* do not free ipo itself */ +/* Free data from old IPO-Blocks (those which haven't been converted), but not IPO block itself */ +// XXX this shouldn't be necessary anymore, but may occur while not all data is converted yet void free_ipo (Ipo *ipo) { IpoCurve *icu, *icn; - - if (ipo == NULL) - return; + int n= 0; for (icu= ipo->curve.first; icu; icu= icn) { icn= icu->next; + n++; - /* must remove the link before freeing, as the curve is freed too */ - BLI_remlink(&ipo->curve, icu); - free_ipo_curve(icu); + if (icu->bezt) MEM_freeN(icu->bezt); + if (icu->bp) MEM_freeN(icu->bp); + if (icu->driver) MEM_freeN(icu->driver); + + BLI_freelinkN(&ipo->curve, icu); } + + if (G.f & G_DEBUG) + printf("Freed %d (Unconverted) Ipo-Curves from IPO '%s' \n", n, ipo->id.name+2); } -/* ---------------------- Init --------------------------- */ +/* *************************************************** */ +/* ADRCODE to RNA-Path Conversion Code - Special (Bitflags) */ + +/* Mapping Table for bitflag <-> RNA path */ +typedef struct AdrBit2Path { + int bit; + char *path; + int array_index; +} AdrBit2Path; + +/* ----------------- */ +/* Mapping Tables to use bits <-> RNA paths */ + +/* Object layers */ +static AdrBit2Path ob_layer_bits[]= { + {(1<<0), "layer", 0}, + {(1<<1), "layer", 1}, + {(1<<2), "layer", 2}, + {(1<<3), "layer", 3}, + {(1<<4), "layer", 4}, + {(1<<5), "layer", 5}, + {(1<<6), "layer", 6}, + {(1<<7), "layer", 7}, + {(1<<8), "layer", 8}, + {(1<<9), "layer", 9}, + {(1<<10), "layer", 10}, + {(1<<11), "layer", 11}, + {(1<<12), "layer", 12}, + {(1<<13), "layer", 13}, + {(1<<14), "layer", 14}, + {(1<<15), "layer", 15}, + {(1<<16), "layer", 16}, + {(1<<17), "layer", 17}, + {(1<<18), "layer", 18}, + {(1<<19), "layer", 19}, + {(1<<20), "layer", 20} +}; -/* on adding new ipos, or for empty views */ -void ipo_default_v2d_cur (int blocktype, rctf *cur) -{ - switch (blocktype) { - case ID_CA: - cur->xmin= (float)G.scene->r.sfra; - cur->xmax= (float)G.scene->r.efra; - cur->ymin= 0.0f; - cur->ymax= 100.0f; - break; - - case ID_MA: case ID_WO: case ID_LA: - case ID_CU: case ID_CO: - cur->xmin= (float)(G.scene->r.sfra - 0.1f); - cur->xmax= (float)G.scene->r.efra; - cur->ymin= (float)-0.1f; - cur->ymax= (float)+1.1f; - break; - - case ID_TE: - cur->xmin= (float)(G.scene->r.sfra - 0.1f); - cur->xmax= (float)G.scene->r.efra; - cur->ymin= (float)-0.1f; - cur->ymax= (float)+1.1f; - break; - - case ID_SEQ: - cur->xmin= -5.0f; - cur->xmax= 105.0f; - cur->ymin= (float)-0.1f; - cur->ymax= (float)+1.1f; - break; - - case ID_KE: - cur->xmin= (float)(G.scene->r.sfra - 0.1f); - cur->xmax= (float)G.scene->r.efra; - cur->ymin= (float)-0.1f; - cur->ymax= (float)+2.1f; - break; - - default: /* ID_OB and everything else */ - cur->xmin= (float)G.scene->r.sfra; - cur->xmax= (float)G.scene->r.efra; - cur->ymin= -5.0f; - cur->ymax= +5.0f; - break; +/* Material mode */ +static AdrBit2Path ma_mode_bits[]= { +// {MA_TRACEBLE, "traceable", 0}, +// {MA_SHADOW, "shadow", 0}, +// {MA_SHLESS, "shadeless", 0}, +// ... + {MA_RAYTRANSP, "raytrace_transparency.enabled", 0}, + {MA_RAYMIRROR, "raytrace_mirror.enabled", 0}, +// {MA_HALO, "type", MA_TYPE_HALO} +}; + +/* ----------------- */ + +/* quick macro for returning the appropriate array for adrcode_bitmaps_to_paths() */ +#define RET_ABP(items) \ + { \ + *tot= sizeof(items)/sizeof(AdrBit2Path); \ + return items; \ } -} -/* create a new IPO block (allocates the block) */ -Ipo *add_ipo (char name[], int blocktype) +/* This function checks if a Blocktype+Adrcode combo, returning a mapping table */ +static AdrBit2Path *adrcode_bitmaps_to_paths (int blocktype, int adrcode, int *tot) { - Ipo *ipo; - - ipo= alloc_libblock(&G.main->ipo, ID_IP, name); - ipo->blocktype= blocktype; - ipo_default_v2d_cur(blocktype, &ipo->cur); - - return ipo; + /* Object layers */ + if ((blocktype == ID_OB) && (adrcode == OB_LAY)) + RET_ABP(ob_layer_bits) + else if ((blocktype == ID_MA) && (adrcode == MA_MODE)) + RET_ABP(ma_mode_bits) + // XXX TODO: add other types... + + /* Normal curve */ + return NULL; } -/* ---------------------- Copy --------------------------- */ +/* *************************************************** */ +/* ADRCODE to RNA-Path Conversion Code - Standard */ -/* duplicate an IPO block and all its data */ -Ipo *copy_ipo (Ipo *src) +/* Object types */ +static char *ob_adrcodes_to_paths (int adrcode, int *array_index) { - Ipo *dst; - IpoCurve *icu; + /* set array index like this in-case nothing sets it correctly */ + *array_index= 0; - if (src == NULL) - return NULL; - - dst= copy_libblock(src); - duplicatelist(&dst->curve, &src->curve); - - for (icu= src->curve.first; icu; icu= icu->next) { - icu->bezt= MEM_dupallocN(icu->bezt); + /* result depends on adrcode */ + switch (adrcode) { + case OB_LOC_X: + *array_index= 0; return "location"; + case OB_LOC_Y: + *array_index= 1; return "location"; + case OB_LOC_Z: + *array_index= 2; return "location"; + case OB_DLOC_X: + *array_index= 0; return "delta_location"; + case OB_DLOC_Y: + *array_index= 1; return "delta_location"; + case OB_DLOC_Z: + *array_index= 2; return "delta_location"; - if (icu->driver) - icu->driver= MEM_dupallocN(icu->driver); + case OB_ROT_X: + *array_index= 0; return "rotation"; + case OB_ROT_Y: + *array_index= 1; return "rotation"; + case OB_ROT_Z: + *array_index= 2; return "rotation"; + case OB_DROT_X: + *array_index= 0; return "delta_rotation"; + case OB_DROT_Y: + *array_index= 1; return "delta_rotation"; + case OB_DROT_Z: + *array_index= 2; return "delta_rotation"; + + case OB_SIZE_X: + *array_index= 0; return "scale"; + case OB_SIZE_Y: + *array_index= 1; return "scale"; + case OB_SIZE_Z: + *array_index= 2; return "scale"; + case OB_DSIZE_X: + *array_index= 0; return "delta_scale"; + case OB_DSIZE_Y: + *array_index= 1; return "delta_scale"; + case OB_DSIZE_Z: + *array_index= 2; return "delta_scale"; + case OB_COL_R: + *array_index= 0; return "color"; + case OB_COL_G: + *array_index= 1; return "color"; + case OB_COL_B: + *array_index= 2; return "color"; + case OB_COL_A: + *array_index= 3; return "color"; +#if 0 + case OB_PD_FSTR: + if (ob->pd) poin= &(ob->pd->f_strength); + break; + case OB_PD_FFALL: + if (ob->pd) poin= &(ob->pd->f_power); + break; + case OB_PD_SDAMP: + if (ob->pd) poin= &(ob->pd->pdef_damp); + break; + case OB_PD_RDAMP: + if (ob->pd) poin= &(ob->pd->pdef_rdamp); + break; + case OB_PD_PERM: + if (ob->pd) poin= &(ob->pd->pdef_perm); + break; + case OB_PD_FMAXD: + if (ob->pd) poin= &(ob->pd->maxdist); + break; +#endif } - return dst; + return NULL; } -/* ---------------------- Relink --------------------------- */ - -/* uses id->newid to match pointers with other copied data - * - called after single-user or other such +/* PoseChannel types + * NOTE: pchan name comes from 'actname' added earlier... */ -void ipo_idnew (Ipo *ipo) +static char *pchan_adrcodes_to_paths (int adrcode, int *array_index) { - if (ipo) { - IpoCurve *icu; - - for (icu= ipo->curve.first; icu; icu= icu->next) { - if (icu->driver) - ID_NEW(icu->driver->ob); - } - } -} - -/* --------------------- Find + Check ----------------------- */ - -/* find the IPO-curve within a given IPO-block with the adrcode of interest */ -IpoCurve *find_ipocurve (Ipo *ipo, int adrcode) -{ - if (ipo) { - IpoCurve *icu; + /* set array index like this in-case nothing sets it correctly */ + *array_index= 0; + + /* result depends on adrcode */ + switch (adrcode) { + case AC_QUAT_W: + *array_index= 0; return "rotation"; + case AC_QUAT_X: + *array_index= 1; return "rotation"; + case AC_QUAT_Y: + *array_index= 2; return "rotation"; + case AC_QUAT_Z: + *array_index= 3; return "rotation"; + + case AC_EUL_X: + *array_index= 0; return "euler_rotation"; + case AC_EUL_Y: + *array_index= 1; return "euler_rotation"; + case AC_EUL_Z: + *array_index= 2; return "euler_rotation"; + + case -1: /* special case for euler-rotations used by old drivers */ + *array_index= 0; return "euler_rotation"; + + case AC_LOC_X: + *array_index= 0; return "location"; + case AC_LOC_Y: + *array_index= 1; return "location"; + case AC_LOC_Z: + *array_index= 2; return "location"; - for (icu= ipo->curve.first; icu; icu= icu->next) { - if (icu->adrcode == adrcode) - return icu; - } + case AC_SIZE_X: + *array_index= 0; return "scale"; + case AC_SIZE_Y: + *array_index= 1; return "scale"; + case AC_SIZE_Z: + *array_index= 2; return "scale"; } + + /* for debugging only */ + printf("ERROR: unmatched PoseChannel setting (code %d) \n", adrcode); return NULL; } -/* return whether the given IPO block has a IPO-curve with the given adrcode */ -short has_ipo_code(Ipo *ipo, int adrcode) +/* Constraint types */ +static char *constraint_adrcodes_to_paths (int adrcode, int *array_index) { - /* return success of faliure from trying to find such an IPO-curve */ - return (find_ipocurve(ipo, adrcode) != NULL); -} - -/* ---------------------- Make Local --------------------------- */ - - -/* make the given IPO local (for Objects) - * - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ -void make_local_obipo (Ipo *src) -{ - Object *ob; - Ipo *dst; - int local=0, lib=0; - - /* check if only local and/or lib */ - for (ob= G.main->object.first; ob; ob= ob->id.next) { - if (ob->ipo == src) { - if (ob->id.lib) lib= 1; - else local= 1; - } - } + /* set array index like this in-case nothing sets it correctly */ + *array_index= 0; - /* only local - set flag */ - if (local && lib==0) { - src->id.lib= 0; - src->id.flag= LIB_LOCAL; - new_id(0, (ID *)src, 0); - } - /* mixed: make copy */ - else if (local && lib) { - dst= copy_ipo(src); - dst->id.us= 0; - - for (ob= G.main->object.first; ob; ob= ob->id.next) { - if (ob->ipo == src) { - if (ob->id.lib == NULL) { - ob->ipo= dst; - dst->id.us++; - src->id.us--; - } - } - } + /* result depends on adrcode */ + switch (adrcode) { + case CO_ENFORCE: + return "influence"; + case CO_HEADTAIL: // XXX this needs to be wrapped in RNA.. probably then this path will be invalid + return "data.head_tail"; } + + return NULL; } -/* make the given IPO local (for Materials) - * - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy +/* ShapeKey types + * NOTE: as we don't have access to the keyblock where the data comes from (for now), + * we'll just use numerical indicies for now... */ -void make_local_matipo (Ipo *src) +static char *shapekey_adrcodes_to_paths (int adrcode, int *array_index) { - Material *ma; - Ipo *dst; - int local=0, lib=0; - - /* check if only local and/or lib */ - for (ma= G.main->mat.first; ma; ma= ma->id.next) { - if (ma->ipo == src) { - if (ma->id.lib) lib= 1; - else local= 1; - } - } + static char buf[128]; - /* only local - set flag */ - if (local && lib==0) { - src->id.lib= 0; - src->id.flag= LIB_LOCAL; - new_id(0, (ID *)src, 0); - } - /* mixed: make copy */ - else if (local && lib) { - dst= copy_ipo(src); - dst->id.us= 0; - - for (ma= G.main->mat.first; ma; ma= ma->id.next) { - if (ma->ipo == src) { - if (ma->id.lib == NULL) { - ma->ipo= dst; - dst->id.us++; - src->id.us--; - } - } - } - } + /* block will be attached to ID_KE block, and setting that we alter is the 'value' (which sets keyblock.curval) */ + // XXX adrcode 0 was dummy 'speed' curve + if (adrcode == 0) + sprintf(buf, "speed"); + else + sprintf(buf, "keys[%d].value", adrcode); + return buf; } -/* make the given IPO local (for ShapeKeys) - * - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ -void make_local_keyipo (Ipo *src) +/* MTex (Texture Slot) types */ +static char *mtex_adrcodes_to_paths (int adrcode, int *array_index) { - Key *key; - Ipo *dst; - int local=0, lib=0; - - /* check if only local and/or lib */ - for (key= G.main->key.first; key; key= key->id.next) { - if (key->ipo == src) { - if (key->id.lib) lib= 1; - else local= 1; - } + char *base=NULL, *prop=NULL; + static char buf[128]; + + /* base part of path */ + if (adrcode & MA_MAP1) base= "textures[0]"; + else if (adrcode & MA_MAP2) base= "textures[1]"; + else if (adrcode & MA_MAP3) base= "textures[2]"; + else if (adrcode & MA_MAP4) base= "textures[3]"; + else if (adrcode & MA_MAP5) base= "textures[4]"; + else if (adrcode & MA_MAP6) base= "textures[5]"; + else if (adrcode & MA_MAP7) base= "textures[6]"; + else if (adrcode & MA_MAP8) base= "textures[7]"; + else if (adrcode & MA_MAP9) base= "textures[8]"; + else if (adrcode & MA_MAP10) base= "textures[9]"; + else if (adrcode & MA_MAP11) base= "textures[10]"; + else if (adrcode & MA_MAP12) base= "textures[11]"; + else if (adrcode & MA_MAP13) base= "textures[12]"; + else if (adrcode & MA_MAP14) base= "textures[13]"; + else if (adrcode & MA_MAP15) base= "textures[14]"; + else if (adrcode & MA_MAP16) base= "textures[15]"; + else if (adrcode & MA_MAP17) base= "textures[16]"; + else if (adrcode & MA_MAP18) base= "textures[17]"; + + /* property identifier for path */ + adrcode= (adrcode & (MA_MAP1-1)); + switch (adrcode) { +#if 0 // XXX these are not wrapped in RNA yet! + case MAP_OFS_X: + poin= &(mtex->ofs[0]); break; + case MAP_OFS_Y: + poin= &(mtex->ofs[1]); break; + case MAP_OFS_Z: + poin= &(mtex->ofs[2]); break; + case MAP_SIZE_X: + poin= &(mtex->size[0]); break; + case MAP_SIZE_Y: + poin= &(mtex->size[1]); break; + case MAP_SIZE_Z: + poin= &(mtex->size[2]); break; + case MAP_R: + poin= &(mtex->r); break; + case MAP_G: + poin= &(mtex->g); break; + case MAP_B: + poin= &(mtex->b); break; + case MAP_DVAR: + poin= &(mtex->def_var); break; + case MAP_COLF: + poin= &(mtex->colfac); break; + case MAP_NORF: + poin= &(mtex->norfac); break; + case MAP_VARF: + poin= &(mtex->varfac); break; +#endif + case MAP_DISP: + prop= "warp_factor"; break; } - /* only local - set flag */ - if (local && lib==0) { - src->id.lib= 0; - src->id.flag= LIB_LOCAL; - new_id(0, (ID *)src, 0); - } - /* mixed: make copy */ - else if (local && lib) { - dst= copy_ipo(src); - dst->id.us= 0; - - for (key= G.main->key.first; key; key= key->id.next) { - if (key->ipo == src) { - if (key->id.lib == NULL) { - key->ipo= dst; - dst->id.us++; - src->id.us--; - } - } - } + /* only build and return path if there's a property */ + if (prop) { + BLI_snprintf(buf, 128, "%s.%s", base, prop); + return buf; } + else + return NULL; } - -/* generic call to make IPO's local */ -void make_local_ipo (Ipo *ipo) +/* Texture types */ +static char *texture_adrcodes_to_paths (int adrcode, int *array_index) { - /* can't touch lib-linked data */ - if (ipo->id.lib == NULL) - return; - - /* with only one user, just set local flag */ - if (ipo->id.us == 1) { - ipo->id.lib= 0; - ipo->id.flag= LIB_LOCAL; - new_id(0, (ID *)ipo, 0); - return; - } + /* set array index like this in-case nothing sets it correctly */ + *array_index= 0; - /* when more than 1 user, can only make local for certain blocktypes */ - switch (ipo->blocktype) { - case ID_OB: - make_local_obipo(ipo); + /* result depends on adrcode */ + switch (adrcode) { + case TE_NSIZE: + return "noise_size"; + case TE_TURB: + return "turbulence"; + + case TE_NDEPTH: // XXX texture RNA undefined + //poin= &(tex->noisedepth); *type= IPO_SHORT; break; break; - case ID_MA: - make_local_matipo(ipo); + case TE_NTYPE: // XXX texture RNA undefined + //poin= &(tex->noisetype); *type= IPO_SHORT; break; break; - case ID_KE: - make_local_keyipo(ipo); + + case TE_N_BAS1: + return "noise_basis"; + case TE_N_BAS2: + return "noise_basis"; // XXX this is not yet defined in RNA... + + /* voronoi */ + case TE_VNW1: + *array_index= 0; return "feature_weights"; + case TE_VNW2: + *array_index= 1; return "feature_weights"; + case TE_VNW3: + *array_index= 2; return "feature_weights"; + case TE_VNW4: + *array_index= 3; return "feature_weights"; + case TE_VNMEXP: + return "minkovsky_exponent"; + case TE_VN_DISTM: + return "distance_metric"; + case TE_VN_COLT: + return "color_type"; + + /* distorted noise / voronoi */ + case TE_ISCA: + return "noise_intensity"; + + /* distorted noise */ + case TE_DISTA: + return "distortion_amount"; + + /* musgrave */ + case TE_MG_TYP: // XXX texture RNA undefined + // poin= &(tex->stype); *type= IPO_SHORT; break; break; + case TE_MGH: + return "highest_dimension"; + case TE_MG_LAC: + return "lacunarity"; + case TE_MG_OCT: + return "octaves"; + case TE_MG_OFF: + return "offset"; + case TE_MG_GAIN: + return "gain"; + + case TE_COL_R: + *array_index= 0; return "rgb_factor"; + case TE_COL_G: + *array_index= 1; return "rgb_factor"; + case TE_COL_B: + *array_index= 2; return "rgb_factor"; + + case TE_BRIGHT: + return "brightness"; + case TE_CONTRA: + return "constrast"; } + + return NULL; } -/* ***************************** Keyframe Column Tools ********************************* */ - -/* add a BezTriple to a column */ -void add_to_cfra_elem(ListBase *lb, BezTriple *bezt) +/* Material Types */ +static char *material_adrcodes_to_paths (int adrcode, int *array_index) { - CfraElem *ce, *cen; + /* set array index like this in-case nothing sets it correctly */ + *array_index= 0; - for (ce= lb->first; ce; ce= ce->next) { - /* double key? */ - if (ce->cfra == bezt->vec[1][0]) { - if (bezt->f2 & SELECT) ce->sel= bezt->f2; - return; - } - /* should key be inserted before this column? */ - else if (ce->cfra > bezt->vec[1][0]) break; + /* result depends on adrcode */ + switch (adrcode) { + case MA_COL_R: + *array_index= 0; return "diffuse_color"; + case MA_COL_G: + *array_index= 1; return "diffuse_color"; + case MA_COL_B: + *array_index= 2; return "diffuse_color"; + + case MA_SPEC_R: + *array_index= 0; return "specular_color"; + case MA_SPEC_G: + *array_index= 1; return "specular_color"; + case MA_SPEC_B: + *array_index= 2; return "specular_color"; + + case MA_MIR_R: + *array_index= 0; return "mirror_color"; + case MA_MIR_G: + *array_index= 1; return "mirror_color"; + case MA_MIR_B: + *array_index= 2; return "mirror_color"; + + case MA_ALPHA: + return "alpha"; + + case MA_REF: + return "diffuse_reflection"; + + case MA_EMIT: + return "emit"; + + case MA_AMB: + return "ambient"; + + case MA_SPEC: + return "specular_reflection"; + + case MA_HARD: + return "specular_hardness"; + + case MA_SPTR: + return "specular_opacity"; + + case MA_IOR: + return "ior"; + + case MA_HASIZE: + return "halo.size"; + + case MA_TRANSLU: + return "translucency"; + + case MA_RAYM: + return "raytrace_mirror.reflect"; + + case MA_FRESMIR: + return "raytrace_mirror.fresnel"; + + case MA_FRESMIRI: + return "raytrace_mirror.fresnel_fac"; + + case MA_FRESTRA: + return "raytrace_transparency.fresnel"; + + case MA_FRESTRAI: + return "raytrace_transparency.fresnel_fac"; + + case MA_ADD: + return "halo.add"; + + default: /* for now, we assume that the others were MTex channels */ + return mtex_adrcodes_to_paths(adrcode, array_index); } - /* create a new column */ - cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); - if (ce) BLI_insertlinkbefore(lb, ce, cen); - else BLI_addtail(lb, cen); - - cen->cfra= bezt->vec[1][0]; - cen->sel= bezt->f2; + return NULL; } -/* make a list of keyframe 'columns' in an IPO block */ -void make_cfra_list (Ipo *ipo, ListBase *elems) +/* Camera Types */ +static char *camera_adrcodes_to_paths (int adrcode, int *array_index) { - IpoCurve *icu; - BezTriple *bezt; - int a; - - for (icu= ipo->curve.first; icu; icu= icu->next) { - if (icu->flag & IPO_VISIBLE) { - /* ... removed old checks for adrcode types from here ... - * - (was this used for IpoKeys in the past?) - */ + /* set array index like this in-case nothing sets it correctly */ + *array_index= 0; + + /* result depends on adrcode */ + switch (adrcode) { + case CAM_LENS: +#if 0 // XXX this cannot be resolved easily... perhaps we assume camera is perspective (works for most cases... + if (ca->type == CAM_ORTHO) + return "ortho_scale"; + else + return "lens"; +#endif // XXX this cannot be resolved easily + break; - bezt= icu->bezt; - if (bezt) { - for (a=0; a < icu->totvert; a++, bezt++) { - add_to_cfra_elem(elems, bezt); - } - } - } + case CAM_STA: + return "clip_start"; + case CAM_END: + return "clip_end"; + +#if 0 // XXX these are not defined in RNA + case CAM_YF_APERT: + poin= &(ca->YF_aperture); break; + case CAM_YF_FDIST: + poin= &(ca->YF_dofdist); break; +#endif // XXX these are not defined in RNA + + case CAM_SHIFT_X: + return "shift_x"; + case CAM_SHIFT_Y: + return "shift_y"; } -} - -/* ***************************** Timing Stuff ********************************* */ - -/* This (evil) function is needed to cope with two legacy Blender rendering features - * mblur (motion blur that renders 'subframes' and blurs them together), and fields - * rendering. Thus, the use of ugly globals from object.c - */ -// BAD... EVIL... JUJU...!!!! -float frame_to_float (int cfra) /* see also bsystem_time in object.c */ -{ - extern float bluroffs; /* bad stuff borrowed from object.c */ - extern float fieldoffs; - float ctime; - - ctime= (float)cfra; - ctime+= bluroffs+fieldoffs; - ctime*= G.scene->r.framelen; - return ctime; + /* unrecognised adrcode, or not-yet-handled ones! */ + return NULL; } -/* ***************************** IPO Curve Sanity ********************************* */ -/* The functions here are used in various parts of Blender, usually after some editing - * of keyframe data has occurred. They ensure that keyframe data is properly ordered and - * that the handles are correctly - */ - -/* This function recalculates the handles of an IPO-Curve - * If the BezTriples have been rearranged, sort them first before using this. - */ -void calchandles_ipocurve (IpoCurve *icu) +/* Lamp Types */ +static char *lamp_adrcodes_to_paths (int adrcode, int *array_index) { - BezTriple *bezt, *prev, *next; - int a= icu->totvert; - - /* Error checking: - * - need at least two points - * - need bezier keys - * - only bezier-interpolation has handles (for now) - */ - if (ELEM(NULL, icu, icu->bezt) || (a < 2) || ELEM(icu->ipo, IPO_CONST, IPO_LIN)) - return; - - /* get initial pointers */ - bezt= icu->bezt; - prev= NULL; - next= (bezt + 1); + /* set array index like this in-case nothing sets it correctly */ + *array_index= 0; - /* loop over all beztriples, adjusting handles */ - while (a--) { - /* clamp timing of handles to be on either side of beztriple */ - if (bezt->vec[0][0] > bezt->vec[1][0]) bezt->vec[0][0]= bezt->vec[1][0]; - if (bezt->vec[2][0] < bezt->vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0]; - - /* calculate autohandles */ - if (icu->flag & IPO_AUTO_HORIZ) - calchandleNurb(bezt, prev, next, 2); /* 2==special autohandle && keep extrema horizontal */ - else - calchandleNurb(bezt, prev, next, 1); /* 1==special autohandle */ - - /* for automatic ease in and out */ - if ((bezt->h1==HD_AUTO) && (bezt->h2==HD_AUTO)) { - /* only do this on first or last beztriple */ - if ((a==0) || (a==icu->totvert-1)) { - /* set both handles to have same horizontal value as keyframe */ - if (icu->extrap==IPO_HORIZ) { - bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1]; - } - } - } + /* result depends on adrcode */ + switch (adrcode) { + case LA_ENERGY: + return "energy"; + + case LA_COL_R: + *array_index= 0; return "color"; + case LA_COL_G: + *array_index= 1; return "color"; + case LA_COL_B: + *array_index= 2; return "color"; + + case LA_DIST: + return "distance"; - /* advance pointers for next iteration */ - prev= bezt; - if (a == 1) next= NULL; - else next++; - bezt++; + case LA_SPOTSI: + return "spot_size"; + case LA_SPOTBL: + return "spot_blend"; + + case LA_QUAD1: + return "linear_attenuation"; + case LA_QUAD2: + return "quadratic_attenuation"; + + case LA_HALOINT: + return "halo_intensity"; + + default: /* for now, we assume that the others were MTex channels */ + return mtex_adrcodes_to_paths(adrcode, array_index); } + + /* unrecognised adrcode, or not-yet-handled ones! */ + return NULL; } -/* Use when IPO-Curve with handles has changed - * It treats all BezTriples with the following rules: - * - PHASE 1: do types have to be altered? - * -> Auto handles: become aligned when selection status is NOT(000 || 111) - * -> Vector handles: become 'nothing' when (one half selected AND other not) - * - PHASE 2: recalculate handles -*/ -void testhandles_ipocurve (IpoCurve *icu) +/* Sound Types */ +static char *sound_adrcodes_to_paths (int adrcode, int *array_index) { - BezTriple *bezt; - int a; - - /* only beztriples have handles (bpoints don't though) */ - if (ELEM(NULL, icu, icu->bezt)) - return; + /* set array index like this in-case nothing sets it correctly */ + *array_index= 0; - /* loop over beztriples */ - for (a=0, bezt=icu->bezt; a < icu->totvert; a++, bezt++) { - short flag= 0; - - /* flag is initialised as selection status - * of beztriple control-points (labelled 0,1,2) - */ - if (bezt->f1 & SELECT) flag |= (1<<0); // == 1 - if (bezt->f2 & SELECT) flag |= (1<<1); // == 2 - if (bezt->f3 & SELECT) flag |= (1<<2); // == 4 - - /* one or two handles selected only */ - if (ELEM(flag, 0, 7)==0) { - /* auto handles become aligned */ - if (bezt->h1==HD_AUTO) - bezt->h1= HD_ALIGN; - if(bezt->h2==HD_AUTO) - bezt->h2= HD_ALIGN; - - /* vector handles become 'free' when only one half selected */ - if(bezt->h1==HD_VECT) { - /* only left half (1 or 2 or 1+2) */ - if (flag < 4) - bezt->h1= 0; - } - if(bezt->h2==HD_VECT) { - /* only right half (4 or 2+4) */ - if (flag > 3) - bezt->h2= 0; - } - } + /* result depends on adrcode */ + switch (adrcode) { + case SND_VOLUME: + return "volume"; + case SND_PITCH: + return "pitch"; + /* XXX Joshua -- I had wrapped panning in rna, but someone commented out, calling it "unused" */ + /* case SND_PANNING: + return "panning"; */ + case SND_ATTEN: + return "attenuation"; } - - /* recalculate handles */ - calchandles_ipocurve(icu); + + /* unrecognised adrcode, or not-yet-handled ones! */ + return NULL; } -/* This function sorts BezTriples so that they are arranged in chronological order, - * as tools working on IPO-Curves expect that the BezTriples are in order. - */ -void sort_time_ipocurve(IpoCurve *icu) +/* World Types */ +static char *world_adrcodes_to_paths (int adrcode, int *array_index) { - short ok= 1; + /* set array index like this in-case nothing sets it correctly */ + *array_index= 0; - /* keep adjusting order of beztriples until nothing moves (bubble-sort) */ - while (ok) { - ok= 0; + /* result depends on adrcode */ + switch (adrcode) { + case WO_HOR_R: + *array_index= 0; return "horizon_color"; + case WO_HOR_G: + *array_index= 1; return "horizon_color"; + case WO_HOR_B: + *array_index= 2; return "horizon_color"; + case WO_ZEN_R: + *array_index= 0; return "zenith_color"; + case WO_ZEN_G: + *array_index= 1; return "zenith_color"; + case WO_ZEN_B: + *array_index= 2; return "zenith_color"; - /* currently, will only be needed when there are beztriples */ - if (icu->bezt) { - BezTriple *bezt; - int a; - - /* loop over ALL points to adjust position in array and recalculate handles */ - for (a=0, bezt=icu->bezt; a < icu->totvert; a++, bezt++) { - /* check if thee's a next beztriple which we could try to swap with current */ - if (a < (icu->totvert-1)) { - /* swap if one is after the other (and indicate that order has changed) */ - if (bezt->vec[1][0] > (bezt+1)->vec[1][0]) { - SWAP(BezTriple, *bezt, *(bezt+1)); - ok= 1; - } - - /* if either one of both of the points exceeds crosses over the keyframe time... */ - if ( (bezt->vec[0][0] > bezt->vec[1][0]) && (bezt->vec[2][0] < bezt->vec[1][0]) ) { - /* swap handles if they have switched sides for some reason */ - SWAP(float, bezt->vec[0][0], bezt->vec[2][0]); - SWAP(float, bezt->vec[0][1], bezt->vec[2][1]); - } - else { - /* clamp handles */ - if (bezt->vec[0][0] > bezt->vec[1][0]) - bezt->vec[0][0]= bezt->vec[1][0]; - if (bezt->vec[2][0] < bezt->vec[1][0]) - bezt->vec[2][0]= bezt->vec[1][0]; - } - } - } + case WO_EXPOS: + return "exposure"; + + case WO_MISI: + return "mist.intensity"; + case WO_MISTDI: + return "mist.depth"; + case WO_MISTSTA: + return "mist.start"; + case WO_MISTHI: + return "mist.height"; + + /* Star Color is unused -- recommend removal */ + /* case WO_STAR_R: + *array_index= 0; return "stars.color"; + case WO_STAR_G: + *array_index= 1; return "stars.color"; + case WO_STAR_B: + *array_index= 2; return "stars.color"; */ + + case WO_STARDIST: + return "stars.min_distance"; + case WO_STARSIZE: + return "stars.size"; + + default: /* for now, we assume that the others were MTex channels */ + return mtex_adrcodes_to_paths(adrcode, array_index); } - } + + return NULL; } -/* This function tests if any BezTriples are out of order, thus requiring a sort */ -int test_time_ipocurve (IpoCurve *icu) +/* Particle Types */ +static char *particle_adrcodes_to_paths (int adrcode, int *array_index) { - int a; + /* set array index like this in-case nothing sets it correctly */ + *array_index= 0; - /* currently, only need to test beztriples */ - if (icu->bezt) { - BezTriple *bezt; + /* result depends on adrcode */ + switch (adrcode) { + case PART_CLUMP: + return "settings.clump_factor"; + case PART_AVE: + return "settings.angular_velocity_factor"; + case PART_SIZE: + return "settings.particle_size"; + case PART_DRAG: + return "settings.drag_factor"; + case PART_BROWN: + return "settings.brownian_factor"; + case PART_DAMP: + return "settings.damp_factor"; + case PART_LENGTH: + return "settings.length"; + case PART_GRAV_X: + *array_index= 0; return "settings.acceleration"; + case PART_GRAV_Y: + *array_index= 1; return "settings.acceleration"; + case PART_GRAV_Z: + *array_index= 2; return "settings.acceleration"; + case PART_KINK_AMP: + return "settings.kink_amplitude"; + case PART_KINK_FREQ: + return "settings.kink_frequency"; + case PART_KINK_SHAPE: + return "settings.kink_shape"; + case PART_BB_TILT: + return "settings.billboard_tilt"; - /* loop through all beztriples, stopping when one exceeds the one after it */ - for (a=0, bezt= icu->bezt; a < (icu->totvert - 1); a++, bezt++) { - if (bezt->vec[1][0] > (bezt+1)->vec[1][0]) - return 1; + /* PartDeflect needs to be sorted out properly in rna_object_force; + If anyone else works on this, but is unfamiliar, these particular + settings reference the particles of the system themselves + being used as forces -- it will use the same rna structure + as the similar object forces */ + /*case PART_PD_FSTR: + if (part->pd) poin= &(part->pd->f_strength); + break; + case PART_PD_FFALL: + if (part->pd) poin= &(part->pd->f_power); + break; + case PART_PD_FMAXD: + if (part->pd) poin= &(part->pd->maxdist); + break; + case PART_PD2_FSTR: + if (part->pd2) poin= &(part->pd2->f_strength); + break; + case PART_PD2_FFALL: + if (part->pd2) poin= &(part->pd2->f_power); + break; + case PART_PD2_FMAXD: + if (part->pd2) poin= &(part->pd2->maxdist); + break;*/ + } - } - - /* none need any swapping */ - return 0; + + return NULL; } -/* --------- */ +/* ------- */ -/* The total length of the handles is not allowed to be more - * than the horizontal distance between (v1-v4). - * This is to prevent curve loops. -*/ -void correct_bezpart (float *v1, float *v2, float *v3, float *v4) +/* Allocate memory for RNA-path for some property given a blocktype, adrcode, and 'root' parts of path + * Input: + * - blocktype, adrcode - determines setting to get + * - actname, constname - used to build path + * Output: + * - array_index - index in property's array (if applicable) to use + * - return - the allocated path... + */ +char *get_rna_access (int blocktype, int adrcode, char actname[], char constname[], int *array_index) { - float h1[2], h2[2], len1, len2, len, fac; - - /* calculate handle deltas */ - h1[0]= v1[0]-v2[0]; - h1[1]= v1[1]-v2[1]; - h2[0]= v4[0]-v3[0]; - h2[1]= v4[1]-v3[1]; - - /* calculate distances: - * - len = span of time between keyframes - * - len1 = length of handle of start key - * - len2 = length of handle of end key - */ - len= v4[0]- v1[0]; - len1= (float)fabs(h1[0]); - len2= (float)fabs(h2[0]); + DynStr *path= BLI_dynstr_new(); + char *propname=NULL, *rpath=NULL; + char buf[512]; + int dummy_index= 0; - /* if the handles have no length, no need to do any corrections */ - if ((len1+len2) == 0.0) - return; + /* hack: if constname is set, we can only be dealing with an Constraint curve */ + if (constname) + blocktype= ID_CO; + + /* get property name based on blocktype */ + switch (blocktype) { + case ID_OB: /* object */ + propname= ob_adrcodes_to_paths(adrcode, &dummy_index); + break; - /* the two handles cross over each other, so force them - * apart using the proportion they overlap + case ID_PO: /* pose channel */ + propname= pchan_adrcodes_to_paths(adrcode, &dummy_index); + break; + + case ID_KE: /* shapekeys */ + propname= shapekey_adrcodes_to_paths(adrcode, &dummy_index); + break; + + case ID_CO: /* constraint */ + propname= constraint_adrcodes_to_paths(adrcode, &dummy_index); + break; + + case ID_TE: /* texture */ + propname= texture_adrcodes_to_paths(adrcode, &dummy_index); + break; + + case ID_MA: /* material */ + propname= material_adrcodes_to_paths(adrcode, &dummy_index); + break; + + case ID_CA: /* camera */ + propname= camera_adrcodes_to_paths(adrcode, &dummy_index); + break; + + case ID_LA: /* lamp */ + propname= lamp_adrcodes_to_paths(adrcode, &dummy_index); + break; + + case ID_SO: /* sound */ + propname= sound_adrcodes_to_paths(adrcode, &dummy_index); + + case ID_WO: /* world */ + propname= world_adrcodes_to_paths(adrcode, &dummy_index); + + case ID_PA: /* particle */ + propname= particle_adrcodes_to_paths(adrcode, &dummy_index); + + /* XXX problematic blocktypes */ + case ID_CU: /* curve */ + /* this used to be a 'dummy' curve which got evaluated on the fly... + * now we've got real var for this! + */ + propname= "eval_time"; + break; + + case ID_SEQ: /* sequencer strip */ + //SEQ_FAC1: + // poin= &(seq->facf0); // XXX this doesn't seem to be included anywhere in sequencer RNA... + break; + + /* special hacks */ + case -1: + /* special case for rotdiff drivers... we don't need a property for this... */ + break; + + // TODO... add other blocktypes... + default: + printf("IPO2ANIMATO WARNING: No path for blocktype %d, adrcode %d yet \n", blocktype, adrcode); + break; + } + + /* check if any property found + * - blocktype < 0 is special case for a specific type of driver, where we don't need a property name... */ - if ((len1+len2) > len) { - fac= len/(len1+len2); + if ((propname == NULL) && (blocktype > 0)) { + /* nothing was found, so exit */ + if (array_index) + *array_index= 0; + + BLI_dynstr_free(path); - v2[0]= (v1[0]-fac*h1[0]); - v2[1]= (v1[1]-fac*h1[1]); + return NULL; + } + else { + if (array_index) + *array_index= dummy_index; + } + + /* append preceeding bits to path */ + if ((actname && actname[0]) && (constname && constname[0])) { + /* Constraint in Pose-Channel */ + sprintf(buf, "pose.pose_channels[\"%s\"].constraints[\"%s\"]", actname, constname); + } + else if (actname && actname[0]) { + /* Pose-Channel */ + sprintf(buf, "pose.pose_channels[\"%s\"]", actname); + } + else if (constname && constname[0]) { + /* Constraint in Object */ + sprintf(buf, "constraints[\"%s\"]", constname); + } + else + strcpy(buf, ""); /* empty string */ + BLI_dynstr_append(path, buf); + + /* append property to path (only if applicable) */ + if (blocktype > 0) { + /* need to add dot before property if there was anything precceding this */ + if (buf[0]) + BLI_dynstr_append(path, "."); - v3[0]= (v4[0]-fac*h2[0]); - v3[1]= (v4[1]-fac*h2[1]); + /* now write name of property */ + BLI_dynstr_append(path, propname); } -} - -#if 0 // TODO: enable when we have per-segment interpolation -/* This function sets the interpolation mode for an entire Ipo-Curve. - * It is primarily used for patching old files, but is also used in the interface - * to make sure that all segments of the curve use the same interpolation. - */ -void set_interpolation_ipocurve (IpoCurve *icu, short ipo) -{ - BezTriple *bezt; - int a; - /* validate arguments */ - if (icu == NULL) return; - if (ELEM3(ipo, IPO_CONST, IPO_LIN, IPO_BEZ)==0) return; - - /* set interpolation mode for whole curve */ - icu->ipo= ipo; + /* convert to normal MEM_malloc'd string */ + rpath= BLI_dynstr_get_cstring(path); + BLI_dynstr_free(path); - /* set interpolation mode of all beztriples */ - for (a=0, bezt=icu->bezt; a<icu->totvert; a++, bezt++) - bezt->ipo= ipo; + /* return path... */ + return rpath; } -#endif // TODO: enable when we have per-segment interpolation -/* ***************************** Curve Calculations ********************************* */ +/* *************************************************** */ +/* Conversion Utilities */ -/* find root/zero */ -int findzero (float x, float q0, float q1, float q2, float q3, float *o) +/* Convert IpoDriver to ChannelDriver - will free the old data (i.e. the old driver) */ +static ChannelDriver *idriver_to_cdriver (IpoDriver *idriver) { - double c0, c1, c2, c3, a, b, c, p, q, d, t, phi; - int nr= 0; - - c0= q0 - x; - c1= 3 * (q1 - q0); - c2= 3 * (q0 - 2*q1 + q2); - c3= q3 - q0 + 3 * (q1 - q2); - - if (c3 != 0.0) { - a= c2/c3; - b= c1/c3; - c= c0/c3; - a= a/3; - - p= b/3 - a*a; - q= (2*a*a*a - a*b + c) / 2; - d= q*q + p*p*p; - - if (d > 0.0) { - t= sqrt(d); - o[0]= (float)(Sqrt3d(-q+t) + Sqrt3d(-q-t) - a); - - if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1; - else return 0; - } - else if (d == 0.0) { - t= Sqrt3d(-q); - o[0]= (float)(2*t - a); - - if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++; - o[nr]= (float)(-t-a); - - if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1; - else return nr; - } - else { - phi= acos(-q / sqrt(-(p*p*p))); - t= sqrt(-p); - p= cos(phi/3); - q= sqrt(3 - 3*p*p); - o[0]= (float)(2*t*p - a); - - if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++; - o[nr]= (float)(-t * (p + q) - a); - - if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) nr++; - o[nr]= (float)(-t * (p - q) - a); - - if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1; - else return nr; - } + ChannelDriver *cdriver; + DriverTarget *dtar=NULL, *dtar2=NULL; + + /* allocate memory for new driver */ + cdriver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver"); + + /* if 'pydriver', just copy data across */ + if (idriver->type == IPO_DRIVER_TYPE_PYTHON) { + /* PyDriver only requires the expression to be copied */ + // TODO: but the expression will be useless... + cdriver->type = DRIVER_TYPE_PYTHON; + strcpy(cdriver->expression, idriver->name); // XXX is this safe? } else { - a=c2; - b=c1; - c=c0; - - if (a != 0.0) { - // discriminant - p= b*b - 4*a*c; - - if (p > 0) { - p= sqrt(p); - o[0]= (float)((-b-p) / (2 * a)); + /* what to store depends on the 'blocktype' (ID_OB or ID_PO - object or posechannel) */ + if (idriver->blocktype == ID_AR) { + /* ID_PO */ + if (idriver->adrcode == OB_ROT_DIFF) { + /* Rotational Difference is a special type of driver now... */ + cdriver->type= DRIVER_TYPE_ROTDIFF; + + /* make 2 driver targets */ + dtar= driver_add_new_target(cdriver); + dtar2= driver_add_new_target(cdriver); - if ((o[0] >= SMALL) && (o[0] <= 1.000001)) nr++; - o[nr]= (float)((-b+p)/(2*a)); + /* driver must use bones from same armature... */ + dtar->id= dtar2->id= (ID *)idriver->ob; - if ((o[nr] >= SMALL) && (o[nr] <= 1.000001)) return nr+1; - else return nr; + /* paths for the two targets get the pointers to the relevant Pose-Channels + * - return pointers to Pose-Channels not rotation channels, as calculation code is picky + * - old bone names were stored in same var, in idriver->name + * + * - we use several hacks here - blocktype == -1 specifies that no property needs to be found, and + * providing a name for 'actname' will automatically imply Pose-Channel with name 'actname' + */ + dtar->rna_path= get_rna_access(-1, -1, idriver->name, NULL, NULL); + dtar2->rna_path= get_rna_access(-1, -1, idriver->name+DRIVER_NAME_OFFS, NULL, NULL); } - else if (p == 0) { - o[0]= (float)(-b / (2 * a)); - if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1; - else return 0; + else { + /* 'standard' driver */ + cdriver->type= DRIVER_TYPE_AVERAGE; + + /* make 1 driver target */ + dtar= driver_add_new_target(cdriver); + dtar->id= (ID *)idriver->ob; + + switch (idriver->adrcode) { + case OB_LOC_X: /* x,y,z location are quite straightforward */ + dtar->rna_path= get_rna_access(ID_PO, AC_LOC_X, idriver->name, NULL, &dtar->array_index); + break; + case OB_LOC_Y: + dtar->rna_path= get_rna_access(ID_PO, AC_LOC_Y, idriver->name, NULL, &dtar->array_index); + break; + case OB_LOC_Z: + dtar->rna_path= get_rna_access(ID_PO, AC_LOC_Z, idriver->name, NULL, &dtar->array_index); + break; + + case OB_SIZE_X: /* x,y,z scaling are also quite straightforward */ + dtar->rna_path= get_rna_access(ID_PO, AC_SIZE_X, idriver->name, NULL, &dtar->array_index); + break; + case OB_SIZE_Y: + dtar->rna_path= get_rna_access(ID_PO, AC_SIZE_Y, idriver->name, NULL, &dtar->array_index); + break; + case OB_SIZE_Z: + dtar->rna_path= get_rna_access(ID_PO, AC_SIZE_Z, idriver->name, NULL, &dtar->array_index); + break; + + case OB_ROT_X: /* rotation - we need to be careful with this... */ + case OB_ROT_Y: + case OB_ROT_Z: + { + /* -1 here, not rotation code, since old system didn't have eulers */ + dtar->rna_path= get_rna_access(ID_PO, -1, idriver->name, NULL, NULL); + dtar->array_index= idriver->adrcode - OB_ROT_X; + } + break; + } } } - else if (b != 0.0) { - o[0]= (float)(-c/b); + else { + /* ID_OB */ + cdriver->type= DRIVER_TYPE_AVERAGE; - if ((o[0] >= SMALL) && (o[0] <= 1.000001)) return 1; - else return 0; - } - else if (c == 0.0) { - o[0]= 0.0; - return 1; + /* make 1 driver target */ + dtar= driver_add_new_target(cdriver); + + dtar->id= (ID *)idriver->ob; + dtar->rna_path= get_rna_access(ID_OB, idriver->adrcode, NULL, NULL, &dtar->array_index); } - - return 0; - } -} - -void berekeny (float f1, float f2, float f3, float f4, float *o, int b) -{ - float t, c0, c1, c2, c3; - int a; - - c0= f1; - c1= 3.0f * (f2 - f1); - c2= 3.0f * (f1 - 2.0f*f2 + f3); - c3= f4 - f1 + 3.0f * (f2 - f3); - - for (a=0; a < b; a++) { - t= o[a]; - o[a]= c0 + t*c1 + t*t*c2 + t*t*t*c3; - } -} - -void berekenx (float *f, float *o, int b) -{ - float t, c0, c1, c2, c3; - int a; - - c0= f[0]; - c1= 3 * (f[3] - f[0]); - c2= 3 * (f[0] - 2*f[3] + f[6]); - c3= f[9] - f[0] + 3 * (f[3] - f[6]); - - for (a=0; a < b; a++) { - t= o[a]; - o[a]= c0 + t*c1 + t*t*c2 + t*t*t*c3; } + + + /* free old driver */ + MEM_freeN(idriver); + + /* return the new one */ + return cdriver; } -/* ***************************** IPO - Calculations ********************************* */ - -/* ---------------------- Curve Evaluation --------------------------- */ - -/* helper function for evaluating drivers: - * - we need the local transform = current transform - (parent transform + bone transform) - * - (local transform is on action channel level) +/* Add F-Curve to the correct list + * - grpname is needed to be used as group name where relevant, and is usually derived from actname */ -static void posechannel_get_local_transform (bPoseChannel *pchan, float loc[], float eul[], float size[]) +static void fcurve_add_to_list (ListBase *groups, ListBase *list, FCurve *fcu, char *grpname) { - float parmat[4][4], offs_bone[4][4], imat[4][4]; - float diff_mat[4][4]; - - /* get first the parent + bone transform in parmat */ - if (pchan->parent) { - /* bone transform itself */ - Mat4CpyMat3(offs_bone, pchan->bone->bone_mat); + /* If we're adding to an action, we will have groups to write to... */ + if (groups && grpname) { + /* wrap the pointers given into a dummy action that we pass to the API func + * and extract the resultant lists... + */ + bAction tmp_act; + bActionGroup *agrp= NULL; - /* The bone's root offset (is in the parent's coordinate system) */ - VECCOPY(offs_bone[3], pchan->bone->head); + /* init the temp action */ + //memset(&tmp_act, 0, sizeof(bAction)); // XXX only enable this line if we get errors + tmp_act.groups.first= groups->first; + tmp_act.groups.last= groups->last; + tmp_act.curves.first= list->first; + tmp_act.curves.last= list->last; + /* ... xxx, the other vars don't need to be filled in */ - /* Get the length translation of parent (length along y axis) */ - offs_bone[3][1]+= pchan->parent->bone->length; + /* get the group to use */ + agrp= action_groups_find_named(&tmp_act, grpname); + if (agrp == NULL) { + /* no matching group, so add one */ + if (agrp == NULL) { + /* Add a new group, and make it active */ + agrp= MEM_callocN(sizeof(bActionGroup), "bActionGroup"); + + agrp->flag = AGRP_SELECTED; + BLI_snprintf(agrp->name, 64, grpname); + + BLI_addtail(&tmp_act.groups, agrp); + BLI_uniquename(&tmp_act.groups, agrp, "Group", '.', offsetof(bActionGroup, name), 64); + } + } - Mat4MulSerie(parmat, pchan->parent->pose_mat, offs_bone, NULL, NULL, NULL, NULL, NULL, NULL); + /* add F-Curve to group */ + /* WARNING: this func should only need to look at the stuff we initialised, if not, things may crash */ + action_groups_add_channel(&tmp_act, agrp, fcu); - /* invert it */ - Mat4Invert(imat, parmat); + /* set the output lists based on the ones in the temp action */ + groups->first= tmp_act.groups.first; + groups->last= tmp_act.groups.last; + list->first= tmp_act.curves.first; + list->last= tmp_act.curves.last; } else { - Mat4CpyMat3(offs_bone, pchan->bone->bone_mat); - VECCOPY(offs_bone[3], pchan->bone->head); - - /* invert it */ - Mat4Invert(imat, offs_bone); + /* simply add the F-Curve to the end of the given list */ + BLI_addtail(list, fcu); } - - /* difference: current transform - (parent transform + bone transform) */ - Mat4MulMat4(diff_mat, pchan->pose_mat, imat); - - /* extract relevant components */ - if (loc) - VECCOPY(loc, diff_mat[3]); - if (eul) - Mat4ToEul(diff_mat, eul); - if (size) - Mat4ToSize(diff_mat, size); } -/* evaluate an IPO-driver to get a 'time' value to use instead of "ipotime" - * - "ipotime" is the frame at which IPO-curve is being evaluated - * - has to return a float value +/* Convert IPO-Curve to F-Curve (including Driver data), and free any of the old data that + * is not relevant, BUT do not free the IPO-Curve itself... + * actname: name of Action-Channel (if applicable) that IPO-Curve's IPO-block belonged to + * constname: name of Constraint-Channel (if applicable) that IPO-Curve's IPO-block belonged to */ -static float eval_driver (IpoDriver *driver, float ipotime) +static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, char *actname, char *constname) { -#ifndef DISABLE_PYTHON - /* currently, drivers are either PyDrivers (evaluating a PyExpression, or Object/Pose-Channel transforms) */ - if (driver->type == IPO_DRIVER_TYPE_PYTHON) { - /* check for empty or invalid expression */ - if ( (driver->name[0] == '\0') || - (driver->flag & IPO_DRIVER_FLAG_INVALID) ) + AdrBit2Path *abp; + FCurve *fcu; + int i=0, totbits; + + /* allocate memory for a new F-Curve */ + fcu= MEM_callocN(sizeof(FCurve), "FCurve"); + + /* convert driver - will free the old one... */ + if (icu->driver) { + fcu->driver= idriver_to_cdriver(icu->driver); + icu->driver= NULL; + } + + /* copy flags */ + if (icu->flag & IPO_VISIBLE) fcu->flag |= FCURVE_VISIBLE; + if (icu->flag & IPO_SELECT) fcu->flag |= FCURVE_SELECTED; + if (icu->flag & IPO_ACTIVE) fcu->flag |= FCURVE_ACTIVE; + if (icu->flag & IPO_MUTE) fcu->flag |= FCURVE_MUTED; + if (icu->flag & IPO_PROTECT) fcu->flag |= FCURVE_PROTECTED; + if (icu->flag & IPO_AUTO_HORIZ) fcu->flag |= FCURVE_AUTO_HANDLES; + + /* set extrapolation */ + switch (icu->extrap) { + case IPO_HORIZ: /* constant extrapolation */ + case IPO_DIR: /* linear extrapolation */ { - return 0.0f; + /* just copy, as the new defines match the old ones... */ + fcu->extend= icu->extrap; } - - /* this evaluates the expression using Python,and returns its result: - * - on errors it reports, then returns 0.0f - */ - return BPY_pydriver_eval(driver); - } - else -#endif /* DISABLE_PYTHON */ - { - - Object *ob= driver->ob; - - /* must have an object to evaluate */ - if (ob == NULL) - return 0.0f; - - /* if a proxy, use the proxy source*/ - if (ob->proxy_from) - ob= ob->proxy_from; - - /* use given object as driver */ - if (driver->blocktype == ID_OB) { - /* depsgraph failure: ob ipos are calculated in where_is_object, this might get called too late */ - if ((ob->ipo) && (ob->ctime != ipotime)) { - /* calculate the value of relevant channel on the Object, but do not write the value - * calculated on to the Object but onto "ipotime" instead - */ - calc_ipo_spec(ob->ipo, driver->adrcode, &ipotime); - return ipotime; - } + break; - /* return the value of the relevant channel */ - switch (driver->adrcode) { - case OB_LOC_X: - return ob->loc[0]; - case OB_LOC_Y: - return ob->loc[1]; - case OB_LOC_Z: - return ob->loc[2]; - case OB_ROT_X: /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */ - return (float)( ob->rot[0]/(M_PI_2/9.0) ); - case OB_ROT_Y: /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */ - return (float)( ob->rot[1]/(M_PI_2/9.0) ); - case OB_ROT_Z: /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */ - return (float)( ob->rot[2]/(M_PI_2/9.0) ); - case OB_SIZE_X: - return ob->size[0]; - case OB_SIZE_Y: - return ob->size[1]; - case OB_SIZE_Z: - return ob->size[2]; - } + case IPO_CYCL: /* cyclic extrapolation */ + case IPO_CYCLX: /* cyclic extrapolation + offset */ + { + /* Add a new FModifier (Cyclic) instead of setting extend value + * as that's the new equivilant of that option. + */ + FModifier *fcm= add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES); + FMod_Cycles *data= (FMod_Cycles *)fcm->data; + + /* if 'offset' one is in use, set appropriate settings */ + if (icu->extrap == IPO_CYCLX) + data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC_OFFSET; + else + data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC; } + break; + } + + /* -------- */ + + /* get adrcode <-> bitflags mapping to handle nasty bitflag curves? */ + abp= adrcode_bitmaps_to_paths(icu->blocktype, icu->adrcode, &totbits); + if (abp && totbits) { + FCurve *fcurve; + int b; + + if (G.f & G_DEBUG) printf("\tconvert bitflag ipocurve, totbits = %d \n", totbits); + + /* add the 'only int values' flag */ + fcu->flag |= (FCURVE_INT_VALUES|FCURVE_DISCRETE_VALUES); - /* use given pose-channel as driver */ - else { /* ID_AR */ - bPoseChannel *pchan= get_pose_channel(ob->pose, driver->name); + /* for each bit we have to remap + check for: + * 1) we need to make copy the existing F-Curve data (fcu -> fcurve), + * except for the last one which will use the original + * 2) copy the relevant path info across + * 3) filter the keyframes for the flag of interest + */ + for (b=0; b < totbits; b++, abp++) { + /* make a copy of existing base-data if not the last curve */ + if (b < (totbits-1)) + fcurve= copy_fcurve(fcu); + else + fcurve= fcu; + + /* set path */ + fcurve->rna_path= BLI_strdupn(abp->path, strlen(abp->path)); + fcurve->array_index= abp->array_index; - /* must have at least 1 bone to use */ - if (pchan && pchan->bone) { - /* rotation difference is not a simple driver (i.e. value drives value), but the angle between 2 bones is driving stuff... - * - the name of the second pchan is also stored in driver->name, but packed after the other one by DRIVER_NAME_OFFS chars - */ - if (driver->adrcode == OB_ROT_DIFF) { - bPoseChannel *pchan2= get_pose_channel(ob->pose, driver->name+DRIVER_NAME_OFFS); - - if (pchan2 && pchan2->bone) { - float q1[4], q2[4], quat[4], angle; - - Mat4ToQuat(pchan->pose_mat, q1); - Mat4ToQuat(pchan2->pose_mat, q2); - - QuatInv(q1); - QuatMul(quat, q1, q2); - angle = 2.0f * (saacos(quat[0])); - angle= ABS(angle); - - return (angle > M_PI) ? (float)((2.0f * M_PI) - angle) : (float)(angle); - } - } + /* convert keyframes + * - beztriples and bpoints are mutually exclusive, so we won't have both at the same time + * - beztriples are more likely to be encountered as they are keyframes (the other type wasn't used yet) + */ + fcurve->totvert= icu->totvert; + + if (icu->bezt) { + BezTriple *dst, *src; + + /* allocate new array for keyframes/beztriples */ + fcurve->bezt= MEM_callocN(sizeof(BezTriple)*fcurve->totvert, "BezTriples"); - /* standard driver */ - else { - float loc[3], eul[3], size[3]; + /* loop through copying all BezTriples individually, as we need to modify a few things */ + for (dst=fcurve->bezt, src=icu->bezt; i < fcurve->totvert; i++, dst++, src++) { + /* firstly, copy BezTriple data */ + *dst= *src; - /* retrieve local transforms to return - * - we use eulers here NOT quats, so that Objects can be driven by bones easily - * also, this way is more understandable for users - */ - posechannel_get_local_transform(pchan, loc, eul, size); + /* interpolation can only be constant... */ + dst->ipo= BEZT_IPO_CONST; - switch (driver->adrcode) { - case OB_LOC_X: - return loc[0]; - case OB_LOC_Y: - return loc[1]; - case OB_LOC_Z: - return loc[2]; - case OB_ROT_X: /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */ - return (float)( eul[0]/(M_PI_2/9.0) ); - case OB_ROT_Y: /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */ - return (float)( eul[1]/(M_PI_2/9.0) ); - case OB_ROT_Z: /* hack: euler rotations are divided by 10 deg to fit on same axes as other channels */ - return (float)( eul[2]/(M_PI_2/9.0) ); - case OB_SIZE_X: - return size[0]; - case OB_SIZE_Y: - return size[1]; - case OB_SIZE_Z: - return size[2]; - } + /* correct values, by checking if the flag of interest is set */ + if ( ((int)(dst->vec[1][1])) & (abp->bit) ) + dst->vec[0][1]= dst->vec[1][1]= dst->vec[2][1] = 1.0f; + else + dst->vec[0][1]= dst->vec[1][1]= dst->vec[2][1] = 0.0f; } } - } - } - - /* return 0.0f, as couldn't find relevant data to use */ - return 0.0f; -} - -/* evaluate and return the value of the given IPO-curve at the specified frame ("evaltime") */ -float eval_icu(IpoCurve *icu, float evaltime) -{ - float cvalue = 0.0f; - - /* if there is a driver, evaluate it to find value to use as "evaltime" - * - this value will also be returned as the value of the 'curve', if there are no keyframes - */ - if (icu->driver) { - /* ipotime now serves as input for the curve */ - evaltime= cvalue= eval_driver(icu->driver, evaltime); - } - - /* there are keyframes (in the form of BezTriples) which can be interpolated between */ - if (icu->bezt) { - /* get pointers */ - BezTriple *bezt, *prevbezt, *lastbezt; - float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac; - float cycdx, cycdy, ofs, cycyofs= 0.0; - int a, b; - - /* get pointers */ - a= icu->totvert-1; - prevbezt= icu->bezt; - bezt= prevbezt+1; - lastbezt= prevbezt + a; - - /* extrapolation mode is 'cyclic' - find relative place within a cycle */ - if (icu->extrap & IPO_CYCL) { - /* ofs is start frame of cycle */ - ofs= prevbezt->vec[1][0]; - - /* calculate period and amplitude (total height) of a cycle */ - cycdx= lastbezt->vec[1][0] - prevbezt->vec[1][0]; - cycdy= lastbezt->vec[1][1] - prevbezt->vec[1][1]; - - /* cycle occurs over some period of time (cycdx should be positive all the time) */ - if (cycdx) { - /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle - * - IPO_CYCLX = (IPO_CYCL + IPO_DIR) - */ - if (icu->extrap & IPO_DIR) { - cycyofs = (float)floor((evaltime - ofs) / cycdx); - cycyofs *= cycdy; - } - - /* calculate where in the cycle we are (overwrite evaltime to reflect this) */ - evaltime= (float)(fmod(evaltime-ofs, cycdx) + ofs); - if (evaltime < ofs) evaltime += cycdx; + else if (icu->bp) { + /* TODO: need to convert from BPoint type to the more compact FPoint type... but not priority, since no data used this */ + //BPoint *bp; + //FPoint *fpt; } + + /* add new F-Curve to list */ + fcurve_add_to_list(groups, list, fcurve, actname); } - /* evaluation time at or past endpoints? */ - // TODO: for per-bezt interpolation, replace all icu->ipo with (bezt)->ipo - if (prevbezt->vec[1][0] >= evaltime) { - /* before or on first keyframe */ - if ((icu->extrap & IPO_DIR) && (icu->ipo != IPO_CONST)) { - /* linear or bezier interpolation */ - if (icu->ipo==IPO_LIN) { - /* Use the next center point instead of our own handle for - * linear interpolated extrapolate - */ - if (icu->totvert == 1) - cvalue= prevbezt->vec[1][1]; - else { - bezt = prevbezt+1; - dx= prevbezt->vec[1][0] - evaltime; - fac= bezt->vec[1][0] - prevbezt->vec[1][0]; - - /* prevent division by zero */ - if (fac) { - fac= (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac; - cvalue= prevbezt->vec[1][1] - (fac * dx); - } - else - cvalue= prevbezt->vec[1][1]; - } - } - else { - /* Use the first handle (earlier) of first BezTriple to calculate the - * gradient and thus the value of the curve at evaltime - */ - dx= prevbezt->vec[1][0] - evaltime; - fac= prevbezt->vec[1][0] - prevbezt->vec[0][0]; + /* free old data of curve now that it's no longer needed for converting any more curves */ + if (icu->bezt) MEM_freeN(icu->bezt); + if (icu->bp) MEM_freeN(icu->bezt); + } + else { + /* get rna-path + * - we will need to set the 'disabled' flag if no path is able to be made (for now) + */ + fcu->rna_path= get_rna_access(icu->blocktype, icu->adrcode, actname, constname, &fcu->array_index); + if (fcu->rna_path == NULL) + fcu->flag |= FCURVE_DISABLED; + + /* convert keyframes + * - beztriples and bpoints are mutually exclusive, so we won't have both at the same time + * - beztriples are more likely to be encountered as they are keyframes (the other type wasn't used yet) + */ + fcu->totvert= icu->totvert; + + if (icu->bezt) { + BezTriple *dst, *src; + + /* allocate new array for keyframes/beztriples */ + fcu->bezt= MEM_callocN(sizeof(BezTriple)*fcu->totvert, "BezTriples"); + + /* loop through copying all BezTriples individually, as we need to modify a few things */ + for (dst=fcu->bezt, src=icu->bezt; i < fcu->totvert; i++, dst++, src++) { + /* firstly, copy BezTriple data */ + *dst= *src; + + /* now copy interpolation from curve (if not already set) */ + if (icu->ipo != IPO_MIXED) + dst->ipo= icu->ipo; - /* prevent division by zero */ - if (fac) { - fac= (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac; - cvalue= prevbezt->vec[1][1] - (fac * dx); - } - else - cvalue= prevbezt->vec[1][1]; + /* correct values for euler rotation curves - they were degrees/10 */ + // XXX for now, just make them into radians as RNA sets/reads directly in that form + if ( ((icu->blocktype == ID_OB) && ELEM3(icu->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) || + ((icu->blocktype == ID_PO) && ELEM3(icu->adrcode, AC_EUL_X, AC_EUL_Y, AC_EUL_Z)) ) + { + const float fac= (float)M_PI / 18.0f; //10.0f * M_PI/180.0f; + + dst->vec[0][1] *= fac; + dst->vec[1][1] *= fac; + dst->vec[2][1] *= fac; } - } - else { - /* constant (IPO_HORIZ) extrapolation or constant interpolation, - * so just extend first keyframe's value + + /* correct times for rotation drivers + * - need to go from degrees to radians... + * - there's only really 1 target to worry about */ - cvalue= prevbezt->vec[1][1]; - } - } - else if (lastbezt->vec[1][0] <= evaltime) { - /* after or on last keyframe */ - if( (icu->extrap & IPO_DIR) && (icu->ipo != IPO_CONST)) { - /* linear or bezier interpolation */ - if (icu->ipo==IPO_LIN) { - /* Use the next center point instead of our own handle for - * linear interpolated extrapolate + if (fcu->driver && fcu->driver->targets.first) { + DriverTarget *dtar= fcu->driver->targets.first; + + /* since drivers could only be for objects, we should just check for 'rotation' being + * in the name of the path given + * - WARNING: this will break if we encounter a bone or object explictly named in that way... */ - if (icu->totvert == 1) - cvalue= lastbezt->vec[1][1]; - else { - prevbezt = lastbezt - 1; - dx= evaltime - lastbezt->vec[1][0]; - fac= lastbezt->vec[1][0] - prevbezt->vec[1][0]; + if ((dtar && dtar->rna_path) && strstr(dtar->rna_path, "rotation")) { + const float fac= (float)M_PI / 180.0f; - /* prevent division by zero */ - if (fac) { - fac= (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac; - cvalue= lastbezt->vec[1][1] + (fac * dx); - } - else - cvalue= lastbezt->vec[1][1]; - } - } - else { - /* Use the gradient of the second handle (later) of last BezTriple to calculate the - * gradient and thus the value of the curve at evaltime - */ - dx= evaltime - lastbezt->vec[1][0]; - fac= lastbezt->vec[2][0] - lastbezt->vec[1][0]; - - /* prevent division by zero */ - if (fac) { - fac= (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac; - cvalue= lastbezt->vec[1][1] + (fac * dx); + dst->vec[0][0] *= fac; + dst->vec[1][0] *= fac; + dst->vec[2][0] *= fac; } - else - cvalue= lastbezt->vec[1][1]; } } - else { - /* constant (IPO_HORIZ) extrapolation or constant interpolation, - * so just extend last keyframe's value - */ - cvalue= lastbezt->vec[1][1]; - } + + /* free this data now */ + MEM_freeN(icu->bezt); } - else { - /* evaltime occurs somewhere in the middle of the curve */ - // TODO: chould be optimised by using a binary search instead??? - for (a=0; prevbezt && bezt && (a < icu->totvert-1); a++, prevbezt=bezt, bezt++) { - /* evaltime occurs within the interval defined by these two keyframes */ - if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) { - /* value depends on interpolation mode */ - if (icu->ipo == IPO_CONST) { - /* constant (evaltime not relevant, so no interpolation needed) */ - cvalue= prevbezt->vec[1][1]; - } - else if (icu->ipo == IPO_LIN) { - /* linear - interpolate between values of the two keyframes */ - fac= bezt->vec[1][0] - prevbezt->vec[1][0]; - - /* prevent division by zero */ - if (fac) { - fac= (evaltime - prevbezt->vec[1][0]) / fac; - cvalue= prevbezt->vec[1][1] + (fac * (bezt->vec[1][1] - prevbezt->vec[1][1])); - } - else - cvalue= prevbezt->vec[1][1]; - } - else { - /* bezier interpolation */ - /* v1,v2 are the first keyframe and its 2nd handle */ - v1[0]= prevbezt->vec[1][0]; - v1[1]= prevbezt->vec[1][1]; - v2[0]= prevbezt->vec[2][0]; - v2[1]= prevbezt->vec[2][1]; - /* v3,v4 are the last keyframe's 1st handle + the last keyframe */ - v3[0]= bezt->vec[0][0]; - v3[1]= bezt->vec[0][1]; - v4[0]= bezt->vec[1][0]; - v4[1]= bezt->vec[1][1]; - - /* adjust handles so that they don't overlap (forming a loop) */ - correct_bezpart(v1, v2, v3, v4); - - /* try to get a value for this position - if failure, try another set of points */ - b= findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl); - if (b) { - berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1); - cvalue= opl[0]; - break; - } - } - } - } + else if (icu->bp) { + /* TODO: need to convert from BPoint type to the more compact FPoint type... but not priority, since no data used this */ + //BPoint *bp; + //FPoint *fpt; } - /* apply y-offset (for 'cyclic extrapolation') to calculated value */ - cvalue+= cycyofs; + /* add new F-Curve to list */ + fcurve_add_to_list(groups, list, fcu, actname); } - - /* clamp evaluated value to lie within allowable value range for this channel */ - if (icu->ymin < icu->ymax) { - CLAMP(cvalue, icu->ymin, icu->ymax); - } - - /* return evaluated value */ - return cvalue; } -/* ------------------- IPO-Block/Curve Calculation - General API ----------------------- */ - -/* calculate the value of the given IPO-curve at the current frame, and set its curval */ -void calc_icu (IpoCurve *icu, float ctime) -{ - /* calculate and set curval (evaluates driver too) */ - icu->curval= eval_icu(icu, ctime); -} +/* ------------------------- */ -/* calculate for the current frame, all IPO-curves in IPO-block that can be evaluated - * - icu->curval is set for all IPO-curves which are evaluated! +/* Convert IPO-block (i.e. all its IpoCurves) to the new system. + * This does not assume that any ID or AnimData uses it, but does assume that + * it is given two lists, which it will perform driver/animation-data separation. */ -void calc_ipo (Ipo *ipo, float ctime) +static void ipo_to_animato (Ipo *ipo, char actname[], char constname[], ListBase *animgroups, ListBase *anim, ListBase *drivers) { - IpoCurve *icu; - - /* if there is no IPO block to evaluate, or whole block is "muted" */ - if (ipo == NULL) return; - if (ipo->muteipo) return; - - /* loop over all curves */ - for (icu= ipo->curve.first; icu; icu= icu->next) { - /* only evaluated curve if allowed to: - * - Muted channels should not be evaluated as they shouldn't have any effect - * --> user explictly turned them off! - * - Drivers should be evaluated at all updates - * --> TODO Note: drivers should be separated from standard channels - * - IPO_LOCK is not set, as it is set by some internal mechanisms to prevent - * IPO-curve from overwriting data (currently only used for IPO-Record). - */ - if ((icu->driver) || (icu->flag & IPO_LOCK)==0) { - if ((icu->flag & IPO_MUTE)==0) - calc_icu(icu, ctime); - } - } -} - -/* ------------------- IPO-Block/Curve Calculation - Special Hacks ----------------------- */ - -/* Calculate and return the value of the 'Time' Ipo-Curve from an Object, - * OR return the current time if not found - * - used in object.c -> bsystem_time() - */ -float calc_ipo_time (Ipo *ipo, float ctime) -{ - /* only Time IPO from Object IPO-blocks are relevant */ - if ((ipo) && (ipo->blocktype == ID_OB)) { - IpoCurve *icu= find_ipocurve(ipo, OB_TIME); - - /* only calculate (and set icu->curval) for time curve */ - if (icu) { - calc_icu(icu, ctime); - return (10.0f * icu->curval); - } - } - - /* no appropriate time-curve found */ - return ctime; -} - -/* Evaluate the specified channel in the given IPO block on the specified frame (ctime), - * writing the value into that channel's icu->curval, but ALSO dumping it in ctime. - * - Returns success and modifies ctime! - */ -short calc_ipo_spec (Ipo *ipo, int adrcode, float *ctime) -{ - IpoCurve *icu= find_ipocurve(ipo, adrcode); + IpoCurve *icu, *icn; - /* only evaluate if found */ - if (icu) { - /* only calculate if allowed to (not locked and not muted) - * - drivers not taken into account, because this may be called when calculating a driver - */ - if ((icu->flag & (IPO_LOCK|IPO_MUTE))==0) - calc_icu(icu, *ctime); + /* sanity check */ + if (ELEM3(NULL, ipo, anim, drivers)) + return; + + if (G.f & G_DEBUG) printf("ipo_to_animato \n"); - /* value resulting from calculations is written into ctime! */ - *ctime= icu->curval; - return 1; + /* validate actname and constname + * - clear actname if it was one of the generic <builtin> ones (i.e. 'Object', or 'Shapes') + * - actname can then be used to assign F-Curves in Action to Action Groups + * (i.e. thus keeping the benefits that used to be provided by Action Channels for grouping + * F-Curves for bones). This may be added later... for now let's just dump without them... + */ + if (actname) { + if ((ipo->blocktype == ID_OB) && (strcmp(actname, "Object") == 0)) + actname= NULL; + else if ((ipo->blocktype == ID_OB) && (strcmp(actname, "Shape") == 0)) + actname= NULL; } - /* couldn't evaluate */ - return 0; -} - -/* ***************************** IPO - DataAPI ********************************* */ - -/* --------------------- Flush/Execute IPO Values ----------------------------- */ - -/* Flush IpoCurve->curvals to the data they affect (defined by ID) - * - not for Actions or Constraints! (those have their own special handling) - */ -void execute_ipo (ID *id, Ipo *ipo) -{ - IpoCurve *icu; - void *poin; - int type; - - /* don't do anything without an IPO block */ - if (ipo == NULL) - return; - - /* loop over IPO Curves, getting pointer to var to affect, and write into that pointer */ - for (icu= ipo->curve.first; icu; icu= icu->next) { - poin= get_ipo_poin(id, icu, &type); - if (poin) write_ipo_poin(poin, type, icu->curval); - } -} - -/* Flush Action-Channel IPO data to Pose Channel */ -void execute_action_ipo (bActionChannel *achan, bPoseChannel *pchan) -{ - /* only do this if there's an Action Channel and Pose Channel to use */ - if (achan && achan->ipo && pchan) { - IpoCurve *icu; + /* loop over IPO-Curves, freeing as we progress */ + for (icu= ipo->curve.first; icu; icu= icn) { + /* get link to next (for later) */ + icn= icu->next; - /* loop over IPO-curves, getting a pointer to pchan var to write to - * - assume for now that only 'float' channels will ever get written into + /* Since an IPO-Curve may end up being made into many F-Curves (i.e. bitflag curves), + * we figure out the best place to put the channel, then tell the curve-converter to just dump there */ - for (icu= achan->ipo->curve.first; icu; icu= icu->next) { - void *poin= get_pchan_ipo_poin(pchan, icu->adrcode); - if (poin) write_ipo_poin(poin, IPO_FLOAT, icu->curval); + if (icu->driver) { + /* Blender 2.4x allowed empty drivers, but we don't now, since they cause more trouble than they're worth */ + if ((icu->driver->ob) || (icu->driver->type == IPO_DRIVER_TYPE_PYTHON)) + icu_to_fcurves(NULL, drivers, icu, actname, constname); + else + MEM_freeN(icu->driver); } - } -} - - -/* --------------------- Force Calculation + Flush IPO Values ----------------------------- */ - -/* Calculate values for given IPO block, then flush to all of block's users - * - for general usage - */ -void do_ipo (Ipo *ipo) -{ - if (ipo) { - float ctime= frame_to_float(G.scene->r.cfra); + else + icu_to_fcurves(animgroups, anim, icu, actname, constname); - /* calculate values, then flush to all users of this IPO block */ - calc_ipo(ipo, ctime); - do_ipo_nocalc(ipo); + /* free this IpoCurve now that it's been converted */ + BLI_freelinkN(&ipo->curve, icu); } } -/* Calculate values for given Material's IPO block, then flush to given Material only */ -void do_mat_ipo (Material *ma) -{ - float ctime; - - if (ELEM(NULL, ma, ma->ipo)) - return; - - ctime= frame_to_float(G.scene->r.cfra); - /* if(ob->ipoflag & OB_OFFS_OB) ctime-= ob->sf; */ - - /* calculate values for current time, then flush values to given material only */ - calc_ipo(ma->ipo, ctime); - execute_ipo((ID *)ma, ma->ipo); -} - -/* Calculate values for given Object's IPO block, then flush to given Object only - * - there's also some funky stuff that looks like it's for scene layers +/* Convert Action-block to new system, separating animation and drivers + * New curves may not be converted directly into the given Action (i.e. for Actions linked + * to Objects, where ob->ipo and ob->action need to be combined). + * NOTE: we need to be careful here, as same data-structs are used for new system too! */ -void do_ob_ipo (Object *ob) +static void action_to_animato (bAction *act, ListBase *groups, ListBase *curves, ListBase *drivers) { - float ctime; - unsigned int lay; + bActionChannel *achan, *achann; + bConstraintChannel *conchan, *conchann; - if (ob->ipo == NULL) + /* only continue if there are Action Channels (indicating unconverted data) */ + if (act->chanbase.first == NULL) return; - - /* do not set ob->ctime here: for example when parent in invisible layer */ - ctime= bsystem_time(ob, (float) G.scene->r.cfra, 0.0); - - /* calculate values of */ - calc_ipo(ob->ipo, ctime); - - /* Patch: remember localview */ - lay= ob->lay & 0xFF000000; - - /* flush IPO values to this object only */ - execute_ipo((ID *)ob, ob->ipo); - - /* hack: for layer animation??? - is this what this is? (Aligorith, 28Sep2008) */ - ob->lay |= lay; - if ((ob->id.name[2]=='S') && (ob->id.name[3]=='C') && (ob->id.name[4]=='E')) { - if (strcmp(G.scene->id.name+2, ob->id.name+6)==0) { - G.scene->lay= ob->lay; - copy_view3d_lock(0); - /* no redraw here! creates too many calls */ + + /* get rid of all Action Groups */ + // XXX this is risky if there's some old + some new data in the Action... + if (act->groups.first) + BLI_freelistN(&act->groups); + + /* loop through Action-Channels, converting data, freeing as we go */ + for (achan= act->chanbase.first; achan; achan= achann) { + /* get pointer to next Action Channel */ + achann= achan->next; + + /* convert Action Channel's IPO data */ + if (achan->ipo) { + ipo_to_animato(achan->ipo, achan->name, NULL, groups, curves, drivers); + achan->ipo->id.us--; + achan->ipo= NULL; } - } -} - -/* Only execute those IPO-Curves with drivers, on the current frame, for the given Object - * - TODO: Drivers should really be made separate from standard anim channels - */ -void do_ob_ipodrivers (Object *ob, Ipo *ipo, float ctime) -{ - IpoCurve *icu; - void *poin; - int type; - - for (icu= ipo->curve.first; icu; icu= icu->next) { - if (icu->driver) { - icu->curval= eval_icu(icu, ctime); + + /* convert constraint channel IPO-data */ + for (conchan= achan->constraintChannels.first; conchan; conchan= conchann) { + /* get pointer to next Constraint Channel */ + conchann= conchan->next; - poin= get_ipo_poin((ID *)ob, icu, &type); - if (poin) write_ipo_poin(poin, type, icu->curval); - } - } -} - -/* Special variation to calculate IPO values for Sequence + perform other stuff */ -void do_seq_ipo (Sequence *seq, int cfra) -{ - float ctime, div; - - /* seq_ipo has an exception: calc both fields immediately */ - if (seq->ipo) { - if ((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) { - ctime = frame_to_float(cfra); - div = 1.0; - } - else { - ctime= frame_to_float(cfra - seq->startdisp); - div= (seq->enddisp - seq->startdisp) / 100.0f; - if (div == 0.0) return; + /* convert Constraint Channel's IPO data */ + if (conchan->ipo) { + ipo_to_animato(conchan->ipo, achan->name, conchan->name, groups, curves, drivers); + conchan->ipo->id.us--; + conchan->ipo= NULL; + } + + /* free Constraint Channel */ + BLI_freelinkN(&achan->constraintChannels, conchan); } - /* 2nd field */ - calc_ipo(seq->ipo, (ctime+0.5f)/div); - execute_ipo((ID *)seq, seq->ipo); - seq->facf1= seq->facf0; - - /* 1st field */ - calc_ipo(seq->ipo, ctime/div); - execute_ipo((ID *)seq, seq->ipo); + /* free Action Channel */ + BLI_freelinkN(&act->chanbase, achan); } - else - seq->facf1= seq->facf0= 1.0f; } -/* --------- */ +/* ------------------------- */ -/* exception: it does calc for objects... - * now find out why this routine was used anyway! +/* Convert IPO-block (i.e. all its IpoCurves) for some ID to the new system + * This assumes that AnimData has been added already. Separation of drivers + * from animation data is accomplished here too... */ -void do_ipo_nocalc (Ipo *ipo) +static void ipo_to_animdata (ID *id, Ipo *ipo, char actname[], char constname[]) { - Object *ob; - Material *ma; - Tex *tex; - World *wo; - Lamp *la; - Camera *ca; - bSound *snd; - - if (ipo == NULL) - return; + AnimData *adt= BKE_animdata_from_id(id); + ListBase anim = {NULL, NULL}; + ListBase drivers = {NULL, NULL}; - /* only flush IPO values (without calculating first/again) on - * to the datablocks that use the given IPO block - */ - switch (ipo->blocktype) { - case ID_OB: - for (ob= G.main->object.first; ob; ob= ob->id.next) { - if (ob->ipo == ipo) do_ob_ipo(ob); - } - break; - case ID_MA: - for (ma= G.main->mat.first; ma; ma= ma->id.next) { - if (ma->ipo == ipo) execute_ipo((ID *)ma, ipo); - } - break; - case ID_TE: - for (tex= G.main->tex.first; tex; tex= tex->id.next) { - if (tex->ipo == ipo) execute_ipo((ID *)tex, ipo); - } - break; - case ID_WO: - for (wo= G.main->world.first; wo; wo= wo->id.next) { - if (wo->ipo == ipo) execute_ipo((ID *)wo, ipo); - } - break; - case ID_LA: - for (la= G.main->lamp.first; la; la= la->id.next) { - if (la->ipo == ipo) execute_ipo((ID *)la, ipo); - } - break; - case ID_CA: - for (ca= G.main->camera.first; ca; ca= ca->id.next) { - if (ca->ipo == ipo) execute_ipo((ID *)ca, ipo); - } - break; - case ID_SO: - for (snd= G.main->sound.first; snd; snd= snd->id.next) { - if (snd->ipo == ipo) execute_ipo((ID *)snd, ipo); - } - break; + /* sanity check */ + if ELEM(NULL, id, ipo) + return; + if (adt == NULL) { + printf("ERROR ipo_to_animdata(): adt invalid \n"); + return; } -} - -/* Executes IPO's for whole database on frame change, in a specified order, - * with datablocks being calculated in alphabetical order - * - called on scene_update_for_newframe() only - */ -void do_all_data_ipos () -{ - Material *ma; - Tex *tex; - World *wo; - Ipo *ipo; - Lamp *la; - Key *key; - Camera *ca; - bSound *snd; - Sequence *seq; - Editing *ed; - Base *base; - float ctime; - - ctime= frame_to_float(G.scene->r.cfra); - /* this exception cannot be depgraphed yet... what todo with objects in other layers?... */ - for (base= G.scene->base.first; base; base= base->next) { - Object *ob= base->object; - - /* only update layer when an ipo */ - if (has_ipo_code(ob->ipo, OB_LAY)) { - do_ob_ipo(ob); - base->lay= ob->lay; - } + if (G.f & G_DEBUG) { + printf("ipo to animdata - ID:%s, IPO:%s, actname:%s constname:%s curves:%d \n", + id->name+2, ipo->id.name+2, (actname)?actname:"<None>", (constname)?constname:"<None>", + BLI_countlist(&ipo->curve)); } - /* layers for the set...*/ - if (G.scene->set) { - for (base= G.scene->set->base.first; base; base= base->next) { - Object *ob= base->object; - - if (has_ipo_code(ob->ipo, OB_LAY)) { - do_ob_ipo(ob); - base->lay= ob->lay; - } - } - } + /* Convert curves to animato system (separated into separate lists of F-Curves for animation and drivers), + * and the try to put these lists in the right places, but do not free the lists here + */ + // XXX there shouldn't be any need for the groups, so don't supply pointer for that now... + ipo_to_animato(ipo, actname, constname, NULL, &anim, &drivers); - /* Calculate all IPO blocks in use, execept those for Objects */ - for (ipo= G.main->ipo.first; ipo; ipo= ipo->id.next) { - if ((ipo->id.us) && (ipo->blocktype != ID_OB)) { - calc_ipo(ipo, ctime); + /* deal with animation first */ + if (anim.first) { + if (G.f & G_DEBUG) printf("\thas anim \n"); + /* try to get action */ + if (adt->action == NULL) { + adt->action= add_empty_action("ConvData_Action"); // XXX we need a better name for this + if (G.f & G_DEBUG) printf("\t\tadded new action \n"); } - } - - /* Texture Blocks */ - for (tex= G.main->tex.first; tex; tex= tex->id.next) { - if (tex->ipo) execute_ipo((ID *)tex, tex->ipo); - } - - /* Material Blocks */ - for (ma= G.main->mat.first; ma; ma= ma->id.next) { - if (ma->ipo) execute_ipo((ID *)ma, ma->ipo); - } - - /* World Blocks */ - for (wo= G.main->world.first; wo; wo= wo->id.next) { - if (wo->ipo) execute_ipo((ID *)wo, wo->ipo); - } - - /* ShapeKey Blocks */ - for (key= G.main->key.first; key; key= key->id.next) { - if (key->ipo) execute_ipo((ID *)key, key->ipo); - } - - /* Lamp Blocks */ - for (la= G.main->lamp.first; la; la= la->id.next) { - if (la->ipo) execute_ipo((ID *)la, la->ipo); - } - - /* Camera Blocks */ - for (ca= G.main->camera.first; ca; ca= ca->id.next) { - if (ca->ipo) execute_ipo((ID *)ca, ca->ipo); + + /* add F-Curves to action */ + addlisttolist(&adt->action->curves, &anim); } - /* Sound Blocks (Old + Unused) */ - for (snd= G.main->sound.first; snd; snd= snd->id.next) { - if (snd->ipo) execute_ipo((ID *)snd, snd->ipo); - } - - /* Sequencer: process FAC Ipos used as volume envelopes */ - ed= G.scene->ed; - if (ed) { - for (seq= ed->seqbasep->first; seq; seq= seq->next) { - if ( ((seq->type == SEQ_RAM_SOUND) || (seq->type == SEQ_HD_SOUND)) && - (seq->startdisp <= G.scene->r.cfra+2) && - (seq->enddisp>G.scene->r.cfra) && - (seq->ipo) ) - { - do_seq_ipo(seq, G.scene->r.cfra); - } - } + /* deal with drivers */ + if (drivers.first) { + if (G.f & G_DEBUG) printf("\thas drivers \n"); + /* add drivers to end of driver stack */ + addlisttolist(&adt->drivers, &drivers); } } - -/* --------------------- Assorted ----------------------------- */ - -/* clear delta-transforms on all Objects which use the given IPO block */ -void clear_delta_obipo(Ipo *ipo) +/* Convert Action-block to new system + * NOTE: we need to be careful here, as same data-structs are used for new system too! + */ +static void action_to_animdata (ID *id, bAction *act) { - Object *ob; + AnimData *adt= BKE_animdata_from_id(id); - /* only search if there's an IPO */ - if (ipo == NULL) + /* only continue if there are Action Channels (indicating unconverted data) */ + if (ELEM(NULL, adt, act->chanbase.first)) return; - /* search through all objects in database */ - for (ob= G.main->object.first; ob; ob= ob->id.next) { - /* can only update if not a library */ - if (ob->id.lib == NULL) { - if (ob->ipo == ipo) { - memset(&ob->dloc, 0, 12); - memset(&ob->drot, 0, 12); - memset(&ob->dsize, 0, 12); - } - } + /* check if we need to set this Action as the AnimData's action */ + if (adt->action == NULL) { + /* set this Action as AnimData's Action */ + if (G.f & G_DEBUG) printf("act_to_adt - set adt action to act \n"); + adt->action= act; } + + /* convert Action data */ + action_to_animato(act, &adt->action->groups, &adt->action->curves, &adt->drivers); } -/* ***************************** IPO - DataAPI ********************************* */ - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!! FIXME - BAD CRUFT WARNING !!!!!!!!!!!!!!!!!!!!!!! - -/* These functions here should be replaced eventually by the Data API, as this is - * inflexible duplication... - */ +/* ------------------------- */ -/* --------------------- Get Pointer API ----------------------------- */ +// TODO: +// - NLA group duplicators info +// - NLA curve/stride modifiers... -/* get pointer to pose-channel's channel, but set appropriate flags first */ -void *get_pchan_ipo_poin (bPoseChannel *pchan, int adrcode) +/* Convert NLA-Strip to new system */ +static void nlastrips_to_animdata (ID *id, ListBase *strips) { - void *poin= NULL; - - switch (adrcode) { - case AC_QUAT_W: - poin= &(pchan->quat[0]); - pchan->flag |= POSE_ROT; - break; - case AC_QUAT_X: - poin= &(pchan->quat[1]); - pchan->flag |= POSE_ROT; - break; - case AC_QUAT_Y: - poin= &(pchan->quat[2]); - pchan->flag |= POSE_ROT; - break; - case AC_QUAT_Z: - poin= &(pchan->quat[3]); - pchan->flag |= POSE_ROT; - break; + AnimData *adt= BKE_animdata_from_id(id); + NlaTrack *nlt = NULL; + NlaStrip *strip; + bActionStrip *as, *asn; + + /* for each one of the original strips, convert to a new strip and free the old... */ + for (as= strips->first; as; as= asn) { + asn= as->next; + + /* this old strip is only worth something if it had an action... */ + if (as->act) { + /* convert Action data (if not yet converted), storing the results in the same Action */ + action_to_animato(as->act, &as->act->groups, &as->act->curves, &adt->drivers); - case AC_LOC_X: - poin= &(pchan->loc[0]); - pchan->flag |= POSE_LOC; - break; - case AC_LOC_Y: - poin= &(pchan->loc[1]); - pchan->flag |= POSE_LOC; - break; - case AC_LOC_Z: - poin= &(pchan->loc[2]); - pchan->flag |= POSE_LOC; - break; + /* create a new-style NLA-strip which references this Action, then copy over relevant settings */ + { + /* init a new strip, and assign the action to it + * - no need to muck around with the user-counts, since this is just + * passing over the ref to the new owner, not creating an additional ref + */ + strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip"); + strip->act= as->act; + + /* endpoints */ + strip->start= as->start; + strip->end= as->end; + strip->actstart= as->actstart; + strip->actend= as->actend; + + /* action reuse */ + strip->repeat= as->repeat; + strip->scale= as->scale; + if (as->flag & ACTSTRIP_LOCK_ACTION) strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH; + + /* blending */ + strip->blendin= as->blendin; + strip->blendout= as->blendout; + strip->blendmode= (as->mode==ACTSTRIPMODE_ADD) ? NLASTRIP_MODE_ADD : NLASTRIP_MODE_REPLACE; + if (as->flag & ACTSTRIP_AUTO_BLENDS) strip->flag |= NLASTRIP_FLAG_AUTO_BLENDS; + + /* assorted setting flags */ + if (as->flag & ACTSTRIP_SELECT) strip->flag |= NLASTRIP_FLAG_SELECT; + if (as->flag & ACTSTRIP_ACTIVE) strip->flag |= NLASTRIP_FLAG_ACTIVE; + + if (as->flag & ACTSTRIP_MUTE) strip->flag |= NLASTRIP_FLAG_MUTED; + if (as->flag & ACTSTRIP_REVERSE) strip->flag |= NLASTRIP_FLAG_REVERSE; + + /* by default, we now always extrapolate, while in the past this was optional */ + if ((as->flag & ACTSTRIP_HOLDLASTFRAME)==0) + strip->extendmode= NLASTRIP_EXTEND_NOTHING; + } + + /* try to add this strip to the current NLA-Track (i.e. the 'last' one on the stack atm) */ + if (BKE_nlatrack_add_strip(nlt, strip) == 0) { + /* trying to add to the current failed (no space), + * so add a new track to the stack, and add to that... + */ + nlt= add_nlatrack(adt, NULL); + BKE_nlatrack_add_strip(nlt, strip); + } + } - case AC_SIZE_X: - poin= &(pchan->size[0]); - pchan->flag |= POSE_SIZE; - break; - case AC_SIZE_Y: - poin= &(pchan->size[1]); - pchan->flag |= POSE_SIZE; - break; - case AC_SIZE_Z: - poin= &(pchan->size[2]); - pchan->flag |= POSE_SIZE; - break; + /* modifiers */ + // FIXME: for now, we just free them... + if (as->modifiers.first) + BLI_freelistN(&as->modifiers); + + /* free the old strip */ + BLI_freelinkN(strips, as); } - - /* return pointer */ - return poin; } -/* get texture channel */ -static void *give_tex_poin (Tex *tex, int adrcode, int *type ) -{ - void *poin= NULL; +/* *************************************************** */ +/* External API - Only Called from do_versions() */ - switch (adrcode) { - case TE_NSIZE: - poin= &(tex->noisesize); break; - case TE_TURB: - poin= &(tex->turbul); break; - case TE_NDEPTH: - poin= &(tex->noisedepth); *type= IPO_SHORT; break; - case TE_NTYPE: - poin= &(tex->noisetype); *type= IPO_SHORT; break; - case TE_VNW1: - poin= &(tex->vn_w1); break; - case TE_VNW2: - poin= &(tex->vn_w2); break; - case TE_VNW3: - poin= &(tex->vn_w3); break; - case TE_VNW4: - poin= &(tex->vn_w4); break; - case TE_VNMEXP: - poin= &(tex->vn_mexp); break; - case TE_ISCA: - poin= &(tex->ns_outscale); break; - case TE_DISTA: - poin= &(tex->dist_amount); break; - case TE_VN_COLT: - poin= &(tex->vn_coltype); *type= IPO_SHORT; break; - case TE_VN_DISTM: - poin= &(tex->vn_distm); *type= IPO_SHORT; break; - case TE_MG_TYP: - poin= &(tex->stype); *type= IPO_SHORT; break; - case TE_MGH: - poin= &(tex->mg_H); break; - case TE_MG_LAC: - poin= &(tex->mg_lacunarity); break; - case TE_MG_OCT: - poin= &(tex->mg_octaves); break; - case TE_MG_OFF: - poin= &(tex->mg_offset); break; - case TE_MG_GAIN: - poin= &(tex->mg_gain); break; - case TE_N_BAS1: - poin= &(tex->noisebasis); *type= IPO_SHORT; break; - case TE_N_BAS2: - poin= &(tex->noisebasis2); *type= IPO_SHORT; break; - case TE_COL_R: - poin= &(tex->rfac); break; - case TE_COL_G: - poin= &(tex->gfac); break; - case TE_COL_B: - poin= &(tex->bfac); break; - case TE_BRIGHT: - poin= &(tex->bright); break; - case TE_CONTRA: - poin= &(tex->contrast); break; - } - - /* return pointer */ - return poin; -} - -/* get texture-slot/mapping channel */ -void *give_mtex_poin (MTex *mtex, int adrcode) +/* Called from do_versions() in readfile.c to convert the old 'IPO/adrcode' system + * to the new 'Animato/RNA' system. + * + * The basic method used here, is to loop over datablocks which have IPO-data, and + * add those IPO's to new AnimData blocks as Actions. + * Action/NLA data only works well for Objects, so these only need to be checked for there. + * + * Data that has been converted should be freed immediately, which means that it is immediately + * clear which datablocks have yet to be converted, and also prevent freeing errors when we exit. + */ +// XXX currently done after all file reading... +void do_versions_ipos_to_animato(Main *main) { - void *poin= NULL; + ListBase drivers = {NULL, NULL}; + ID *id; + AnimData *adt; - switch (adrcode) { - case MAP_OFS_X: - poin= &(mtex->ofs[0]); break; - case MAP_OFS_Y: - poin= &(mtex->ofs[1]); break; - case MAP_OFS_Z: - poin= &(mtex->ofs[2]); break; - case MAP_SIZE_X: - poin= &(mtex->size[0]); break; - case MAP_SIZE_Y: - poin= &(mtex->size[1]); break; - case MAP_SIZE_Z: - poin= &(mtex->size[2]); break; - case MAP_R: - poin= &(mtex->r); break; - case MAP_G: - poin= &(mtex->g); break; - case MAP_B: - poin= &(mtex->b); break; - case MAP_DVAR: - poin= &(mtex->def_var); break; - case MAP_COLF: - poin= &(mtex->colfac); break; - case MAP_NORF: - poin= &(mtex->norfac); break; - case MAP_VARF: - poin= &(mtex->varfac); break; - case MAP_DISP: - poin= &(mtex->dispfac); break; + if (main == NULL) { + printf("Argh! Main is NULL in do_versions_ipos_to_animato() \n"); + return; } - - /* return pointer */ - return poin; -} - -/* GS reads the memory pointed at in a specific ordering. There are, - * however two definitions for it. I have jotted them down here, both, - * but I think the first one is actually used. The thing is that - * big-endian systems might read this the wrong way round. OTOH, we - * constructed the IDs that are read out with this macro explicitly as - * well. I expect we'll sort it out soon... */ - -/* from blendef: */ -#define GS(a) (*((short *)(a))) - -/* from misc_util: flip the bytes from x */ -/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */ - - -/* general function to get pointer to source/destination data */ -void *get_ipo_poin (ID *id, IpoCurve *icu, int *type) -{ - void *poin= NULL; - MTex *mtex= NULL; - - /* most channels will have float data, but those with other types will override this */ - *type= IPO_FLOAT; - - /* data is divided into 'blocktypes' based on ID-codes */ - switch (GS(id->name)) { - case ID_OB: /* object channels ----------------------------- */ - { - Object *ob= (Object *)id; - - switch (icu->adrcode) { - case OB_LOC_X: - poin= &(ob->loc[0]); break; - case OB_LOC_Y: - poin= &(ob->loc[1]); break; - case OB_LOC_Z: - poin= &(ob->loc[2]); break; - case OB_DLOC_X: - poin= &(ob->dloc[0]); break; - case OB_DLOC_Y: - poin= &(ob->dloc[1]); break; - case OB_DLOC_Z: - poin= &(ob->dloc[2]); break; - - case OB_ROT_X: - poin= &(ob->rot[0]); *type= IPO_FLOAT_DEGR; break; - case OB_ROT_Y: - poin= &(ob->rot[1]); *type= IPO_FLOAT_DEGR; break; - case OB_ROT_Z: - poin= &(ob->rot[2]); *type= IPO_FLOAT_DEGR; break; - case OB_DROT_X: - poin= &(ob->drot[0]); *type= IPO_FLOAT_DEGR; break; - case OB_DROT_Y: - poin= &(ob->drot[1]); *type= IPO_FLOAT_DEGR; break; - case OB_DROT_Z: - poin= &(ob->drot[2]); *type= IPO_FLOAT_DEGR; break; - - case OB_SIZE_X: - poin= &(ob->size[0]); break; - case OB_SIZE_Y: - poin= &(ob->size[1]); break; - case OB_SIZE_Z: - poin= &(ob->size[2]); break; - case OB_DSIZE_X: - poin= &(ob->dsize[0]); break; - case OB_DSIZE_Y: - poin= &(ob->dsize[1]); break; - case OB_DSIZE_Z: - poin= &(ob->dsize[2]); break; - - case OB_LAY: - poin= &(ob->lay); *type= IPO_INT_BIT; break; - - case OB_COL_R: - poin= &(ob->col[0]); break; - case OB_COL_G: - poin= &(ob->col[1]); break; - case OB_COL_B: - poin= &(ob->col[2]); break; - case OB_COL_A: - poin= &(ob->col[3]); break; - - case OB_PD_FSTR: - if (ob->pd) poin= &(ob->pd->f_strength); - break; - case OB_PD_FFALL: - if (ob->pd) poin= &(ob->pd->f_power); - break; - case OB_PD_SDAMP: - if (ob->pd) poin= &(ob->pd->pdef_damp); - break; - case OB_PD_RDAMP: - if (ob->pd) poin= &(ob->pd->pdef_rdamp); - break; - case OB_PD_PERM: - if (ob->pd) poin= &(ob->pd->pdef_perm); - break; - case OB_PD_FMAXD: - if (ob->pd) poin= &(ob->pd->maxdist); - break; - } - } - break; - case ID_MA: /* material channels ----------------------------- */ - { - Material *ma= (Material *)id; - - switch (icu->adrcode) { - case MA_COL_R: - poin= &(ma->r); break; - case MA_COL_G: - poin= &(ma->g); break; - case MA_COL_B: - poin= &(ma->b); break; - case MA_SPEC_R: - poin= &(ma->specr); break; - case MA_SPEC_G: - poin= &(ma->specg); break; - case MA_SPEC_B: - poin= &(ma->specb); break; - case MA_MIR_R: - poin= &(ma->mirr); break; - case MA_MIR_G: - poin= &(ma->mirg); break; - case MA_MIR_B: - poin= &(ma->mirb); break; - case MA_REF: - poin= &(ma->ref); break; - case MA_ALPHA: - poin= &(ma->alpha); break; - case MA_EMIT: - poin= &(ma->emit); break; - case MA_AMB: - poin= &(ma->amb); break; - case MA_SPEC: - poin= &(ma->spec); break; - case MA_HARD: - poin= &(ma->har); *type= IPO_SHORT; break; - case MA_SPTR: - poin= &(ma->spectra); break; - case MA_IOR: - poin= &(ma->ang); break; - case MA_MODE: - poin= &(ma->mode); *type= IPO_INT_BIT; break; // evil... dumping bitflags directly to user! - case MA_HASIZE: - poin= &(ma->hasize); break; - case MA_TRANSLU: - poin= &(ma->translucency); break; - case MA_RAYM: - poin= &(ma->ray_mirror); break; - case MA_FRESMIR: - poin= &(ma->fresnel_mir); break; - case MA_FRESMIRI: - poin= &(ma->fresnel_mir_i); break; - case MA_FRESTRA: - poin= &(ma->fresnel_tra); break; - case MA_FRESTRAI: - poin= &(ma->fresnel_tra_i); break; - case MA_ADD: - poin= &(ma->add); break; - } + + /* only convert if version is right */ + // XXX??? + if (main->versionfile >= 250) { + printf("WARNING: Animation data too new to convert (Version %d) \n", main->versionfile); + return; + } + else + printf("INFO: Converting to Animato... \n"); // xxx debug + + /* ----------- Animation Attached to Data -------------- */ + + /* objects */ + for (id= main->object.first; id; id= id->next) { + Object *ob= (Object *)id; + bPoseChannel *pchan; + bConstraint *con; + bConstraintChannel *conchan, *conchann; + + if (G.f & G_DEBUG) printf("\tconverting ob %s \n", id->name+2); + + /* check if object has any animation data */ + if (ob->nlastrips.first) { + /* Add AnimData block */ + adt= BKE_id_add_animdata(id); - if (poin == NULL) { - if (icu->adrcode & MA_MAP1) mtex= ma->mtex[0]; - else if (icu->adrcode & MA_MAP2) mtex= ma->mtex[1]; - else if (icu->adrcode & MA_MAP3) mtex= ma->mtex[2]; - else if (icu->adrcode & MA_MAP4) mtex= ma->mtex[3]; - else if (icu->adrcode & MA_MAP5) mtex= ma->mtex[4]; - else if (icu->adrcode & MA_MAP6) mtex= ma->mtex[5]; - else if (icu->adrcode & MA_MAP7) mtex= ma->mtex[6]; - else if (icu->adrcode & MA_MAP8) mtex= ma->mtex[7]; - else if (icu->adrcode & MA_MAP9) mtex= ma->mtex[8]; - else if (icu->adrcode & MA_MAP10) mtex= ma->mtex[9]; - else if (icu->adrcode & MA_MAP12) mtex= ma->mtex[11]; - else if (icu->adrcode & MA_MAP11) mtex= ma->mtex[10]; - else if (icu->adrcode & MA_MAP13) mtex= ma->mtex[12]; - else if (icu->adrcode & MA_MAP14) mtex= ma->mtex[13]; - else if (icu->adrcode & MA_MAP15) mtex= ma->mtex[14]; - else if (icu->adrcode & MA_MAP16) mtex= ma->mtex[15]; - else if (icu->adrcode & MA_MAP17) mtex= ma->mtex[16]; - else if (icu->adrcode & MA_MAP18) mtex= ma->mtex[17]; + /* IPO first to take into any non-NLA'd Object Animation */ + if (ob->ipo) { + ipo_to_animdata(id, ob->ipo, NULL, NULL); - if (mtex) - poin= give_mtex_poin(mtex, (icu->adrcode & (MA_MAP1-1))); - } - } - break; - case ID_TE: /* texture channels ----------------------------- */ - { - Tex *tex= (Tex *)id; - - if (tex) - poin= give_tex_poin(tex, icu->adrcode, type); - } - break; - case ID_SEQ: /* sequence channels ----------------------------- */ - { - Sequence *seq= (Sequence *)id; - - switch (icu->adrcode) { - case SEQ_FAC1: - poin= &(seq->facf0); break; + ob->ipo->id.us--; + ob->ipo= NULL; } - } - break; - case ID_CU: /* curve channels ----------------------------- */ - { - poin= &(icu->curval); - } - break; - case ID_KE: /* shapekey channels ----------------------------- */ - { - Key *key= (Key *)id; - KeyBlock *kb; - for(kb= key->block.first; kb; kb= kb->next) { - if (kb->adrcode == icu->adrcode) - break; + /* Action is skipped since it'll be used by some strip in the NLA anyway, + * causing errors with evaluation in the new evaluation pipeline + */ + if (ob->action) { + ob->action->id.us--; + ob->action= NULL; } - if (kb) - poin= &(kb->curval); + /* finally NLA */ + nlastrips_to_animdata(id, &ob->nlastrips); } - break; - case ID_WO: /* world channels ----------------------------- */ - { - World *wo= (World *)id; - - switch (icu->adrcode) { - case WO_HOR_R: - poin= &(wo->horr); break; - case WO_HOR_G: - poin= &(wo->horg); break; - case WO_HOR_B: - poin= &(wo->horb); break; - case WO_ZEN_R: - poin= &(wo->zenr); break; - case WO_ZEN_G: - poin= &(wo->zeng); break; - case WO_ZEN_B: - poin= &(wo->zenb); break; - - case WO_EXPOS: - poin= &(wo->exposure); break; - - case WO_MISI: - poin= &(wo->misi); break; - case WO_MISTDI: - poin= &(wo->mistdist); break; - case WO_MISTSTA: - poin= &(wo->miststa); break; - case WO_MISTHI: - poin= &(wo->misthi); break; - - case WO_STAR_R: - poin= &(wo->starr); break; - case WO_STAR_G: - poin= &(wo->starg); break; - case WO_STAR_B: - poin= &(wo->starb); break; - - case WO_STARDIST: - poin= &(wo->stardist); break; - case WO_STARSIZE: - poin= &(wo->starsize); break; - } + else if ((ob->ipo) || (ob->action)) { + /* Add AnimData block */ + adt= BKE_id_add_animdata(id); - if (poin == NULL) { - if (icu->adrcode & MA_MAP1) mtex= wo->mtex[0]; - else if (icu->adrcode & MA_MAP2) mtex= wo->mtex[1]; - else if (icu->adrcode & MA_MAP3) mtex= wo->mtex[2]; - else if (icu->adrcode & MA_MAP4) mtex= wo->mtex[3]; - else if (icu->adrcode & MA_MAP5) mtex= wo->mtex[4]; - else if (icu->adrcode & MA_MAP6) mtex= wo->mtex[5]; - else if (icu->adrcode & MA_MAP7) mtex= wo->mtex[6]; - else if (icu->adrcode & MA_MAP8) mtex= wo->mtex[7]; - else if (icu->adrcode & MA_MAP9) mtex= wo->mtex[8]; - else if (icu->adrcode & MA_MAP10) mtex= wo->mtex[9]; - else if (icu->adrcode & MA_MAP11) mtex= wo->mtex[10]; - else if (icu->adrcode & MA_MAP12) mtex= wo->mtex[11]; - else if (icu->adrcode & MA_MAP13) mtex= wo->mtex[12]; - else if (icu->adrcode & MA_MAP14) mtex= wo->mtex[13]; - else if (icu->adrcode & MA_MAP15) mtex= wo->mtex[14]; - else if (icu->adrcode & MA_MAP16) mtex= wo->mtex[15]; - else if (icu->adrcode & MA_MAP17) mtex= wo->mtex[16]; - else if (icu->adrcode & MA_MAP18) mtex= wo->mtex[17]; + /* Action first - so that Action name get conserved */ + if (ob->action) { + action_to_animdata(id, ob->action); - if (mtex) - poin= give_mtex_poin(mtex, (icu->adrcode & (MA_MAP1-1))); - } - } - break; - case ID_LA: /* lamp channels ----------------------------- */ - { - Lamp *la= (Lamp *)id; - - switch (icu->adrcode) { - case LA_ENERGY: - poin= &(la->energy); break; - case LA_COL_R: - poin= &(la->r); break; - case LA_COL_G: - poin= &(la->g); break; - case LA_COL_B: - poin= &(la->b); break; - case LA_DIST: - poin= &(la->dist); break; - case LA_SPOTSI: - poin= &(la->spotsize); break; - case LA_SPOTBL: - poin= &(la->spotblend); break; - case LA_QUAD1: - poin= &(la->att1); break; - case LA_QUAD2: - poin= &(la->att2); break; - case LA_HALOINT: - poin= &(la->haint); break; + /* only decrease usercount if this Action isn't now being used by AnimData */ + if (ob->action != adt->action) { + ob->action->id.us--; + ob->action= NULL; + } } - if (poin == NULL) { - if (icu->adrcode & MA_MAP1) mtex= la->mtex[0]; - else if (icu->adrcode & MA_MAP2) mtex= la->mtex[1]; - else if (icu->adrcode & MA_MAP3) mtex= la->mtex[2]; - else if (icu->adrcode & MA_MAP4) mtex= la->mtex[3]; - else if (icu->adrcode & MA_MAP5) mtex= la->mtex[4]; - else if (icu->adrcode & MA_MAP6) mtex= la->mtex[5]; - else if (icu->adrcode & MA_MAP7) mtex= la->mtex[6]; - else if (icu->adrcode & MA_MAP8) mtex= la->mtex[7]; - else if (icu->adrcode & MA_MAP9) mtex= la->mtex[8]; - else if (icu->adrcode & MA_MAP10) mtex= la->mtex[9]; - else if (icu->adrcode & MA_MAP11) mtex= la->mtex[10]; - else if (icu->adrcode & MA_MAP12) mtex= la->mtex[11]; - else if (icu->adrcode & MA_MAP13) mtex= la->mtex[12]; - else if (icu->adrcode & MA_MAP14) mtex= la->mtex[13]; - else if (icu->adrcode & MA_MAP15) mtex= la->mtex[14]; - else if (icu->adrcode & MA_MAP16) mtex= la->mtex[15]; - else if (icu->adrcode & MA_MAP17) mtex= la->mtex[16]; - else if (icu->adrcode & MA_MAP18) mtex= la->mtex[17]; - - if (mtex) - poin= give_mtex_poin(mtex, (icu->adrcode & (MA_MAP1-1))); - } - } - break; - case ID_CA: /* camera channels ----------------------------- */ - { - Camera *ca= (Camera *)id; - - switch (icu->adrcode) { - case CAM_LENS: - if (ca->type == CAM_ORTHO) - poin= &(ca->ortho_scale); - else - poin= &(ca->lens); - break; - case CAM_STA: - poin= &(ca->clipsta); break; - case CAM_END: - poin= &(ca->clipend); break; - - case CAM_YF_APERT: - poin= &(ca->YF_aperture); break; - case CAM_YF_FDIST: - poin= &(ca->YF_dofdist); break; - - case CAM_SHIFT_X: - poin= &(ca->shiftx); break; - case CAM_SHIFT_Y: - poin= &(ca->shifty); break; - } - } - break; - case ID_SO: /* sound channels ----------------------------- */ - { - bSound *snd= (bSound *)id; - - switch (icu->adrcode) { - case SND_VOLUME: - poin= &(snd->volume); break; - case SND_PITCH: - poin= &(snd->pitch); break; - case SND_PANNING: - poin= &(snd->panning); break; - case SND_ATTEN: - poin= &(snd->attenuation); break; - } - } - break; - case ID_PA: /* particle channels ----------------------------- */ - { - ParticleSettings *part= (ParticleSettings *)id; - - switch (icu->adrcode) { - case PART_EMIT_FREQ: - case PART_EMIT_LIFE: - case PART_EMIT_VEL: - case PART_EMIT_AVE: - case PART_EMIT_SIZE: - poin= NULL; - break; - - case PART_CLUMP: - poin= &(part->clumpfac); break; - case PART_AVE: - poin= &(part->avefac); break; - case PART_SIZE: - poin= &(part->size); break; - case PART_DRAG: - poin= &(part->dragfac); break; - case PART_BROWN: - poin= &(part->brownfac); break; - case PART_DAMP: - poin= &(part->dampfac); break; - case PART_LENGTH: - poin= &(part->length); break; - case PART_GRAV_X: - poin= &(part->acc[0]); break; - case PART_GRAV_Y: - poin= &(part->acc[1]); break; - case PART_GRAV_Z: - poin= &(part->acc[2]); break; - case PART_KINK_AMP: - poin= &(part->kink_amp); break; - case PART_KINK_FREQ: - poin= &(part->kink_freq); break; - case PART_KINK_SHAPE: - poin= &(part->kink_shape); break; - case PART_BB_TILT: - poin= &(part->bb_tilt); break; - - case PART_PD_FSTR: - if (part->pd) poin= &(part->pd->f_strength); - break; - case PART_PD_FFALL: - if (part->pd) poin= &(part->pd->f_power); - break; - case PART_PD_FMAXD: - if (part->pd) poin= &(part->pd->maxdist); - break; - case PART_PD2_FSTR: - if (part->pd2) poin= &(part->pd2->f_strength); - break; - case PART_PD2_FFALL: - if (part->pd2) poin= &(part->pd2->f_power); - break; - case PART_PD2_FMAXD: - if (part->pd2) poin= &(part->pd2->maxdist); - break; + /* IPO second... */ + if (ob->ipo) { + ipo_to_animdata(id, ob->ipo, NULL, NULL); + ob->ipo->id.us--; + ob->ipo= NULL; } } - break; - } - - /* return pointer */ - return poin; -} - -/* --------------------- IPO-Curve Limits ----------------------------- */ - -/* set limits for IPO-curve - * Note: must be synced with UI and PyAPI - */ -void set_icu_vars (IpoCurve *icu) -{ - /* defaults. 0.0 for y-extents makes these ignored */ - icu->ymin= icu->ymax= 0.0; - icu->ipo= IPO_BEZ; - - switch (icu->blocktype) { - case ID_OB: /* object channels ----------------------------- */ - { - if (icu->adrcode == OB_LAY) { - icu->ipo= IPO_CONST; - icu->vartype= IPO_BITS; - } - } - break; - case ID_MA: /* material channels ----------------------------- */ - { - if (icu->adrcode < MA_MAP1) { - switch (icu->adrcode) { - case MA_HASIZE: - icu->ymax= 10000.0; break; - case MA_HARD: - icu->ymax= 511.0; break; - case MA_SPEC: - icu->ymax= 2.0; break; - case MA_MODE: - icu->ipo= IPO_CONST; - icu->vartype= IPO_BITS; break; - case MA_RAYM: - icu->ymax= 1.0; break; - case MA_TRANSLU: - icu->ymax= 1.0; break; - case MA_IOR: - icu->ymin= 1.0; - icu->ymax= 3.0; break; - case MA_FRESMIR: - icu->ymax= 5.0; break; - case MA_FRESMIRI: - icu->ymin= 1.0; - icu->ymax= 5.0; break; - case MA_FRESTRA: - icu->ymax= 5.0; break; - case MA_FRESTRAI: - icu->ymin= 1.0; - icu->ymax= 5.0; break; - case MA_ADD: - icu->ymax= 1.0; break; - case MA_EMIT: - icu->ymax= 2.0; break; - default: - icu->ymax= 1.0; break; - } - } - else { - switch (icu->adrcode & (MA_MAP1-1)) { - case MAP_OFS_X: - case MAP_OFS_Y: - case MAP_OFS_Z: - case MAP_SIZE_X: - case MAP_SIZE_Y: - case MAP_SIZE_Z: - icu->ymax= 1000.0; - icu->ymin= -1000.0; - break; - case MAP_R: - case MAP_G: - case MAP_B: - case MAP_DVAR: - case MAP_COLF: - case MAP_VARF: - case MAP_DISP: - icu->ymax= 1.0; - break; - case MAP_NORF: - icu->ymax= 25.0; - break; + + /* check PoseChannels for constraints with local data */ + if (ob->pose) { + /* Verify if there's AnimData block */ + BKE_id_add_animdata(id); + + for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + for (con= pchan->constraints.first; con; con= con->next) { + /* if constraint has own IPO, convert add these to Object + * (NOTE: they're most likely to be drivers too) + */ + if (con->ipo) { + /* although this was the constraint's local IPO, we still need to provide pchan + con + * so that drivers can be added properly... + */ + ipo_to_animdata(id, con->ipo, pchan->name, con->name); + con->ipo->id.us--; + con->ipo= NULL; + } } } } - break; - case ID_TE: /* texture channels ----------------------------- */ - { - switch (icu->adrcode & (MA_MAP1-1)) { - case TE_NSIZE: - icu->ymin= 0.0001f; - icu->ymax= 2.0f; - break; - case TE_NDEPTH: - icu->vartype= IPO_SHORT; - icu->ipo= IPO_CONST; - icu->ymax= 6.0f; - break; - case TE_NTYPE: - icu->vartype= IPO_SHORT; - icu->ipo= IPO_CONST; - icu->ymax= 1.0f; - break; - case TE_TURB: - icu->ymax= 200.0f; - break; - case TE_VNW1: - case TE_VNW2: - case TE_VNW3: - case TE_VNW4: - icu->ymax= 2.0f; - icu->ymin= -2.0f; - break; - case TE_VNMEXP: - icu->ymax= 10.0f; - icu->ymin= 0.01f; - break; - case TE_VN_DISTM: - icu->vartype= IPO_SHORT; - icu->ipo= IPO_CONST; - icu->ymax= 6.0f; - break; - case TE_VN_COLT: - icu->vartype= IPO_SHORT; - icu->ipo= IPO_CONST; - icu->ymax= 3.0f; - break; - case TE_ISCA: - icu->ymax= 10.0f; - icu->ymin= 0.01f; - break; - case TE_DISTA: - icu->ymax= 10.0f; - break; - case TE_MG_TYP: - icu->vartype= IPO_SHORT; - icu->ipo= IPO_CONST; - icu->ymax= 6.0f; - break; - case TE_MGH: - icu->ymin= 0.0001f; - icu->ymax= 2.0f; - break; - case TE_MG_LAC: - case TE_MG_OFF: - case TE_MG_GAIN: - icu->ymax= 6.0f; break; - case TE_MG_OCT: - icu->ymax= 8.0f; break; - case TE_N_BAS1: - case TE_N_BAS2: - icu->vartype= IPO_SHORT; - icu->ipo= IPO_CONST; - icu->ymax= 8.0f; - break; - case TE_COL_R: - icu->ymax= 0.0f; break; - case TE_COL_G: - icu->ymax= 2.0f; break; - case TE_COL_B: - icu->ymax= 2.0f; break; - case TE_BRIGHT: - icu->ymax= 2.0f; break; - case TE_CONTRA: - icu->ymax= 5.0f; break; - } - } - break; - case ID_SEQ: /* sequence channels ----------------------------- */ - { - icu->ymax= 1.0f; - } - break; - case ID_CU: /* curve channels ----------------------------- */ - { - icu->ymax= 1.0f; - } - break; - case ID_WO: /* world channels ----------------------------- */ - { - if (icu->adrcode < MA_MAP1) { - switch (icu->adrcode) { - case WO_EXPOS: - icu->ymax= 5.0f; break; + + /* check constraints for local IPO's */ + for (con= ob->constraints.first; con; con= con->next) { + /* if constraint has own IPO, convert add these to Object + * (NOTE: they're most likely to be drivers too) + */ + if (con->ipo) { + /* Verify if there's AnimData block, just in case */ + BKE_id_add_animdata(id); - case WO_MISTDI: - case WO_MISTSTA: - case WO_MISTHI: - case WO_STARDIST: - case WO_STARSIZE: - break; - - default: - icu->ymax= 1.0f; - break; - } - } - else { - switch (icu->adrcode & (MA_MAP1-1)) { - case MAP_OFS_X: - case MAP_OFS_Y: - case MAP_OFS_Z: - case MAP_SIZE_X: - case MAP_SIZE_Y: - case MAP_SIZE_Z: - icu->ymax= 100.0f; - icu->ymin= -100.0f; - break; - case MAP_R: - case MAP_G: - case MAP_B: - case MAP_DVAR: - case MAP_COLF: - case MAP_NORF: - case MAP_VARF: - case MAP_DISP: - icu->ymax= 1.0f; - } + /* although this was the constraint's local IPO, we still need to provide con + * so that drivers can be added properly... + */ + ipo_to_animdata(id, con->ipo, NULL, con->name); + con->ipo->id.us--; + con->ipo= NULL; } + + /* check for Action Constraint */ + // XXX do we really want to do this here? } - break; - case ID_LA: /* lamp channels ----------------------------- */ - { - if (icu->adrcode < MA_MAP1) { - switch (icu->adrcode) { - case LA_ENERGY: - case LA_DIST: - break; - - case LA_COL_R: - case LA_COL_G: - case LA_COL_B: - case LA_SPOTBL: - case LA_QUAD1: - case LA_QUAD2: - icu->ymax= 1.0f; break; - - case LA_SPOTSI: - icu->ymax= 180.0f; break; + + /* check constraint channels - we need to remove them anyway... */ + if (ob->constraintChannels.first) { + /* Verify if there's AnimData block */ + BKE_id_add_animdata(id); + + for (conchan= ob->constraintChannels.first; conchan; conchan= conchann) { + /* get pointer to next Constraint Channel */ + conchann= conchan->next; - case LA_HALOINT: - icu->ymax= 5.0f; break; - } - } - else { - switch (icu->adrcode & (MA_MAP1-1)) { - case MAP_OFS_X: - case MAP_OFS_Y: - case MAP_OFS_Z: - case MAP_SIZE_X: - case MAP_SIZE_Y: - case MAP_SIZE_Z: - icu->ymax= 100.0f; - icu->ymin= -100.0f; - break; - case MAP_R: - case MAP_G: - case MAP_B: - case MAP_DVAR: - case MAP_COLF: - case MAP_NORF: - case MAP_VARF: - case MAP_DISP: - icu->ymax= 1.0f; + /* convert Constraint Channel's IPO data */ + if (conchan->ipo) { + ipo_to_animdata(id, conchan->ipo, NULL, conchan->name); + conchan->ipo->id.us--; + conchan->ipo= NULL; } - } - } - break; - case ID_CA: /* camera channels ----------------------------- */ - { - switch (icu->adrcode) { - case CAM_LENS: - icu->ymin= 1.0f; - icu->ymax= 1000.0f; - break; - case CAM_STA: - icu->ymin= 0.001f; - break; - case CAM_END: - icu->ymin= 0.1f; - break; - case CAM_YF_APERT: - icu->ymin = 0.0f; - icu->ymax = 2.0f; - break; - case CAM_YF_FDIST: - icu->ymin = 0.0f; - icu->ymax = 5000.0f; - break; - - case CAM_SHIFT_X: - case CAM_SHIFT_Y: - icu->ymin= -2.0f; - icu->ymax= 2.0f; - break; + /* free Constraint Channel */ + BLI_freelinkN(&ob->constraintChannels, conchan); } } - break; - case ID_SO: /* sound channels ----------------------------- */ - { - switch (icu->adrcode) { - case SND_VOLUME: - icu->ymin= 0.0f; - icu->ymax= 1.0f; - break; - case SND_PITCH: - icu->ymin= -12.0f; - icu->ymin= 12.0f; - break; - case SND_PANNING: - icu->ymin= 0.0f; - icu->ymax= 1.0f; - break; - case SND_ATTEN: - icu->ymin= 0.0f; - icu->ymin= 1.0f; - break; - } - } - break; - case ID_PA: /* particle channels ----------------------------- */ - { - switch (icu->adrcode) { - case PART_EMIT_LIFE: - case PART_SIZE: - case PART_KINK_FREQ: - case PART_EMIT_VEL: - case PART_EMIT_AVE: - case PART_EMIT_SIZE: - icu->ymin= 0.0f; - break; - case PART_CLUMP: - icu->ymin= -1.0f; - icu->ymax= 1.0f; - break; - case PART_DRAG: - case PART_DAMP: - case PART_LENGTH: - icu->ymin= 0.0f; - icu->ymax= 1.0f; - break; - case PART_KINK_SHAPE: - icu->ymin= -0.999f; - icu->ymax= 0.999f; - break; - } + } + + /* shapekeys */ + for (id= main->key.first; id; id= id->next) { + Key *key= (Key *)id; + + if (G.f & G_DEBUG) printf("\tconverting key %s \n", id->name+2); + + /* we're only interested in the IPO + * NOTE: for later, it might be good to port these over to Object instead, as many of these + * are likely to be drivers, but it's hard to trace that from here, so move this to Ob loop? + */ + if (key->ipo) { + /* Add AnimData block */ + adt= BKE_id_add_animdata(id); + + /* Convert Shapekey data... */ + ipo_to_animdata(id, key->ipo, NULL, NULL); + key->ipo->id.us--; + key->ipo= NULL; } - break; - case ID_CO: /* constraint channels ----------------------------- */ - { - icu->ymin= 0.0f; - icu->ymax= 1.0f; + } + + /* materials */ + for (id= main->mat.first; id; id= id->next) { + Material *ma= (Material *)id; + + if (G.f & G_DEBUG) printf("\tconverting material %s \n", id->name+2); + + /* we're only interested in the IPO */ + if (ma->ipo) { + /* Add AnimData block */ + adt= BKE_id_add_animdata(id); + + /* Convert Material data... */ + ipo_to_animdata(id, ma->ipo, NULL, NULL); + ma->ipo->id.us--; + ma->ipo= NULL; } - break; } - /* by default, slider limits will be icu->ymin and icu->ymax */ - icu->slide_min= icu->ymin; - icu->slide_max= icu->ymax; -} - -/* --------------------- Pointer I/O API ----------------------------- */ - -/* write the given value directly into the given pointer */ -void write_ipo_poin (void *poin, int type, float val) -{ - /* Note: we only support a limited number of types, with the value - * to set needing to be cast to the appropriate type first - * -> (float to integer conversions could be slow) - */ - switch(type) { - case IPO_FLOAT: - *((float *)poin)= val; - break; - - case IPO_FLOAT_DEGR: /* special hack for rotation so that it fits on same axis as other transforms */ - *((float *)poin)= (float)(val * M_PI_2 / 9.0); - break; - - case IPO_INT: - case IPO_INT_BIT: // fixme... directly revealing bitflag combinations is evil! - case IPO_LONG: - *((int *)poin)= (int)val; - break; - - case IPO_SHORT: - case IPO_SHORT_BIT: // fixme... directly revealing bitflag combinations is evil! - *((short *)poin)= (short)val; - break; - - case IPO_CHAR: - case IPO_CHAR_BIT: // fixme... directly revealing bitflag combinations is evil! - *((char *)poin)= (char)val; - break; + /* textures */ + for (id= main->tex.first; id; id= id->next) { + Tex *te= (Tex *)id; + + if (G.f & G_DEBUG) printf("\tconverting texture %s \n", id->name+2); + + /* we're only interested in the IPO */ + if (te->ipo) { + /* Add AnimData block */ + adt= BKE_id_add_animdata(id); + + /* Convert Texture data... */ + ipo_to_animdata(id, te->ipo, NULL, NULL); + te->ipo->id.us--; + te->ipo= NULL; + } } -} - -/* read the value from the pointer that was obtained */ -float read_ipo_poin (void *poin, int type) -{ - float val = 0.0; - /* Note: we only support a limited number of types, with the value - * to set needing to be cast to the appropriate type first - * -> (int to float conversions may loose accuracy in rare cases) - */ - switch (type) { - case IPO_FLOAT: - val= *((float *)poin); - break; - - case IPO_FLOAT_DEGR: /* special hack for rotation so that it fits on same axis as other transforms */ - val= *( (float *)poin); - val = (float)(val / (M_PI_2/9.0)); - break; - - case IPO_INT: - case IPO_INT_BIT: // fixme... directly revealing bitflag combinations is evil! - case IPO_LONG: - val= (float)( *((int *)poin) ); - break; - - case IPO_SHORT: - case IPO_SHORT_BIT: // fixme... directly revealing bitflag combinations is evil! - val= *((short *)poin); - break; - - case IPO_CHAR: - case IPO_CHAR_BIT: // fixme... directly revealing bitflag combinations is evil - val= *((char *)poin); - break; + /* cameras */ + for (id= main->camera.first; id; id= id->next) { + Camera *ca= (Camera *)id; + + if (G.f & G_DEBUG) printf("\tconverting camera %s \n", id->name+2); + + /* we're only interested in the IPO */ + if (ca->ipo) { + /* Add AnimData block */ + adt= BKE_id_add_animdata(id); + + /* Convert Camera data... */ + ipo_to_animdata(id, ca->ipo, NULL, NULL); + ca->ipo->id.us--; + ca->ipo= NULL; + } } - /* return value */ - return val; -} - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!! FIXME - BAD CRUFT WARNING !!!!!!!!!!!!!!!!!!!!!!! - - -/* ***************************** IPO <--> GameEngine Interface ********************************* */ - -/* channels is max 32 items, allocated by calling function */ -short IPO_GetChannels (Ipo *ipo, IPO_Channel *channels) -{ - IpoCurve *icu; - int total = 0; + /* lamps */ + for (id= main->lamp.first; id; id= id->next) { + Lamp *la= (Lamp *)id; + + if (G.f & G_DEBUG) printf("\tconverting lamp %s \n", id->name+2); + + /* we're only interested in the IPO */ + if (la->ipo) { + /* Add AnimData block */ + adt= BKE_id_add_animdata(id); + + /* Convert Lamp data... */ + ipo_to_animdata(id, la->ipo, NULL, NULL); + la->ipo->id.us--; + la->ipo= NULL; + } + } - /* don't do anything with no IPO-block */ - if (ipo == NULL) - return 0; + /* --------- Unconverted Animation Data ------------------ */ + /* For Animation data which may not be directly connected (i.e. not linked) to any other + * data, we need to perform a separate pass to make sure that they are converted to standalone + * Actions which may then be able to be reused. This does mean that we will be going over data that's + * already been converted, but there are no problems with that. + * + * The most common case for this will be Action Constraints, or IPO's with Fake-Users. + * We collect all drivers that were found into a temporary collection, and free them in one go, as they're + * impossible to resolve. + */ - /* store the IPO-curve's adrcode in the relevant channel slot */ - for (icu=ipo->curve.first; (icu) && (total < 31); icu=icu->next, total++) - channels[total]= icu->adrcode; + /* actions */ + for (id= main->action.first; id; id= id->next) { + bAction *act= (bAction *)id; + + if (G.f & G_DEBUG) printf("\tconverting action %s \n", id->name+2); + + /* be careful! some of the actions we encounter will be converted ones... */ + action_to_animato(act, &act->groups, &act->curves, &drivers); + } - /* return the number of channels stored */ - return total; -} - -/* Get the float value for channel 'channel' at time 'ctime' */ -float IPO_GetFloatValue (Ipo *ipo, IPO_Channel channel, float ctime) -{ - /* don't evaluate if no IPO to use */ - if (ipo == NULL) - return 0; + /* ipo's */ + for (id= main->ipo.first; id; id= id->next) { + Ipo *ipo= (Ipo *)id; + + if (G.f & G_DEBUG) printf("\tconverting ipo %s \n", id->name+2); + + /* most likely this IPO has already been processed, so check if any curves left to convert */ + if (ipo->curve.first) { + bAction *new_act; + + /* add a new action for this, and convert all data into that action */ + new_act= add_empty_action("ConvIPO_Action"); // XXX need a better name... + ipo_to_animato(ipo, NULL, NULL, NULL, &new_act->curves, &drivers); + } + + /* clear fake-users, and set user-count to zero to make sure it is cleared on file-save */ + ipo->id.us= 0; + ipo->id.flag &= ~LIB_FAKEUSER; + } - /* only calculate the specified channel */ - calc_ipo_spec(ipo, channel, &ctime); + /* free unused drivers from actions + ipos */ + free_fcurves(&drivers); - /* unapply rotation hack, as gameengine doesn't use it */ - if ((ipo->blocktype == ID_OB) && (OB_ROT_X <= channel) && (channel <= OB_DROT_Z)) - ctime *= (float)(M_PI_2/9.0); - - /* return the value of this channel */ - return ctime; + printf("INFO: Animato convert done \n"); // xxx debug } + diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 755a41ec4b2..a2fa97cabc9 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -35,8 +35,8 @@ #include "MEM_guardedalloc.h" +#include "DNA_anim_types.h" #include "DNA_curve_types.h" -#include "DNA_ipo_types.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" @@ -44,12 +44,11 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BKE_animsys.h" #include "BKE_action.h" -#include "BKE_bad_level_calls.h" #include "BKE_blender.h" #include "BKE_curve.h" #include "BKE_global.h" -#include "BKE_ipo.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" @@ -60,7 +59,6 @@ #include "BLI_blenlib.h" -#include "blendef.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -69,6 +67,11 @@ #define KEY_BPOINT 1 #define KEY_BEZTRIPLE 2 + // old defines from DNA_ipo_types.h for data-type +#define IPO_FLOAT 4 +#define IPO_BEZTRIPLE 100 +#define IPO_BPOINT 101 + int slurph_opt= 1; @@ -76,8 +79,7 @@ void free_key(Key *key) { KeyBlock *kb; - if(key->ipo) key->ipo->id.us--; - + BKE_free_animdata((ID *)key); while( (kb= key->block.first) ) { @@ -112,6 +114,7 @@ Key *add_key(ID *id) /* common function */ key->type= KEY_NORMAL; key->from= id; + // XXX the code here uses some defines which will soon be depreceated... if( GS(id->name)==ID_ME) { el= key->elemstr; @@ -152,9 +155,11 @@ Key *copy_key(Key *key) keyn= copy_libblock(key); +#if 0 // XXX old animation system keyn->ipo= copy_ipo(key->ipo); - - duplicatelist(&keyn->block, &key->block); +#endif // XXX old animation system + + BLI_duplicatelist(&keyn->block, &key->block); kb= key->block.first; kbn= keyn->block.first; @@ -181,11 +186,13 @@ void make_local_key(Key *key) key->id.lib= 0; new_id(0, (ID *)key, 0); + +#if 0 // XXX old animation system make_local_ipo(key->ipo); +#endif // XXX old animation system } -/* - * Sort shape keys and Ipo curves after a change. This assumes that at most +/* Sort shape keys and Ipo curves after a change. This assumes that at most * one key was moved, which is a valid assumption for the places it's * currently being called. */ @@ -193,30 +200,30 @@ void make_local_key(Key *key) void sort_keys(Key *key) { KeyBlock *kb; - short i, adrcode; - IpoCurve *icu = NULL; + //short i, adrcode; + //IpoCurve *icu = NULL; KeyBlock *kb2; /* locate the key which is out of position */ - for( kb= key->block.first; kb; kb= kb->next ) - if( kb->next && kb->pos > kb->next->pos ) + for (kb= key->block.first; kb; kb= kb->next) + if ((kb->next) && (kb->pos > kb->next->pos)) break; /* if we find a key, move it */ - if( kb ) { + if (kb) { kb = kb->next; /* next key is the out-of-order one */ BLI_remlink(&key->block, kb); - + /* find the right location and insert before */ - for( kb2=key->block.first; kb2; kb2= kb2->next ) { - if( kb2->pos > kb->pos ) { + for (kb2=key->block.first; kb2; kb2= kb2->next) { + if (kb2->pos > kb->pos) { BLI_insertlink(&key->block, kb2->prev, kb); break; } } - + /* if more than one Ipo curve, see if this key had a curve */ - +#if 0 // XXX old animation system if(key->ipo && key->ipo->curve.first != key->ipo->curve.last ) { for(icu= key->ipo->curve.first; icu; icu= icu->next) { /* if we find the curve, remove it and reinsert in the @@ -234,13 +241,13 @@ void sort_keys(Key *key) } } } - + /* kb points at the moved key, icu at the moved ipo (if it exists). * go back now and renumber adrcodes */ /* first new code */ adrcode = kb2->adrcode; - for( i = kb->adrcode - adrcode; i >= 0; --i, ++adrcode ) { + for (i = kb->adrcode - adrcode; i >= 0; i--, adrcode++) { /* if the next ipo curve matches the current key, renumber it */ if(icu && icu->adrcode == kb->adrcode ) { icu->adrcode = adrcode; @@ -250,6 +257,7 @@ void sort_keys(Key *key) kb->adrcode = adrcode; kb = kb->next; } +#endif // XXX old animation system } /* new rule; first key is refkey, this to match drawing channels... */ @@ -638,6 +646,8 @@ void do_rel_key(int start, int end, int tot, char *basispoin, Key *key, int mode if(key->from==NULL) return; + if (G.f & G_DEBUG) printf("do_rel_key() \n"); + if( GS(key->from->name)==ID_ME ) { ofs[0]= sizeof(MVert); ofs[1]= 0; @@ -673,11 +683,15 @@ void do_rel_key(int start, int end, int tot, char *basispoin, Key *key, int mode if(kb!=key->refkey) { float icuval= kb->curval; + if (G.f & G_DEBUG) printf("\tdo rel key %s : %s = %f \n", key->id.name+2, kb->name, icuval); + /* only with value, and no difference allowed */ if(!(kb->flag & KEYBLOCK_MUTE) && icuval!=0.0f && kb->totelem==tot) { KeyBlock *refb; float weight, *weights= kb->weights; + if (G.f & G_DEBUG) printf("\t\tnot skipped \n"); + poin= basispoin; from= kb->data; /* reference now can be any block */ @@ -748,6 +762,8 @@ static void do_key(int start, int end, int tot, char *poin, Key *key, KeyBlock * if(key->from==0) return; + if (G.f & G_DEBUG) printf("do_key() \n"); + if( GS(key->from->name)==ID_ME ) { ofs[0]= sizeof(MVert); ofs[1]= 0; @@ -995,7 +1011,7 @@ static float *get_weights_array(Object *ob, char *vgroup) return NULL; } -static int do_mesh_key(Object *ob, Mesh *me) +static int do_mesh_key(Scene *scene, Object *ob, Mesh *me) { KeyBlock *k[4]; float cfra, ctime, t[4], delta, loc[3], size[3]; @@ -1008,7 +1024,11 @@ static int do_mesh_key(Object *ob, Mesh *me) /* prevent python from screwing this up? anyhoo, the from pointer could be dropped */ me->key->from= (ID *)me; + if (G.f & G_DEBUG) printf("do mesh key ob:%s me:%s ke:%s \n", ob->id.name+2, me->id.name+2, me->key->id.name+2); + if(me->key->slurph && me->key->type!=KEY_RELATIVE ) { + if (G.f & G_DEBUG) printf("\tslurph key\n"); + delta= me->key->slurph; delta/= me->totvert; @@ -1019,15 +1039,20 @@ static int do_mesh_key(Object *ob, Mesh *me) /* in do_key and cp_key the case a>tot is handled */ } - cfra= G.scene->r.cfra; + cfra= (float)scene->r.cfra; for(a=0; a<me->totvert; a+=step, cfra+= delta) { - ctime= bsystem_time(0, cfra, 0.0); + ctime= bsystem_time(scene, 0, cfra, 0.0); // xxx ugly cruft! +#if 0 // XXX old animation system if(calc_ipo_spec(me->key->ipo, KEY_SPEED, &ctime)==0) { ctime /= 100.0; CLAMP(ctime, 0.0, 1.0); } +#endif // XXX old animation system + // XXX for now... since speed curve cannot be directly ported yet + ctime /= 100.0f; + CLAMP(ctime, 0.0f, 1.0f); // XXX for compat, we use this, but this clamping was confusing flag= setkeys(ctime, &me->key->block, k, t, 0); if(flag==0) { @@ -1043,10 +1068,11 @@ static int do_mesh_key(Object *ob, Mesh *me) else boundbox_mesh(me, loc, size); } else { - if(me->key->type==KEY_RELATIVE) { KeyBlock *kb; + if (G.f & G_DEBUG) printf("\tdo relative \n"); + for(kb= me->key->block.first; kb; kb= kb->next) kb->weights= get_weights_array(ob, kb->vgroup); @@ -1058,13 +1084,20 @@ static int do_mesh_key(Object *ob, Mesh *me) } } else { - ctime= bsystem_time(ob, G.scene->r.cfra, 0.0); - + if (G.f & G_DEBUG) printf("\tdo absolute \n"); + + ctime= bsystem_time(scene, ob, (float)scene->r.cfra, 0.0f); // xxx old cruft + +#if 0 // XXX old animation system if(calc_ipo_spec(me->key->ipo, KEY_SPEED, &ctime)==0) { ctime /= 100.0; CLAMP(ctime, 0.0, 1.0); } - +#endif // XXX old animation system + // XXX for now... since speed curve cannot be directly ported yet + ctime /= 100.0f; + CLAMP(ctime, 0.0f, 1.0f); // XXX for compat, we use this, but this clamping was confusing + flag= setkeys(ctime, &me->key->block, k, t, 0); if(flag==0) { do_key(0, me->totvert, me->totvert, (char *)me->mvert->co, me->key, k, t, 0); @@ -1151,7 +1184,7 @@ static void do_rel_cu_key(Curve *cu, float ctime) } } -static int do_curve_key(Curve *cu) +static int do_curve_key(Scene *scene, Curve *cu) { KeyBlock *k[4]; float cfra, ctime, t[4], delta; @@ -1174,15 +1207,16 @@ static int do_curve_key(Curve *cu) /* in do_key and cp_key the case a>tot has been handled */ } - cfra= G.scene->r.cfra; + cfra= (float)scene->r.cfra; for(a=0; a<tot; a+=step, cfra+= delta) { - - ctime= bsystem_time(0, cfra, 0.0); + ctime= bsystem_time(scene, 0, cfra, 0.0f); // XXX old cruft +#if 0 // XXX old animation system if(calc_ipo_spec(cu->key->ipo, KEY_SPEED, &ctime)==0) { ctime /= 100.0; CLAMP(ctime, 0.0, 1.0); } +#endif // XXX old animation system flag= setkeys(ctime, &cu->key->block, k, t, 0); if(flag==0) { @@ -1200,16 +1234,18 @@ static int do_curve_key(Curve *cu) } else { - ctime= bsystem_time(NULL, (float)G.scene->r.cfra, 0.0); + ctime= bsystem_time(scene, NULL, (float)scene->r.cfra, 0.0); if(cu->key->type==KEY_RELATIVE) { do_rel_cu_key(cu, ctime); } else { +#if 0 // XXX old animation system if(calc_ipo_spec(cu->key->ipo, KEY_SPEED, &ctime)==0) { ctime /= 100.0; CLAMP(ctime, 0.0, 1.0); } +#endif // XXX old animation system flag= setkeys(ctime, &cu->key->block, k, t, 0); @@ -1223,7 +1259,7 @@ static int do_curve_key(Curve *cu) return 1; } -static int do_latt_key(Object *ob, Lattice *lt) +static int do_latt_key(Scene *scene, Object *ob, Lattice *lt) { KeyBlock *k[4]; float delta, cfra, ctime, t[4]; @@ -1238,15 +1274,17 @@ static int do_latt_key(Object *ob, Lattice *lt) delta= lt->key->slurph; delta/= (float)tot; - cfra= G.scene->r.cfra; + cfra= (float)scene->r.cfra; for(a=0; a<tot; a++, cfra+= delta) { - ctime= bsystem_time(0, cfra, 0.0); + ctime= bsystem_time(scene, 0, cfra, 0.0); // XXX old cruft +#if 0 // XXX old animation system if(calc_ipo_spec(lt->key->ipo, KEY_SPEED, &ctime)==0) { ctime /= 100.0; CLAMP(ctime, 0.0, 1.0); } +#endif // XXX old animation system flag= setkeys(ctime, <->key->block, k, t, 0); if(flag==0) { @@ -1259,7 +1297,7 @@ static int do_latt_key(Object *ob, Lattice *lt) } } else { - ctime= bsystem_time(NULL, (float)G.scene->r.cfra, 0.0); + ctime= bsystem_time(scene, NULL, (float)scene->r.cfra, 0.0); if(lt->key->type==KEY_RELATIVE) { KeyBlock *kb; @@ -1275,10 +1313,12 @@ static int do_latt_key(Object *ob, Lattice *lt) } } else { +#if 0 // XXX old animation system if(calc_ipo_spec(lt->key->ipo, KEY_SPEED, &ctime)==0) { ctime /= 100.0; CLAMP(ctime, 0.0, 1.0); } +#endif // XXX old animation system flag= setkeys(ctime, <->key->block, k, t, 0); if(flag==0) { @@ -1296,7 +1336,7 @@ static int do_latt_key(Object *ob, Lattice *lt) } /* returns 1 when key applied */ -int do_ob_key(Object *ob) +int do_ob_key(Scene *scene, Object *ob) { Key *key= ob_get_key(ob); @@ -1305,7 +1345,9 @@ int do_ob_key(Object *ob) if(ob->shapeflag & (OB_SHAPE_LOCK|OB_SHAPE_TEMPLOCK)) { KeyBlock *kb= BLI_findlink(&key->block, ob->shapenr-1); - + + if (G.f & G_DEBUG) printf("ob %s, key %s locked \n", ob->id.name+2, key->id.name+2); + if(kb && (kb->flag & KEYBLOCK_MUTE)) kb= key->refkey; @@ -1340,17 +1382,17 @@ int do_ob_key(Object *ob) return 1; } else { - if(ob->ipoflag & OB_ACTION_KEY) - do_all_object_actions(ob); - else { - calc_ipo(key->ipo, bsystem_time(ob, G.scene->r.cfra, 0.0)); - execute_ipo((ID *)key, key->ipo); - } + /* do shapekey local drivers */ + float ctime= (float)scene->r.cfra; // XXX this needs to be checked + + if (G.f & G_DEBUG) + printf("ob %s - do shapekey (%s) drivers \n", ob->id.name+2, key->id.name+2); + BKE_animsys_evaluate_animdata(&key->id, key->adt, ctime, ADT_RECALC_DRIVERS); - if(ob->type==OB_MESH) return do_mesh_key(ob, ob->data); - else if(ob->type==OB_CURVE) return do_curve_key( ob->data); - else if(ob->type==OB_SURF) return do_curve_key( ob->data); - else if(ob->type==OB_LATTICE) return do_latt_key(ob, ob->data); + if(ob->type==OB_MESH) return do_mesh_key(scene, ob, ob->data); + else if(ob->type==OB_CURVE) return do_curve_key(scene, ob->data); + else if(ob->type==OB_SURF) return do_curve_key(scene, ob->data); + else if(ob->type==OB_LATTICE) return do_latt_key(scene, ob, ob->data); } return 0; @@ -1407,3 +1449,18 @@ KeyBlock *key_get_keyblock(Key *key, int index) return NULL; } + +/* get the appropriate KeyBlock given a name to search for */ +KeyBlock *key_get_named_keyblock(Key *key, const char name[]) +{ + KeyBlock *kb; + + if (key && name) { + for (kb= key->block.first; kb; kb= kb->next) { + if (strcmp(name, kb->name)==0) + return kb; + } + } + + return NULL; +} diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 6614c657647..67d63d527cb 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -30,6 +30,7 @@ * ***** END GPL LICENSE BLOCK ***** */ + #include <stdio.h> #include <string.h> #include <math.h> @@ -41,7 +42,6 @@ #include "BLI_arithb.h" #include "DNA_armature_types.h" -#include "DNA_ipo_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" @@ -59,7 +59,6 @@ #include "BKE_deform.h" #include "BKE_displist.h" #include "BKE_global.h" -#include "BKE_ipo.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" @@ -70,18 +69,7 @@ #include "BKE_screen.h" #include "BKE_utildefines.h" -#include "BIF_editdeform.h" - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "blendef.h" - -Lattice *editLatt=0; -static Lattice *deformLatt=0; - -static float *latticedata=0, latmat[4][4]; +//XXX #include "BIF_editdeform.h" void calc_lat_fudu(int flag, int res, float *fu, float *du) { @@ -223,7 +211,9 @@ Lattice *copy_lattice(Lattice *lt) ltn= copy_libblock(lt); ltn->def= MEM_dupallocN(lt->def); +#if 0 // XXX old animation system id_us_plus((ID *)ltn->ipo); +#endif // XXX old animation system ltn->key= copy_key(ltn->key); if(ltn->key) ltn->key->from= (ID *)ltn; @@ -241,6 +231,11 @@ void free_lattice(Lattice *lt) { if(lt->def) MEM_freeN(lt->def); if(lt->dvert) free_dverts(lt->dvert, lt->pntsu*lt->pntsv*lt->pntsw); + if(lt->editlatt) { + if(lt->editlatt->def) MEM_freeN(lt->editlatt->def); + if(lt->editlatt->dvert) free_dverts(lt->editlatt->dvert, lt->pntsu*lt->pntsv*lt->pntsw); + MEM_freeN(lt->editlatt); + } } @@ -299,31 +294,34 @@ void make_local_lattice(Lattice *lt) void init_latt_deform(Object *oblatt, Object *ob) { /* we make an array with all differences */ - Lattice *lt = deformLatt = (oblatt==G.obedit)?editLatt:oblatt->data; - BPoint *bp = lt->def; + Lattice *lt= oblatt->data; + BPoint *bp; DispList *dl = find_displist(&oblatt->disp, DL_VERTS); float *co = dl?dl->verts:NULL; float *fp, imat[4][4]; float fu, fv, fw; int u, v, w; - fp= latticedata= MEM_mallocN(sizeof(float)*3*deformLatt->pntsu*deformLatt->pntsv*deformLatt->pntsw, "latticedata"); + if(lt->editlatt) lt= lt->editlatt; + bp = lt->def; + + fp= lt->latticedata= MEM_mallocN(sizeof(float)*3*lt->pntsu*lt->pntsv*lt->pntsw, "latticedata"); /* for example with a particle system: ob==0 */ - if(ob==0) { + if(ob==NULL) { /* in deformspace, calc matrix */ - Mat4Invert(latmat, oblatt->obmat); + Mat4Invert(lt->latmat, oblatt->obmat); /* back: put in deform array */ - Mat4Invert(imat, latmat); + Mat4Invert(imat, lt->latmat); } else { /* in deformspace, calc matrix */ Mat4Invert(imat, oblatt->obmat); - Mat4MulMat4(latmat, ob->obmat, imat); + Mat4MulMat4(lt->latmat, ob->obmat, imat); /* back: put in deform array */ - Mat4Invert(imat, latmat); + Mat4Invert(imat, lt->latmat); } for(w=0,fw=lt->fw; w<lt->pntsw; w++,fw+=lt->dw) { @@ -345,21 +343,20 @@ void init_latt_deform(Object *oblatt, Object *ob) } } -void calc_latt_deform(float *co, float weight) +void calc_latt_deform(Object *ob, float *co, float weight) { - Lattice *lt; + Lattice *lt= ob->data; float u, v, w, tu[4], tv[4], tw[4]; float *fpw, *fpv, *fpu, vec[3]; int ui, vi, wi, uu, vv, ww; - if(latticedata==0) return; - - lt= deformLatt; /* just for shorter notation! */ + if(lt->editlatt) lt= lt->editlatt; + if(lt->latticedata==NULL) return; /* co is in local coords, treat with latmat */ VECCOPY(vec, co); - Mat4MulVecfl(latmat, vec); + Mat4MulVecfl(lt->latmat, vec); /* u v w coords */ @@ -401,10 +398,10 @@ void calc_latt_deform(float *co, float weight) if(w!=0.0) { if(ww>0) { - if(ww<lt->pntsw) fpw= latticedata + 3*ww*lt->pntsu*lt->pntsv; - else fpw= latticedata + 3*(lt->pntsw-1)*lt->pntsu*lt->pntsv; + if(ww<lt->pntsw) fpw= lt->latticedata + 3*ww*lt->pntsu*lt->pntsv; + else fpw= lt->latticedata + 3*(lt->pntsw-1)*lt->pntsu*lt->pntsv; } - else fpw= latticedata; + else fpw= lt->latticedata; for(vv= vi-1; vv<=vi+2; vv++) { v= w*tv[vv-vi+1]; @@ -437,11 +434,15 @@ void calc_latt_deform(float *co, float weight) } } -void end_latt_deform() +void end_latt_deform(Object *ob) { - - MEM_freeN(latticedata); - latticedata= 0; + Lattice *lt= ob->data; + + if(lt->editlatt) lt= lt->editlatt; + + if(lt->latticedata) + MEM_freeN(lt->latticedata); + lt->latticedata= NULL; } /* calculations is in local space of deformed object @@ -516,7 +517,7 @@ static int where_on_path_deform(Object *ob, float ctime, float *vec, float *dir) /* co: local coord, result local too */ /* returns quaternion for rotation, using cd->no_rot_axis */ /* axis is using another define!!! */ -static int calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd, float *quatp) +static int calc_curve_deform(Scene *scene, Object *par, float *co, short axis, CurveDeform *cd, float *quatp) { Curve *cu= par->data; float fac, loc[4], dir[3], cent[3]; @@ -545,7 +546,7 @@ static int calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd } /* to be sure, mostly after file load */ if(cu->path==NULL) { - makeDispListCurveTypes(par, 0); + makeDispListCurveTypes(scene, par, 0); if(cu->path==NULL) return 0; // happens on append... } @@ -563,13 +564,16 @@ static int calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist); } +#if 0 // XXX old animation system /* we want the ipo to work on the default 100 frame range, because there's no actual time involved in path position */ + // huh? by WHY!!!!???? - Aligorith if(cu->ipo) { fac*= 100.0f; if(calc_ipo_spec(cu->ipo, CU_SPEED, &fac)==0) fac/= 100.0; } +#endif // XXX old animation system if( where_on_path_deform(par, fac, loc, dir)) { /* returns OK */ float q[4], mat[3][3], quat[4]; @@ -606,7 +610,7 @@ static int calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd return 0; } -void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis) +void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis) { Curve *cu; int a, flag; @@ -672,7 +676,7 @@ void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*v for(j = 0; j < dvert->totweight; j++) { if(dvert->dw[j].def_nr == index) { VECCOPY(vec, vertexCos[a]); - calc_curve_deform(cuOb, vec, defaxis, &cd, NULL); + calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL); VecLerpf(vertexCos[a], vertexCos[a], vec, dvert->dw[j].weight); Mat4MulVecfl(cd.objectspace, vertexCos[a]); @@ -690,7 +694,7 @@ void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*v } for(a = 0; a < numVerts; a++) { - calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL); + calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL); Mat4MulVecfl(cd.objectspace, vertexCos[a]); } } @@ -700,7 +704,7 @@ void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*v /* input vec and orco = local coord in armature space */ /* orco is original not-animated or deformed reference point */ /* result written in vec and mat */ -void curve_deform_vector(Object *cuOb, Object *target, float *orco, float *vec, float mat[][3], int no_rot_axis) +void curve_deform_vector(Scene *scene, Object *cuOb, Object *target, float *orco, float *vec, float mat[][3], int no_rot_axis) { CurveDeform cd; float quat[4]; @@ -718,7 +722,7 @@ void curve_deform_vector(Object *cuOb, Object *target, float *orco, float *vec, Mat4MulVecfl(cd.curvespace, vec); - if(calc_curve_deform(cuOb, vec, target->trackflag+1, &cd, quat)) { + if(calc_curve_deform(scene, cuOb, vec, target->trackflag+1, &cd, quat)) { float qmat[3][3]; QuatToMat3(quat, qmat); @@ -773,17 +777,17 @@ void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm, if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT); for(j = 0; j < dvert->totweight; j++) { if (dvert->dw[j].def_nr == index) { - calc_latt_deform(vertexCos[a], dvert->dw[j].weight); + calc_latt_deform(laOb, vertexCos[a], dvert->dw[j].weight); } } } } } else { for(a = 0; a < numVerts; a++) { - calc_latt_deform(vertexCos[a], 1.0f); + calc_latt_deform(laOb, vertexCos[a], 1.0f); } } - end_latt_deform(); + end_latt_deform(laOb); } int object_deform_mball(Object *ob) @@ -813,67 +817,81 @@ void outside_lattice(Lattice *lt) int u, v, w; float fac1, du=0.0, dv=0.0, dw=0.0; - bp= lt->def; + if(lt->flag & LT_OUTSIDE) { + bp= lt->def; - if(lt->pntsu>1) du= 1.0f/((float)lt->pntsu-1); - if(lt->pntsv>1) dv= 1.0f/((float)lt->pntsv-1); - if(lt->pntsw>1) dw= 1.0f/((float)lt->pntsw-1); - - for(w=0; w<lt->pntsw; w++) { - - for(v=0; v<lt->pntsv; v++) { - - for(u=0; u<lt->pntsu; u++, bp++) { - if(u==0 || v==0 || w==0 || u==lt->pntsu-1 || v==lt->pntsv-1 || w==lt->pntsw-1); - else { - - bp->hide= 1; - bp->f1 &= ~SELECT; - - /* u extrema */ - bp1= latt_bp(lt, 0, v, w); - bp2= latt_bp(lt, lt->pntsu-1, v, w); - - fac1= du*u; - bp->vec[0]= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; - bp->vec[1]= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; - bp->vec[2]= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; - - /* v extrema */ - bp1= latt_bp(lt, u, 0, w); - bp2= latt_bp(lt, u, lt->pntsv-1, w); - - fac1= dv*v; - bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; - bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; - bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; - - /* w extrema */ - bp1= latt_bp(lt, u, v, 0); - bp2= latt_bp(lt, u, v, lt->pntsw-1); - - fac1= dw*w; - bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; - bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; - bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; - - VecMulf(bp->vec, 0.3333333f); + if(lt->pntsu>1) du= 1.0f/((float)lt->pntsu-1); + if(lt->pntsv>1) dv= 1.0f/((float)lt->pntsv-1); + if(lt->pntsw>1) dw= 1.0f/((float)lt->pntsw-1); + + for(w=0; w<lt->pntsw; w++) { + + for(v=0; v<lt->pntsv; v++) { + + for(u=0; u<lt->pntsu; u++, bp++) { + if(u==0 || v==0 || w==0 || u==lt->pntsu-1 || v==lt->pntsv-1 || w==lt->pntsw-1); + else { + bp->hide= 1; + bp->f1 &= ~SELECT; + + /* u extrema */ + bp1= latt_bp(lt, 0, v, w); + bp2= latt_bp(lt, lt->pntsu-1, v, w); + + fac1= du*u; + bp->vec[0]= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; + bp->vec[1]= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; + bp->vec[2]= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; + + /* v extrema */ + bp1= latt_bp(lt, u, 0, w); + bp2= latt_bp(lt, u, lt->pntsv-1, w); + + fac1= dv*v; + bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; + bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; + bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; + + /* w extrema */ + bp1= latt_bp(lt, u, v, 0); + bp2= latt_bp(lt, u, v, lt->pntsw-1); + + fac1= dw*w; + bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0]; + bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1]; + bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2]; + + VecMulf(bp->vec, 0.3333333f); + + } } + } } - } - + else { + bp= lt->def; + + for(w=0; w<lt->pntsw; w++) + for(v=0; v<lt->pntsv; v++) + for(u=0; u<lt->pntsu; u++, bp++) + bp->hide= 0; + } } float (*lattice_getVertexCos(struct Object *ob, int *numVerts_r))[3] { - Lattice *lt = (G.obedit==ob)?editLatt:ob->data; - int i, numVerts = *numVerts_r = lt->pntsu*lt->pntsv*lt->pntsw; - float (*vertexCos)[3] = MEM_mallocN(sizeof(*vertexCos)*numVerts,"lt_vcos"); + Lattice *lt = ob->data; + int i, numVerts; + float (*vertexCos)[3]; + if(lt->editlatt) lt= lt->editlatt; + numVerts = *numVerts_r = lt->pntsu*lt->pntsv*lt->pntsw; + + vertexCos = MEM_mallocN(sizeof(*vertexCos)*numVerts,"lt_vcos"); + for (i=0; i<numVerts; i++) { VECCOPY(vertexCos[i], lt->def[i].vec); } @@ -891,28 +909,31 @@ void lattice_applyVertexCos(struct Object *ob, float (*vertexCos)[3]) } } -void lattice_calc_modifiers(Object *ob) +void lattice_calc_modifiers(Scene *scene, Object *ob) { - float (*vertexCos)[3] = NULL; + Lattice *lt= ob->data; ModifierData *md = modifiers_getVirtualModifierList(ob); - int numVerts, editmode = G.obedit==ob; + float (*vertexCos)[3] = NULL; + int numVerts, editmode = (lt->editlatt!=NULL); freedisplist(&ob->disp); if (!editmode) { - do_ob_key(ob); + do_ob_key(scene, ob); } for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); + md->scene= scene; + if (!(md->mode&eModifierMode_Realtime)) continue; if (editmode && !(md->mode&eModifierMode_Editmode)) continue; if (mti->isDisabled && mti->isDisabled(md)) continue; if (mti->type!=eModifierTypeType_OnlyDeform) continue; if (!vertexCos) vertexCos = lattice_getVertexCos(ob, &numVerts); - mti->deformVerts(md, ob, NULL, vertexCos, numVerts); + mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0, 0); } /* always displist to make this work like derivedmesh */ @@ -933,7 +954,8 @@ struct MDeformVert* lattice_get_deform_verts(struct Object *oblatt) { if(oblatt->type == OB_LATTICE) { - Lattice *lt = (oblatt==G.obedit)?editLatt:(Lattice*)oblatt->data; + Lattice *lt = (Lattice*)oblatt->data; + if(lt->editlatt) lt= lt->editlatt; return lt->dvert; } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 2994c981b17..3c8bf9200f8 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -76,12 +76,16 @@ #include "DNA_effect_types.h" #include "DNA_brush_types.h" #include "DNA_particle_types.h" -#include "BKE_particle.h" +#include "DNA_space_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_anim_types.h" +#include "DNA_gpencil_types.h" #include "BLI_blenlib.h" #include "BLI_dynstr.h" -#include "BKE_bad_level_calls.h" +#include "BKE_animsys.h" +#include "BKE_context.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_global.h" @@ -110,8 +114,8 @@ #include "BKE_effect.h" #include "BKE_brush.h" #include "BKE_idprop.h" - -#include "DNA_space_types.h" +#include "BKE_particle.h" +#include "BKE_gpencil.h" #define MAX_IDPUP 60 /* was 24 */ @@ -138,6 +142,12 @@ void id_us_plus(ID *id) } } +void id_us_min(ID *id) +{ + if(id) + id->us--; +} + ListBase *wich_libbase(Main *mainlib, short type) { switch( type ) { @@ -195,6 +205,10 @@ ListBase *wich_libbase(Main *mainlib, short type) return &(mainlib->brush); case ID_PA: return &(mainlib->particle); + case ID_WM: + return &(mainlib->wm); + case ID_GD: + return &(mainlib->gpencil); } return 0; } @@ -229,6 +243,7 @@ int set_listbasepointers(Main *main, ListBase **lb) /* BACKWARDS! also watch order of free-ing! (mesh<->mat) */ lb[a++]= &(main->ipo); + lb[a++]= &(main->action); // xxx moved here to avoid problems when freeing with animato (aligorith) lb[a++]= &(main->key); lb[a++]= &(main->nodetree); lb[a++]= &(main->image); @@ -241,7 +256,6 @@ int set_listbasepointers(Main *main, ListBase **lb) */ lb[a++]= &(main->armature); - lb[a++]= &(main->action); lb[a++]= &(main->mesh); lb[a++]= &(main->curve); @@ -264,6 +278,8 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[a++]= &(main->object); lb[a++]= &(main->scene); lb[a++]= &(main->library); + lb[a++]= &(main->wm); + lb[a++]= &(main->gpencil); lb[a]= NULL; @@ -343,7 +359,7 @@ static ID *alloc_libblock_notest(short type) id= MEM_callocN(sizeof(Text), "text"); break; case ID_SCRIPT: - id= MEM_callocN(sizeof(Script), "script"); + //XXX id= MEM_callocN(sizeof(Script), "script"); break; case ID_SO: id= MEM_callocN(sizeof(bSound), "sound"); @@ -366,6 +382,12 @@ static ID *alloc_libblock_notest(short type) case ID_PA: id = MEM_callocN(sizeof(ParticleSettings), "ParticleSettings"); break; + case ID_WM: + id = MEM_callocN(sizeof(wmWindowManager), "Window manager"); + break; + case ID_GD: + id = MEM_callocN(sizeof(bGPdata), "Grease Pencil"); + break; } return id; } @@ -394,6 +416,45 @@ void *alloc_libblock(ListBase *lb, short type, const char *name) /* from blendef: */ #define GS(a) (*((short *)(a))) +/* by spec, animdata is first item after ID */ +/* we still read ->adt itself, to ensure compiler warns when it doesnt exist */ +static void id_copy_animdata(ID *id) +{ + switch(GS(id->name)) { + case ID_OB: + ((Object *)id)->adt= BKE_copy_animdata(((Object *)id)->adt); + break; + case ID_CU: + ((Curve *)id)->adt= BKE_copy_animdata(((Curve *)id)->adt); + break; + case ID_CA: + ((Camera *)id)->adt= BKE_copy_animdata(((Camera *)id)->adt); + break; + case ID_KE: + ((Key *)id)->adt= BKE_copy_animdata(((Key *)id)->adt); + break; + case ID_LA: + ((Lamp *)id)->adt= BKE_copy_animdata(((Lamp *)id)->adt); + break; + case ID_MA: + ((Material *)id)->adt= BKE_copy_animdata(((Material *)id)->adt); + break; + case ID_NT: + ((bNodeTree *)id)->adt= BKE_copy_animdata(((bNodeTree *)id)->adt); + break; + case ID_SCE: + ((Scene *)id)->adt= BKE_copy_animdata(((Scene *)id)->adt); + break; + case ID_TE: + ((Tex *)id)->adt= BKE_copy_animdata(((Tex *)id)->adt); + break; + case ID_WO: + ((World *)id)->adt= BKE_copy_animdata(((World *)id)->adt); + break; + } + +} + /* used everywhere in blenkernel and text.c */ void *copy_libblock(void *rt) { @@ -422,6 +483,8 @@ void *copy_libblock(void *rt) idn->flag |= LIB_NEW; if (id->properties) idn->properties = IDP_CopyProperty(id->properties); + id_copy_animdata(id); + return idn; } @@ -430,6 +493,13 @@ static void free_library(Library *lib) /* no freeing needed for libraries yet */ } +static void (*free_windowmanager_cb)(bContext *, wmWindowManager *)= NULL; + +void set_free_windowmanager_cb(void (*func)(bContext *C, wmWindowManager *) ) +{ + free_windowmanager_cb= func; +} + /* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */ void free_libblock(ListBase *lb, void *idv) { @@ -494,10 +564,10 @@ void free_libblock(ListBase *lb, void *idv) free_text((Text *)id); break; case ID_SCRIPT: - free_script((Script *)id); + //XXX free_script((Script *)id); break; case ID_SO: - sound_free_sound((bSound *)id); + sound_free((bSound*)id); break; case ID_GR: free_group((Group *)id); @@ -517,6 +587,13 @@ void free_libblock(ListBase *lb, void *idv) case ID_PA: psys_free_settings((ParticleSettings *)id); break; + case ID_WM: + if(free_windowmanager_cb) + free_windowmanager_cb(NULL, (wmWindowManager *)id); + break; + case ID_GD: + free_gpencil_data((bGPdata *)id); + break; } if (id->properties) { @@ -539,7 +616,7 @@ void free_libblock_us(ListBase *lb, void *idv) /* test users */ else printf("ERROR block %s users %d\n", id->name, id->us); } if(id->us==0) { - if( GS(id->name)==ID_OB ) unlink_object((Object *)id); + if( GS(id->name)==ID_OB ) unlink_object(NULL, (Object *)id); free_libblock(lb, id); } @@ -664,52 +741,6 @@ static void IDnames_to_dyn_pupstring(DynStr *pupds, ListBase *lb, ID *link, shor } } - /* Silly routine, the only difference between the one - * above is that it only adds items with a matching - * blocktype... this should be unified somehow... - zr - */ -static void IPOnames_to_dyn_pupstring(DynStr *pupds, ListBase *lb, ID *link, short *nr, int blocktype) -{ - ID *id; - int i, nids; - - for (id= lb->first, nids= 0; id; id= id->next) { - Ipo *ipo= (Ipo*) id; - - if (ipo->blocktype==blocktype) - nids++; - } - - if (nids>MAX_IDPUP) { - BLI_dynstr_append(pupds, "DataBrowse %x-2"); - } else { - for (i=0, id= lb->first; id; id= id->next) { - Ipo *ipo= (Ipo*) id; - - if (ipo->blocktype==blocktype) { - char buf[32]; - - if (id==link) - *nr= i+1; - - if (U.uiflag & USER_HIDE_DOT && id->name[2]=='.') - continue; - - get_flags_for_id(id, buf); - - BLI_dynstr_append(pupds, buf); - BLI_dynstr_append(pupds, id->name+2); - sprintf(buf, "%%x%d", i+1); - BLI_dynstr_append(pupds, buf); - - if(id->next) - BLI_dynstr_append(pupds, "|"); - - i++; - } - } - } -} /* used by headerbuttons.c buttons.c editobject.c editseq.c */ /* if nr==NULL no MAX_IDPUP, this for non-header browsing */ @@ -757,28 +788,6 @@ void IMAnames_to_pupstring(char **str, char *title, char *extraops, ListBase *lb } -/* only used by headerbuttons.c */ -void IPOnames_to_pupstring(char **str, char *title, char *extraops, ListBase *lb, ID *link, short *nr, int blocktype) -{ - DynStr *pupds= BLI_dynstr_new(); - - if (title) { - BLI_dynstr_append(pupds, title); - BLI_dynstr_append(pupds, "%t|"); - } - - if (extraops) { - BLI_dynstr_append(pupds, extraops); - if (BLI_dynstr_get_len(pupds)) - BLI_dynstr_append(pupds, "|"); - } - - IPOnames_to_dyn_pupstring(pupds, lb, link, nr, blocktype); - - *str= BLI_dynstr_get_cstring(pupds); - BLI_dynstr_free(pupds); -} - /* used by buttons.c library.c mball.c */ void splitIDname(char *name, char *left, int *nr) { @@ -994,14 +1003,15 @@ static void lib_indirect_test_id(ID *id) if(id->lib) return; - + if(GS(id->name)==ID_OB) { Object *ob= (Object *)id; bActionStrip *strip; Mesh *me; int a; - + + // XXX old animation system! for (strip=ob->nlastrips.first; strip; strip=strip->next){ LIBTAG(strip->object); LIBTAG(strip->act); @@ -1112,6 +1122,27 @@ void test_idbutton(char *name) if(idtest) if( new_id(lb, idtest, name)==0 ) sort_alpha_id(lb, idtest); } +void text_idbutton(struct ID *id, char *text) +{ + if(id) { + if(GS(id->name)==ID_SCE) + strcpy(text, "SCE: "); + else if(GS(id->name)==ID_SCE) + strcpy(text, "SCR: "); + else if(GS(id->name)==ID_MA && ((Material*)id)->use_nodes) + strcpy(text, "NT: "); + else { + text[0]= id->name[0]; + text[1]= id->name[1]; + text[2]= ':'; + text[3]= ' '; + text[4]= 0; + } + } + else + strcpy(text, ""); +} + void rename_id(ID *id, char *name) { ListBase *lb; diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 753058b1fdd..08a19cada7d 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -43,11 +43,12 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_texture_types.h" +#include "DNA_userdef_types.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" -#include "BKE_bad_level_calls.h" +#include "BKE_animsys.h" #include "BKE_blender.h" #include "BKE_displist.h" #include "BKE_global.h" @@ -79,10 +80,6 @@ void free_material(Material *ma) { MTex *mtex; int a; - -#ifndef DISABLE_PYTHON - BPY_free_scriptlink(&ma->scriptlink); -#endif for(a=0; a<MAX_MTEX; a++) { mtex= ma->mtex[a]; @@ -93,6 +90,8 @@ void free_material(Material *ma) if(ma->ramp_col) MEM_freeN(ma->ramp_col); if(ma->ramp_spec) MEM_freeN(ma->ramp_spec); + BKE_free_animdata((ID *)ma); + BKE_previewimg_free(&ma->preview); BKE_icon_delete((struct ID*)ma); ma->id.icon_id = 0; @@ -194,7 +193,9 @@ Material *copy_material(Material *ma) man= copy_libblock(ma); +#if 0 // XXX old animation system id_us_plus((ID *)man->ipo); +#endif // XXX old animation system id_us_plus((ID *)man->group); @@ -205,10 +206,6 @@ Material *copy_material(Material *ma) id_us_plus((ID *)man->mtex[a]->tex); } } - -#ifndef DISABLE_PYTHON - BPY_copy_scriptlink(&ma->scriptlink); -#endif if(ma->ramp_col) man->ramp_col= MEM_dupallocN(ma->ramp_col); if(ma->ramp_spec) man->ramp_spec= MEM_dupallocN(ma->ramp_spec); @@ -441,7 +438,7 @@ Material *give_current_material(Object *ob, int act) if(act>ob->totcol) act= ob->totcol; else if(act<=0) act= 1; - if( BTST(ob->colbits, act-1) ) { /* in object */ + if(ob->matbits[act-1]) { /* in object */ ma= ob->mat[act-1]; } else { /* in data */ @@ -469,7 +466,7 @@ ID *material_from(Object *ob, int act) if(ob->totcol==0) return ob->data; if(act==0) act= 1; - if( BTST(ob->colbits, act-1) ) return (ID *)ob; + if(ob->matbits[act-1]) return (ID *)ob; else return ob->data; } @@ -494,6 +491,7 @@ void test_object_materials(ID *id) Curve *cu; MetaBall *mb; Material **newmatar; + char *newmatbits; int totcol=0; if(id==0) return; @@ -520,16 +518,22 @@ void test_object_materials(ID *id) if(totcol==0) { if(ob->totcol) { MEM_freeN(ob->mat); - ob->mat= 0; + MEM_freeN(ob->matbits); + ob->mat= NULL; + ob->matbits= NULL; } } else if(ob->totcol<totcol) { newmatar= MEM_callocN(sizeof(void *)*totcol, "newmatar"); + newmatbits= MEM_callocN(sizeof(char)*totcol, "newmatbits"); if(ob->totcol) { memcpy(newmatar, ob->mat, sizeof(void *)*ob->totcol); + memcpy(newmatbits, ob->matbits, sizeof(char)*ob->totcol); MEM_freeN(ob->mat); + MEM_freeN(ob->matbits); } ob->mat= newmatar; + ob->matbits= newmatbits; } ob->totcol= totcol; if(ob->totcol && ob->actcol==0) ob->actcol= 1; @@ -543,6 +547,7 @@ void test_object_materials(ID *id) void assign_material(Object *ob, Material *ma, int act) { Material *mao, **matar, ***matarar; + char *matbits; short *totcolp; if(act>MAXMAT) return; @@ -555,29 +560,41 @@ void assign_material(Object *ob, Material *ma, int act) if(totcolp==0 || matarar==0) return; - if( act > *totcolp) { + if(act > *totcolp) { matar= MEM_callocN(sizeof(void *)*act, "matarray1"); - if( *totcolp) { - memcpy(matar, *matarar, sizeof(void *)*( *totcolp )); + + if(*totcolp) { + memcpy(matar, *matarar, sizeof(void *)*(*totcolp)); MEM_freeN(*matarar); } + *matarar= matar; *totcolp= act; } if(act > ob->totcol) { matar= MEM_callocN(sizeof(void *)*act, "matarray2"); + matbits= MEM_callocN(sizeof(char)*act, "matbits1"); if( ob->totcol) { memcpy(matar, ob->mat, sizeof(void *)*( ob->totcol )); + memcpy(matbits, ob->matbits, sizeof(char)*(*totcolp)); MEM_freeN(ob->mat); + MEM_freeN(ob->matbits); } ob->mat= matar; + ob->matbits= matbits; ob->totcol= act; + + /* copy object/mesh linking, or assign based on userpref */ + if(ob->actcol) + ob->matbits[act-1]= ob->matbits[ob->actcol-1]; + else + ob->matbits[act-1]= (U.flag & USER_MAT_ON_OB)? 1: 0; } /* do it */ - if( BTST(ob->colbits, act-1) ) { /* in object */ + if(ob->matbits[act-1]) { /* in object */ mao= ob->mat[act-1]; if(mao) mao->id.us--; ob->mat[act-1]= ma; @@ -587,7 +604,9 @@ void assign_material(Object *ob, Material *ma, int act) if(mao) mao->id.us--; (*matarar)[act-1]= ma; } - id_us_plus((ID *)ma); + + if(ma) + id_us_plus((ID *)ma); test_object_materials(ob->data); } @@ -611,7 +630,7 @@ int find_material_index(Object *ob, Material *ma) return 0; } -void new_material_to_objectdata(Object *ob) +void object_add_material_slot(Object *ob) { Material *ma; @@ -619,19 +638,7 @@ void new_material_to_objectdata(Object *ob) if(ob->totcol>=MAXMAT) return; ma= give_current_material(ob, ob->actcol); - if(ma==NULL) - ma= add_material("Material"); - else - ma= copy_material(ma); - - ma->id.us= 0; /* eeh... */ - - if(ob->actcol) { - if( BTST(ob->colbits, ob->actcol-1) ) { - ob->colbits= BSET(ob->colbits, ob->totcol); - } - } - + assign_material(ob, ma, ob->totcol+1); ob->actcol= ob->totcol; } @@ -656,6 +663,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb) ma->mapto |= mtex->mapto; if(r_mode & R_OSA) { if ELEM3(mtex->tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP) ma->texco |= TEXCO_OSA; + else if(mtex->texflag & MTEX_NEW_BUMP) ma->texco |= TEXCO_OSA; // NEWBUMP: need texture derivatives for procedurals as well } if(ma->texco & (TEXCO_ORCO|TEXCO_REFL|TEXCO_NORM|TEXCO_STRAND|TEXCO_STRESS)) needuv= 1; @@ -850,21 +858,16 @@ void automatname(Material *ma) } -void delete_material_index() +void object_remove_material_slot(Object *ob) { Material *mao, ***matarar; - Object *ob, *obt; + Object *obt; Curve *cu; Nurb *nu; short *totcolp; int a, actcol; - if(G.obedit) { - error("Unable to perform function in EditMode"); - return; - } - ob= ((G.scene->basact)? (G.scene->basact->object) : 0) ; - if(ob==0 || ob->totcol==0) return; + if(ob==NULL || ob->totcol==0) return; /* take a mesh/curve/mball as starting point, remove 1 index, * AND with all objects that share the ob->data @@ -881,9 +884,8 @@ void delete_material_index() if(mao) mao->id.us--; } - for(a=ob->actcol; a<ob->totcol; a++) { + for(a=ob->actcol; a<ob->totcol; a++) (*matarar)[a-1]= (*matarar)[a]; - } (*totcolp)--; if(*totcolp==0) { @@ -901,13 +903,18 @@ void delete_material_index() mao= obt->mat[actcol-1]; if(mao) mao->id.us--; - for(a=actcol; a<obt->totcol; a++) obt->mat[a-1]= obt->mat[a]; + for(a=actcol; a<obt->totcol; a++) { + obt->mat[a-1]= obt->mat[a]; + obt->matbits[a-1]= obt->matbits[a]; + } obt->totcol--; if(obt->actcol > obt->totcol) obt->actcol= obt->totcol; if(obt->totcol==0) { MEM_freeN(obt->mat); + MEM_freeN(obt->matbits); obt->mat= 0; + obt->matbits= NULL; } } obt= obt->id.next; diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 97226b5ec42..3ca7dac4bc9 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -50,12 +50,12 @@ #include "BLI_arithb.h" #include "BKE_utildefines.h" -#include "BKE_bad_level_calls.h" #include "BKE_global.h" #include "BKE_main.h" /* #include "BKE_object.h" */ +#include "BKE_animsys.h" #include "BKE_scene.h" #include "BKE_blender.h" #include "BKE_library.h" @@ -69,10 +69,10 @@ /* Global variables */ -float thresh= 0.6f; -int totelem=0; -MetaElem **mainb; -octal_tree *metaball_tree = NULL; +static float thresh= 0.6f; +static int totelem=0; +static MetaElem **mainb; +static octal_tree *metaball_tree = NULL; /* Functions */ void unlink_mball(MetaBall *mb) @@ -91,6 +91,7 @@ void free_mball(MetaBall *mb) { unlink_mball(mb); + if(mb->adt) BKE_free_animdata((ID *)mb); if(mb->mat) MEM_freeN(mb->mat); if(mb->bb) MEM_freeN(mb->bb); BLI_freelistN(&mb->elems); @@ -120,7 +121,7 @@ MetaBall *copy_mball(MetaBall *mb) mbn= copy_libblock(mb); - duplicatelist(&mbn->elems, &mb->elems); + BLI_duplicatelist(&mbn->elems, &mb->elems); mbn->mat= MEM_dupallocN(mb->mat); for(a=0; a<mbn->totcol; a++) { @@ -279,6 +280,47 @@ int is_basis_mball(Object *ob) return 1; } +/* \brief copy some properties from object to other metaball object with same base name + * + * When some properties (wiresize, threshold, update flags) of metaball are changed, then this properties + * are copied to all metaballs in same "group" (metaballs with same base name: MBall, + * MBall.001, MBall.002, etc). The most important is to copy properties to the base metaball, + * because this metaball influence polygonisation of metaballs. */ +void copy_mball_properties(Scene *scene, Object *active_object) +{ + Base *base; + Object *ob; + MetaBall *active_mball = (MetaBall*)active_object->data; + int basisnr, obnr; + char basisname[32], obname[32]; + + splitIDname(active_object->id.name+2, basisname, &basisnr); + + /* XXX recursion check, see scene.c, just too simple code this next_object() */ + if(F_ERROR==next_object(scene, 0, 0, 0)) + return; + + while(next_object(scene, 1, &base, &ob)) { + if (ob->type==OB_MBALL) { + if(ob!=active_object){ + splitIDname(ob->id.name+2, obname, &obnr); + + /* Object ob has to be in same "group" ... it means, that it has to have + * same base of its name */ + if(strcmp(obname, basisname)==0){ + MetaBall *mb= ob->data; + + /* Copy properties from selected/edited metaball */ + mb->wiresize= active_mball->wiresize; + mb->rendersize= active_mball->rendersize; + mb->thresh= active_mball->thresh; + mb->flag= active_mball->flag; + } + } + } + } +} + /** \brief This function finds basic MetaBall. * * Basic MetaBall doesn't include any number at the end of @@ -286,7 +328,7 @@ int is_basis_mball(Object *ob) * blended. MetaBalls with different basic name can't be * blended. */ -Object *find_basis_mball(Object *basis) +Object *find_basis_mball(Scene *scene, Object *basis) { Base *base; Object *ob,*bob= basis; @@ -298,20 +340,20 @@ Object *find_basis_mball(Object *basis) totelem= 0; /* XXX recursion check, see scene.c, just too simple code this next_object() */ - if(F_ERROR==next_object(0, 0, 0)) + if(F_ERROR==next_object(scene, 0, 0, 0)) return NULL; - while(next_object(1, &base, &ob)) { + while(next_object(scene, 1, &base, &ob)) { if (ob->type==OB_MBALL) { if(ob==bob){ + MetaBall *mb= ob->data; + /* if bob object is in edit mode, then dynamic list of all MetaElems * is stored in editelems */ - if(ob==G.obedit) ml= editelems.first; - /* keep track of linked data too! */ - else if(G.obedit && G.obedit->data==ob->data) ml= editelems.first; + if(mb->editelems) ml= mb->editelems->first; /* if bob object is in object mode */ - else ml= ((MetaBall*)ob->data)->elems.first; + else ml= mb->elems.first; } else{ splitIDname(ob->id.name+2, obname, &obnr); @@ -319,13 +361,13 @@ Object *find_basis_mball(Object *basis) /* object ob has to be in same "group" ... it means, that it has to have * same base of its name */ if(strcmp(obname, basisname)==0){ + MetaBall *mb= ob->data; + /* if object is in edit mode, then dynamic list of all MetaElems * is stored in editelems */ - if(ob==G.obedit) ml= editelems.first; - /* keep track of linked data too! */ - else if(bob==G.obedit && bob->data==ob->data) ml= editelems.first; - /* object is in object mode */ - else ml= ((MetaBall*)ob->data)->elems.first; + if(mb->editelems) ml= mb->editelems->first; + /* if bob object is in object mode */ + else ml= mb->elems.first; if(obnr<basisnr){ if(!(ob->flag & OB_FROMDUPLI)){ @@ -1455,7 +1497,7 @@ void polygonize(PROCESS *mbproc, MetaBall *mb) } } -float init_meta(Object *ob) /* return totsize */ +float init_meta(Scene *scene, Object *ob) /* return totsize */ { Base *base; Object *bob; @@ -1474,8 +1516,8 @@ float init_meta(Object *ob) /* return totsize */ /* make main array */ - next_object(0, 0, 0); - while(next_object(1, &base, &bob)) { + next_object(scene, 0, 0, 0); + while(next_object(scene, 1, &base, &bob)) { if(bob->type==OB_MBALL) { zero_size= 0; @@ -1485,8 +1527,7 @@ float init_meta(Object *ob) /* return totsize */ mat= imat= 0; mb= ob->data; - if(ob==G.obedit) ml= editelems.first; - else if(G.obedit && G.obedit->type==OB_MBALL && G.obedit->data==mb) ml= editelems.first; + if(mb->editelems) ml= mb->editelems->first; else ml= mb->elems.first; } else { @@ -1496,8 +1537,8 @@ float init_meta(Object *ob) /* return totsize */ splitIDname(bob->id.name+2, name, &nr); if( strcmp(obname, name)==0 ) { mb= bob->data; - if(G.obedit && G.obedit->type==OB_MBALL && G.obedit->data==mb) - ml= editelems.first; + + if(mb->editelems) ml= mb->editelems->first; else ml= mb->elems.first; } } @@ -2039,7 +2080,7 @@ void init_metaball_octal_tree(int depth) subdivide_metaball_octal_node(node, size[0], size[1], size[2], metaball_tree->depth); } -void metaball_polygonize(Object *ob) +void metaball_polygonize(Scene *scene, Object *ob) { PROCESS mbproc; MetaBall *mb; @@ -2062,7 +2103,7 @@ void metaball_polygonize(Object *ob) mainb= MEM_mallocN(sizeof(void *)*totelem, "mainb"); /* initialize all mainb (MetaElems) */ - totsize= init_meta(ob); + totsize= init_meta(scene, ob); if(metaball_tree){ free_metaball_octal_node(metaball_tree->first); diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 0c8cd1d9593..c7454d3b832 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -24,9 +24,7 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. + * Contributor(s): Blender Foundation * * ***** END GPL LICENSE BLOCK ***** */ @@ -58,7 +56,6 @@ #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_mesh.h" -#include "BKE_multires.h" #include "BKE_subsurf.h" #include "BKE_displist.h" #include "BKE_library.h" @@ -69,16 +66,22 @@ /* -- */ #include "BKE_object.h" #include "BKE_utildefines.h" -#include "BKE_bad_level_calls.h" - -#ifdef WITH_VERSE -#include "BKE_verse.h" -#endif #include "BLI_blenlib.h" #include "BLI_editVert.h" #include "BLI_arithb.h" + +EditMesh *BKE_mesh_get_editmesh(Mesh *me) +{ + return me->edit_mesh; +} + +void BKE_mesh_end_editmesh(Mesh *me, EditMesh *em) +{ +} + + void mesh_update_customdata_pointers(Mesh *me) { me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT); @@ -143,8 +146,7 @@ void free_mesh(Mesh *me) if(me->bb) MEM_freeN(me->bb); if(me->mselect) MEM_freeN(me->mselect); - - if(me->mr) multires_free(me->mr); + if(me->edit_mesh) MEM_freeN(me->edit_mesh); } void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount) @@ -194,11 +196,8 @@ Mesh *add_mesh(char *name) me->texflag= AUTOSPACE; me->flag= ME_TWOSIDED; me->bb= unit_boundbox(); - -#ifdef WITH_VERSE - me->vnode = NULL; -#endif - + me->drawflag= ME_DRAWEDGES|ME_DRAWFACES|ME_DRAWCREASES; + return me; } @@ -232,9 +231,6 @@ Mesh *copy_mesh(Mesh *me) } } - if(me->mr) - men->mr= multires_copy(me->mr); - men->mselect= NULL; men->bb= MEM_dupallocN(men->bb); @@ -242,10 +238,6 @@ Mesh *copy_mesh(Mesh *me) men->key= copy_key(me->key); if(men->key) men->key->from= (ID *)men; -#ifdef WITH_VERSE - men->vnode = NULL; -#endif - return men; } @@ -959,7 +951,8 @@ void nurbs_to_mesh(Object *ob) } -void mesh_delete_material_index(Mesh *me, int index) { +void mesh_delete_material_index(Mesh *me, int index) +{ int i; for (i=0; i<me->totface; i++) { @@ -969,7 +962,8 @@ void mesh_delete_material_index(Mesh *me, int index) { } } -void mesh_set_smooth_flag(Object *meshOb, int enableSmooth) { +void mesh_set_smooth_flag(Object *meshOb, int enableSmooth) +{ Mesh *me = meshOb->data; int i; @@ -983,7 +977,7 @@ void mesh_set_smooth_flag(Object *meshOb, int enableSmooth) { } } - DAG_object_flush_update(G.scene, meshOb, OB_RECALC_DATA); +// XXX do this in caller DAG_object_flush_update(scene, meshOb, OB_RECALC_DATA); } void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float **faceNors_r) @@ -1032,38 +1026,14 @@ void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*mesh_getVertexCos(Mesh *me, int *numVerts_r))[3] { -#ifdef WITH_VERSE - if(me->vnode) { - struct VLayer *vlayer; - struct VerseVert *vvert; - unsigned int i, numVerts; - float (*cos)[3]; - - vlayer = find_verse_layer_type((VGeomData*)((VNode*)me->vnode)->data, VERTEX_LAYER); - - vvert = vlayer->dl.lb.first; - numVerts = vlayer->dl.da.count; - cos = MEM_mallocN(sizeof(*cos)*numVerts, "verse_vertexcos"); - - for(i=0; i<numVerts && vvert; vvert = vvert->next, i++) { - VECCOPY(cos[i], vvert->co); - } - - return cos; - } - else { -#endif - int i, numVerts = me->totvert; - float (*cos)[3] = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos1"); - - if (numVerts_r) *numVerts_r = numVerts; - for (i=0; i<numVerts; i++) - VECCOPY(cos[i], me->mvert[i].co); - - return cos; -#ifdef WITH_VERSE - } -#endif + int i, numVerts = me->totvert; + float (*cos)[3] = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos1"); + + if (numVerts_r) *numVerts_r = numVerts; + for (i=0; i<numVerts; i++) + VECCOPY(cos[i], me->mvert[i].co); + + return cos; } float (*mesh_getRefKeyCos(Mesh *me, int *numVerts_r))[3] @@ -1198,6 +1168,48 @@ void free_uv_vert_map(UvVertMap *vmap) } } +/* Generates a map where the key is the vertex and the value is a list + of faces that use that vertex as a corner. The lists are allocated + from one memory pool. */ +void create_vert_face_map(ListBase **map, IndexNode **mem, const MFace *mface, const int totvert, const int totface) +{ + int i,j; + IndexNode *node = NULL; + + (*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert face map"); + (*mem) = MEM_callocN(sizeof(IndexNode) * totface*4, "vert face map mem"); + node = *mem; + + /* Find the users */ + for(i = 0; i < totface; ++i){ + for(j = 0; j < (mface[i].v4?4:3); ++j, ++node) { + node->index = i; + BLI_addtail(&(*map)[((unsigned int*)(&mface[i]))[j]], node); + } + } +} + +/* Generates a map where the key is the vertex and the value is a list + of edges that use that vertex as an endpoint. The lists are allocated + from one memory pool. */ +void create_vert_edge_map(ListBase **map, IndexNode **mem, const MEdge *medge, const int totvert, const int totedge) +{ + int i, j; + IndexNode *node = NULL; + + (*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert edge map"); + (*mem) = MEM_callocN(sizeof(IndexNode) * totedge * 2, "vert edge map mem"); + node = *mem; + + /* Find the users */ + for(i = 0; i < totedge; ++i){ + for(j = 0; j < 2; ++j, ++node) { + node->index = i; + BLI_addtail(&(*map)[((unsigned int*)(&medge[i].v1))[j]], node); + } + } +} + /* Partial Mesh Visibility */ PartialVisibility *mesh_pmv_copy(PartialVisibility *pmv) { @@ -1253,7 +1265,7 @@ void mesh_pmv_revert(Object *ob, Mesh *me) MEM_freeN(me->pv->vert_map); me->pv->vert_map= NULL; - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); +// XXX do this in caller DAG_object_flush_update(scene, ob, OB_RECALC_DATA); } } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index fa2f857cc8b..ecba1c1a6ad 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -20,8 +20,6 @@ * The Original Code is Copyright (C) 2005 by the Blender Foundation. * All rights reserved. * -* The Original Code is: all of this file. -* * Contributor(s): Daniel Dunbar * Ton Roosendaal, * Ben Batt, @@ -60,14 +58,17 @@ #include "DNA_cloth_types.h" #include "DNA_curve_types.h" #include "DNA_effect_types.h" +#include "DNA_group_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" +#include "DNA_object_fluidsim.h" #include "DNA_object_force.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" +#include "DNA_smoke_types.h" #include "DNA_texture_types.h" #include "BLI_editVert.h" @@ -77,9 +78,8 @@ #include "BKE_main.h" #include "BKE_anim.h" -#include "BKE_bad_level_calls.h" #include "BKE_bmesh.h" -#include "BKE_booleanops.h" +// XXX #include "BKE_booleanops.h" #include "BKE_cloth.h" #include "BKE_collision.h" #include "BKE_cdderivedmesh.h" @@ -89,6 +89,7 @@ #include "BKE_displist.h" #include "BKE_fluidsim.h" #include "BKE_global.h" +#include "BKE_multires.h" #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_material.h" @@ -97,6 +98,7 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_pointcache.h" +#include "BKE_smoke.h" #include "BKE_softbody.h" #include "BKE_subsurf.h" #include "BKE_texture.h" @@ -107,13 +109,18 @@ #include "BKE_shrinkwrap.h" #include "BKE_simple_deform.h" -#include "LOD_DependKludge.h" +//XXX #include "LOD_DependKludge.h" #include "LOD_decimation.h" +// XXX +static struct DerivedMesh *NewBooleanDerivedMesh() {return NULL;} + #include "CCGSubSurf.h" #include "RE_shader_ext.h" +//XXX #include "BIF_meshlaplacian.h" + /* Utility */ static int is_last_displist(Object *ob) @@ -139,7 +146,7 @@ static int is_last_displist(Object *ob) return 0; } -static DerivedMesh *get_original_dm(Object *ob, float (*vertexCos)[3], int orco) +static DerivedMesh *get_original_dm(Scene *scene, Object *ob, float (*vertexCos)[3], int orco) { DerivedMesh *dm= NULL; @@ -167,7 +174,7 @@ static DerivedMesh *get_original_dm(Object *ob, float (*vertexCos)[3], int orco) /* copies the data */ tmpobj->data = copy_curve((Curve *) ob->data); - makeDispListCurveTypes(tmpobj, 1); + makeDispListCurveTypes(scene, tmpobj, 1); nurbs_to_mesh(tmpobj); dm = CDDM_from_mesh((Mesh*)(tmpobj->data), tmpobj); @@ -235,7 +242,7 @@ static void curveModifier_foreachObjectLink( } static void curveModifier_updateDepgraph( - ModifierData *md, DagForest *forest, + ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { CurveModifierData *cmd = (CurveModifierData*) md; @@ -250,11 +257,11 @@ static void curveModifier_updateDepgraph( static void curveModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { CurveModifierData *cmd = (CurveModifierData*) md; - curve_deform_verts(cmd->object, ob, derivedData, vertexCos, numVerts, + curve_deform_verts(md->scene, cmd->object, ob, derivedData, vertexCos, numVerts, cmd->name, cmd->defaxis); } @@ -266,7 +273,7 @@ static void curveModifier_deformVertsEM( if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); - curveModifier_deformVerts(md, ob, dm, vertexCos, numVerts); + curveModifier_deformVerts(md, ob, dm, vertexCos, numVerts, 0, 0); if(!derivedData) dm->release(dm); } @@ -310,7 +317,7 @@ static void latticeModifier_foreachObjectLink( walk(userData, ob, &lmd->object); } -static void latticeModifier_updateDepgraph(ModifierData *md, DagForest *forest, +static void latticeModifier_updateDepgraph(ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { LatticeModifierData *lmd = (LatticeModifierData*) md; @@ -339,7 +346,7 @@ static void modifier_vgroup_cache(ModifierData *md, float (*vertexCos)[3]) static void latticeModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { LatticeModifierData *lmd = (LatticeModifierData*) md; @@ -358,7 +365,7 @@ static void latticeModifier_deformVertsEM( if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); - latticeModifier_deformVerts(md, ob, dm, vertexCos, numVerts); + latticeModifier_deformVerts(md, ob, dm, vertexCos, numVerts, 0, 0); if(!derivedData) dm->release(dm); } @@ -486,10 +493,10 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, for(i = 0; i < maxFaces; ++i) faceMap[i] = i; if (ob) { - frac = bsystem_time(ob, (float)G.scene->r.cfra, + frac = bsystem_time(md->scene, ob, md->scene->r.cfra, bmd->start - 1.0f) / bmd->length; } else { - frac = G.scene->r.cfra - bmd->start / bmd->length; + frac = md->scene->r.cfra - bmd->start / bmd->length; } CLAMP(frac, 0.0, 1.0); @@ -679,7 +686,7 @@ static void maskModifier_foreachObjectLink( walk(userData, ob, &mmd->ob_arm); } -static void maskModifier_updateDepgraph(ModifierData *md, DagForest *forest, +static void maskModifier_updateDepgraph(ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { MaskModifierData *mmd = (MaskModifierData *)md; @@ -1065,7 +1072,7 @@ static void arrayModifier_foreachObjectLink( walk(userData, ob, &amd->offset_ob); } -static void arrayModifier_updateDepgraph(ModifierData *md, DagForest *forest, +static void arrayModifier_updateDepgraph(ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { ArrayModifierData *amd = (ArrayModifierData*) md; @@ -1154,7 +1161,7 @@ static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum) } static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, - Object *ob, DerivedMesh *dm, + Scene *scene, Object *ob, DerivedMesh *dm, int initFlags) { int i, j; @@ -1178,9 +1185,9 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, /* need to avoid infinite recursion here */ if(amd->start_cap && amd->start_cap != ob) - start_cap = mesh_get_derived_final(amd->start_cap, CD_MASK_MESH); + start_cap = mesh_get_derived_final(scene, amd->start_cap, CD_MASK_MESH); if(amd->end_cap && amd->end_cap != ob) - end_cap = mesh_get_derived_final(amd->end_cap, CD_MASK_MESH); + end_cap = mesh_get_derived_final(scene, amd->end_cap, CD_MASK_MESH); MTC_Mat4One(offset); @@ -1225,7 +1232,7 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, if(!cu->path) { cu->flag |= CU_PATH; // needed for path & bevlist - makeDispListCurveTypes(amd->curve_ob, 0); + makeDispListCurveTypes(scene, amd->curve_ob, 0); } if(cu->path) length = scale*cu->path->totdist; @@ -1701,7 +1708,7 @@ static DerivedMesh *arrayModifier_applyModifier( DerivedMesh *result; ArrayModifierData *amd = (ArrayModifierData*) md; - result = arrayModifier_doArray(amd, ob, derivedData, 0); + result = arrayModifier_doArray(amd, md->scene, ob, derivedData, 0); if(result != derivedData) CDDM_calc_normals(result); @@ -1748,7 +1755,7 @@ static void mirrorModifier_foreachObjectLink( walk(userData, ob, &mmd->mirror_ob); } -static void mirrorModifier_updateDepgraph(ModifierData *md, DagForest *forest, +static void mirrorModifier_updateDepgraph(ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { MirrorModifierData *mmd = (MirrorModifierData*) md; @@ -3527,7 +3534,7 @@ static int displaceModifier_isDisabled(ModifierData *md) } static void displaceModifier_updateDepgraph( - ModifierData *md, DagForest *forest, + ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { DisplaceModifierData *dmd = (DisplaceModifierData*) md; @@ -3540,7 +3547,7 @@ static void displaceModifier_updateDepgraph( } } -static void validate_layer_name(const CustomData *data, int type, char *name) +static void validate_layer_name(const CustomData *data, int type, char *name, char *outname) { int index = -1; @@ -3553,8 +3560,10 @@ static void validate_layer_name(const CustomData *data, int type, char *name) * deleted, so assign the active layer to name */ index = CustomData_get_active_layer_index(data, CD_MTFACE); - strcpy(name, data->layers[index].name); + strcpy(outname, data->layers[index].name); } + else + strcpy(outname, name); } static void get_texture_coords(DisplaceModifierData *dmd, Object *ob, @@ -3580,12 +3589,11 @@ static void get_texture_coords(DisplaceModifierData *dmd, Object *ob, char *done = MEM_callocN(sizeof(*done) * numVerts, "get_texture_coords done"); int numFaces = dm->getNumFaces(dm); + char uvname[32]; MTFace *tf; - validate_layer_name(&dm->faceData, CD_MTFACE, dmd->uvlayer_name); - - tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, - dmd->uvlayer_name); + validate_layer_name(&dm->faceData, CD_MTFACE, dmd->uvlayer_name, uvname); + tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname); /* verts are given the UV from the first face that uses them */ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) { @@ -3749,7 +3757,7 @@ static void displaceModifier_do( static void displaceModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { DerivedMesh *dm; @@ -3848,7 +3856,7 @@ static void uvprojectModifier_foreachIDLink(ModifierData *md, Object *ob, } static void uvprojectModifier_updateDepgraph(ModifierData *md, - DagForest *forest, Object *ob, DagNode *obNode) + DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { UVProjectModifierData *umd = (UVProjectModifierData*) md; int i; @@ -3881,6 +3889,7 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, Projector projectors[MOD_UVPROJECT_MAXPROJECTORS]; int num_projectors = 0; float aspect; + char uvname[32]; if(umd->aspecty != 0) aspect = umd->aspectx / umd->aspecty; else aspect = 1.0f; @@ -3895,12 +3904,11 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, if(!dm->getFaceDataArray(dm, CD_MTFACE)) return dm; /* make sure we're using an existing layer */ - validate_layer_name(&dm->faceData, CD_MTFACE, umd->uvlayer_name); + validate_layer_name(&dm->faceData, CD_MTFACE, umd->uvlayer_name, uvname); /* make sure we are not modifying the original UV layer */ tface = CustomData_duplicate_referenced_layer_named(&dm->faceData, - CD_MTFACE, - umd->uvlayer_name); + CD_MTFACE, uvname); numVerts = dm->getNumVerts(dm); @@ -4125,11 +4133,11 @@ static DerivedMesh *decimateModifier_applyModifier( ModifierData *md, Object *ob, DerivedMesh *derivedData, int useRenderParams, int isFinalCalc) { - DecimateModifierData *dmd = (DecimateModifierData*) md; + // DecimateModifierData *dmd = (DecimateModifierData*) md; DerivedMesh *dm = derivedData, *result = NULL; MVert *mvert; MFace *mface; - LOD_Decimation_Info lod; + // LOD_Decimation_Info lod; int totvert, totface; int a, numTris; @@ -4151,6 +4159,8 @@ static DerivedMesh *decimateModifier_applyModifier( goto exit; } + // XXX +#if 0 lod.vertex_buffer= MEM_mallocN(3*sizeof(float)*totvert, "vertices"); lod.vertex_normal_buffer= MEM_mallocN(3*sizeof(float)*totvert, "normals"); lod.triangle_index_buffer= MEM_mallocN(3*sizeof(int)*numTris, "trias"); @@ -4235,6 +4245,10 @@ static DerivedMesh *decimateModifier_applyModifier( MEM_freeN(lod.vertex_buffer); MEM_freeN(lod.vertex_normal_buffer); MEM_freeN(lod.triangle_index_buffer); +#else + modifier_setError(md, "Modifier not working yet in 2.5."); + goto exit; +#endif exit: return result; @@ -4428,7 +4442,7 @@ static void smoothModifier_do( static void smoothModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { DerivedMesh *dm; @@ -4527,7 +4541,7 @@ static void castModifier_foreachObjectLink( } static void castModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, + ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { CastModifierData *cmd = (CastModifierData*) md; @@ -5008,7 +5022,7 @@ static void castModifier_cuboid_do( static void castModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { DerivedMesh *dm = derivedData; CastModifierData *cmd = (CastModifierData *)md; @@ -5058,7 +5072,7 @@ static void waveModifier_initData(ModifierData *md) wmd->map_object = NULL; wmd->height= 0.5f; wmd->width= 1.5f; - wmd->speed= 0.5f; + wmd->speed= 0.25f; wmd->narrow= 1.5f; wmd->lifetime= 0.0f; wmd->damp= 10.0f; @@ -5116,7 +5130,7 @@ static void waveModifier_foreachIDLink(ModifierData *md, Object *ob, } static void waveModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, + ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { WaveModifierData *wmd = (WaveModifierData*) md; @@ -5176,12 +5190,11 @@ static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob, char *done = MEM_callocN(sizeof(*done) * numVerts, "get_texture_coords done"); int numFaces = dm->getNumFaces(dm); + char uvname[32]; MTFace *tf; - validate_layer_name(&dm->faceData, CD_MTFACE, wmd->uvlayer_name); - - tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, - wmd->uvlayer_name); + validate_layer_name(&dm->faceData, CD_MTFACE, wmd->uvlayer_name, uvname); + tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, uvname); /* verts are given the UV from the first face that uses them */ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) { @@ -5241,15 +5254,15 @@ static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob, } } -static void waveModifier_do( - WaveModifierData *md, Object *ob, DerivedMesh *dm, +static void waveModifier_do(WaveModifierData *md, + Scene *scene, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { WaveModifierData *wmd = (WaveModifierData*) md; MVert *mvert = NULL; MDeformVert *dvert = NULL; int defgrp_index; - float ctime = bsystem_time(ob, (float)G.scene->r.cfra, 0.0); + float ctime = bsystem_time(scene, ob, (float)scene->r.cfra, 0.0); float minfac = (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow)); float lifefac = wmd->height; @@ -5411,7 +5424,7 @@ static void waveModifier_do( static void waveModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { DerivedMesh *dm; WaveModifierData *wmd = (WaveModifierData *)md; @@ -5427,7 +5440,7 @@ static void waveModifier_deformVerts( CDDM_calc_normals(dm); } - waveModifier_do(wmd, ob, dm, vertexCos, numVerts); + waveModifier_do(wmd, md->scene, ob, dm, vertexCos, numVerts); if(dm != derivedData) dm->release(dm); } @@ -5449,7 +5462,7 @@ static void waveModifier_deformVertsEM( CDDM_calc_normals(dm); } - waveModifier_do(wmd, ob, dm, vertexCos, numVerts); + waveModifier_do(wmd, md->scene, ob, dm, vertexCos, numVerts); if(dm != derivedData) dm->release(dm); } @@ -5501,7 +5514,7 @@ static void armatureModifier_foreachObjectLink( } static void armatureModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, + ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { ArmatureModifierData *amd = (ArmatureModifierData*) md; @@ -5516,7 +5529,7 @@ static void armatureModifier_updateDepgraph( static void armatureModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { ArmatureModifierData *amd = (ArmatureModifierData*) md; @@ -5622,7 +5635,7 @@ static void hookModifier_foreachObjectLink( walk(userData, ob, &hmd->object); } -static void hookModifier_updateDepgraph(ModifierData *md, DagForest *forest, +static void hookModifier_updateDepgraph(ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { HookModifierData *hmd = (HookModifierData*) md; @@ -5637,7 +5650,7 @@ static void hookModifier_updateDepgraph(ModifierData *md, DagForest *forest, static void hookModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { HookModifierData *hmd = (HookModifierData*) md; float vec[3], mat[4][4]; @@ -5758,7 +5771,7 @@ static void hookModifier_deformVertsEM( if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); - hookModifier_deformVerts(md, ob, derivedData, vertexCos, numVerts); + hookModifier_deformVerts(md, ob, derivedData, vertexCos, numVerts, 0, 0); if(!derivedData) dm->release(dm); } @@ -5767,9 +5780,9 @@ static void hookModifier_deformVertsEM( static void softbodyModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { - sbObjectStep(ob, (float)G.scene->r.cfra, vertexCos, numVerts); + sbObjectStep(md->scene, ob, (float)md->scene->r.cfra, vertexCos, numVerts); } static int softbodyModifier_dependsOnTime(ModifierData *md) @@ -5777,6 +5790,100 @@ static int softbodyModifier_dependsOnTime(ModifierData *md) return 1; } +/* Smoke */ + +static void smokeModifier_initData(ModifierData *md) +{ + SmokeModifierData *smd = (SmokeModifierData*) md; + + smd->domain = NULL; + smd->flow = NULL; + smd->coll = NULL; + smd->type = 0; + smd->time = -1; + + /* + smd->fluid = NULL; + smd->maxres = 48; + smd->amplify = 4; + smd->omega = 0.5; + smd->time = 0; + smd->flags = 0; + smd->noise = MOD_SMOKE_NOISEWAVE; + smd->visibility = 1; + + // init 3dview buffer + smd->tvox = NULL; + smd->tray = NULL; + smd->tvoxbig = NULL; + smd->traybig = NULL; + smd->viewsettings = 0; + smd->bind = NULL; + smd->max_textures = 0; + */ +} + +static void smokeModifier_freeData(ModifierData *md) +{ + SmokeModifierData *smd = (SmokeModifierData*) md; + + smokeModifier_free (smd); +} + +static void smokeModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) +{ + SmokeModifierData *smd = (SmokeModifierData*) md; + DerivedMesh *dm = NULL; + + if(derivedData) dm = derivedData; + else if(ob->type == OB_MESH) dm = CDDM_from_mesh(ob->data, ob); + else return; + + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + + smokeModifier_do(smd, md->scene, ob, dm, useRenderParams, isFinalCalc); + + if(dm != derivedData) dm->release(dm); +} + +static int smokeModifier_dependsOnTime(ModifierData *md) +{ + return 1; +} + +static void smokeModifier_updateDepgraph( + ModifierData *md, DagForest *forest, Scene *scene, Object *ob, + DagNode *obNode) +{ + SmokeModifierData *smd = (SmokeModifierData *) md; + /* + if(smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) + { + if(smd->domain->fluid_group) + { + GroupObject *go = NULL; + + for(go = smd->domain->fluid_group->gobject.first; go; go = go->next) + { + if(go->ob) + { + SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke); + + // check for initialized smoke object + if(smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) + { + DagNode *curNode = dag_get_node(forest, go->ob); + dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Smoke Flow"); + } + } + } + } + } + */ +} /* Cloth */ @@ -5786,7 +5893,7 @@ static void clothModifier_initData(ModifierData *md) clmd->sim_parms = MEM_callocN(sizeof(ClothSimSettings), "cloth sim parms"); clmd->coll_parms = MEM_callocN(sizeof(ClothCollSettings), "cloth coll parms"); - clmd->point_cache = BKE_ptcache_add(); + clmd->point_cache = BKE_ptcache_add(&clmd->ptcaches); /* check for alloc failing */ if(!clmd->sim_parms || !clmd->coll_parms || !clmd->point_cache) @@ -5810,7 +5917,7 @@ static DerivedMesh *clothModifier_applyModifier(ModifierData *md, Object *ob, return derivedData; } - result = clothModifier_do(clmd, ob, derivedData, useRenderParams, isFinalCalc); + result = clothModifier_do(clmd, md->scene, ob, derivedData, useRenderParams, isFinalCalc); if(result) { @@ -5821,7 +5928,7 @@ static DerivedMesh *clothModifier_applyModifier(ModifierData *md, Object *ob, } static void clothModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, + ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { ClothModifierData *clmd = (ClothModifierData*) md; @@ -5830,7 +5937,7 @@ static void clothModifier_updateDepgraph( if(clmd) { - for(base = G.scene->base.first; base; base= base->next) + for(base = scene->base.first; base; base= base->next) { Object *ob1= base->object; if(ob1 != ob) @@ -5865,12 +5972,13 @@ static void clothModifier_copyData(ModifierData *md, ModifierData *target) MEM_freeN(tclmd->sim_parms); if(tclmd->coll_parms) MEM_freeN(tclmd->coll_parms); - if(tclmd->point_cache) - BKE_ptcache_free(tclmd->point_cache); + + BKE_ptcache_free_list(&tclmd->ptcaches); + tclmd->point_cache = NULL; tclmd->sim_parms = MEM_dupallocN(clmd->sim_parms); tclmd->coll_parms = MEM_dupallocN(clmd->coll_parms); - tclmd->point_cache = BKE_ptcache_copy(clmd->point_cache); + tclmd->point_cache = BKE_ptcache_copy_list(&tclmd->ptcaches, &clmd->ptcaches); tclmd->clothObject = NULL; } @@ -5894,8 +6002,9 @@ static void clothModifier_freeData(ModifierData *md) MEM_freeN(clmd->sim_parms); if(clmd->coll_parms) MEM_freeN(clmd->coll_parms); - if(clmd->point_cache) - BKE_ptcache_free(clmd->point_cache); + + BKE_ptcache_free_list(&clmd->ptcaches); + clmd->point_cache = NULL; } } @@ -5955,7 +6064,7 @@ static int collisionModifier_dependsOnTime(ModifierData *md) static void collisionModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { CollisionModifierData *collmd = (CollisionModifierData*) md; DerivedMesh *dm = NULL; @@ -5978,7 +6087,7 @@ static void collisionModifier_deformVerts( CDDM_apply_vert_coords(dm, vertexCos); CDDM_calc_normals(dm); - current_time = bsystem_time ( ob, ( float ) G.scene->r.cfra, 0.0 ); + current_time = bsystem_time (md->scene, ob, ( float ) md->scene->r.cfra, 0.0 ); if(G.rt > 0) printf("current_time %f, collmd->time %f\n", current_time, collmd->time); @@ -6103,9 +6212,14 @@ static void surfaceModifier_freeData(ModifierData *md) MEM_freeN(surmd->bvhtree); } - if(surmd->dm) - surmd->dm->release(surmd->dm); + surmd->dm->release(surmd->dm); + + if(surmd->x) + MEM_freeN(surmd->x); + if(surmd->v) + MEM_freeN(surmd->v); + surmd->bvhtree = NULL; surmd->dm = NULL; } @@ -6118,7 +6232,7 @@ static int surfaceModifier_dependsOnTime(ModifierData *md) static void surfaceModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { SurfaceModifierData *surmd = (SurfaceModifierData*) md; unsigned int numverts = 0, i = 0; @@ -6128,7 +6242,7 @@ static void surfaceModifier_deformVerts( /* if possible use/create DerivedMesh */ if(derivedData) surmd->dm = CDDM_copy(derivedData); - else surmd->dm = get_original_dm(ob, NULL, 0); + else surmd->dm = get_original_dm(md->scene, ob, NULL, 0); if(!ob->pd) { @@ -6138,14 +6252,47 @@ static void surfaceModifier_deformVerts( if(surmd->dm) { + int init = 0; + float *vec; + MVert *x, *v; + CDDM_apply_vert_coords(surmd->dm, vertexCos); CDDM_calc_normals(surmd->dm); numverts = surmd->dm->getNumVerts ( surmd->dm ); - /* convert to global coordinates */ - for(i = 0; i<numverts; i++) - Mat4MulVecfl(ob->obmat, CDDM_get_vert(surmd->dm, i)->co); + if(numverts != surmd->numverts || surmd->x == NULL || surmd->v == NULL || md->scene->r.cfra != surmd->cfra+1) { + if(surmd->x) { + MEM_freeN(surmd->x); + surmd->x = NULL; + } + if(surmd->v) { + MEM_freeN(surmd->v); + surmd->v = NULL; + } + + surmd->x = MEM_callocN(numverts * sizeof(MVert), "MVert"); + surmd->v = MEM_callocN(numverts * sizeof(MVert), "MVert"); + + surmd->numverts = numverts; + + init = 1; + } + + /* convert to global coordinates and calculate velocity */ + for(i = 0, x = surmd->x, v = surmd->v; i<numverts; i++, x++, v++) { + vec = CDDM_get_vert(surmd->dm, i)->co; + Mat4MulVecfl(ob->obmat, vec); + + if(init) + v->co[0] = v->co[1] = v->co[2] = 0.0f; + else + VecSubf(v->co, vec, x->co); + + VecCopyf(x->co, vec); + } + + surmd->cfra = md->scene->r.cfra; if(surmd->bvhtree) free_bvhtree_from_mesh(surmd->bvhtree); @@ -6186,7 +6333,7 @@ static void booleanModifier_foreachObjectLink( } static void booleanModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, + ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { BooleanModifierData *bmd = (BooleanModifierData*) md; @@ -6205,7 +6352,7 @@ static DerivedMesh *booleanModifier_applyModifier( { // XXX doesn't handle derived data BooleanModifierData *bmd = (BooleanModifierData*) md; - DerivedMesh *dm = mesh_get_derived_final(bmd->object, CD_MASK_BAREMESH); + DerivedMesh *dm = mesh_get_derived_final(md->scene, bmd->object, CD_MASK_BAREMESH); /* we do a quick sanity check */ if(dm && (derivedData->getNumFaces(derivedData) > 3) @@ -6286,6 +6433,9 @@ CustomDataMask particleSystemModifier_requiredDataMask(Object *ob, ModifierData MTex *mtex; int i; + if(!psmd->psys->part) + return 0; + ma= give_current_material(ob, psmd->psys->part->omat); if(ma) { for(i=0; i<MAX_MTEX; i++) { @@ -6319,12 +6469,11 @@ CustomDataMask particleSystemModifier_requiredDataMask(Object *ob, ModifierData /* saves the current emitter state for a particle system and calculates particles */ static void particleSystemModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { DerivedMesh *dm = derivedData; ParticleSystemModifierData *psmd= (ParticleSystemModifierData*) md; ParticleSystem * psys=0; - Mesh *me; int needsFree=0; if(ob->particlesystem.first) @@ -6332,19 +6481,11 @@ static void particleSystemModifier_deformVerts( else return; - /* multires check */ - if(ob->type == OB_MESH) { - me= (Mesh*)ob->data; - if(me->mr && me->mr->current != 1) - modifier_setError(md, - "Particles only supported on first multires level."); - } - if(!psys_check_enabled(ob, psys)) return; if(dm==0) { - dm= get_original_dm(ob, vertexCos, 1); + dm= get_original_dm(md->scene, ob, vertexCos, 1); if(!dm) return; @@ -6377,8 +6518,7 @@ static void particleSystemModifier_deformVerts( psmd->dm->getNumFaces(psmd->dm)!=psmd->totdmface){ /* in file read dm hasn't really changed but just wasn't saved in file */ - psys->recalc |= PSYS_RECALC_HAIR; - psys->recalc |= PSYS_DISTR; + psys->recalc |= PSYS_RECALC_RESET; psmd->flag |= eParticleSystemFlag_DM_changed; psmd->totdmvert= psmd->dm->getNumVerts(psmd->dm); @@ -6387,7 +6527,8 @@ static void particleSystemModifier_deformVerts( } if(psys){ - particle_system_update(ob,psys); + psmd->flag &= ~eParticleSystemFlag_psys_updated; + particle_system_update(md->scene, ob, psys); psmd->flag |= eParticleSystemFlag_psys_updated; psmd->flag &= ~eParticleSystemFlag_DM_changed; } @@ -6418,6 +6559,8 @@ static void particleInstanceModifier_initData(ModifierData *md) pimd->flag = eParticleInstanceFlag_Parents|eParticleInstanceFlag_Unborn| eParticleInstanceFlag_Alive|eParticleInstanceFlag_Dead; pimd->psys = 1; + pimd->position = 1.0f; + pimd->axis = 2; } static void particleInstanceModifier_copyData(ModifierData *md, ModifierData *target) @@ -6428,6 +6571,8 @@ static void particleInstanceModifier_copyData(ModifierData *md, ModifierData *ta tpimd->ob = pimd->ob; tpimd->psys = pimd->psys; tpimd->flag = pimd->flag; + tpimd->position = pimd->position; + tpimd->random_position = pimd->random_position; } static int particleInstanceModifier_dependsOnTime(ModifierData *md) @@ -6435,7 +6580,7 @@ static int particleInstanceModifier_dependsOnTime(ModifierData *md) return 0; } static void particleInstanceModifier_updateDepgraph(ModifierData *md, DagForest *forest, - Object *ob, DagNode *obNode) + Scene *scene,Object *ob, DagNode *obNode) { ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData*) md; @@ -6467,8 +6612,9 @@ static DerivedMesh * particleInstanceModifier_applyModifier( MFace *mface, *orig_mface; MVert *mvert, *orig_mvert; int i,totvert, totpart=0, totface, maxvert, maxface, first_particle=0; - short track=ob->trackflag%3, trackneg; + short track=ob->trackflag%3, trackneg, axis = pimd->axis; float max_co=0.0, min_co=0.0, temp_co[3], cross[3]; + float *size=NULL; trackneg=((ob->trackflag>2)?1:0); @@ -6495,6 +6641,25 @@ static DerivedMesh * particleInstanceModifier_applyModifier( if(totpart==0) return derivedData; + if(pimd->flag & eParticleInstanceFlag_UseSize) { + int p; + float *si; + si = size = MEM_callocN(totpart * sizeof(float), "particle size array"); + + if(pimd->flag & eParticleInstanceFlag_Parents) { + for(p=0, pa= psys->particles; p<psys->totpart; p++, pa++, si++) + *si = pa->size; + } + + if(pimd->flag & eParticleInstanceFlag_Children) { + ChildParticle *cpa = psys->child; + + for(p=0; p<psys->totchild; p++, cpa++, si++) { + *si = psys_get_child_size(psys, cpa, 0.0f, NULL); + } + } + } + pars=psys->particles; totvert=dm->getNumVerts(dm); @@ -6503,9 +6668,9 @@ static DerivedMesh * particleInstanceModifier_applyModifier( maxvert=totvert*totpart; maxface=totface*totpart; - psys->lattice=psys_get_lattice(ob, psys); + psys->lattice=psys_get_lattice(md->scene, ob, psys); - if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED)){ + if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED){ float min_r[3], max_r[3]; INIT_MINMAX(min_r, max_r); @@ -6530,40 +6695,59 @@ static DerivedMesh * particleInstanceModifier_applyModifier( /*change orientation based on object trackflag*/ VECCOPY(temp_co,mv->co); - mv->co[0]=temp_co[track]; - mv->co[1]=temp_co[(track+1)%3]; - mv->co[2]=temp_co[(track+2)%3]; + mv->co[axis]=temp_co[track]; + mv->co[(axis+1)%3]=temp_co[(track+1)%3]; + mv->co[(axis+2)%3]=temp_co[(track+2)%3]; + + if((psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && pimd->flag & eParticleInstanceFlag_Path){ + float ran = 0.0f; + if(pimd->random_position != 0.0f) { + /* just use some static collection of random numbers */ + /* TODO: use something else that's unique to each instanced object */ + pa = psys->particles + (i/totvert)%totpart; + ran = pimd->random_position * 0.5 * (1.0f + pa->r_ave[0]); + } - if(psys->flag & (PSYS_HAIR_DONE|PSYS_KEYED) && pimd->flag & eParticleInstanceFlag_Path){ - state.time=(mv->co[0]-min_co)/(max_co-min_co); - if(trackneg) - state.time=1.0f-state.time; - psys_get_particle_on_path(pimd->ob,psys,first_particle + i/totvert,&state,1); + if(pimd->flag & eParticleInstanceFlag_KeepShape) { + state.time = pimd->position * (1.0f - ran); + } + else { + state.time=(mv->co[axis]-min_co)/(max_co-min_co) * pimd->position * (1.0f - ran); - mv->co[0] = 0.0; + if(trackneg) + state.time=1.0f-state.time; + + mv->co[axis] = 0.0; + } + + psys_get_particle_on_path(md->scene, pimd->ob, psys,first_particle + i/totvert, &state,1); Normalize(state.vel); - if(state.vel[0] < -0.9999 || state.vel[0] > 0.9999) { - state.rot[0] = 1.0; + /* TODO: incremental rotations somehow */ + if(state.vel[axis] < -0.9999 || state.vel[axis] > 0.9999) { + state.rot[0] = 1; state.rot[1] = state.rot[2] = state.rot[3] = 0.0f; } else { - /* a cross product of state.vel and a unit vector in x-direction */ - cross[0] = 0.0f; - cross[1] = -state.vel[2]; - cross[2] = state.vel[1]; + float temp[3] = {0.0f,0.0f,0.0f}; + temp[axis] = 1.0f; - /* state.vel[0] is the only component surviving from a dot product with a vector in x-direction*/ - VecRotToQuat(cross,saacos(state.vel[0]),state.rot); + Crossf(cross, temp, state.vel); + + /* state.vel[axis] is the only component surviving from a dot product with the axis */ + VecRotToQuat(cross,saacos(state.vel[axis]),state.rot); } + } else{ state.time=-1.0; - psys_get_particle_state(pimd->ob,psys,i/totvert,&state,1); + psys_get_particle_state(md->scene, pimd->ob, psys, first_particle + i/totvert, &state,1); } QuatMulVecf(state.rot,mv->co); + if(pimd->flag & eParticleInstanceFlag_UseSize) + VecMulf(mv->co, size[i/totvert]); VECADD(mv->co,mv->co,state.co); } @@ -6612,10 +6796,13 @@ static DerivedMesh * particleInstanceModifier_applyModifier( CDDM_calc_normals(result); if(psys->lattice){ - end_latt_deform(); - psys->lattice=0; + end_latt_deform(psys->lattice); + psys->lattice= NULL; } + if(size) + MEM_freeN(size); + return result; } static DerivedMesh *particleInstanceModifier_applyModifierEM( @@ -7231,7 +7418,7 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive } static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, - ParticleSystemModifierData *psmd, Object *ob, + ParticleSystemModifierData *psmd, Scene *scene, Object *ob, DerivedMesh *to_explode) { DerivedMesh *explode, *dm=to_explode; @@ -7254,10 +7441,10 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, timestep= psys_get_timestep(part); - if(part->flag & PART_GLOB_TIME) - cfra=bsystem_time(0,(float)G.scene->r.cfra,0.0); - else - cfra=bsystem_time(ob,(float)G.scene->r.cfra,0.0); + //if(part->flag & PART_GLOB_TIME) + cfra=bsystem_time(scene, 0,(float)scene->r.cfra,0.0); + //else + // cfra=bsystem_time(scene, ob,(float)scene->r.cfra,0.0); /* hash table for vertice <-> particle relations */ vertpahash= BLI_edgehash_new(); @@ -7295,7 +7482,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, /* getting back to object space */ Mat4Invert(imat,ob->obmat); - psmd->psys->lattice = psys_get_lattice(ob, psmd->psys); + psmd->psys->lattice = psys_get_lattice(scene, ob, psmd->psys); /* duplicate & displace vertices */ ehi= BLI_edgehashIterator_new(vertpahash); @@ -7323,7 +7510,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, Mat4MulVecfl(ob->obmat,loc0); state.time=cfra; - psys_get_particle_state(ob,psmd->psys,i,&state,1); + psys_get_particle_state(scene, ob, psmd->psys, i, &state,1); vertco=CDDM_get_vert(explode,v)->co; @@ -7388,8 +7575,8 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, CDDM_calc_normals(explode); if(psmd->psys->lattice){ - end_latt_deform(); - psmd->psys->lattice=0; + end_latt_deform(psmd->psys->lattice); + psmd->psys->lattice= NULL; } return explode; @@ -7439,7 +7626,7 @@ static DerivedMesh * explodeModifier_applyModifier( if(emd->flag & eExplodeFlag_EdgeSplit){ int *facepa = emd->facepa; DerivedMesh *splitdm=explodeModifier_splitEdges(emd,dm); - DerivedMesh *explode=explodeModifier_explodeMesh(emd,psmd,ob,splitdm); + DerivedMesh *explode=explodeModifier_explodeMesh(emd, psmd, md->scene, ob, splitdm); MEM_freeN(emd->facepa); emd->facepa=facepa; @@ -7447,7 +7634,7 @@ static DerivedMesh * explodeModifier_applyModifier( return explode; } else - return explodeModifier_explodeMesh(emd,psmd,ob,derivedData); + return explodeModifier_explodeMesh(emd, psmd, md->scene, ob, derivedData); } return derivedData; } @@ -7493,7 +7680,7 @@ static DerivedMesh * fluidsimModifier_applyModifier( return derivedData; } - result = fluidsimModifier_do(fluidmd, ob, derivedData, useRenderParams, isFinalCalc); + result = fluidsimModifier_do(fluidmd, md->scene, ob, derivedData, useRenderParams, isFinalCalc); if(result) { @@ -7504,7 +7691,7 @@ static DerivedMesh * fluidsimModifier_applyModifier( } static void fluidsimModifier_updateDepgraph( - ModifierData *md, DagForest *forest, + ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { FluidsimModifierData *fluidmd= (FluidsimModifierData*) md; @@ -7514,7 +7701,7 @@ static void fluidsimModifier_updateDepgraph( { if(fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) { - for(base = G.scene->base.first; base; base= base->next) + for(base = scene->base.first; base; base= base->next) { Object *ob1= base->object; if(ob1 != ob) @@ -7596,7 +7783,7 @@ static void meshdeformModifier_foreachObjectLink( } static void meshdeformModifier_updateDepgraph( - ModifierData *md, DagForest *forest, Object *ob, + ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; @@ -7667,22 +7854,25 @@ static void meshdeformModifier_do( float (*vertexCos)[3], int numVerts) { MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; - float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4]; - float weight, totweight, fac, co[3], *weights, (*dco)[3], (*bindcos)[3]; - int a, b, totvert, totcagevert, defgrp_index; + Mesh *me= ob->data; DerivedMesh *tmpdm, *cagedm; MDeformVert *dvert = NULL; MDeformWeight *dw; + EditMesh *em = BKE_mesh_get_editmesh(me); MVert *cagemvert; - + float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4]; + float weight, totweight, fac, co[3], *weights, (*dco)[3], (*bindcos)[3]; + int a, b, totvert, totcagevert, defgrp_index; + if(!mmd->object || (!mmd->bindcos && !mmd->needbind)) return; /* get cage derivedmesh */ - if(mmd->object == G.obedit) { - tmpdm= editmesh_get_derived_cage_and_final(&cagedm, 0); + if(em) { + tmpdm= editmesh_get_derived_cage_and_final(md->scene, ob, em, &cagedm, 0); if(tmpdm) tmpdm->release(tmpdm); + BKE_mesh_end_editmesh(me, em); } else cagedm= mmd->object->derivedFinal; @@ -7690,7 +7880,7 @@ static void meshdeformModifier_do( /* if we don't have one computed, use derivedmesh from data * without any modifiers */ if(!cagedm) { - cagedm= get_original_dm(mmd->object, NULL, 0); + cagedm= get_original_dm(md->scene, mmd->object, NULL, 0); if(cagedm) cagedm->needsFree= 1; } @@ -7712,7 +7902,7 @@ static void meshdeformModifier_do( /* progress bar redraw can make this recursive .. */ if(!recursive) { recursive = 1; - harmonic_coordinates_bind(mmd, vertexCos, numVerts, cagemat); + //XXX harmonic_coordinates_bind(mmd, vertexCos, numVerts, cagemat); recursive = 0; } } @@ -7824,12 +8014,12 @@ static void meshdeformModifier_do( static void meshdeformModifier_deformVerts( ModifierData *md, Object *ob, DerivedMesh *derivedData, - float (*vertexCos)[3], int numVerts) + float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { DerivedMesh *dm; if (!derivedData) { - dm= get_original_dm(ob, NULL, 0); + dm= get_original_dm(md->scene, ob, NULL, 0); if (dm == NULL) return; } else dm= derivedData; @@ -7860,6 +8050,60 @@ static void meshdeformModifier_deformVertsEM( dm->release(dm); } +/* Multires */ +static void multiresModifier_initData(ModifierData *md) +{ + MultiresModifierData *mmd = (MultiresModifierData*)md; + + mmd->lvl = mmd->totlvl = 1; +} + +static void multiresModifier_freeData(ModifierData *md) +{ + MultiresModifierData *mmd = (MultiresModifierData*)md; + + if(mmd->undo_verts) + MEM_freeN(mmd->undo_verts); +} + +static void multiresModifier_copyData(ModifierData *md, ModifierData *target) +{ + MultiresModifierData *mmd = (MultiresModifierData*) md; + MultiresModifierData *tmmd = (MultiresModifierData*) target; + + tmmd->totlvl = mmd->totlvl; + tmmd->lvl = mmd->lvl; +} + +static DerivedMesh *multiresModifier_applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, + int useRenderParams, int isFinalCalc) +{ + MultiresModifierData *mmd = (MultiresModifierData*)md; + Mesh *me = get_mesh(ob); + DerivedMesh *final; + + /* TODO: for now just skip a level1 mesh */ + if(mmd->lvl == 1) + return dm; + + final = multires_dm_create_from_derived(mmd, dm, me, useRenderParams, isFinalCalc); + if(mmd->undo_signal && mmd->undo_verts && mmd->undo_verts_tot == final->getNumVerts(final)) { + int i; + MVert *dst = CDDM_get_verts(final); + for(i = 0; i < mmd->undo_verts_tot; ++i) { + VecCopyf(dst[i].co, mmd->undo_verts[i].co); + } + CDDM_calc_normals(final); + + MultiresDM_mark_as_modified(final); + + MEM_freeN(mmd->undo_verts); + mmd->undo_signal = 0; + mmd->undo_verts = NULL; + } + + return final; +} /* Shrinkwrap */ @@ -7922,7 +8166,7 @@ static void shrinkwrapModifier_foreachObjectLink(ModifierData *md, Object *ob, O walk(userData, ob, &smd->auxTarget); } -static void shrinkwrapModifier_deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +static void shrinkwrapModifier_deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { DerivedMesh *dm = NULL; CustomDataMask dataMask = shrinkwrapModifier_requiredDataMask(ob, md); @@ -7942,7 +8186,7 @@ static void shrinkwrapModifier_deformVerts(ModifierData *md, Object *ob, Derived } } - shrinkwrapModifier_deform((ShrinkwrapModifierData*)md, ob, dm, vertexCos, numVerts); + shrinkwrapModifier_deform((ShrinkwrapModifierData*)md, md->scene, ob, dm, vertexCos, numVerts); if(dm) dm->release(dm); @@ -7967,13 +8211,13 @@ static void shrinkwrapModifier_deformVertsEM(ModifierData *md, Object *ob, EditM } } - shrinkwrapModifier_deform((ShrinkwrapModifierData*)md, ob, dm, vertexCos, numVerts); + shrinkwrapModifier_deform((ShrinkwrapModifierData*)md, md->scene, ob, dm, vertexCos, numVerts); if(dm) dm->release(dm); } -static void shrinkwrapModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode) +static void shrinkwrapModifier_updateDepgraph(ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; @@ -8028,7 +8272,7 @@ static void simpledeformModifier_foreachObjectLink(ModifierData *md, Object *ob, walk(userData, ob, &smd->origin); } -static void simpledeformModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode) +static void simpledeformModifier_updateDepgraph(ModifierData *md, DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { SimpleDeformModifierData *smd = (SimpleDeformModifierData*)md; @@ -8036,7 +8280,7 @@ static void simpledeformModifier_updateDepgraph(ModifierData *md, DagForest *for dag_add_relation(forest, dag_get_node(forest, smd->origin), obNode, DAG_RL_OB_DATA, "SimpleDeform Modifier"); } -static void simpledeformModifier_deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +static void simpledeformModifier_deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts, int useRenderParams, int isFinalCalc) { DerivedMesh *dm = NULL; CustomDataMask dataMask = simpledeformModifier_requiredDataMask(ob, md); @@ -8328,15 +8572,26 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Softbody); mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsCVs - | eModifierTypeFlag_RequiresOriginalData; + | eModifierTypeFlag_RequiresOriginalData + | eModifierTypeFlag_Single; mti->deformVerts = softbodyModifier_deformVerts; mti->dependsOnTime = softbodyModifier_dependsOnTime; + + mti = INIT_TYPE(Smoke); + mti->type = eModifierTypeType_OnlyDeform; + mti->initData = smokeModifier_initData; + mti->freeData = smokeModifier_freeData; + mti->flags = eModifierTypeFlag_AcceptsMesh; + mti->deformVerts = smokeModifier_deformVerts; + mti->dependsOnTime = smokeModifier_dependsOnTime; + mti->updateDepgraph = smokeModifier_updateDepgraph; mti = INIT_TYPE(Cloth); mti->type = eModifierTypeType_Nonconstructive; mti->initData = clothModifier_initData; mti->flags = eModifierTypeFlag_AcceptsMesh - | eModifierTypeFlag_UsesPointCache; + | eModifierTypeFlag_UsesPointCache + | eModifierTypeFlag_Single; mti->dependsOnTime = clothModifier_dependsOnTime; mti->freeData = clothModifier_freeData; mti->requiredDataMask = clothModifier_requiredDataMask; @@ -8347,7 +8602,8 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Collision); mti->type = eModifierTypeType_OnlyDeform; mti->initData = collisionModifier_initData; - mti->flags = eModifierTypeFlag_AcceptsMesh; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_Single; mti->dependsOnTime = collisionModifier_dependsOnTime; mti->freeData = collisionModifier_freeData; mti->deformVerts = collisionModifier_deformVerts; @@ -8430,7 +8686,8 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Fluidsim); mti->type = eModifierTypeType_Nonconstructive - | eModifierTypeFlag_RequiresOriginalData; + | eModifierTypeFlag_RequiresOriginalData + | eModifierTypeFlag_Single; mti->flags = eModifierTypeFlag_AcceptsMesh; mti->initData = fluidsimModifier_initData; mti->freeData = fluidsimModifier_freeData; @@ -8468,6 +8725,14 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->foreachObjectLink = simpledeformModifier_foreachObjectLink; mti->updateDepgraph = simpledeformModifier_updateDepgraph; + mti = INIT_TYPE(Multires); + mti->type = eModifierTypeType_Constructive; + mti->flags = eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_RequiresOriginalData; + mti->initData = multiresModifier_initData; + mti->freeData = multiresModifier_freeData; + mti->copyData = multiresModifier_copyData; + mti->applyModifier = multiresModifier_applyModifier; + typeArrInit = 0; #undef INIT_TYPE } @@ -8549,8 +8814,6 @@ void modifiers_clearErrors(Object *ob) qRedraw = 1; } } - - if (qRedraw) allqueue(REDRAWBUTSEDIT, 0); } void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, @@ -8616,7 +8879,6 @@ void modifier_setError(ModifierData *md, char *format, ...) md->error = BLI_strdup(buffer); - allqueue(REDRAWBUTSEDIT, 0); } /* used for buttons, to find out if the 'draw deformed in editmode' option is @@ -8700,7 +8962,7 @@ LinkNode *modifiers_calcDataMasks(Object *ob, ModifierData *md, CustomDataMask d if(mti->requiredDataMask) mask = mti->requiredDataMask(ob, md); - BLI_linklist_prepend(&dataMasks, (void *)mask); + BLI_linklist_prepend(&dataMasks, SET_INT_IN_POINTER(mask)); } /* build the list of required data masks - each mask in the list must @@ -8711,14 +8973,14 @@ LinkNode *modifiers_calcDataMasks(Object *ob, ModifierData *md, CustomDataMask d */ for(curr = dataMasks, prev = NULL; curr; prev = curr, curr = curr->next) { if(prev) { - CustomDataMask prev_mask = (CustomDataMask)prev->link; - CustomDataMask curr_mask = (CustomDataMask)curr->link; + CustomDataMask prev_mask = (CustomDataMask)GET_INT_FROM_POINTER(prev->link); + CustomDataMask curr_mask = (CustomDataMask)GET_INT_FROM_POINTER(curr->link); - curr->link = (void *)(curr_mask | prev_mask); + curr->link = SET_INT_IN_POINTER(curr_mask | prev_mask); } else { - CustomDataMask curr_mask = (CustomDataMask)curr->link; + CustomDataMask curr_mask = (CustomDataMask)GET_INT_FROM_POINTER(curr->link); - curr->link = (void *)(curr_mask | dataMask); + curr->link = SET_INT_IN_POINTER(curr_mask | dataMask); } } @@ -8859,14 +9121,15 @@ int modifier_isDeformer(ModifierData *md) return 0; } -int modifiers_isDeformed(Object *ob) +int modifiers_isDeformed(Scene *scene, Object *ob) { ModifierData *md = modifiers_getVirtualModifierList(ob); for (; md; md=md->next) { - if(ob==G.obedit && (md->mode & eModifierMode_Editmode)==0); - else if(modifier_isDeformer(md)) - return 1; + if(ob==scene->obedit && (md->mode & eModifierMode_Editmode)==0); + else + if(modifier_isDeformer(md)) + return 1; } return 0; } diff --git a/source/blender/blenkernel/intern/multires-firstlevel.c b/source/blender/blenkernel/intern/multires-firstlevel.c deleted file mode 100644 index 3d417565eb1..00000000000 --- a/source/blender/blenkernel/intern/multires-firstlevel.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The Original Code is Copyright (C) 2006 by Nicholas Bishop - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * - * Deals with the first-level data in multires (edge flags, weights, and UVs) - * - * multires.h - * - */ - -#include "DNA_customdata_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BIF_editmesh.h" - -#include "BKE_customdata.h" -#include "BKE_global.h" -#include "BKE_mesh.h" -#include "BKE_multires.h" - -#include "BLI_editVert.h" - -#include "MEM_guardedalloc.h" - -#include "blendef.h" - -#include <string.h> - -MDeformVert *subdivide_dverts(MDeformVert *src, MultiresLevel *lvl); -MTFace *subdivide_mtfaces(MTFace *src, MultiresLevel *lvl); -void multires_update_edge_flags(Mesh *me, EditMesh *em); -void eed_to_medge_flag(EditEdge *eed, short *flag, char *crease); - -/*********** Generic ***********/ - -CustomDataMask cdmask(const int type) -{ - if(type == CD_MDEFORMVERT) - return CD_MASK_MDEFORMVERT; - else if(type == CD_MTFACE) - return CD_MASK_MTFACE; - return -1; -} - -char type_ok(const int type) -{ - return (type == CD_MDEFORMVERT) || (type == CD_MTFACE); -} - -/* Copy vdata or fdata from Mesh or EditMesh to Multires. */ -void multires_update_customdata(MultiresLevel *lvl1, EditMesh *em, CustomData *src, CustomData *dst, const int type) -{ - if(src && dst && type_ok(type)) { - const int tot= (type == CD_MDEFORMVERT ? lvl1->totvert : lvl1->totface); - int i; - - CustomData_free(dst, tot); - - if(CustomData_has_layer(src, type)) { - if(em) { - EditVert *eve= G.editMesh->verts.first; - EditFace *efa= G.editMesh->faces.first; - CustomData_copy(src, dst, cdmask(type), CD_CALLOC, tot); - for(i=0; i<tot; ++i) { - if(type == CD_MDEFORMVERT) { - CustomData_from_em_block(&G.editMesh->vdata, dst, eve->data, i); - eve= eve->next; - } - else if(type == CD_MTFACE) { - CustomData_from_em_block(&G.editMesh->fdata, dst, efa->data, i); - efa= efa->next; - } - } - } - else - CustomData_copy(src, dst, cdmask(type), CD_DUPLICATE, tot); - } - } -} - -/* Uses subdivide_dverts or subdivide_mtfaces to subdivide src to match lvl_end. Does not free src. */ -void *subdivide_customdata_to_level(void *src, MultiresLevel *lvl_start, - MultiresLevel *lvl_end, const int type) -{ - if(src && lvl_start && lvl_end && type_ok(type)) { - MultiresLevel *lvl; - void *cr_data= NULL, *pr_data= NULL; - - pr_data= src; - for(lvl= lvl_start; lvl && lvl != lvl_end; lvl= lvl->next) { - if(type == CD_MDEFORMVERT) - cr_data= subdivide_dverts(pr_data, lvl); - else if(type == CD_MTFACE) - cr_data= subdivide_mtfaces(pr_data, lvl); - - /* Free previous subdivision level's data */ - if(lvl != lvl_start) { - if(type == CD_MDEFORMVERT) - free_dverts(pr_data, lvl->totvert); - else if(type == CD_MTFACE) - MEM_freeN(pr_data); - } - - pr_data= cr_data; - cr_data= NULL; - } - - return pr_data; - } - - return NULL; -} - -/* Directly copy src into dst (handles both Mesh and EditMesh) */ -void customdata_to_mesh(Mesh *me, EditMesh *em, CustomData *src, CustomData *dst, const int tot, const int type) -{ - if(me && me->mr && src && dst && type_ok(type)) { - if(em) { - int i; - EditVert *eve= em->verts.first; - EditFace *efa= em->faces.first; - CustomData_copy(src, dst, cdmask(type), CD_CALLOC, 0); - - for(i=0; i<tot; ++i) { - if(type == CD_MDEFORMVERT) { - CustomData_to_em_block(src, dst, i, &eve->data); - eve= eve->next; - } - else if(type == CD_MTFACE) { - CustomData_to_em_block(src, dst, i, &efa->data); - efa= efa->next; - } - } - } else { - CustomData_merge(src, dst, cdmask(type), CD_DUPLICATE, tot); - } - } -} - -/* Subdivide vdata or fdata from Multires into either Mesh or EditMesh. */ -void multires_customdata_to_mesh(Mesh *me, EditMesh *em, MultiresLevel *lvl, CustomData *src, - CustomData *dst, const int type) -{ - if(me && me->mr && lvl && src && dst && type_ok(type) && - CustomData_has_layer(src, type)) { - const int tot= (type == CD_MDEFORMVERT ? lvl->totvert : lvl->totface); - if(lvl == me->mr->levels.first) { - customdata_to_mesh(me, em, src, dst, tot, type); - } - else { - CustomData cdf; - const int count = CustomData_number_of_layers(src, type); - int i; - - /* Construct a new CustomData containing the subdivided data */ - CustomData_copy(src, &cdf, cdmask(type), CD_ASSIGN, tot); - for(i=0; i<count; ++i) { - void *layer= CustomData_get_layer_n(&cdf, type, i); - CustomData_set_layer_n(&cdf, type, i, - subdivide_customdata_to_level(layer, me->mr->levels.first, lvl, type)); - } - - customdata_to_mesh(me, em, &cdf, dst, tot, type); - CustomData_free(&cdf, tot); - } - } -} - -/* Subdivide the first-level customdata up to cr_lvl, then delete the original data */ -void multires_del_lower_customdata(Multires *mr, MultiresLevel *cr_lvl) -{ - MultiresLevel *lvl1= mr->levels.first; - MDeformVert *dverts= NULL; - CustomData cdf; - int i; - - /* dverts */ - dverts= subdivide_customdata_to_level(CustomData_get(&mr->vdata, 0, CD_MDEFORMVERT), - lvl1, cr_lvl, CD_MDEFORMVERT); - if(dverts) { - CustomData_free_layers(&mr->vdata, CD_MDEFORMVERT, lvl1->totvert); - CustomData_add_layer(&mr->vdata, CD_MDEFORMVERT, CD_ASSIGN, dverts, cr_lvl->totvert); - } - - /* mtfaces */ - CustomData_copy(&mr->fdata, &cdf, CD_MASK_MTFACE, CD_ASSIGN, cr_lvl->totface); - for(i=0; i<CustomData_number_of_layers(&mr->fdata, CD_MTFACE); ++i) { - MTFace *mtfaces= - subdivide_customdata_to_level(CustomData_get_layer_n(&mr->fdata, CD_MTFACE, i), - lvl1, cr_lvl, CD_MTFACE); - if(mtfaces) - CustomData_set_layer_n(&cdf, CD_MTFACE, i, mtfaces); - } - - CustomData_free(&mr->fdata, lvl1->totface); - mr->fdata= cdf; -} - -/* Update all special first-level data, if the first-level is active */ -void multires_update_first_level(Mesh *me, EditMesh *em) -{ - if(me && me->mr && me->mr->current == 1) { - multires_update_customdata(me->mr->levels.first, em, em ? &em->vdata : &me->vdata, - &me->mr->vdata, CD_MDEFORMVERT); - multires_update_customdata(me->mr->levels.first, em, em ? &em->fdata : &me->fdata, - &me->mr->fdata, CD_MTFACE); - multires_update_edge_flags(me, em); - } -} - -/*********** Multires.edge_flags ***********/ -void multires_update_edge_flags(Mesh *me, EditMesh *em) -{ - MultiresLevel *lvl= me->mr->levels.first; - EditEdge *eed= NULL; - int i; - - if(em) eed= em->edges.first; - for(i=0; i<lvl->totedge; ++i) { - if(em) { - me->mr->edge_flags[i]= 0; - eed_to_medge_flag(eed, &me->mr->edge_flags[i], &me->mr->edge_creases[i]); - eed= eed->next; - } - else { - me->mr->edge_flags[i]= me->medge[i].flag; - me->mr->edge_creases[i]= me->medge[i].crease; - } - } -} - - - -/*********** Multires.vdata ***********/ - -/* MDeformVert */ - -/* Add each weight from in to out. Scale each weight by w. */ -void multires_add_dvert(MDeformVert *out, const MDeformVert *in, const float w) -{ - if(out && in) { - int i, j; - char found; - - for(i=0; i<in->totweight; ++i) { - found= 0; - for(j=0; j<out->totweight; ++j) { - if(out->dw[j].def_nr==in->dw[i].def_nr) { - out->dw[j].weight += in->dw[i].weight * w; - found= 1; - } - } - if(!found) { - MDeformWeight *newdw= MEM_callocN(sizeof(MDeformWeight)*(out->totweight+1), - "multires dvert"); - if(out->dw) { - memcpy(newdw, out->dw, sizeof(MDeformWeight)*out->totweight); - MEM_freeN(out->dw); - } - - out->dw= newdw; - out->dw[out->totweight].weight= in->dw[i].weight * w; - out->dw[out->totweight].def_nr= in->dw[i].def_nr; - - ++out->totweight; - } - } - } -} - -/* Takes an input array of dverts and subdivides them (linear) using the topology of lvl */ -MDeformVert *subdivide_dverts(MDeformVert *src, MultiresLevel *lvl) -{ - if(lvl && lvl->next) { - MDeformVert *out = MEM_callocN(sizeof(MDeformVert)*lvl->next->totvert, "dvert prop array"); - int i, j; - - /* Copy lower level */ - for(i=0; i<lvl->totvert; ++i) - multires_add_dvert(&out[i], &src[i], 1); - /* Edge verts */ - for(i=0; i<lvl->totedge; ++i) { - for(j=0; j<2; ++j) - multires_add_dvert(&out[lvl->totvert+i], &src[lvl->edges[i].v[j]],0.5); - } - - /* Face verts */ - for(i=0; i<lvl->totface; ++i) { - for(j=0; j<(lvl->faces[i].v[3]?4:3); ++j) - multires_add_dvert(&out[lvl->totvert + lvl->totedge + i], - &src[lvl->faces[i].v[j]], - lvl->faces[i].v[3]?0.25:(1.0f/3.0f)); - } - - return out; - } - - return NULL; -} - - - -/*********** Multires.fdata ***********/ - -/* MTFace */ - -void multires_uv_avg2(float out[2], const float a[2], const float b[2]) -{ - int i; - for(i=0; i<2; ++i) - out[i] = (a[i] + b[i]) / 2.0f; -} - -/* Takes an input array of mtfaces and subdivides them (linear) using the topology of lvl */ -MTFace *subdivide_mtfaces(MTFace *src, MultiresLevel *lvl) -{ - if(lvl && lvl->next) { - MTFace *out= MEM_callocN(sizeof(MultiresColFace)*lvl->next->totface,"Multirescolfaces"); - int i, j, curf; - - for(i=0, curf=0; i<lvl->totface; ++i) { - const char sides= lvl->faces[i].v[3]?4:3; - float cntr[2]= {0, 0}; - - /* Find average uv coord of the current face */ - for(j=0; j<sides; ++j) { - cntr[0]+= src[i].uv[j][0]; - cntr[1]+= src[i].uv[j][1]; - } - cntr[0]/= sides; - cntr[1]/= sides; - - for(j=0; j<sides; ++j, ++curf) { - out[curf]= src[i]; - - multires_uv_avg2(out[curf].uv[0], src[i].uv[j], src[i].uv[j==0?sides-1:j-1]); - - out[curf].uv[1][0]= src[i].uv[j][0]; - out[curf].uv[1][1]= src[i].uv[j][1]; - - multires_uv_avg2(out[curf].uv[2], src[i].uv[j], src[i].uv[j==sides-1?0:j+1]); - - out[curf].uv[3][0]= cntr[0]; - out[curf].uv[3][1]= cntr[1]; - } - } - - return out; - } - - return NULL; -} - -void multires_delete_layer(Mesh *me, CustomData *cd, const int type, int n) -{ - if(me && me->mr && cd) { - MultiresLevel *lvl1= me->mr->levels.first; - - multires_update_levels(me, 0); - - CustomData_set_layer_active(cd, type, n); - CustomData_free_layer_active(cd, type, lvl1->totface); - - multires_level_to_mesh(OBACT, me, 0); - } -} - -void multires_add_layer(Mesh *me, CustomData *cd, const int type, const int n) -{ - if(me && me->mr && cd) { - multires_update_levels(me, 0); - - if(CustomData_has_layer(cd, type)) - CustomData_add_layer(cd, type, CD_DUPLICATE, CustomData_get_layer(cd, type), - current_level(me->mr)->totface); - else - CustomData_add_layer(cd, type, CD_DEFAULT, NULL, current_level(me->mr)->totface); - - CustomData_set_layer_active(cd, type, n); - multires_level_to_mesh(OBACT, me, 0); - } -} diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index ee9255df837..e91f318adad 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -32,1279 +32,1548 @@ #include "DNA_key_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" -#include "DNA_vec_types.h" - -#include "BIF_editmesh.h" +#include "DNA_scene_types.h" +#include "DNA_view3d_types.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" -#include "BLI_editVert.h" +#include "BKE_cdderivedmesh.h" #include "BKE_customdata.h" #include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" #include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_modifier.h" #include "BKE_multires.h" - -#include "blendef.h" -#include "editmesh.h" +#include "BKE_object.h" +#include "BKE_subsurf.h" #include <math.h> +#include <string.h> -/* Returns the active multires level (currently applied to the mesh) */ -MultiresLevel *current_level(Multires *mr) -{ - return BLI_findlink(&mr->levels, mr->current - 1); -} +/* MULTIRES MODIFIER */ +static const int multires_max_levels = 13; +static const int multires_quad_tot[] = {4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409}; +static const int multires_side_tot[] = {2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097}; -/* Returns the nth multires level, starting at 1 */ -MultiresLevel *multires_level_n(Multires *mr, int n) +MultiresModifierData *find_multires_modifier(Object *ob) { - if(mr) - return BLI_findlink(&mr->levels, n - 1); - else - return NULL; -} + ModifierData *md; + MultiresModifierData *mmd = NULL; -/* Free and clear the temporary connectivity data */ -static void multires_free_temp_data(MultiresLevel *lvl) -{ - if(lvl) { - if(lvl->edge_boundary_states) MEM_freeN(lvl->edge_boundary_states); - if(lvl->vert_edge_map) MEM_freeN(lvl->vert_edge_map); - if(lvl->vert_face_map) MEM_freeN(lvl->vert_face_map); - if(lvl->map_mem) MEM_freeN(lvl->map_mem); - - lvl->edge_boundary_states = NULL; - lvl->vert_edge_map = lvl->vert_face_map = NULL; - lvl->map_mem = NULL; + for(md = ob->modifiers.first; md; md = md->next) { + if(md->type == eModifierType_Multires) { + mmd = (MultiresModifierData*)md; + break; + } } + + return mmd; + } -/* Does not actually free lvl itself */ -void multires_free_level(MultiresLevel *lvl) +int multiresModifier_switch_level(Object *ob, const int distance) { - if(lvl) { - if(lvl->faces) MEM_freeN(lvl->faces); - if(lvl->edges) MEM_freeN(lvl->edges); - if(lvl->colfaces) MEM_freeN(lvl->colfaces); - - multires_free_temp_data(lvl); + MultiresModifierData *mmd = find_multires_modifier(ob); + + if(mmd) { + mmd->lvl += distance; + if(mmd->lvl < 1) mmd->lvl = 1; + else if(mmd->lvl > mmd->totlvl) mmd->lvl = mmd->totlvl; + /* XXX: DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + object_handle_update(ob);*/ + return 1; } + else + return 0; } -void multires_free(Multires *mr) +/* XXX */ +#if 0 +void multiresModifier_join(Object *ob) { - if(mr) { - MultiresLevel* lvl= mr->levels.first; - - /* Free the first-level data */ - if(lvl) { - CustomData_free(&mr->vdata, lvl->totvert); - CustomData_free(&mr->fdata, lvl->totface); - MEM_freeN(mr->edge_flags); - MEM_freeN(mr->edge_creases); + Base *base = NULL; + int highest_lvl = 0; + + /* First find the highest level of subdivision */ + base = FIRSTBASE; + while(base) { + if(TESTBASELIB_BGMODE(v3d, base) && base->object->type==OB_MESH) { + ModifierData *md; + for(md = base->object->modifiers.first; md; md = md->next) { + if(md->type == eModifierType_Multires) { + int totlvl = ((MultiresModifierData*)md)->totlvl; + if(totlvl > highest_lvl) + highest_lvl = totlvl; + + /* Ensure that all updates are processed */ + multires_force_update(base->object); + } + } } + base = base->next; + } - while(lvl) { - multires_free_level(lvl); - lvl= lvl->next; - } + /* No multires meshes selected */ + if(highest_lvl == 0) + return; - if(mr->verts) - MEM_freeN(mr->verts); + /* Subdivide all the displacements to the highest level */ + base = FIRSTBASE; + while(base) { + if(TESTBASELIB_BGMODE(v3d, base) && base->object->type==OB_MESH) { + ModifierData *md = NULL; + MultiresModifierData *mmd = NULL; - BLI_freelistN(&mr->levels); + for(md = base->object->modifiers.first; md; md = md->next) { + if(md->type == eModifierType_Multires) + mmd = (MultiresModifierData*)md; + } - MEM_freeN(mr); - } -} + /* If the object didn't have multires enabled, give it a new modifier */ + if(!mmd) { + md = base->object->modifiers.first; + + while(md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) + md = md->next; + + mmd = (MultiresModifierData*)modifier_new(eModifierType_Multires); + BLI_insertlinkbefore(&base->object->modifiers, md, mmd); + } -static MultiresLevel *multires_level_copy(MultiresLevel *orig) -{ - if(orig) { - MultiresLevel *lvl= MEM_dupallocN(orig); - - lvl->next= lvl->prev= NULL; - lvl->faces= MEM_dupallocN(orig->faces); - lvl->colfaces= MEM_dupallocN(orig->colfaces); - lvl->edges= MEM_dupallocN(orig->edges); - lvl->edge_boundary_states = NULL; - lvl->vert_edge_map= lvl->vert_face_map= NULL; - lvl->map_mem= NULL; - - return lvl; + if(mmd) + multiresModifier_subdivide(mmd, base->object, highest_lvl - mmd->totlvl, 0, 0); + } + base = base->next; } - return NULL; } +#endif -Multires *multires_copy(Multires *orig) +/* Returns 0 on success, 1 if the src's totvert doesn't match */ +int multiresModifier_reshape(MultiresModifierData *mmd, Object *dst, Object *src) { - const CustomDataMask vdata_mask= CD_MASK_MDEFORMVERT; + Mesh *src_me = get_mesh(src); + DerivedMesh *mrdm = dst->derivedFinal; - if(orig) { - Multires *mr= MEM_dupallocN(orig); - MultiresLevel *lvl; - - mr->levels.first= mr->levels.last= NULL; - - for(lvl= orig->levels.first; lvl; lvl= lvl->next) - BLI_addtail(&mr->levels, multires_level_copy(lvl)); + if(mrdm && mrdm->getNumVerts(mrdm) == src_me->totvert) { + MVert *mvert = CDDM_get_verts(mrdm); + int i; - mr->verts= MEM_dupallocN(orig->verts); - - lvl= mr->levels.first; - if(lvl) { - CustomData_copy(&orig->vdata, &mr->vdata, vdata_mask, CD_DUPLICATE, lvl->totvert); - CustomData_copy(&orig->fdata, &mr->fdata, CD_MASK_MTFACE, CD_DUPLICATE, lvl->totface); - mr->edge_flags= MEM_dupallocN(orig->edge_flags); - mr->edge_creases= MEM_dupallocN(orig->edge_creases); - } - - return mr; - } - return NULL; -} + for(i = 0; i < src_me->totvert; ++i) + VecCopyf(mvert[i].co, src_me->mvert[i].co); + mrdm->needsFree = 1; + MultiresDM_mark_as_modified(mrdm); + mrdm->release(mrdm); + dst->derivedFinal = NULL; -static void multires_get_vert(MVert *out, EditVert *eve, MVert *m, int i) -{ - if(eve) { - VecCopyf(out->co, eve->co); - out->flag= 0; - if(eve->f & SELECT) out->flag |= 1; - if(eve->h) out->flag |= ME_HIDE; - eve->tmp.l= i; + return 0; } - else - *out= *m; -} -void eed_to_medge_flag(EditEdge *eed, short *flag, char *crease) -{ - if(!eed || !flag) return; - - /* Would be nice if EditMesh edge flags could be unified with Mesh flags! */ - *flag= (eed->f & SELECT) | ME_EDGERENDER; - if(eed->f2<2) *flag |= ME_EDGEDRAW; - if(eed->f2==0) *flag |= ME_LOOSEEDGE; - if(eed->sharp) *flag |= ME_SHARP; - if(eed->seam) *flag |= ME_SEAM; - if(eed->h & EM_FGON) *flag |= ME_FGON; - if(eed->h & 1) *flag |= ME_HIDE; - - *crease= (char)(255.0*eed->crease); + return 1; } -static void multires_get_edge(MultiresEdge *e, EditEdge *eed, MEdge *m, short *flag, char *crease) +static void Mat3FromColVecs(float mat[][3], float v1[3], float v2[3], float v3[3]) { - if(eed) { - e->v[0]= eed->v1->tmp.l; - e->v[1]= eed->v2->tmp.l; - eed_to_medge_flag(eed, flag, crease); - } else { - e->v[0]= m->v1; - e->v[1]= m->v2; - *flag= m->flag; - *crease= m->crease; - } + VecCopyf(mat[0], v1); + VecCopyf(mat[1], v2); + VecCopyf(mat[2], v3); } -static void multires_get_face(MultiresFace *f, CustomData *fdata, int findex, EditFace *efa, MFace *m) +static DerivedMesh *multires_subdisp_pre(DerivedMesh *mrdm, int distance, int simple) { - if(efa) { - MFace tmp; - int j; - tmp.v1= efa->v1->tmp.l; - tmp.v2= efa->v2->tmp.l; - tmp.v3= efa->v3->tmp.l; - tmp.v4= 0; - if(efa->v4) tmp.v4= efa->v4->tmp.l; - test_index_face(&tmp, fdata, findex, efa->v4?4:3); - for(j=0; j<4; ++j) f->v[j]= (&tmp.v1)[j]; - - /* Flags */ - f->flag= efa->flag; - if(efa->f & 1) f->flag |= ME_FACE_SEL; - else f->flag &= ~ME_FACE_SEL; - if(efa->h) f->flag |= ME_HIDE; - f->mat_nr= efa->mat_nr; - } else { - f->v[0]= m->v1; - f->v[1]= m->v2; - f->v[2]= m->v3; - f->v[3]= m->v4; - f->flag= m->flag; - f->mat_nr= m->mat_nr; - } + DerivedMesh *final; + SubsurfModifierData smd; + + memset(&smd, 0, sizeof(SubsurfModifierData)); + smd.levels = distance; + if(simple) + smd.subdivType = ME_SIMPLE_SUBSURF; + + final = subsurf_make_derived_from_derived_with_multires(mrdm, &smd, NULL, 0, NULL, 0, 0); + + return final; } -/* For manipulating vertex colors / uvs */ -static void mcol_to_multires(MultiresColFace *mrf, MCol *mcol) +static void VecAddUf(float a[3], float b[3]) { - char i; - for(i=0; i<4; ++i) { - mrf->col[i].a= mcol[i].a; - mrf->col[i].r= mcol[i].r; - mrf->col[i].g= mcol[i].g; - mrf->col[i].b= mcol[i].b; - } + a[0] += b[0]; + a[1] += b[1]; + a[2] += b[2]; } -/* 1 <= count <= 4 */ -static void multires_col_avg(MultiresCol *avg, MultiresCol cols[4], char count) +static void multires_subdisp(DerivedMesh *orig, Mesh *me, DerivedMesh *final, int lvl, int totlvl, + int totsubvert, int totsubedge, int totsubface, int addverts) { - unsigned i; - avg->a= avg->r= avg->g= avg->b= 0; - for(i=0; i<count; ++i) { - avg->a+= cols[i].a; - avg->r+= cols[i].r; - avg->g+= cols[i].g; - avg->b+= cols[i].b; + DerivedMesh *mrdm; + MultiresModifierData mmd_sub; + MVert *mvs = CDDM_get_verts(final); + MVert *mvd, *mvd_f1, *mvs_f1, *mvd_f3, *mvd_f4; + MVert *mvd_f2, *mvs_f2, *mvs_e1, *mvd_e1, *mvs_e2; + int totvert; + int slo1 = multires_side_tot[lvl - 1]; + int sll = slo1 / 2; + int slo2 = multires_side_tot[totlvl - 2]; + int shi2 = multires_side_tot[totlvl - 1]; + int skip = multires_side_tot[totlvl - lvl] - 1; + int i, j, k; + + memset(&mmd_sub, 0, sizeof(MultiresModifierData)); + mmd_sub.lvl = mmd_sub.totlvl = totlvl; + mrdm = multires_dm_create_from_derived(&mmd_sub, orig, me, 0, 0); + + mvd = CDDM_get_verts(mrdm); + /* Need to map from ccg to mrdm */ + totvert = mrdm->getNumVerts(mrdm); + + if(!addverts) { + for(i = 0; i < totvert; ++i) { + float z[3] = {0,0,0}; + VecCopyf(mvd[i].co, z); + } } - avg->a/= count; - avg->r/= count; - avg->g/= count; - avg->b/= count; -} -static void multires_col_avg2(MultiresCol *avg, MultiresCol *c1, MultiresCol *c2) -{ - MultiresCol in[2]; - in[0]= *c1; - in[1]= *c2; - multires_col_avg(avg,in,2); -} + /* Load base verts */ + for(i = 0; i < me->totvert; ++i) + VecAddUf(mvd[totvert - me->totvert + i].co, mvs[totvert - me->totvert + i].co); + + mvd_f1 = mvd; + mvs_f1 = mvs; + mvd_f2 = mvd; + mvs_f2 = mvs + totvert - totsubvert; + mvs_e1 = mvs + totsubface * (skip-1) * (skip-1); + + for(i = 0; i < me->totface; ++i) { + const int end = me->mface[i].v4 ? 4 : 3; + int x, y, x2, y2, mov= 0; + + mvd_f1 += 1 + end * (slo2-2); //center+edgecross + mvd_f3 = mvd_f4 = mvd_f1; + + for(j = 0; j < end; ++j) { + mvd_f1 += (skip/2 - 1) * (slo2 - 2) + (skip/2 - 1); + /* Update sub faces */ + for(y = 0; y < sll; ++y) { + for(x = 0; x < sll; ++x) { + /* Face center */ + VecAddUf(mvd_f1->co, mvs_f1->co); + mvs_f1 += 1; + + /* Now we hold the center of the subface at mvd_f1 + and offset it to the edge cross and face verts */ + + /* Edge cross */ + for(k = 0; k < 4; ++k) { + if(k == 0) mov = -1; + else if(k == 1) mov = slo2 - 2; + else if(k == 2) mov = 1; + else if(k == 3) mov = -(slo2 - 2); + + for(x2 = 1; x2 < skip/2; ++x2) { + VecAddUf((mvd_f1 + mov * x2)->co, mvs_f1->co); + ++mvs_f1; + } + } -void multires_load_cols(Mesh *me) -{ - MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1), *cur; - EditMesh *em= G.obedit ? G.editMesh : NULL; - CustomData *src= em ? &em->fdata : &me->fdata; - EditFace *efa= NULL; - unsigned i,j; + /* Main face verts */ + for(k = 0; k < 4; ++k) { + int movx= 0, movy= 0; + + if(k == 0) { movx = -1; movy = -(slo2 - 2); } + else if(k == 1) { movx = slo2 - 2; movy = -1; } + else if(k == 2) { movx = 1; movy = slo2 - 2; } + else if(k == 3) { movx = -(slo2 - 2); movy = 1; } + + for(y2 = 1; y2 < skip/2; ++y2) { + for(x2 = 1; x2 < skip/2; ++x2) { + VecAddUf((mvd_f1 + movy * y2 + movx * x2)->co, mvs_f1->co); + ++mvs_f1; + } + } + } + + mvd_f1 += skip; + } + mvd_f1 += (skip - 1) * (slo2 - 2) - 1; + } + mvd_f1 -= (skip - 1) * (slo2 - 2) - 1 + skip; + mvd_f1 += (slo2 - 2) * (skip/2-1) + skip/2-1 + 1; + } - if(!CustomData_has_layer(src, CD_MCOL) && !CustomData_has_layer(src, CD_MTFACE)) return; + /* update face center verts */ + VecAddUf(mvd_f2->co, mvs_f2->co); - /* Add texcol data */ - for(cur= me->mr->levels.first; cur; cur= cur->next) - if(!cur->colfaces) - cur->colfaces= MEM_callocN(sizeof(MultiresColFace)*cur->totface,"ColFaces"); + mvd_f2 += 1; + mvs_f2 += 1; - me->mr->use_col= CustomData_has_layer(src, CD_MCOL); + /* update face edge verts */ + for(j = 0; j < end; ++j) { + MVert *restore; - if(em) efa= em->faces.first; - for(i=0; i<lvl->totface; ++i) { - MultiresColFace *f= &lvl->colfaces[i]; + /* Super-face edge cross */ + for(k = 0; k < skip-1; ++k) { + VecAddUf(mvd_f2->co, mvs_e1->co); + mvd_f2++; + mvs_e1++; + } + for(x = 1; x < sll; ++x) { + VecAddUf(mvd_f2->co, mvs_f2->co); + mvd_f2++; + mvs_f2++; + + for(k = 0; k < skip-1; ++k) { + VecAddUf(mvd_f2->co, mvs_e1->co); + mvd_f2++; + mvs_e1++; + } + } - if(me->mr->use_col) - mcol_to_multires(f, em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]); - - if(em) efa= efa->next; + restore = mvs_e1; + for(y = 0; y < sll - 1; ++y) { + for(x = 0; x < sll; ++x) { + for(k = 0; k < skip - 1; ++k) { + VecAddUf(mvd_f3[(skip-1)+(y*skip) + (x*skip+k)*(slo2-2)].co, + mvs_e1->co); + ++mvs_e1; + } + mvs_e1 += skip-1; + } + } + + mvs_e1 = restore + skip - 1; + for(y = 0; y < sll - 1; ++y) { + for(x = 0; x < sll; ++x) { + for(k = 0; k < skip - 1; ++k) { + VecAddUf(mvd_f3[(slo2-2)*(skip-1)+(x*skip)+k + y*skip*(slo2-2)].co, + mvs_e1->co); + ++mvs_e1; + } + mvs_e1 += skip - 1; + } + } + + mvd_f3 += (slo2-2)*(slo2-2); + mvs_e1 -= skip - 1; + } + + /* update base (2) face verts */ + for(j = 0; j < end; ++j) { + mvd_f2 += (slo2 - 1) * (skip - 1); + for(y = 0; y < sll - 1; ++y) { + for(x = 0; x < sll - 1; ++x) { + VecAddUf(mvd_f2->co, mvs_f2->co); + mvd_f2 += skip; + ++mvs_f2; + } + mvd_f2 += (slo2 - 1) * (skip - 1); + } + mvd_f2 -= (skip - 1); + } } - /* Update higher levels */ - lvl= lvl->next; - while(lvl) { - MultiresColFace *cf= lvl->colfaces; - for(i=0; i<lvl->prev->totface; ++i) { - const char sides= lvl->prev->faces[i].v[3]?4:3; - MultiresCol cntr; - - /* Find average color of 4 (or 3 for triangle) verts */ - multires_col_avg(&cntr,lvl->prev->colfaces[i].col,sides); + /* edges */ + mvd_e1 = mvd + totvert - me->totvert - me->totedge * (shi2-2); + mvs_e2 = mvs + totvert - me->totvert - me->totedge * (slo1-2); + for(i = 0; i < me->totedge; ++i) { + for(j = 0; j < skip - 1; ++j) { + VecAddUf(mvd_e1->co, mvs_e1->co); + mvd_e1++; + mvs_e1++; + } + for(j = 0; j < slo1 - 2; j++) { + VecAddUf(mvd_e1->co, mvs_e2->co); + mvd_e1++; + mvs_e2++; - for(j=0; j<sides; ++j) { - MultiresColFace *pf= &lvl->prev->colfaces[i]; - - multires_col_avg2(&cf->col[0], - &pf->col[j], - &pf->col[j==0?sides-1:j-1]); - cf->col[1]= pf->col[j]; - multires_col_avg2(&cf->col[2], - &pf->col[j], - &pf->col[j==sides-1?0:j+1]); - cf->col[3]= cntr; - - ++cf; + for(k = 0; k < skip - 1; ++k) { + VecAddUf(mvd_e1->co, mvs_e1->co); + mvd_e1++; + mvs_e1++; } } - lvl= lvl->next; } - /* Update lower levels */ - lvl= me->mr->levels.last; - lvl= lvl->prev; - while(lvl) { - unsigned curf= 0; - for(i=0; i<lvl->totface; ++i) { - MultiresFace *f= &lvl->faces[i]; - for(j=0; j<(f->v[3]?4:3); ++j) { - lvl->colfaces[i].col[j]= lvl->next->colfaces[curf].col[1]; - ++curf; + final->needsFree = 1; + final->release(final); + mrdm->needsFree = 1; + MultiresDM_mark_as_modified(mrdm); + mrdm->release(mrdm); +} + +/* direction=1 for delete higher, direction=0 for lower (not implemented yet) */ +void multiresModifier_del_levels(struct MultiresModifierData *mmd, struct Object *ob, int direction) +{ + Mesh *me = get_mesh(ob); + int distance = mmd->totlvl - mmd->lvl; + MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS); + + multires_force_update(ob); + + if(mdisps && distance > 0 && direction == 1) { + int skip = multires_side_tot[distance] - 1; + int st = multires_side_tot[mmd->totlvl - 1]; + int totdisp = multires_quad_tot[mmd->lvl - 1]; + int i, j, x, y; + + for(i = 0; i < me->totface; ++i) { + float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires del disps"); + + for(j = 0, y = 0; y < st; y += skip) { + for(x = 0; x < st; x += skip) { + VecCopyf(disps[j], mdisps[i].disps[y * st + x]); + ++j; + } } + + MEM_freeN(mdisps[i].disps); + mdisps[i].disps = disps; + mdisps[i].totdisp = totdisp; } - lvl= lvl->prev; } + + mmd->totlvl = mmd->lvl; } -void multires_create(Object *ob, Mesh *me) +void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int distance, int updateblock, int simple) { - MultiresLevel *lvl; - EditMesh *em= G.obedit ? G.editMesh : NULL; - EditVert *eve= NULL; - EditFace *efa= NULL; - EditEdge *eed= NULL; + DerivedMesh *final = NULL; + int totsubvert = 0, totsubface = 0, totsubedge = 0; + Mesh *me = get_mesh(ob); + MDisps *mdisps; int i; - - lvl= MEM_callocN(sizeof(MultiresLevel), "multires level"); - if(me->pv) mesh_pmv_off(ob, me); + if(distance == 0) + return; - me->mr= MEM_callocN(sizeof(Multires), "multires data"); - - BLI_addtail(&me->mr->levels,lvl); - me->mr->current= 1; - me->mr->level_count= 1; - me->mr->edgelvl= 1; - me->mr->pinlvl= 1; - me->mr->renderlvl= 1; - - /* Load mesh (or editmesh) into multires data */ - - /* Load vertices and vdata (MDeformVerts) */ - lvl->totvert= em ? BLI_countlist(&em->verts) : me->totvert; - me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert,"multires verts"); - multires_update_customdata(me->mr->levels.first, em, em ? &em->vdata : &me->vdata, - &me->mr->vdata, CD_MDEFORMVERT); - if(em) eve= em->verts.first; - for(i=0; i<lvl->totvert; ++i) { - multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i); - if(em) eve= eve->next; + if(mmd->totlvl > multires_max_levels) + mmd->totlvl = multires_max_levels; + if(mmd->lvl > multires_max_levels) + mmd->lvl = multires_max_levels; + + multires_force_update(ob); + + mmd->lvl = mmd->totlvl; + mmd->totlvl += distance; + + mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS); + if(!mdisps) + mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface); + + if(mdisps->disps && !updateblock && mmd->totlvl > 2) { + DerivedMesh *orig, *mrdm; + MultiresModifierData mmd_sub; + + orig = CDDM_from_mesh(me, NULL); + memset(&mmd_sub, 0, sizeof(MultiresModifierData)); + mmd_sub.lvl = mmd_sub.totlvl = mmd->lvl; + mrdm = multires_dm_create_from_derived(&mmd_sub, orig, me, 0, 0); + totsubvert = mrdm->getNumVerts(mrdm); + totsubedge = mrdm->getNumEdges(mrdm); + totsubface = mrdm->getNumFaces(mrdm); + orig->needsFree = 1; + orig->release(orig); + + final = multires_subdisp_pre(mrdm, distance, simple); + mrdm->needsFree = 1; + mrdm->release(mrdm); } - /* Load faces and fdata (MTFaces) */ - lvl->totface= em ? BLI_countlist(&em->faces) : me->totface; - lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces"); - multires_update_customdata(me->mr->levels.first, em, em ? &em->fdata : &me->fdata, - &me->mr->fdata, CD_MTFACE); - if(em) efa= em->faces.first; - for(i=0; i<lvl->totface; ++i) { - multires_get_face(&lvl->faces[i], &me->mr->fdata, i, efa, &me->mface[i]); - if(em) efa= efa->next; + for(i = 0; i < me->totface; ++i) { + const int totdisp = multires_quad_tot[mmd->totlvl - 1]; + float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps"); + + if(mdisps[i].disps) + MEM_freeN(mdisps[i].disps); + + mdisps[i].disps = disps; + mdisps[i].totdisp = totdisp; } - /* Load edges and edge_flags */ - lvl->totedge= em ? BLI_countlist(&em->edges) : me->totedge; - lvl->edges= MEM_callocN(sizeof(MultiresEdge)*lvl->totedge,"multires edges"); - me->mr->edge_flags= MEM_callocN(sizeof(short)*lvl->totedge, "multires edge flags"); - me->mr->edge_creases= MEM_callocN(sizeof(short)*lvl->totedge, "multires edge creases"); - if(em) eed= em->edges.first; - for(i=0; i<lvl->totedge; ++i) { - multires_get_edge(&lvl->edges[i], eed, &me->medge[i], &me->mr->edge_flags[i], &me->mr->edge_creases[i]); - if(em) eed= eed->next; + + if(final) { + DerivedMesh *orig; + + orig = CDDM_from_mesh(me, NULL); + + multires_subdisp(orig, me, final, mmd->lvl, mmd->totlvl, totsubvert, totsubedge, totsubface, 0); + + orig->needsFree = 1; + orig->release(orig); } - multires_load_cols(me); + mmd->lvl = mmd->totlvl; } -typedef struct MultiresMapNode { - struct MultiresMapNode *next, *prev; - unsigned Index; -} MultiresMapNode; +typedef struct DisplacerEdges { + /* DerivedMesh index at the start of each edge (using face x/y directions to define the start) */ + int base[4]; + /* 1 if edge moves in the positive x or y direction, -1 otherwise */ + int dir[4]; +} DisplacerEdges; + +typedef struct DisplacerSpill { + /* Index of face (in base mesh), -1 for none */ + int face; + + /* Spill flag */ + /* 1 = Negative variable axis */ + /* 2 = Near fixed axis */ + /* 4 = Flip axes */ + int f; + + /* Neighboring edges */ + DisplacerEdges edges; +} DisplacerSpill; + +typedef struct MultiresDisplacer { + Mesh *me; + MDisps *grid; + MFace *face; + + int dm_first_base_vert_index; + + int spacing; + int sidetot, interior_st, disp_st; + int sidendx; + int type; + int invert; + MVert *subco; + int subco_index, face_index; + float weight; + + /* Valence for each corner */ + int valence[4]; + + /* Neighboring edges for current face */ + DisplacerEdges edges_primary; + + /* Neighboring faces */ + DisplacerSpill spill_x, spill_y; -/* Produces temporary connectivity data for the multires lvl */ -static void multires_calc_temp_data(MultiresLevel *lvl) + int *face_offsets; + + int x, y, ax, ay; +} MultiresDisplacer; + +static int mface_v(MFace *f, int v) { - unsigned i, j, emax; - MultiresMapNode *indexnode= NULL; + return v == 0 ? f->v1 : v == 1 ? f->v2 : v == 2 ? f->v3 : v == 3 ? f->v4 : -1; +} - lvl->map_mem= MEM_mallocN(sizeof(MultiresMapNode)*(lvl->totedge*2 + lvl->totface*4), "map_mem"); - indexnode= lvl->map_mem; - - /* edge map */ - lvl->vert_edge_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_edge_map"); - for(i=0; i<lvl->totedge; ++i) { - for(j=0; j<2; ++j, ++indexnode) { - indexnode->Index= i; - BLI_addtail(&lvl->vert_edge_map[lvl->edges[i].v[j]], indexnode); - } - } +/* Get the edges (and their directions) */ +static void find_displacer_edges(MultiresDisplacer *d, DerivedMesh *dm, DisplacerEdges *de, MFace *f) +{ + ListBase *emap = MultiresDM_get_vert_edge_map(dm); + IndexNode *n; + int i, end = f->v4 ? 4 : 3; + int offset = dm->getNumVerts(dm) - d->me->totvert - d->me->totedge * d->interior_st; - /* face map */ - lvl->vert_face_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_face_map"); - for(i=0; i<lvl->totface; ++i){ - for(j=0; j<(lvl->faces[i].v[3]?4:3); ++j, ++indexnode) { - indexnode->Index= i; - BLI_addtail(&lvl->vert_face_map[lvl->faces[i].v[j]], indexnode); - } - } + for(i = 0; i < end; ++i) { + int vcur = mface_v(f, i); + int vnext = mface_v(f, i == end - 1 ? 0 : i + 1); - /* edge boundaries */ - emax = (lvl->prev ? (lvl->prev->totedge * 2) : lvl->totedge); - lvl->edge_boundary_states= MEM_callocN(sizeof(char)*lvl->totedge, "edge_boundary_states"); - for(i=0; i<emax; ++i) { - MultiresMapNode *n1= lvl->vert_face_map[lvl->edges[i].v[0]].first; - unsigned total= 0; + de->dir[i] = 1; - lvl->edge_boundary_states[i] = 1; - while(n1 && lvl->edge_boundary_states[i] == 1) { - MultiresMapNode *n2= lvl->vert_face_map[lvl->edges[i].v[1]].first; - while(n2) { - if(n1->Index == n2->Index) { - ++total; - - if(total > 1) { - lvl->edge_boundary_states[i] = 0; - break; - } + for(n = emap[vcur].first; n; n = n->next) { + MEdge *e = &d->me->medge[n->index]; + + if(e->v1 == vnext || e->v2 == vnext) { + de->base[i] = n->index * d->interior_st; + if(((i == 0 || i == 1) && e->v1 == vnext) || + ((i == 2 || i == 3) && e->v2 == vnext)) { + de->dir[i] = -1; + de->base[i] += d->interior_st - 1; } - - n2= n2->next; + de->base[i] += offset; + break; } - n1= n1->next; } } } -/* CATMULL-CLARK - ============= */ - -typedef struct MultiApplyData { - /* Smooth faces */ - float *corner1, *corner2, *corner3, *corner4; - char quad; - - /* Smooth edges */ - char boundary; - float edge_face_neighbor_midpoints_accum[3]; - unsigned edge_face_neighbor_midpoints_total; - float *endpoint1, *endpoint2; - - /* Smooth verts */ - /* uses 'char boundary' */ - float *original; - int edge_count; - float vert_face_neighbor_midpoints_average[3]; - float vert_edge_neighbor_midpoints_average[3]; - float boundary_edges_average[3]; -} MultiApplyData; - -/* Simply averages the four corners of a polygon. */ -static float catmullclark_smooth_face(MultiApplyData *data, const unsigned i) +/* Returns in out the corners [0-3] that use v1 and v2 */ +void find_face_corners(MFace *f, int v1, int v2, int out[2]) { - const float total= data->corner1[i]+data->corner2[i]+data->corner3[i]; - return data->quad ? (total+data->corner4[i])/4 : total/3; + int i, end = f->v4 ? 4 : 3; + + for(i = 0; i < end; ++i) { + int corner = mface_v(f, i); + if(corner == v1) + out[0] = i; + if(corner == v2) + out[1] = i; + } } -static float catmullclark_smooth_edge(MultiApplyData *data, const unsigned i) +static void multires_displacer_get_spill_faces(MultiresDisplacer *d, DerivedMesh *dm, MFace *mface) { - float accum= 0; - unsigned count= 2; - - accum+= data->endpoint1[i] + data->endpoint2[i]; + ListBase *map = MultiresDM_get_vert_face_map(dm); + IndexNode *n1, *n2; + int v4 = d->face->v4 ? d->face->v4 : d->face->v1; + int crn[2], lv; + + memset(&d->spill_x, 0, sizeof(DisplacerSpill)); + memset(&d->spill_y, 0, sizeof(DisplacerSpill)); + d->spill_x.face = d->spill_y.face = -1; + + for(n1 = map[d->face->v3].first; n1; n1 = n1->next) { + if(n1->index == d->face_index) + continue; + + for(n2 = map[d->face->v2].first; n2; n2 = n2->next) { + if(n1->index == n2->index) + d->spill_x.face = n1->index; + } + for(n2 = map[v4].first; n2; n2 = n2->next) { + if(n1->index == n2->index) + d->spill_y.face = n1->index; + } + } - if(!data->boundary) { - accum+= data->edge_face_neighbor_midpoints_accum[i]; - count+= data->edge_face_neighbor_midpoints_total; + if(d->spill_x.face != -1) { + /* Neighbor of v2/v3 found, find flip and orientation */ + find_face_corners(&mface[d->spill_x.face], d->face->v2, d->face->v3, crn); + lv = mface[d->spill_x.face].v4 ? 3 : 2; + + if(crn[0] == 0 && crn[1] == lv) + d->spill_x.f = 0+2+0; + else if(crn[0] == lv && crn[1] == 0) + d->spill_x.f = 1+2+0; + else if(crn[0] == 1 && crn[1] == 0) + d->spill_x.f = 1+2+4; + else if(crn[0] == 0 && crn[1] == 1) + d->spill_x.f = 0+2+4; + else if(crn[0] == 2 && crn[1] == 1) + d->spill_x.f = 1+0+0; + else if(crn[0] == 1 && crn[1] == 2) + d->spill_x.f = 0+0+0; + else if(crn[0] == 3 && crn[1] == 2) + d->spill_x.f = 0+0+4; + else if(crn[0] == 2 && crn[1] == 3) + d->spill_x.f = 1+0+4; + + find_displacer_edges(d, dm, &d->spill_x.edges, &mface[d->spill_x.face]); } - return accum / count; + if(d->spill_y.face != -1) { + /* Neighbor of v3/v4 found, find flip and orientation */ + find_face_corners(&mface[d->spill_y.face], d->face->v3, v4, crn); + lv = mface[d->spill_y.face].v4 ? 3 : 2; + + if(crn[0] == 1 && crn[1] == 0) + d->spill_y.f = 1+2+0; + else if(crn[0] == 0 && crn[1] == 1) + d->spill_y.f = 0+2+0; + else if(crn[0] == 2 && crn[1] == 1) + d->spill_y.f = 1+0+4; + else if(crn[0] == 1 && crn[1] == 2) + d->spill_y.f = 0+0+4; + else if(crn[0] == 3 && crn[1] == 2) + d->spill_y.f = 0+0+0; + else if(crn[0] == 2 && crn[1] == 3) + d->spill_y.f = 1+0+0; + else if(crn[0] == 0 && crn[1] == lv) + d->spill_y.f = 0+2+4; + else if(crn[0] == lv && crn[1] == 0) + d->spill_y.f = 1+2+4; + + find_displacer_edges(d, dm, &d->spill_y.edges, &mface[d->spill_y.face]); + } } -static float catmullclark_smooth_vert(MultiApplyData *data, const unsigned i) +static void find_corner_valences(MultiresDisplacer *d, DerivedMesh *dm) { - if(data->boundary) { - return data->original[i]*0.75 + data->boundary_edges_average[i]*0.25; - } else { - return (data->vert_face_neighbor_midpoints_average[i] + - 2*data->vert_edge_neighbor_midpoints_average[i] + - data->original[i]*(data->edge_count-3))/data->edge_count; - } -} + int i; + d->valence[3] = -1; + /* Set the vertex valence for the corners */ + for(i = 0; i < (d->face->v4 ? 4 : 3); ++i) + d->valence[i] = BLI_countlist(&MultiresDM_get_vert_edge_map(dm)[mface_v(d->face, i)]); +} -/* Call func count times, passing in[i] as the input and storing the output in out[i] */ -static void multi_apply(float *out, MultiApplyData *data, - const unsigned count, float (*func)(MultiApplyData *, const unsigned)) +static void multires_displacer_init(MultiresDisplacer *d, DerivedMesh *dm, + const int face_index, const int invert) { - unsigned i; - for(i=0; i<count; ++i) - out[i]= func(data,i); + Mesh *me = MultiresDM_get_mesh(dm); + + d->me = me; + d->face = me->mface + face_index; + d->face_index = face_index; + d->face_offsets = MultiresDM_get_face_offsets(dm); + /* Get the multires grid from customdata */ + d->grid = CustomData_get_layer(&me->fdata, CD_MDISPS); + if(d->grid) + d->grid += face_index; + + d->spacing = pow(2, MultiresDM_get_totlvl(dm) - MultiresDM_get_lvl(dm)); + d->sidetot = multires_side_tot[MultiresDM_get_lvl(dm) - 1]; + d->interior_st = d->sidetot - 2; + d->disp_st = multires_side_tot[MultiresDM_get_totlvl(dm) - 1]; + d->invert = invert; + + multires_displacer_get_spill_faces(d, dm, me->mface); + find_displacer_edges(d, dm, &d->edges_primary, d->face); + find_corner_valences(d, dm); + + d->dm_first_base_vert_index = dm->getNumVerts(dm) - me->totvert; } -static short multires_vert_is_boundary(MultiresLevel *lvl, unsigned v) +static void multires_displacer_weight(MultiresDisplacer *d, const float w) { - MultiresMapNode *node= lvl->vert_edge_map[v].first; - while(node) { - if(lvl->edge_boundary_states[node->Index]) - return 1; - node= node->next; - } - return 0; + d->weight = w; } -#define GET_FLOAT(array, i, j, stride) (((float*)((char*)(array)+((i)*(stride))))[(j)]) +static void multires_displacer_anchor(MultiresDisplacer *d, const int type, const int side_index) +{ + d->sidendx = side_index; + d->x = d->y = d->sidetot / 2; + d->type = type; + + if(type == 2) { + if(side_index == 0) + d->y -= 1; + else if(side_index == 1) + d->x += 1; + else if(side_index == 2) + d->y += 1; + else if(side_index == 3) + d->x -= 1; + } + else if(type == 3) { + if(side_index == 0) { + d->x -= 1; + d->y -= 1; + } + else if(side_index == 1) { + d->x += 1; + d->y -= 1; + } + else if(side_index == 2) { + d->x += 1; + d->y += 1; + } + else if(side_index == 3) { + d->x -= 1; + d->y += 1; + } + } + + d->ax = d->x; + d->ay = d->y; +} -static void edge_face_neighbor_midpoints_accum(MultiApplyData *data, MultiresLevel *lvl, - void *array, const char stride, const MultiresEdge *e) +static void multires_displacer_anchor_edge(MultiresDisplacer *d, int v1, int v2, int x) { - ListBase *neighbors1= &lvl->vert_face_map[e->v[0]]; - ListBase *neighbors2= &lvl->vert_face_map[e->v[1]]; - MultiresMapNode *n1, *n2; - unsigned j,count= 0; - float *out= data->edge_face_neighbor_midpoints_accum; - - out[0]=out[1]=out[2]= 0; - - for(n1= neighbors1->first; n1; n1= n1->next) { - for(n2= neighbors2->first; n2; n2= n2->next) { - if(n1->Index == n2->Index) { - for(j=0; j<3; ++j) - out[j]+= GET_FLOAT(array,lvl->faces[n1->Index].mid,j,stride); - ++count; + d->type = 4; + + if(v1 == d->face->v1) { + d->x = 0; + d->y = 0; + if(v2 == d->face->v2) + d->x += x; + else if(v2 == d->face->v3) { + if(x < d->sidetot / 2) + d->y = x; + else { + d->x = x; + d->y = d->sidetot - 1; } } + else + d->y += x; + } + else if(v1 == d->face->v2) { + d->x = d->sidetot - 1; + d->y = 0; + if(v2 == d->face->v1) + d->x -= x; + else + d->y += x; + } + else if(v1 == d->face->v3) { + d->x = d->sidetot - 1; + d->y = d->sidetot - 1; + if(v2 == d->face->v2) + d->y -= x; + else if(v2 == d->face->v1) { + if(x < d->sidetot / 2) + d->x -= x; + else { + d->x = 0; + d->y -= x; + } + } + else + d->x -= x; + } + else if(v1 == d->face->v4) { + d->x = 0; + d->y = d->sidetot - 1; + if(v2 == d->face->v3) + d->x += x; + else + d->y -= x; } - - data->edge_face_neighbor_midpoints_total= count; } -static void vert_face_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl, - void *array, const char stride, const unsigned i) +static void multires_displacer_anchor_vert(MultiresDisplacer *d, const int v) { - ListBase *neighbors= &lvl->vert_face_map[i]; - MultiresMapNode *n1; - unsigned j,count= 0; - float *out= data->vert_face_neighbor_midpoints_average; + const int e = d->sidetot - 1; - out[0]=out[1]=out[2]= 0; + d->type = 5; - for(n1= neighbors->first; n1; n1= n1->next) { - for(j=0; j<3; ++j) - out[j]+= GET_FLOAT(array,lvl->faces[n1->Index].mid,j,stride); - ++count; - } - for(j=0; j<3; ++j) out[j]/= count; + d->x = d->y = 0; + if(v == d->face->v2) + d->x = e; + else if(v == d->face->v3) + d->x = d->y = e; + else if(v == d->face->v4) + d->y = e; } -static void vert_edge_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl, - void *array, const char stride, const unsigned i) +static void multires_displacer_jump(MultiresDisplacer *d) { - ListBase *neighbors= &lvl->vert_edge_map[i]; - MultiresMapNode *n1; - unsigned j,count= 0; - float *out= data->vert_edge_neighbor_midpoints_average; - - out[0]=out[1]=out[2]= 0; - - for(n1= neighbors->first; n1; n1= n1->next) { - for(j=0; j<3; ++j) - out[j]+= (GET_FLOAT(array,lvl->edges[n1->Index].v[0],j,stride) + - GET_FLOAT(array,lvl->edges[n1->Index].v[1],j,stride)) / 2; - ++count; + if(d->sidendx == 0) { + d->x -= 1; + d->y = d->ay; + } + else if(d->sidendx == 1) { + d->x = d->ax; + d->y -= 1; + } + else if(d->sidendx == 2) { + d->x += 1; + d->y = d->ay; + } + else if(d->sidendx == 3) { + d->x = d->ax; + d->y += 1; } - for(j=0; j<3; ++j) out[j]/= count; } -static void boundary_edges_average(MultiApplyData *data, MultiresLevel *lvl, - void *array, const char stride, const unsigned i) +/* Treating v1 as (0,0) and v3 as (st-1,st-1), + returns the index of the vertex at (x,y). + If x or y is >= st, wraps over to the adjacent face, + or if there is no adjacent face, returns -2. */ +static int multires_index_at_loc(int face_index, int x, int y, MultiresDisplacer *d, DisplacerEdges *de) { - ListBase *neighbors= &lvl->vert_edge_map[i]; - MultiresMapNode *n1; - unsigned j,count= 0; - float *out= data->boundary_edges_average; + int coord_edge = d->sidetot - 1; /* Max value of x/y at edge of grid */ + int mid = d->sidetot / 2; + int lim = mid - 1; + int qtot = lim * lim; + int base = d->face_offsets[face_index]; + + /* Edge spillover */ + if(x == d->sidetot || y == d->sidetot) { + int flags, v_axis, f_axis, lx, ly; + + if(x == d->sidetot && d->spill_x.face != -1) { + flags = d->spill_x.f; + + /* Handle triangle seam between v1 and v3 */ + if(!d->me->mface[d->spill_x.face].v4 && + ((flags == 2 && y >= mid) || (flags == 3 && y < mid))) + flags += 2; + + v_axis = (flags & 1) ? d->sidetot - 1 - y : y; + f_axis = (flags & 2) ? 1 : d->sidetot - 2; + lx = f_axis, ly = v_axis; + + if(flags & 4) { + lx = v_axis; + ly = f_axis; + } - out[0]=out[1]=out[2]= 0; - - for(n1= neighbors->first; n1; n1= n1->next) { - const MultiresEdge *e= &lvl->edges[n1->Index]; - const unsigned end= e->v[0]==i ? e->v[1] : e->v[0]; - - if(lvl->edge_boundary_states[n1->Index]) { - for(j=0; j<3; ++j) - out[j]+= GET_FLOAT(array,end,j,stride); - ++count; + return multires_index_at_loc(d->spill_x.face, lx, ly, d, &d->spill_x.edges); } + else if(y == d->sidetot && d->spill_y.face != -1) { + flags = d->spill_y.f; + + /* Handle triangle seam between v1 and v3 */ + if(!d->me->mface[d->spill_y.face].v4 && + ((flags == 6 && x >= mid) || (flags == 7 && x < mid))) + flags = ~flags; + + v_axis = (flags & 1) ? x : d->sidetot - 1 - x; + f_axis = (flags & 2) ? 1 : d->sidetot - 2; + lx = v_axis, ly = f_axis; + + if(flags & 4) { + lx = f_axis; + ly = v_axis; + } + + return multires_index_at_loc(d->spill_y.face, lx, ly, d, &d->spill_y.edges); + } + else + return -2; } - for(j=0; j<3; ++j) out[j]/= count; + /* Corners */ + else if(x == 0 && y == 0) + return d->dm_first_base_vert_index + d->face->v1; + else if(x == coord_edge && y == 0) + return d->dm_first_base_vert_index + d->face->v2; + else if(x == coord_edge && y == coord_edge) + return d->dm_first_base_vert_index + d->face->v3; + else if(x == 0 && y == coord_edge) + return d->dm_first_base_vert_index + d->face->v4; + /* Edges */ + else if(x == 0) { + if(d->face->v4) + return de->base[3] + de->dir[3] * (y - 1); + else + return de->base[2] + de->dir[2] * (y - 1); + } + else if(y == 0) + return de->base[0] + de->dir[0] * (x - 1); + else if(x == d->sidetot - 1) + return de->base[1] + de->dir[1] * (y - 1); + else if(y == d->sidetot - 1) + return de->base[2] + de->dir[2] * (x - 1); + /* Face center */ + else if(x == mid && y == mid) + return base; + /* Cross */ + else if(x == mid && y < mid) + return base + (mid - y); + else if(y == mid && x > mid) + return base + lim + (x - mid); + else if(x == mid && y > mid) + return base + lim*2 + (y - mid); + else if(y == mid && x < mid) { + if(d->face->v4) + return base + lim*3 + (mid - x); + else + return base + lim*2 + (mid - x); + } + /* Quarters */ + else { + int offset = base + lim * (d->face->v4 ? 4 : 3); + if(x < mid && y < mid) + return offset + ((mid - x - 1)*lim + (mid - y)); + else if(x > mid && y < mid) + return offset + qtot + ((mid - y - 1)*lim + (x - mid)); + else if(x > mid && y > mid) + return offset + qtot*2 + ((x - mid - 1)*lim + (y - mid)); + else if(x < mid && y > mid) + return offset + qtot*3 + ((y - mid - 1)*lim + (mid - x)); + } + + return -1; } -/* END CATMULL-CLARK - ================= */ - -/* Update vertex locations and vertex flags */ -static void multires_update_vertices(Mesh *me, EditMesh *em) +/* Calculate the TS matrix used for applying displacements. + Uses the undisplaced subdivided mesh's curvature to find a + smoothly normal and tangents. */ +static void calc_disp_mat(MultiresDisplacer *d, float mat[3][3]) { - MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL, - *last_lvl= me->mr->levels.last; - vec3f *pr_deltas= NULL, *cr_deltas= NULL, *swap_deltas= NULL; - EditVert *eve= NULL; - MultiApplyData data; - int i, j; - - /* XXX added this to prevent crash, but if it works? (ton) */ - if(me->mr->verts==NULL) - return; + int u = multires_index_at_loc(d->face_index, d->x + 1, d->y, d, &d->edges_primary); + int v = multires_index_at_loc(d->face_index, d->x, d->y + 1, d, &d->edges_primary); + float norm[3], t1[3], t2[3], inv[3][3]; + MVert *base = d->subco + d->subco_index; + + //printf("f=%d, x=%d, y=%d, i=%d, u=%d, v=%d ", d->face_index, d->x, d->y, d->subco_index, u, v); - /* Prepare deltas */ - pr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 1"); - cr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 2"); - - /* Calculate initial deltas -- current mesh subtracted from current level*/ - if(em) eve= em->verts.first; - for(i=0; i<cr_lvl->totvert; ++i) { - if(em) { - VecSubf(&cr_deltas[i].x, eve->co, me->mr->verts[i].co); - eve= eve->next; - } else - VecSubf(&cr_deltas[i].x, me->mvert[i].co, me->mr->verts[i].co); + norm[0] = base->no[0] / 32767.0f; + norm[1] = base->no[1] / 32767.0f; + norm[2] = base->no[2] / 32767.0f; + + /* Special handling for vertices of valence 3 */ + if(d->valence[1] == 3 && d->x == d->sidetot - 1 && d->y == 0) + u = -1; + else if(d->valence[2] == 3 && d->x == d->sidetot - 1 && d->y == d->sidetot - 1) + u = v = -1; + else if(d->valence[3] == 3 && d->x == 0 && d->y == d->sidetot - 1) + v = -1; + + /* If either u or v is -2, it's on a boundary. In this + case, back up by one row/column and use the same + vector as the preceeding sub-edge. */ + + if(u < 0) { + u = multires_index_at_loc(d->face_index, d->x - 1, d->y, d, &d->edges_primary); + VecSubf(t1, base->co, d->subco[u].co); } + else + VecSubf(t1, d->subco[u].co, base->co); - - /* Copy current level's vertex flags and clear the rest */ - if(em) eve= em->verts.first; - for(i=0; i < last_lvl->totvert; ++i) { - if(i < cr_lvl->totvert) { - MVert mvflag; - multires_get_vert(&mvflag, eve, &me->mvert[i], i); - if(em) eve= eve->next; - me->mr->verts[i].flag= mvflag.flag; - } - else - me->mr->verts[i].flag= 0; + if(v < 0) { + v = multires_index_at_loc(d->face_index, d->x, d->y - 1, d, &d->edges_primary); + VecSubf(t2, base->co, d->subco[v].co); } + else + VecSubf(t2, d->subco[v].co, base->co); - /* If already on the highest level, copy current verts (including flags) into current level */ - if(cr_lvl == last_lvl) { - if(em) - eve= em->verts.first; - for(i=0; i<cr_lvl->totvert; ++i) { - multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i); - if(em) eve= eve->next; - } + //printf("uu=%d, vv=%d\n", u, v); + + Normalize(t1); + Normalize(t2); + Mat3FromColVecs(mat, t1, t2, norm); + + if(d->invert) { + Mat3Inv(inv, mat); + Mat3CpyMat3(mat, inv); } +} - /* Update higher levels */ - pr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); - cr_lvl= pr_lvl->next; - while(cr_lvl) { - multires_calc_temp_data(pr_lvl); - - /* Swap the old/new deltas */ - swap_deltas= pr_deltas; - pr_deltas= cr_deltas; - cr_deltas= swap_deltas; - - /* Calculate and add new deltas - ============================ */ - for(i=0; i<pr_lvl->totface; ++i) { - const MultiresFace *f= &pr_lvl->faces[i]; - data.corner1= &pr_deltas[f->v[0]].x; - data.corner2= &pr_deltas[f->v[1]].x; - data.corner3= &pr_deltas[f->v[2]].x; - data.corner4= &pr_deltas[f->v[3]].x; - data.quad= f->v[3] ? 1 : 0; - multi_apply(&cr_deltas[f->mid].x, &data, 3, catmullclark_smooth_face); - - for(j=0; j<(data.quad?4:3); ++j) - me->mr->verts[f->mid].flag |= me->mr->verts[f->v[j]].flag; - } +static void multires_displace(MultiresDisplacer *d, float co[3]) +{ + float disp[3], mat[3][3]; + float *data; + MVert *subco = &d->subco[d->subco_index]; - for(i=0; i<pr_lvl->totedge; ++i) { - const MultiresEdge *e= &pr_lvl->edges[i]; - data.boundary= pr_lvl->edge_boundary_states[i]; - edge_face_neighbor_midpoints_accum(&data,pr_lvl,cr_deltas,sizeof(vec3f),e); - data.endpoint1= &pr_deltas[e->v[0]].x; - data.endpoint2= &pr_deltas[e->v[1]].x; - multi_apply(&cr_deltas[e->mid].x, &data, 3, catmullclark_smooth_edge); - - for(j=0; j<2; ++j) - me->mr->verts[e->mid].flag |= me->mr->verts[e->v[j]].flag; - } + if(!d->grid || !d->grid->disps) return; - for(i=0; i<pr_lvl->totvert; ++i) { - data.boundary= multires_vert_is_boundary(pr_lvl,i); - data.original= &pr_deltas[i].x; - data.edge_count= BLI_countlist(&pr_lvl->vert_edge_map[i]); - if(data.boundary) - boundary_edges_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i); - else { - vert_face_neighbor_midpoints_average(&data,pr_lvl,cr_deltas,sizeof(vec3f),i); - vert_edge_neighbor_midpoints_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i); - } - multi_apply(&cr_deltas[i].x, &data, 3, catmullclark_smooth_vert); - } + data = d->grid->disps[(d->y * d->spacing) * d->disp_st + (d->x * d->spacing)]; + + if(d->invert) + VecSubf(disp, co, subco->co); + else + VecCopyf(disp, data); - /* Apply deltas to vertex locations */ - for(i=0; (cr_lvl == last_lvl) && (i < cr_lvl->totvert); ++i) { - VecAddf(me->mr->verts[i].co, - me->mr->verts[i].co, - &cr_deltas[i].x); - } - multires_free_temp_data(pr_lvl); + /* Apply ts matrix to displacement */ + calc_disp_mat(d, mat); + Mat3MulVecfl(mat, disp); - pr_lvl= pr_lvl->next; - cr_lvl= cr_lvl->next; + if(d->invert) { + VecCopyf(data, disp); + + } + else { + if(d->type == 4 || d->type == 5) + VecMulf(disp, d->weight); + VecAddf(co, co, disp); } - if(pr_deltas) MEM_freeN(pr_deltas); - if(cr_deltas) MEM_freeN(cr_deltas); + if(d->type == 2) { + if(d->sidendx == 0) + d->y -= 1; + else if(d->sidendx == 1) + d->x += 1; + else if(d->sidendx == 2) + d->y += 1; + else if(d->sidendx == 3) + d->x -= 1; + } + else if(d->type == 3) { + if(d->sidendx == 0) + d->y -= 1; + else if(d->sidendx == 1) + d->x += 1; + else if(d->sidendx == 2) + d->y += 1; + else if(d->sidendx == 3) + d->x -= 1; + } } -static void multires_update_faces(Mesh *me, EditMesh *em) +static void multiresModifier_disp_run(DerivedMesh *dm, MVert *subco, int invert) { - MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL, - *last_lvl= me->mr->levels.last; - char *pr_flag_damaged= NULL, *cr_flag_damaged= NULL, *or_flag_damaged= NULL, - *pr_mat_damaged= NULL, *cr_mat_damaged= NULL, *or_mat_damaged= NULL, *swap= NULL; - EditFace *efa= NULL; - unsigned i,j,curf; - - /* Find for each face whether flag/mat has changed */ - pr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1"); - cr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1"); - pr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1"); - cr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1"); - if(em) efa= em->faces.first; - for(i=0; i<cr_lvl->totface; ++i) { - MultiresFace mftmp; - multires_get_face(&mftmp, &me->mr->fdata, i, efa, &me->mface[i]); - if(cr_lvl->faces[i].flag != mftmp.flag) - cr_flag_damaged[i]= 1; - if(cr_lvl->faces[i].mat_nr != mftmp.mat_nr) - cr_mat_damaged[i]= 1; - - /* Update current level */ - cr_lvl->faces[i].flag= mftmp.flag; - cr_lvl->faces[i].mat_nr= mftmp.mat_nr; - - if(em) efa= efa->next; - } - or_flag_damaged= MEM_dupallocN(cr_flag_damaged); - or_mat_damaged= MEM_dupallocN(cr_mat_damaged); - - /* Update lower levels */ - cr_lvl= cr_lvl->prev; - while(cr_lvl) { - swap= pr_flag_damaged; - pr_flag_damaged= cr_flag_damaged; - cr_flag_damaged= swap; - - swap= pr_mat_damaged; - pr_mat_damaged= cr_mat_damaged; - cr_mat_damaged= swap; - - curf= 0; - for(i=0; i<cr_lvl->totface; ++i) { - const int sides= cr_lvl->faces[i].v[3] ? 4 : 3; - - /* Check damages */ - for(j=0; j<sides; ++j, ++curf) { - if(pr_flag_damaged[curf]) { - cr_lvl->faces[i].flag= cr_lvl->next->faces[curf].flag; - cr_flag_damaged[i]= 1; - } - if(pr_mat_damaged[curf]) { - cr_lvl->faces[i].mat_nr= cr_lvl->next->faces[curf].mat_nr; - cr_mat_damaged[i]= 1; - } + const int lvl = MultiresDM_get_lvl(dm); + const int gridFaces = multires_side_tot[lvl - 2] - 1; + const int edgeSize = multires_side_tot[lvl - 1] - 1; + MVert *mvert = CDDM_get_verts(dm); + MEdge *medge = MultiresDM_get_mesh(dm)->medge; + MFace *mface = MultiresDM_get_mesh(dm)->mface; + ListBase *map = MultiresDM_get_vert_face_map(dm); + Mesh *me = MultiresDM_get_mesh(dm); + MultiresDisplacer d; + int i, S, x, y; + + d.subco = subco; + d.subco_index = 0; + + for(i = 0; i < me->totface; ++i) { + const int numVerts = mface[i].v4 ? 4 : 3; + + /* Center */ + multires_displacer_init(&d, dm, i, invert); + multires_displacer_anchor(&d, 1, 0); + multires_displace(&d, mvert->co); + ++mvert; + ++d.subco_index; + + /* Cross */ + for(S = 0; S < numVerts; ++S) { + multires_displacer_anchor(&d, 2, S); + for(x = 1; x < gridFaces; ++x) { + multires_displace(&d, mvert->co); + ++mvert; + ++d.subco_index; } } - cr_lvl= cr_lvl->prev; - } - - /* Clear to original damages */ - if(cr_flag_damaged) MEM_freeN(cr_flag_damaged); - if(cr_mat_damaged) MEM_freeN(cr_mat_damaged); - cr_flag_damaged= or_flag_damaged; - cr_mat_damaged= or_mat_damaged; - - /* Update higher levels */ - pr_lvl= current_level(me->mr); - cr_lvl= pr_lvl->next; - while(cr_lvl) { - swap= pr_flag_damaged; - pr_flag_damaged= cr_flag_damaged; - cr_flag_damaged= swap; - - swap= pr_mat_damaged; - pr_mat_damaged= cr_mat_damaged; - cr_mat_damaged= swap; - - /* Update faces */ - for(i=0, curf= 0; i<pr_lvl->totface; ++i) { - const int sides= cr_lvl->prev->faces[i].v[3] ? 4 : 3; - for(j=0; j<sides; ++j, ++curf) { - if(pr_flag_damaged[i]) { - cr_lvl->faces[curf].flag= pr_lvl->faces[i].flag; - cr_flag_damaged[curf]= 1; - } - if(pr_mat_damaged[i]) { - cr_lvl->faces[curf].mat_nr= pr_lvl->faces[i].mat_nr; - cr_mat_damaged[curf]= 1; + /* Quarters */ + for(S = 0; S < numVerts; S++) { + multires_displacer_anchor(&d, 3, S); + for(y = 1; y < gridFaces; y++) { + for(x = 1; x < gridFaces; x++) { + multires_displace(&d, mvert->co); + ++mvert; + ++d.subco_index; } + multires_displacer_jump(&d); } } - - pr_lvl= pr_lvl->next; - cr_lvl= cr_lvl->next; } - if(pr_flag_damaged) MEM_freeN(pr_flag_damaged); - if(cr_flag_damaged) MEM_freeN(cr_flag_damaged); - if(pr_mat_damaged) MEM_freeN(pr_mat_damaged); - if(cr_mat_damaged) MEM_freeN(cr_mat_damaged); -} - -static void multires_update_colors(Mesh *me, EditMesh *em) -{ - MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); - MultiresCol *pr_deltas= NULL, *cr_deltas= NULL; - CustomData *src= em ? &em->fdata : &me->fdata; - EditFace *efa= NULL; - unsigned i,j,curf= 0; - - if(me->mr->use_col) { - /* Calc initial deltas */ - cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"initial color/uv deltas"); - - if(em) efa= em->faces.first; - for(i=0; i<lvl->totface; ++i) { - MCol *col= em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]; - for(j=0; j<4; ++j) { - if(me->mr->use_col) { - cr_deltas[i*4+j].a= col[j].a - lvl->colfaces[i].col[j].a; - cr_deltas[i*4+j].r= col[j].r - lvl->colfaces[i].col[j].r; - cr_deltas[i*4+j].g= col[j].g - lvl->colfaces[i].col[j].g; - cr_deltas[i*4+j].b= col[j].b - lvl->colfaces[i].col[j].b; + for(i = 0; i < me->totedge; ++i) { + const MEdge *e = &medge[i]; + for(x = 1; x < edgeSize; ++x) { + IndexNode *n1, *n2; + int numFaces = 0; + for(n1 = map[e->v1].first; n1; n1 = n1->next) { + for(n2 = map[e->v2].first; n2; n2 = n2->next) { + if(n1->index == n2->index) + ++numFaces; } } - if(em) efa= efa->next; - } - - /* Update current level */ - if(em) efa= em->faces.first; - for(i=0; i<lvl->totface; ++i) { - MultiresColFace *f= &lvl->colfaces[i]; - - if(me->mr->use_col) - mcol_to_multires(f, em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]); - - if(em) efa= efa->next; - } - - /* Update higher levels */ - lvl= lvl->next; - while(lvl) { - /* Set up new deltas, but keep the ones from the previous level */ - if(pr_deltas) MEM_freeN(pr_deltas); - pr_deltas= cr_deltas; - cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"color deltas"); - - curf= 0; - for(i=0; i<lvl->prev->totface; ++i) { - const char sides= lvl->prev->faces[i].v[3]?4:3; - MultiresCol cntr; - - /* Find average color of 4 (or 3 for triangle) verts */ - multires_col_avg(&cntr,&pr_deltas[i*4],sides); - - for(j=0; j<sides; ++j) { - multires_col_avg2(&cr_deltas[curf*4], - &pr_deltas[i*4+j], - &pr_deltas[i*4+(j==0?sides-1:j-1)]); - cr_deltas[curf*4+1]= pr_deltas[i*4+j]; - multires_col_avg2(&cr_deltas[curf*4+2], - &pr_deltas[i*4+j], - &pr_deltas[i*4+(j==sides-1?0:j+1)]); - cr_deltas[curf*4+3]= cntr; - ++curf; - } - } - - for(i=0; i<lvl->totface; ++i) { - for(j=0; j<4; ++j) { - lvl->colfaces[i].col[j].a+= cr_deltas[i*4+j].a; - lvl->colfaces[i].col[j].r+= cr_deltas[i*4+j].r; - lvl->colfaces[i].col[j].g+= cr_deltas[i*4+j].g; - lvl->colfaces[i].col[j].b+= cr_deltas[i*4+j].b; + multires_displacer_weight(&d, 1.0f / numFaces); + /* TODO: Better to have these loops outside the x loop */ + for(n1 = map[e->v1].first; n1; n1 = n1->next) { + for(n2 = map[e->v2].first; n2; n2 = n2->next) { + if(n1->index == n2->index) { + multires_displacer_init(&d, dm, n1->index, invert); + multires_displacer_anchor_edge(&d, e->v1, e->v2, x); + multires_displace(&d, mvert->co); + } } } - - lvl= lvl->next; + ++mvert; + ++d.subco_index; } - if(pr_deltas) MEM_freeN(pr_deltas); - if(cr_deltas) MEM_freeN(cr_deltas); + } - /* Update lower levels */ - lvl= me->mr->levels.last; - lvl= lvl->prev; - while(lvl) { - MultiresColFace *nf= lvl->next->colfaces; - for(i=0; i<lvl->totface; ++i) { - MultiresFace *f= &lvl->faces[i]; - for(j=0; j<(f->v[3]?4:3); ++j) { - lvl->colfaces[i].col[j]= nf->col[1]; - ++nf; - } - } - lvl= lvl->prev; + for(i = 0; i < me->totvert; ++i) { + IndexNode *n; + multires_displacer_weight(&d, 1.0f / BLI_countlist(&map[i])); + for(n = map[i].first; n; n = n->next) { + multires_displacer_init(&d, dm, n->index, invert); + multires_displacer_anchor_vert(&d, i); + multires_displace(&d, mvert->co); } + ++mvert; + ++d.subco_index; } + + if(!invert) + CDDM_calc_normals(dm); } -void multires_update_levels(Mesh *me, const int render) +static void multiresModifier_update(DerivedMesh *dm) { - EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL; + Mesh *me; + MDisps *mdisps; - multires_update_first_level(me, em); - multires_update_vertices(me, em); - multires_update_faces(me, em); - multires_update_colors(me, em); -} + me = MultiresDM_get_mesh(dm); + mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS); -static void check_colors(Mesh *me, const int render) -{ - CustomData *src= (!render && G.obedit)? &G.editMesh->fdata : &me->fdata; - const char col= CustomData_has_layer(src, CD_MCOL); - - /* Check if vertex colors have been deleted or added */ - if(me->mr->use_col && !col) - me->mr->use_col= 0; - else if(!me->mr->use_col && col) { - me->mr->use_col= 1; - multires_load_cols(me); - } -} + if(mdisps) { + const int lvl = MultiresDM_get_lvl(dm); + const int totlvl = MultiresDM_get_totlvl(dm); + + if(lvl < totlvl) { + /* Propagate disps upwards */ + DerivedMesh *final, *subco_dm, *orig; + MVert *verts_new = NULL, *cur_lvl_orig_verts = NULL; + MultiresModifierData mmd; + int i; + + orig = CDDM_from_mesh(me, NULL); + + /* Regenerate the current level's vertex coordinates + (includes older displacements but not new sculpts) */ + mmd.totlvl = totlvl; + mmd.lvl = lvl; + subco_dm = multires_dm_create_from_derived(&mmd, orig, me, 0, 0); + cur_lvl_orig_verts = CDDM_get_verts(subco_dm); -static unsigned int find_mid_edge(ListBase *vert_edge_map, - MultiresLevel *lvl, - const unsigned int v1, - const unsigned int v2 ) -{ - MultiresMapNode *n= vert_edge_map[v1].first; - while(n) { - if(lvl->edges[n->Index].v[0]==v2 || - lvl->edges[n->Index].v[1]==v2) - return lvl->edges[n->Index].mid; + /* Subtract the original vertex cos from the new vertex cos */ + verts_new = CDDM_get_verts(dm); + for(i = 0; i < dm->getNumVerts(dm); ++i) + VecSubf(verts_new[i].co, verts_new[i].co, cur_lvl_orig_verts[i].co); - n= n->next; + final = multires_subdisp_pre(dm, totlvl - lvl, 0); + + multires_subdisp(orig, me, final, lvl, totlvl, dm->getNumVerts(dm), dm->getNumEdges(dm), + dm->getNumFaces(dm), 1); + + subco_dm->release(subco_dm); + orig->release(orig); + } + else + multiresModifier_disp_run(dm, MultiresDM_get_subco(dm), 1); } - return -1; } -static float clamp_component(const float c) +void multires_mark_as_modified(struct Object *ob) { - if(c<0) return 0; - else if(c>255) return 255; - else return c; + if(ob && ob->derivedFinal) { + MultiresDM_mark_as_modified(ob->derivedFinal); + } } -void multires_to_mcol(MultiresColFace *f, MCol mcol[4]) +void multires_force_update(Object *ob) { - unsigned char j; - for(j=0; j<4; ++j) { - mcol->a= clamp_component(f->col[j].a); - mcol->r= clamp_component(f->col[j].r); - mcol->g= clamp_component(f->col[j].g); - mcol->b= clamp_component(f->col[j].b); - ++mcol; + if(ob && ob->derivedFinal) { + ob->derivedFinal->needsFree =1; + ob->derivedFinal->release(ob->derivedFinal); + ob->derivedFinal = NULL; } } -void multires_level_to_mesh(Object *ob, Mesh *me, const int render) +struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, DerivedMesh *dm, Mesh *me, + int useRenderParams, int isFinalCalc) { - MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); + SubsurfModifierData smd; + MultiresSubsurf ms; + DerivedMesh *result; int i; - EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL; - - if(em) - return; - CustomData_free_layer_active(&me->vdata, CD_MVERT, me->totvert); - CustomData_free_layer_active(&me->edata, CD_MEDGE, me->totedge); - CustomData_free_layer_active(&me->fdata, CD_MFACE, me->totface); - CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert); - CustomData_free_layers(&me->fdata, CD_MTFACE, me->totface); - CustomData_free_layers(&me->fdata, CD_MCOL, me->totface); - - me->totvert= lvl->totvert; - me->totface= lvl->totface; - me->totedge= lvl->totedge; + ms.mmd = mmd; + ms.me = me; - CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert); - CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge); - CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface); - mesh_update_customdata_pointers(me); + memset(&smd, 0, sizeof(SubsurfModifierData)); + smd.levels = smd.renderLevels = mmd->lvl - 1; + smd.flags |= eSubsurfModifierFlag_SubsurfUv; - /* Vertices/Edges/Faces */ - - for(i=0; i<lvl->totvert; ++i) { - me->mvert[i]= me->mr->verts[i]; - } - for(i=0; i<lvl->totedge; ++i) { - me->medge[i].v1= lvl->edges[i].v[0]; - me->medge[i].v2= lvl->edges[i].v[1]; - me->medge[i].flag &= ~ME_HIDE; - } - for(i=0; i<lvl->totface; ++i) { - me->mface[i].v1= lvl->faces[i].v[0]; - me->mface[i].v2= lvl->faces[i].v[1]; - me->mface[i].v3= lvl->faces[i].v[2]; - me->mface[i].v4= lvl->faces[i].v[3]; - me->mface[i].flag= lvl->faces[i].flag; - me->mface[i].flag &= ~ME_HIDE; - me->mface[i].mat_nr= lvl->faces[i].mat_nr; + result = subsurf_make_derived_from_derived_with_multires(dm, &smd, &ms, useRenderParams, NULL, isFinalCalc, 0); + for(i = 0; i < result->getNumVerts(result); ++i) + MultiresDM_get_subco(result)[i] = CDDM_get_verts(result)[i]; + multiresModifier_disp_run(result, MultiresDM_get_subco(result), 0); + MultiresDM_set_update(result, multiresModifier_update); + + return result; +} + +/**** Old Multires code **** +***************************/ + +/* Does not actually free lvl itself */ +void multires_free_level(MultiresLevel *lvl) +{ + if(lvl) { + if(lvl->faces) MEM_freeN(lvl->faces); + if(lvl->edges) MEM_freeN(lvl->edges); + if(lvl->colfaces) MEM_freeN(lvl->colfaces); } - - /* Edge flags */ - if(lvl==me->mr->levels.first) { - for(i=0; i<lvl->totedge; ++i) { - me->medge[i].flag= me->mr->edge_flags[i]; - me->medge[i].crease= me->mr->edge_creases[i]; +} + +void multires_free(Multires *mr) +{ + if(mr) { + MultiresLevel* lvl= mr->levels.first; + + /* Free the first-level data */ + if(lvl) { + CustomData_free(&mr->vdata, lvl->totvert); + CustomData_free(&mr->fdata, lvl->totface); + if(mr->edge_flags) + MEM_freeN(mr->edge_flags); + if(mr->edge_creases) + MEM_freeN(mr->edge_creases); } - } else { - MultiresLevel *lvl1= me->mr->levels.first; - const int last= lvl1->totedge * pow(2, me->mr->current-1); - for(i=0; i<last; ++i) { - const int ndx= i / pow(2, me->mr->current-1); - - me->medge[i].flag= me->mr->edge_flags[ndx]; - me->medge[i].crease= me->mr->edge_creases[ndx]; + + while(lvl) { + multires_free_level(lvl); + lvl= lvl->next; } - } - multires_customdata_to_mesh(me, em, lvl, &me->mr->vdata, em ? &em->vdata : &me->vdata, CD_MDEFORMVERT); - multires_customdata_to_mesh(me, em, lvl, &me->mr->fdata, em ? &em->fdata : &me->fdata, CD_MTFACE); + MEM_freeN(mr->verts); - /* Colors */ - if(me->mr->use_col) { - CustomData *src= &me->fdata; - - if(me->mr->use_col) me->mcol= CustomData_add_layer(src, CD_MCOL, CD_CALLOC, NULL, me->totface); - - for(i=0; i<lvl->totface; ++i) { - if(me->mr->use_col) - multires_to_mcol(&lvl->colfaces[i], &me->mcol[i*4]); - } - + BLI_freelistN(&mr->levels); + + MEM_freeN(mr); } +} + +static void create_old_vert_face_map(ListBase **map, IndexNode **mem, const MultiresFace *mface, + const int totvert, const int totface) +{ + int i,j; + IndexNode *node = NULL; - mesh_update_customdata_pointers(me); + (*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert face map"); + (*mem) = MEM_callocN(sizeof(IndexNode) * totface*4, "vert face map mem"); + node = *mem; - multires_edge_level_update(ob,me); - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + /* Find the users */ + for(i = 0; i < totface; ++i){ + for(j = 0; j < (mface[i].v[3]?4:3); ++j, ++node) { + node->index = i; + BLI_addtail(&(*map)[mface[i].v[j]], node); + } + } } -void multires_add_level(Object *ob, Mesh *me, const char subdiv_type) +static void create_old_vert_edge_map(ListBase **map, IndexNode **mem, const MultiresEdge *medge, + const int totvert, const int totedge) { - int i,j, curf, cure; - MultiresLevel *lvl= NULL; - MultiApplyData data; - MVert *oldverts= NULL; + int i,j; + IndexNode *node = NULL; - lvl= MEM_callocN(sizeof(MultiresLevel), "multireslevel"); - if(me->pv) mesh_pmv_off(ob, me); - - check_colors(me, 0); - multires_update_levels(me, 0); - - ++me->mr->level_count; - BLI_addtail(&me->mr->levels,lvl); - - /* Create vertices - =============== */ - lvl->totvert= lvl->prev->totvert + lvl->prev->totedge + lvl->prev->totface; - oldverts= me->mr->verts; - me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert, "multitres verts"); - /* Copy old verts */ - for(i=0; i<lvl->prev->totvert; ++i) - me->mr->verts[i]= oldverts[i]; - /* Create new edge verts */ - for(i=0; i<lvl->prev->totedge; ++i) { - VecMidf(me->mr->verts[lvl->prev->totvert + i].co, - oldverts[lvl->prev->edges[i].v[0]].co, - oldverts[lvl->prev->edges[i].v[1]].co); - lvl->prev->edges[i].mid= lvl->prev->totvert + i; + (*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert edge map"); + (*mem) = MEM_callocN(sizeof(IndexNode) * totedge*2, "vert edge map mem"); + node = *mem; + + /* Find the users */ + for(i = 0; i < totedge; ++i){ + for(j = 0; j < 2; ++j, ++node) { + node->index = i; + BLI_addtail(&(*map)[medge[i].v[j]], node); + } } - /* Create new face verts */ - for(i=0; i<lvl->prev->totface; ++i) { - lvl->prev->faces[i].mid= lvl->prev->totvert + lvl->prev->totedge + i; +} + +static MultiresFace *find_old_face(ListBase *map, MultiresFace *faces, int v1, int v2, int v3, int v4) +{ + IndexNode *n1; + int v[4] = {v1, v2, v3, v4}, i, j; + + for(n1 = map[v1].first; n1; n1 = n1->next) { + int fnd[4] = {0, 0, 0, 0}; + + for(i = 0; i < 4; ++i) { + for(j = 0; j < 4; ++j) { + if(v[i] == faces[n1->index].v[j]) + fnd[i] = 1; + } + } + + if(fnd[0] && fnd[1] && fnd[2] && fnd[3]) + return &faces[n1->index]; } - multires_calc_temp_data(lvl->prev); + return NULL; +} - /* Create faces - ============ */ - /* Allocate all the new faces (each triangle creates three, and - each quad creates four */ - lvl->totface= 0; - for(i=0; i<lvl->prev->totface; ++i) - lvl->totface+= lvl->prev->faces[i].v[3] ? 4 : 3; - lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces"); +static MultiresEdge *find_old_edge(ListBase *map, MultiresEdge *edges, int v1, int v2) +{ + IndexNode *n1, *n2; - curf= 0; - for(i=0; i<lvl->prev->totface; ++i) { - const int max= lvl->prev->faces[i].v[3] ? 3 : 2; - - for(j=0; j<max+1; ++j) { - lvl->faces[curf].v[0]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev, - lvl->prev->faces[i].v[j], - lvl->prev->faces[i].v[j==0?max:j-1]); - lvl->faces[curf].v[1]= lvl->prev->faces[i].v[j]; - lvl->faces[curf].v[2]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev, - lvl->prev->faces[i].v[j], - lvl->prev->faces[i].v[j==max?0:j+1]); - lvl->faces[curf].v[3]= lvl->prev->totvert + lvl->prev->totedge + i; - lvl->faces[curf].flag= lvl->prev->faces[i].flag; - lvl->faces[curf].mat_nr= lvl->prev->faces[i].mat_nr; - - ++curf; + for(n1 = map[v1].first; n1; n1 = n1->next) { + for(n2 = map[v2].first; n2; n2 = n2->next) { + if(n1->index == n2->index) + return &edges[n1->index]; } } - /* Create edges - ============ */ - /* Figure out how many edges to allocate */ - lvl->totedge= lvl->prev->totedge*2; - for(i=0; i<lvl->prev->totface; ++i) - lvl->totedge+= lvl->prev->faces[i].v[3]?4:3; - lvl->edges= MEM_callocN(sizeof(MultiresEdge)*lvl->totedge,"multires edges"); - - for(i=0; i<lvl->prev->totedge; ++i) { - lvl->edges[i*2].v[0]= lvl->prev->edges[i].v[0]; - lvl->edges[i*2].v[1]= lvl->prev->edges[i].mid; - lvl->edges[i*2+1].v[0]= lvl->prev->edges[i].mid; - lvl->edges[i*2+1].v[1]= lvl->prev->edges[i].v[1]; + return NULL; +} + +static void multires_load_old_edges(ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst, int v1, int v2, int mov) +{ + int emid = find_old_edge(emap[2], lvl->edges, v1, v2)->mid; + vvmap[dst + mov] = emid; + + if(lvl->next->next) { + multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v1, emid, mov / 2); + multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v2, emid, -mov / 2); } - /* Add edges inside of old polygons */ - curf= 0; - cure= lvl->prev->totedge*2; - for(i=0; i<lvl->prev->totface; ++i) { - for(j=0; j<(lvl->prev->faces[i].v[3]?4:3); ++j) { - lvl->edges[cure].v[0]= lvl->faces[curf].v[2]; - lvl->edges[cure].v[1]= lvl->faces[curf].v[3]; - ++cure; - ++curf; +} + +static void multires_load_old_faces(ListBase **fmap, ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst, + int v1, int v2, int v3, int v4, int st2, int st3) +{ + int fmid; + int emid13, emid14, emid23, emid24; + + if(lvl && lvl->next) { + fmid = find_old_face(fmap[1], lvl->faces, v1, v2, v3, v4)->mid; + vvmap[dst] = fmid; + + emid13 = find_old_edge(emap[1], lvl->edges, v1, v3)->mid; + emid14 = find_old_edge(emap[1], lvl->edges, v1, v4)->mid; + emid23 = find_old_edge(emap[1], lvl->edges, v2, v3)->mid; + emid24 = find_old_edge(emap[1], lvl->edges, v2, v4)->mid; + + + multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst + st2 * st3 + st3, + fmid, v2, emid23, emid24, st2, st3 / 2); + + multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst - st2 * st3 + st3, + emid14, emid24, fmid, v4, st2, st3 / 2); + + multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst + st2 * st3 - st3, + emid13, emid23, v3, fmid, st2, st3 / 2); + + multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst - st2 * st3 - st3, + v1, fmid, emid13, emid14, st2, st3 / 2); + + if(lvl->next->next) { + multires_load_old_edges(emap, lvl->next, vvmap, dst, emid24, fmid, st3); + multires_load_old_edges(emap, lvl->next, vvmap, dst, emid13, fmid, -st3); + multires_load_old_edges(emap, lvl->next, vvmap, dst, emid14, fmid, -st2 * st3); + multires_load_old_edges(emap, lvl->next, vvmap, dst, emid23, fmid, st2 * st3); } } +} - /* Smooth vertices - =============== */ - for(i=0; i<lvl->prev->totface; ++i) { - const MultiresFace *f= &lvl->prev->faces[i]; - data.corner1= oldverts[f->v[0]].co; - data.corner2= oldverts[f->v[1]].co; - data.corner3= oldverts[f->v[2]].co; - data.corner4= oldverts[f->v[3]].co; - data.quad= f->v[3] ? 1 : 0; - multi_apply(me->mr->verts[f->mid].co, &data, 3, catmullclark_smooth_face); +/* Loads a multires object stored in the old Multires struct into the new format */ +void multires_load_old(DerivedMesh *dm, Multires *mr) +{ + MultiresLevel *lvl, *lvl1; + MVert *vsrc, *vdst; + int src, dst; + int totlvl = MultiresDM_get_totlvl(dm); + int st = multires_side_tot[totlvl - 2] - 1; + int extedgelen = multires_side_tot[totlvl - 1] - 2; + int *vvmap; // inorder for dst, map to src + int crossedgelen; + int i, j, s, x, totvert, tottri, totquad; + + src = 0; + dst = 0; + vsrc = mr->verts; + vdst = CDDM_get_verts(dm); + totvert = dm->getNumVerts(dm); + vvmap = MEM_callocN(sizeof(int) * totvert, "multires vvmap"); + + lvl1 = mr->levels.first; + /* Load base verts */ + for(i = 0; i < lvl1->totvert; ++i) { + vvmap[totvert - lvl1->totvert + i] = src; + ++src; } - if(subdiv_type == 0) { - for(i=0; i<lvl->prev->totedge; ++i) { - const MultiresEdge *e= &lvl->prev->edges[i]; - data.boundary= lvl->prev->edge_boundary_states[i]; - edge_face_neighbor_midpoints_accum(&data,lvl->prev, me->mr->verts, sizeof(MVert),e); - data.endpoint1= oldverts[e->v[0]].co; - data.endpoint2= oldverts[e->v[1]].co; - multi_apply(me->mr->verts[e->mid].co, &data, 3, catmullclark_smooth_edge); - } - - for(i=0; i<lvl->prev->totvert; ++i) { - data.boundary= multires_vert_is_boundary(lvl->prev,i); - data.original= oldverts[i].co; - data.edge_count= BLI_countlist(&lvl->prev->vert_edge_map[i]); - if(data.boundary) - boundary_edges_average(&data,lvl->prev, oldverts, sizeof(MVert),i); - else { - vert_face_neighbor_midpoints_average(&data,lvl->prev, me->mr->verts, - sizeof(MVert),i); - vert_edge_neighbor_midpoints_average(&data,lvl->prev, oldverts, - sizeof(MVert),i); - } - multi_apply(me->mr->verts[i].co, &data, 3, catmullclark_smooth_vert); + /* Original edges */ + dst = totvert - lvl1->totvert - extedgelen * lvl1->totedge; + for(i = 0; i < lvl1->totedge; ++i) { + int ldst = dst + extedgelen * i; + int lsrc = src; + lvl = lvl1->next; + + for(j = 2; j <= mr->level_count; ++j) { + int base = multires_side_tot[totlvl - j] - 2; + int skip = multires_side_tot[totlvl - j + 1] - 1; + int st = multires_side_tot[j - 2] - 1; + + for(x = 0; x < st; ++x) + vvmap[ldst + base + x * skip] = lsrc + st * i + x; + + lsrc += lvl->totvert - lvl->prev->totvert; + lvl = lvl->next; } } - multires_free_temp_data(lvl->prev); - MEM_freeN(oldverts); - - /* Vertex Colors - ============= */ - curf= 0; - if(me->mr->use_col) { - MultiresColFace *cf= MEM_callocN(sizeof(MultiresColFace)*lvl->totface,"Multirescolfaces"); - lvl->colfaces= cf; - for(i=0; i<lvl->prev->totface; ++i) { - const char sides= lvl->prev->faces[i].v[3]?4:3; - MultiresCol cntr; - - /* Find average color of 4 (or 3 for triangle) verts */ - multires_col_avg(&cntr,lvl->prev->colfaces[i].col,sides); - - for(j=0; j<sides; ++j) { - multires_col_avg2(&cf->col[0], - &lvl->prev->colfaces[i].col[j], - &lvl->prev->colfaces[i].col[j==0?sides-1:j-1]); - cf->col[1]= lvl->prev->colfaces[i].col[j]; - multires_col_avg2(&cf->col[2], - &lvl->prev->colfaces[i].col[j], - &lvl->prev->colfaces[i].col[j==sides-1?0:j+1]); - cf->col[3]= cntr; - - ++cf; - } - } + /* Center points */ + dst = 0; + for(i = 0; i < lvl1->totface; ++i) { + int sides = lvl1->faces[i].v[3] ? 4 : 3; + + vvmap[dst] = src + lvl1->totedge + i; + dst += 1 + sides * (st - 1) * st; } - me->mr->newlvl= me->mr->level_count; - me->mr->current= me->mr->newlvl; - /* Unless the render level has been set to something other than the - highest level (by the user), increment the render level to match - the highest available level */ - if(me->mr->renderlvl == me->mr->level_count - 1) me->mr->renderlvl= me->mr->level_count; - multires_level_to_mesh(ob, me, 0); -} + /* The rest is only for level 3 and up */ + if(lvl1->next && lvl1->next->next) { + ListBase **fmap, **emap; + IndexNode **fmem, **emem; -void multires_set_level(Object *ob, Mesh *me, const int render) -{ - if(me->pv) mesh_pmv_off(ob, me); + /* Face edge cross */ + tottri = totquad = 0; + crossedgelen = multires_side_tot[totlvl - 2] - 2; + dst = 0; + for(i = 0; i < lvl1->totface; ++i) { + int sides = lvl1->faces[i].v[3] ? 4 : 3; - check_colors(me, render); - multires_update_levels(me, render); + lvl = lvl1->next->next; + ++dst; - me->mr->current= me->mr->newlvl; - if(me->mr->current<1) me->mr->current= 1; - else if(me->mr->current>me->mr->level_count) me->mr->current= me->mr->level_count; + for(j = 3; j <= mr->level_count; ++j) { + int base = multires_side_tot[totlvl - j] - 2; + int skip = multires_side_tot[totlvl - j + 1] - 1; + int st = pow(2, j - 2); + int st2 = pow(2, j - 3); + int lsrc = lvl->prev->totvert; - multires_level_to_mesh(ob, me, render); -} + /* Skip exterior edge verts */ + lsrc += lvl1->totedge * st; -/* Update the edge visibility flags to only show edges on or below the edgelvl */ -void multires_edge_level_update(Object *ob, Mesh *me) -{ - if(!G.obedit) { - MultiresLevel *cr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1); - MultiresLevel *edge_lvl= BLI_findlink(&me->mr->levels,me->mr->edgelvl-1); - const int threshold= edge_lvl->totedge * pow(2, me->mr->current - me->mr->edgelvl); - unsigned i; - - for(i=0; i<cr_lvl->totedge; ++i) { - const int ndx= me->pv ? me->pv->edge_map[i] : i; - if(ndx != -1) { /* -1= hidden edge */ - if(me->mr->edgelvl >= me->mr->current || i<threshold) - me->medge[ndx].flag |= ME_EDGEDRAW | ME_EDGERENDER; - else - me->medge[ndx].flag &= ~ME_EDGEDRAW & ~ME_EDGERENDER; + /* Skip earlier face edge crosses */ + lsrc += st2 * (tottri * 3 + totquad * 4); + + for(s = 0; s < sides; ++s) { + for(x = 0; x < st2; ++x) { + vvmap[dst + crossedgelen * (s + 1) - base - x * skip - 1] = lsrc; + ++lsrc; + } + } + + lvl = lvl->next; } + + dst += sides * (st - 1) * st; + + if(sides == 4) ++totquad; + else ++tottri; + } - - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + + /* calculate vert to edge/face maps for each level (except the last) */ + fmap = MEM_callocN(sizeof(ListBase*) * (mr->level_count-1), "multires fmap"); + emap = MEM_callocN(sizeof(ListBase*) * (mr->level_count-1), "multires emap"); + fmem = MEM_callocN(sizeof(IndexNode*) * (mr->level_count-1), "multires fmem"); + emem = MEM_callocN(sizeof(IndexNode*) * (mr->level_count-1), "multires emem"); + lvl = lvl1; + for(i = 0; i < mr->level_count - 1; ++i) { + create_old_vert_face_map(fmap + i, fmem + i, lvl->faces, lvl->totvert, lvl->totface); + create_old_vert_edge_map(emap + i, emem + i, lvl->edges, lvl->totvert, lvl->totedge); + lvl = lvl->next; + } + + /* Interior face verts */ + lvl = lvl1->next->next; + dst = 0; + for(j = 0; j < lvl1->totface; ++j) { + int sides = lvl1->faces[j].v[3] ? 4 : 3; + int ldst = dst + 1 + sides * (st - 1); + + for(s = 0; s < sides; ++s) { + int st2 = multires_side_tot[totlvl - 2] - 2; + int st3 = multires_side_tot[totlvl - 3] - 2; + int st4 = st3 == 0 ? 1 : (st3 + 1) / 2; + int mid = ldst + st2 * st3 + st3; + int cv = lvl1->faces[j].v[s]; + int nv = lvl1->faces[j].v[s == sides - 1 ? 0 : s + 1]; + int pv = lvl1->faces[j].v[s == 0 ? sides - 1 : s - 1]; + + multires_load_old_faces(fmap, emap, lvl1->next, vvmap, mid, + vvmap[dst], cv, + find_old_edge(emap[0], lvl1->edges, pv, cv)->mid, + find_old_edge(emap[0], lvl1->edges, cv, nv)->mid, + st2, st4); + + ldst += (st - 1) * (st - 1); + } + + + dst = ldst; + } + + lvl = lvl->next; + + for(i = 0; i < mr->level_count - 1; ++i) { + MEM_freeN(fmap[i]); + MEM_freeN(fmem[i]); + MEM_freeN(emap[i]); + MEM_freeN(emem[i]); + } + + MEM_freeN(fmap); + MEM_freeN(emap); + MEM_freeN(fmem); + MEM_freeN(emem); } + + /* Transfer verts */ + for(i = 0; i < totvert; ++i) + VecCopyf(vdst[i].co, vsrc[vvmap[i]].co); + + MEM_freeN(vvmap); } diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 245c4179bd1..c41c4ae78e4 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -17,171 +17,1531 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung * All rights reserved. * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Joshua Leung (full recode) * * ***** END GPL LICENSE BLOCK ***** */ #include <stdlib.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <float.h> #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" -#include "DNA_space_types.h" -#include "DNA_nla_types.h" +#include "DNA_anim_types.h" #include "DNA_action_types.h" -#include "DNA_ID.h" -#include "DNA_ipo_types.h" -#include "DNA_object_types.h" -#include "BKE_nla.h" +#include "BKE_animsys.h" #include "BKE_action.h" +#include "BKE_fcurve.h" +#include "BKE_nla.h" #include "BKE_blender.h" #include "BKE_library.h" -#include "BKE_object.h" /* for convert_action_to_strip(ob) */ +#include "BKE_object.h" +#include "BKE_utildefines.h" + +#include "RNA_access.h" +#include "nla_private.h" #ifdef HAVE_CONFIG_H #include <config.h> #endif -/* NOTE: in group.c the strips get copied for group-nla override, this assumes - that strips are one single block, without additional data to be copied */ -void copy_actionstrip (bActionStrip **dst, bActionStrip **src){ - bActionStrip *dstrip; - bActionStrip *sstrip = *src; +/* *************************************************** */ +/* Data Management */ - if (!*src){ - *dst=NULL; +/* Freeing ------------------------------------------- */ + +/* Remove the given NLA strip from the NLA track it occupies, free the strip's data, + * and the strip itself. + */ +void free_nlastrip (ListBase *strips, NlaStrip *strip) +{ + NlaStrip *cs, *csn; + + /* sanity checks */ + if (strip == NULL) return; + + /* free child-strips */ + for (cs= strip->strips.first; cs; cs= csn) { + csn= cs->next; + free_nlastrip(&strip->strips, cs); } + + /* remove reference to action */ + if (strip->act) + strip->act->id.us--; + + /* free remapping info */ + //if (strip->remap) + // BKE_animremap_free(); + + /* free own F-Curves */ + free_fcurves(&strip->fcurves); + + /* free own F-Modifiers */ + free_fmodifiers(&strip->modifiers); + + /* free the strip itself */ + if (strips) + BLI_freelinkN(strips, strip); + else + MEM_freeN(strip); +} - *dst = MEM_dupallocN(sstrip); +/* Remove the given NLA track from the set of NLA tracks, free the track's data, + * and the track itself. + */ +void free_nlatrack (ListBase *tracks, NlaTrack *nlt) +{ + NlaStrip *strip, *stripn; + + /* sanity checks */ + if (nlt == NULL) + return; + + /* free strips */ + for (strip= nlt->strips.first; strip; strip= stripn) { + stripn= strip->next; + free_nlastrip(&nlt->strips, strip); + } + + /* free NLA track itself now */ + if (tracks) + BLI_freelinkN(tracks, nlt); + else + MEM_freeN(nlt); +} + +/* Free the elements of type NLA Tracks provided in the given list, but do not free + * the list itself since that is not free-standing + */ +void free_nladata (ListBase *tracks) +{ + NlaTrack *nlt, *nltn; + + /* sanity checks */ + if ELEM(NULL, tracks, tracks->first) + return; + + /* free tracks one by one */ + for (nlt= tracks->first; nlt; nlt= nltn) { + nltn= nlt->next; + free_nlatrack(tracks, nlt); + } + + /* clear the list's pointers to be safe */ + tracks->first= tracks->last= NULL; +} - dstrip = *dst; - if (dstrip->act) - dstrip->act->id.us++; +/* Copying ------------------------------------------- */ - if (dstrip->ipo) - dstrip->ipo->id.us++; +/* Copy NLA strip */ +NlaStrip *copy_nlastrip (NlaStrip *strip) +{ + NlaStrip *strip_d; + NlaStrip *cs, *cs_d; + + /* sanity check */ + if (strip == NULL) + return NULL; + + /* make a copy */ + strip_d= MEM_dupallocN(strip); + strip_d->next= strip_d->prev= NULL; - if (dstrip->modifiers.first) { - duplicatelist (&dstrip->modifiers, &sstrip->modifiers); + /* increase user-count of action */ + if (strip_d->act) + strip_d->act->id.us++; + + /* copy F-Curves and modifiers */ + copy_fcurves(&strip_d->fcurves, &strip->fcurves); + copy_fmodifiers(&strip_d->modifiers, &strip->modifiers); + + /* make a copy of all the child-strips, one at a time */ + strip_d->strips.first= strip_d->strips.last= NULL; + + for (cs= strip->strips.first; cs; cs= cs->next) { + cs_d= copy_nlastrip(cs); + BLI_addtail(&strip_d->strips, cs_d); } + /* return the strip */ + return strip_d; } -void copy_nlastrips (ListBase *dst, ListBase *src) +/* Copy NLA Track */ +NlaTrack *copy_nlatrack (NlaTrack *nlt) { - bActionStrip *strip; + NlaStrip *strip, *strip_d; + NlaTrack *nlt_d; + + /* sanity check */ + if (nlt == NULL) + return NULL; + + /* make a copy */ + nlt_d= MEM_dupallocN(nlt); + nlt_d->next= nlt_d->prev= NULL; + + /* make a copy of all the strips, one at a time */ + nlt_d->strips.first= nlt_d->strips.last= NULL; + + for (strip= nlt->strips.first; strip; strip= strip->next) { + strip_d= copy_nlastrip(strip); + BLI_addtail(&nlt_d->strips, strip_d); + } + + /* return the copy */ + return nlt_d; +} - dst->first=dst->last=NULL; +/* Copy all NLA data */ +void copy_nladata (ListBase *dst, ListBase *src) +{ + NlaTrack *nlt, *nlt_d; + + /* sanity checks */ + if ELEM(NULL, dst, src) + return; + + /* copy each NLA-track, one at a time */ + for (nlt= src->first; nlt; nlt= nlt->next) { + /* make a copy, and add the copy to the destination list */ + nlt_d= copy_nlatrack(nlt); + BLI_addtail(dst, nlt_d); + } +} - duplicatelist (dst, src); +/* Adding ------------------------------------------- */ - /* Update specific data */ - if (!dst->first) - return; +/* Add a NLA Track to the given AnimData + * - prev: NLA-Track to add the new one after + */ +NlaTrack *add_nlatrack (AnimData *adt, NlaTrack *prev) +{ + NlaTrack *nlt; + + /* sanity checks */ + if (adt == NULL) + return NULL; + + /* allocate new track */ + nlt= MEM_callocN(sizeof(NlaTrack), "NlaTrack"); + + /* set settings requiring the track to not be part of the stack yet */ + nlt->flag = NLATRACK_SELECTED; + nlt->index= BLI_countlist(&adt->nla_tracks); + + /* add track to stack, and make it the active one */ + if (prev) + BLI_insertlinkafter(&adt->nla_tracks, prev, nlt); + else + BLI_addtail(&adt->nla_tracks, nlt); + BKE_nlatrack_set_active(&adt->nla_tracks, nlt); + + /* must have unique name, but we need to seed this */ + sprintf(nlt->name, "NlaTrack"); + BLI_uniquename(&adt->nla_tracks, nlt, "NlaTrack", '.', offsetof(NlaTrack, name), 64); + + /* return the new track */ + return nlt; +} + +/* Add a NLA Strip referencing the given Action */ +NlaStrip *add_nlastrip (bAction *act) +{ + NlaStrip *strip; + + /* sanity checks */ + if (act == NULL) + return NULL; + + /* allocate new strip */ + strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip"); + + /* generic settings + * - selected flag to highlight this to the user + * - auto-blends to ensure that blend in/out values are automatically + * determined by overlaps of strips + * - (XXX) synchronisation of strip-length in accordance with changes to action-length + * is not done though, since this should only really happens in editmode for strips now + * though this decision is still subject to further review... + */ + strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS; + + /* assign the action reference */ + strip->act= act; + id_us_plus(&act->id); + + /* determine initial range + * - strip length cannot be 0... ever... + */ + calc_action_range(strip->act, &strip->actstart, &strip->actend, 1); + + strip->start = strip->actstart; + strip->end = (IS_EQ(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f): (strip->actend); + + /* strip should be referenced as-is */ + strip->scale= 1.0f; + strip->repeat = 1.0f; + + /* return the new strip */ + return strip; +} + +/* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */ +NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act) +{ + NlaStrip *strip; + NlaTrack *nlt; + + /* sanity checks */ + if ELEM(NULL, adt, act) + return NULL; + + /* create a new NLA strip */ + strip= add_nlastrip(act); + if (strip == NULL) + return NULL; + + /* firstly try adding strip to last track, but if that fails, add to a new track */ + if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) { + /* trying to add to the last track failed (no track or no space), + * so add a new track to the stack, and add to that... + */ + nlt= add_nlatrack(adt, NULL); + BKE_nlatrack_add_strip(nlt, strip); + } + + /* automatically name it too */ + BKE_nlastrip_validate_name(adt, strip); + + /* returns the strip added */ + return strip; +} + +/* *************************************************** */ +/* NLA Evaluation <-> Editing Stuff */ + +/* Strip Mapping ------------------------------------- */ - for (strip = dst->first; strip; strip=strip->next){ - if (strip->act) - strip->act->id.us++; - if (strip->ipo) - strip->ipo->id.us++; - if (strip->modifiers.first) { - ListBase listb; - duplicatelist (&listb, &strip->modifiers); - strip->modifiers= listb; +/* non clipped mapping for strip-time <-> global time (for Action-Clips) + * invert = convert action-strip time to global time + */ +static float nlastrip_get_frame_actionclip (NlaStrip *strip, float cframe, short mode) +{ + float actlength, repeat, scale; + + /* get number of repeats */ + if (IS_EQ(strip->repeat, 0.0f)) strip->repeat = 1.0f; + repeat = strip->repeat; + + /* scaling */ + if (IS_EQ(strip->scale, 0.0f)) strip->scale= 1.0f; + scale = (float)fabs(strip->scale); /* scale must be positive - we've got a special flag for reversing */ + + /* length of referenced action */ + actlength = strip->actend - strip->actstart; + if (IS_EQ(actlength, 0.0f)) actlength = 1.0f; + + /* reversed = play strip backwards */ + if (strip->flag & NLASTRIP_FLAG_REVERSE) { + // FIXME: this won't work right with Graph Editor? + if (mode == NLATIME_CONVERT_MAP) { + return strip->end - scale*(cframe - strip->actstart); + } + else if (mode == NLATIME_CONVERT_UNMAP) { + int repeatsNum = (int)((cframe - strip->start) / (actlength * scale)); + + /* this method doesn't clip the values to lie within the action range only + * - the '(repeatsNum * actlength * scale)' compensates for the fmod(...) + * - the fmod(...) works in the same way as for eval + */ + return strip->actend - (repeatsNum * actlength * scale) + - (fmod(cframe - strip->start, actlength*scale) / scale); + } + else /* if (mode == NLATIME_CONVERT_EVAL) */{ + if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) { + /* this case prevents the motion snapping back to the first frame at the end of the strip + * by catching the case where repeats is a whole number, which means that the end of the strip + * could also be interpreted as the end of the start of a repeat + */ + return strip->actstart; + } + else { + /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working + * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat + */ + return strip->actend - fmod(cframe - strip->start, actlength*scale) / scale; + } + } + } + else { + if (mode == NLATIME_CONVERT_MAP) { + return strip->start + scale*(cframe - strip->actstart); + } + else if (mode == NLATIME_CONVERT_UNMAP) { + int repeatsNum = (int)((cframe - strip->start) / (actlength * scale)); + + /* this method doesn't clip the values to lie within the action range only + * - the '(repeatsNum * actlength * scale)' compensates for the fmod(...) + * - the fmod(...) works in the same way as for eval + */ + return strip->actstart + (repeatsNum * actlength * scale) + + (fmod(cframe - strip->start, actlength*scale) / scale); + } + else /* if (mode == NLATIME_CONVERT_EVAL) */{ + if (IS_EQ(cframe, strip->end) && IS_EQ(strip->repeat, ((int)strip->repeat))) { + /* this case prevents the motion snapping back to the first frame at the end of the strip + * by catching the case where repeats is a whole number, which means that the end of the strip + * could also be interpreted as the end of the start of a repeat + */ + return strip->actend; + } + else { + /* - the 'fmod(..., actlength*scale)' is needed to get the repeats working + * - the '/ scale' is needed to ensure that scaling influences the timing within the repeat + */ + return strip->actstart + fmod(cframe - strip->start, actlength*scale) / scale; + } } } } -/* from editnla, for convert_action_to_strip -- no UI code so should be ok here.. */ -void find_stridechannel(Object *ob, bActionStrip *strip) +/* non clipped mapping for strip-time <-> global time (for Transitions) + * invert = convert action-strip time to global time + */ +static float nlastrip_get_frame_transition (NlaStrip *strip, float cframe, short mode) { - if(ob && ob->pose) { - bPoseChannel *pchan; - for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) - if(pchan->flag & POSE_STRIDE) - break; - if(pchan) - BLI_strncpy(strip->stridechannel, pchan->name, 32); + float length; + + /* length of strip */ + length= strip->end - strip->start; + + /* reversed = play strip backwards */ + if (strip->flag & NLASTRIP_FLAG_REVERSE) { + if (mode == NLATIME_CONVERT_MAP) + return strip->end - (length * cframe); + else + return (strip->end - cframe) / length; + } + else { + if (mode == NLATIME_CONVERT_MAP) + return (length * cframe) + strip->start; else - strip->stridechannel[0]= 0; + return (cframe - strip->start) / length; } } -//called by convert_nla / bpy api with an object with the action to be converted to a new strip -bActionStrip *convert_action_to_strip (Object *ob) +/* non clipped mapping for strip-time <-> global time + * mode = eNlaTime_ConvertModes[] -> NLATIME_CONVERT_* + * + * only secure for 'internal' (i.e. within AnimSys evaluation) operations, + * but should not be directly relied on for stuff which interacts with editors + */ +float nlastrip_get_frame (NlaStrip *strip, float cframe, short mode) +{ + switch (strip->type) { + case NLASTRIP_TYPE_META: /* meta - for now, does the same as transition (is really just an empty container) */ + case NLASTRIP_TYPE_TRANSITION: /* transition */ + return nlastrip_get_frame_transition(strip, cframe, mode); + + case NLASTRIP_TYPE_CLIP: /* action-clip (default) */ + default: + return nlastrip_get_frame_actionclip(strip, cframe, mode); + } +} + + +/* Non clipped mapping for strip-time <-> global time + * mode = eNlaTime_ConvertModesp[] -> NLATIME_CONVERT_* + * + * Public API method - perform this mapping using the given AnimData block + * and perform any necessary sanity checks on the value + */ +float BKE_nla_tweakedit_remap (AnimData *adt, float cframe, short mode) +{ + NlaStrip *strip; + + /* sanity checks + * - obviously we've got to have some starting data + * - when not in tweakmode, the active Action does not have any scaling applied :) + * - when in tweakmode, if the no-mapping flag is set, do not map + */ + if ((adt == NULL) || (adt->flag & ADT_NLA_EDIT_ON)==0 || (adt->flag & ADT_NLA_EDIT_NOMAP)) + return cframe; + + /* if the active-strip info has been stored already, access this, otherwise look this up + * and store for (very probable) future usage + */ + if (adt->actstrip == NULL) { + NlaTrack *nlt= BKE_nlatrack_find_active(&adt->nla_tracks); + adt->actstrip= BKE_nlastrip_find_active(nlt); + } + strip= adt->actstrip; + + /* sanity checks + * - in rare cases, we may not be able to find this strip for some reason (internal error) + * - for now, if the user has defined a curve to control the time, this correction cannot be performed + * reliably... + */ + if ((strip == NULL) || (strip->flag & NLASTRIP_FLAG_USR_TIME)) + return cframe; + + /* perform the correction now... */ + return nlastrip_get_frame(strip, cframe, mode); +} + +/* *************************************************** */ +/* NLA API */ + +/* List of Strips ------------------------------------ */ +/* (these functions are used for NLA-Tracks and also for nested/meta-strips) */ + +/* Check if there is any space in the given list to add the given strip */ +short BKE_nlastrips_has_space (ListBase *strips, float start, float end) +{ + NlaStrip *strip; + + /* sanity checks */ + if ((strips == NULL) || IS_EQ(start, end)) + return 0; + if (start > end) { + puts("BKE_nlastrips_has_space() error... start and end arguments swapped"); + SWAP(float, start, end); + } + + /* loop over NLA strips checking for any overlaps with this area... */ + for (strip= strips->first; strip; strip= strip->next) { + /* if start frame of strip is past the target end-frame, that means that + * we've gone past the window we need to check for, so things are fine + */ + if (strip->start > end) + return 1; + + /* if the end of the strip is greater than either of the boundaries, the range + * must fall within the extents of the strip + */ + if ((strip->end > start) || (strip->end > end)) + return 0; + } + + /* if we are still here, we haven't encountered any overlapping strips */ + return 1; +} + +/* Rearrange the strips in the track so that they are always in order + * (usually only needed after a strip has been moved) + */ +void BKE_nlastrips_sort_strips (ListBase *strips) { - bActionStrip *nstrip; + ListBase tmp = {NULL, NULL}; + NlaStrip *strip, *sstrip, *stripn; + + /* sanity checks */ + if ELEM(NULL, strips, strips->first) + return; + + /* we simply perform insertion sort on this list, since it is assumed that per track, + * there are only likely to be at most 5-10 strips + */ + for (strip= strips->first; strip; strip= stripn) { + short not_added = 1; + + stripn= strip->next; + + /* remove this strip from the list, and add it to the new list, searching from the end of + * the list, assuming that the lists are in order + */ + BLI_remlink(strips, strip); + + for (sstrip= tmp.last; sstrip; sstrip= sstrip->prev) { + /* check if add after */ + if (sstrip->end <= strip->start) { + BLI_insertlinkafter(&tmp, sstrip, strip); + not_added= 0; + break; + } + } + + /* add before first? */ + if (not_added) + BLI_addhead(&tmp, strip); + } + + /* reassign the start and end points of the strips */ + strips->first= tmp.first; + strips->last= tmp.last; +} - /* Make new actionstrip */ - nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip"); +/* Add the given NLA-Strip to the given list of strips, assuming that it + * isn't currently a member of another list + */ +short BKE_nlastrips_add_strip (ListBase *strips, NlaStrip *strip) +{ + NlaStrip *ns; + short not_added = 1; + + /* sanity checks */ + if ELEM(NULL, strips, strip) + return 0; + + /* check if any space to add */ + if (BKE_nlastrips_has_space(strips, strip->start, strip->end)==0) + return 0; + + /* find the right place to add the strip to the nominated track */ + for (ns= strips->first; ns; ns= ns->next) { + /* if current strip occurs after the new strip, add it before */ + if (ns->start > strip->end) { + BLI_insertlinkbefore(strips, ns, strip); + not_added= 0; + break; + } + } + if (not_added) { + /* just add to the end of the list of the strips then... */ + BLI_addtail(strips, strip); + } + + /* added... */ + return 1; +} + + +/* Meta-Strips ------------------------------------ */ + +/* Convert 'islands' (i.e. continuous string of) selected strips to be + * contained within 'Meta-Strips' which act as strips which contain strips. + * temp: are the meta-strips to be created 'temporary' ones used for transforms? + */ +void BKE_nlastrips_make_metas (ListBase *strips, short temp) +{ + NlaStrip *mstrip = NULL; + NlaStrip *strip, *stripn; + + /* sanity checks */ + if ELEM(NULL, strips, strips->first) + return; + + /* group all continuous chains of selected strips into meta-strips */ + for (strip= strips->first; strip; strip= stripn) { + stripn= strip->next; + + if (strip->flag & NLASTRIP_FLAG_SELECT) { + /* if there is an existing meta-strip, add this strip to it, otherwise, create a new one */ + if (mstrip == NULL) { + /* add a new meta-strip, and add it before the current strip that it will replace... */ + mstrip= MEM_callocN(sizeof(NlaStrip), "Meta-NlaStrip"); + mstrip->type = NLASTRIP_TYPE_META; + BLI_insertlinkbefore(strips, strip, mstrip); + + /* set flags */ + mstrip->flag = NLASTRIP_FLAG_SELECT; + + /* set temp flag if appropriate (i.e. for transform-type editing) */ + if (temp) + mstrip->flag |= NLASTRIP_FLAG_TEMP_META; + + /* set default repeat/scale values to prevent warnings */ + mstrip->repeat= mstrip->scale= 1.0f; + + /* make its start frame be set to the start frame of the current strip */ + mstrip->start= strip->start; + } + + /* remove the selected strips from the track, and add to the meta */ + BLI_remlink(strips, strip); + BLI_addtail(&mstrip->strips, strip); - /* Link the action to the nstrip */ - nstrip->act = ob->action; - id_us_plus(&nstrip->act->id); - calc_action_range(nstrip->act, &nstrip->actstart, &nstrip->actend, 1); - nstrip->start = nstrip->actstart; - nstrip->end = nstrip->actend; - nstrip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION; + /* expand the meta's dimensions to include the newly added strip- i.e. its last frame */ + mstrip->end= strip->end; + } + else { + /* current strip wasn't selected, so the end of 'island' of selected strips has been reached, + * so stop adding strips to the current meta + */ + mstrip= NULL; + } + } +} + +/* Split a meta-strip into a set of normal strips */ +void BKE_nlastrips_clear_metastrip (ListBase *strips, NlaStrip *strip) +{ + NlaStrip *cs, *csn; + + /* sanity check */ + if ELEM(NULL, strips, strip) + return; + + /* move each one of the meta-strip's children before the meta-strip + * in the list of strips after unlinking them from the meta-strip + */ + for (cs= strip->strips.first; cs; cs= csn) { + csn= cs->next; + BLI_remlink(&strip->strips, cs); + BLI_insertlinkbefore(strips, strip, cs); + } + + /* free the meta-strip now */ + BLI_freelinkN(strips, strip); +} + +/* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips + * sel: only consider selected meta-strips, otherwise all meta-strips are removed + * onlyTemp: only remove the 'temporary' meta-strips used for transforms + */ +void BKE_nlastrips_clear_metas (ListBase *strips, short onlySel, short onlyTemp) +{ + NlaStrip *strip, *stripn; + + /* sanity checks */ + if ELEM(NULL, strips, strips->first) + return; + + /* remove meta-strips fitting the criteria of the arguments */ + for (strip= strips->first; strip; strip= stripn) { + stripn= strip->next; + + /* check if strip is a meta-strip */ + if (strip->type == NLASTRIP_TYPE_META) { + /* if check if selection and 'temporary-only' considerations are met */ + if ((onlySel==0) || (strip->flag & NLASTRIP_FLAG_SELECT)) { + if ((!onlyTemp) || (strip->flag & NLASTRIP_FLAG_TEMP_META)) { + BKE_nlastrips_clear_metastrip(strips, strip); + } + } + } + } +} + +/* Add the given NLA-Strip to the given Meta-Strip, assuming that the + * strip isn't attached to anyy list of strips + */ +short BKE_nlameta_add_strip (NlaStrip *mstrip, NlaStrip *strip) +{ + /* sanity checks */ + if ELEM(NULL, mstrip, strip) + return 0; + + /* firstly, check if the meta-strip has space for this */ + if (BKE_nlastrips_has_space(&mstrip->strips, strip->start, strip->end) == 0) + return 0; + + /* check if this would need to be added to the ends of the meta, + * and subsequently, if the neighbouring strips allow us enough room + */ + if (strip->start < mstrip->start) { + /* check if strip to the left (if it exists) ends before the + * start of the strip we're trying to add + */ + if ((mstrip->prev == NULL) || (mstrip->prev->end <= strip->start)) { + /* add strip to start of meta's list, and expand dimensions */ + BLI_addhead(&mstrip->strips, strip); + mstrip->start= strip->start; - find_stridechannel(ob, nstrip); - //set_active_strip(ob, nstrip); /* is in editnla as does UI calls */ + return 1; + } + else /* failed... no room before */ + return 0; + } + else if (strip->end > mstrip->end) { + /* check if strip to the right (if it exists) starts before the + * end of the strip we're trying to add + */ + if ((mstrip->next == NULL) || (mstrip->next->start >= strip->end)) { + /* add strip to end of meta's list, and expand dimensions */ + BLI_addtail(&mstrip->strips, strip); + mstrip->end= strip->end; - nstrip->repeat = 1.0; + return 1; + } + else /* failed... no room after */ + return 0; + } + else { + /* just try to add to the meta-strip (no dimension changes needed) */ + return BKE_nlastrips_add_strip(&mstrip->strips, strip); + } +} - if(ob->nlastrips.first == NULL) - ob->nlaflag |= OB_NLA_OVERRIDE; +/* Adjust the settings of NLA-Strips contained within a Meta-Strip (recursively), + * until the Meta-Strips children all fit within the Meta-Strip's new dimensions + */ +void BKE_nlameta_flush_transforms (NlaStrip *mstrip) +{ + NlaStrip *strip; + float oStart, oEnd, offset; + float oLen, nLen; + short scaleChanged= 0; + + /* sanity checks + * - strip must exist + * - strip must be a meta-strip with some contents + */ + if ELEM(NULL, mstrip, mstrip->strips.first) + return; + if (mstrip->type != NLASTRIP_TYPE_META) + return; + + /* get the original start/end points, and calculate the start-frame offset + * - these are simply the start/end frames of the child strips, + * since we assume they weren't transformed yet + */ + oStart= ((NlaStrip *)mstrip->strips.first)->start; + oEnd= ((NlaStrip *)mstrip->strips.last)->end; + offset= mstrip->start - oStart; - BLI_addtail(&ob->nlastrips, nstrip); - return nstrip; /* is created, malloced etc. here so is safe to just return the pointer? - this is needed for setting this active in UI, and probably useful for API too */ + /* optimisation: + * don't flush if nothing changed yet + * TODO: maybe we need a flag to say always flush? + */ + if (IS_EQ(oStart, mstrip->start) && IS_EQ(oEnd, mstrip->end)) + return; + /* check if scale changed */ + oLen = oEnd - oStart; + nLen = mstrip->end - mstrip->start; + if (IS_EQ(nLen, oLen) == 0) + scaleChanged= 1; + + /* for each child-strip, calculate new start/end points based on this new info */ + for (strip= mstrip->strips.first; strip; strip= strip->next) { + if (scaleChanged) { + PointerRNA ptr; + float p1, p2, nStart, nEnd; + + /* compute positions of endpoints relative to old extents of strip */ + p1= (strip->start - oStart) / oLen; + p2= (strip->end - oStart) / oLen; + + /* compute the new strip endpoints using the proportions */ + nStart= (p1 * nLen) + mstrip->start; + nEnd= (p2 * nLen) + mstrip->start; + + /* firstly, apply the new positions manually, then apply using RNA + * - first time is to make sure no truncation errors from one endpoint not being + * set yet occur + * - second time is to make sure scale is computed properly... + */ + strip->start= nStart; + strip->end= nEnd; + + RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &ptr); + RNA_float_set(&ptr, "start_frame", nStart); + RNA_float_set(&ptr, "end_frame", nEnd); + } + else { + /* just apply the changes in offset to both ends of the strip */ + strip->start += offset; + strip->end += offset; + } + + /* finally, make sure the strip's children (if it is a meta-itself), get updated */ + BKE_nlameta_flush_transforms(strip); + } } +/* NLA-Tracks ---------------------------------------- */ + +/* Find the active NLA-track for the given stack */ +NlaTrack *BKE_nlatrack_find_active (ListBase *tracks) +{ + NlaTrack *nlt; + + /* sanity check */ + if ELEM(NULL, tracks, tracks->first) + return NULL; + + /* try to find the first active track */ + for (nlt= tracks->first; nlt; nlt= nlt->next) { + if (nlt->flag & NLATRACK_ACTIVE) + return nlt; + } + + /* none found */ + return NULL; +} -/* not strip itself! */ -void free_actionstrip(bActionStrip* strip) +/* Toggle the 'solo' setting for the given NLA-track, making sure that it is the only one + * that has this status in its AnimData block. + */ +void BKE_nlatrack_solo_toggle (AnimData *adt, NlaTrack *nlt) { - if (!strip) + NlaTrack *nt; + + /* sanity check */ + if ELEM(NULL, adt, adt->nla_tracks.first) return; + + /* firstly, make sure 'solo' flag for all tracks is disabled */ + for (nt= adt->nla_tracks.first; nt; nt= nt->next) { + if (nt != nlt) + nt->flag &= ~NLATRACK_SOLO; + } + + /* now, enable 'solo' for the given track if appropriate */ + if (nlt) { + /* toggle solo status */ + nlt->flag ^= NLATRACK_SOLO; + + /* set or clear solo-status on AnimData */ + if (nlt->flag & NLATRACK_SOLO) + adt->flag |= ADT_NLA_SOLO_TRACK; + else + adt->flag &= ~ADT_NLA_SOLO_TRACK; + } + else + adt->flag &= ~ADT_NLA_SOLO_TRACK; +} - if (strip->act){ - strip->act->id.us--; - strip->act = NULL; +/* Make the given NLA-track the active one for the given stack. If no track is provided, + * this function can be used to simply deactivate all the NLA tracks in the given stack too. + */ +void BKE_nlatrack_set_active (ListBase *tracks, NlaTrack *nlt_a) +{ + NlaTrack *nlt; + + /* sanity check */ + if ELEM(NULL, tracks, tracks->first) + return; + + /* deactive all the rest */ + for (nlt= tracks->first; nlt; nlt= nlt->next) + nlt->flag &= ~NLATRACK_ACTIVE; + + /* set the given one as the active one */ + if (nlt_a) + nlt_a->flag |= NLATRACK_ACTIVE; +} + +/* Check if there is any space in the given track to add a strip of the given length */ +short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end) +{ + /* sanity checks */ + if ((nlt == NULL) || IS_EQ(start, end)) + return 0; + if (start > end) { + puts("BKE_nlatrack_has_space() error... start and end arguments swapped"); + SWAP(float, start, end); + } + + /* check if there's any space left in the track for a strip of the given length */ + return BKE_nlastrips_has_space(&nlt->strips, start, end); +} + +/* Rearrange the strips in the track so that they are always in order + * (usually only needed after a strip has been moved) + */ +void BKE_nlatrack_sort_strips (NlaTrack *nlt) +{ + /* sanity checks */ + if ELEM(NULL, nlt, nlt->strips.first) + return; + + /* sort the strips with a more generic function */ + BKE_nlastrips_sort_strips(&nlt->strips); +} + +/* Add the given NLA-Strip to the given NLA-Track, assuming that it + * isn't currently attached to another one + */ +short BKE_nlatrack_add_strip (NlaTrack *nlt, NlaStrip *strip) +{ + /* sanity checks */ + if ELEM(NULL, nlt, strip) + return 0; + + /* try to add the strip to the track using a more generic function */ + return BKE_nlastrips_add_strip(&nlt->strips, strip); +} + +/* NLA Strips -------------------------------------- */ + +/* Find the active NLA-strip within the given track */ +NlaStrip *BKE_nlastrip_find_active (NlaTrack *nlt) +{ + NlaStrip *strip; + + /* sanity check */ + if ELEM(NULL, nlt, nlt->strips.first) + return NULL; + + /* try to find the first active strip */ + for (strip= nlt->strips.first; strip; strip= strip->next) { + if (strip->flag & NLASTRIP_FLAG_ACTIVE) + return strip; + } + + /* none found */ + return NULL; +} + +/* Make the given NLA-Strip the active one within the given block */ +void BKE_nlastrip_set_active (AnimData *adt, NlaStrip *strip) +{ + NlaTrack *nlt; + NlaStrip *nls; + + /* sanity checks */ + if (adt == NULL) + return; + + /* loop over tracks, deactivating*/ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + for (nls= nlt->strips.first; nls; nls= nls->next) { + if (nls != strip) + nls->flag &= ~NLASTRIP_FLAG_ACTIVE; + else + nls->flag |= NLASTRIP_FLAG_ACTIVE; + } } - if (strip->ipo){ - strip->ipo->id.us--; - strip->ipo = NULL; +} + + +/* Does the given NLA-strip fall within the given bounds (times)? */ +short BKE_nlastrip_within_bounds (NlaStrip *strip, float min, float max) +{ + const float stripLen= (strip) ? strip->end - strip->start : 0.0f; + const float boundsLen= (float)fabs(max - min); + + /* sanity checks */ + if ((strip == NULL) || IS_EQ(stripLen, 0.0f) || IS_EQ(boundsLen, 0.0f)) + return 0; + + /* only ok if at least part of the strip is within the bounding window + * - first 2 cases cover when the strip length is less than the bounding area + * - second 2 cases cover when the strip length is greater than the bounding area + */ + if ( (stripLen < boundsLen) && + !(IN_RANGE(strip->start, min, max) || + IN_RANGE(strip->end, min, max)) ) + { + return 0; } - if (strip->modifiers.first) { - BLI_freelistN(&strip->modifiers); + if ( (stripLen > boundsLen) && + !(IN_RANGE(min, strip->start, strip->end) || + IN_RANGE(max, strip->start, strip->end)) ) + { + return 0; + } + + /* should be ok! */ + return 1; +} + +/* Is the given NLA-strip the first one to occur for the given AnimData block */ +// TODO: make this an api method if necesary, but need to add prefix first +short nlastrip_is_first (AnimData *adt, NlaStrip *strip) +{ + NlaTrack *nlt; + NlaStrip *ns; + + /* sanity checks */ + if ELEM(NULL, adt, strip) + return 0; + + /* check if strip has any strips before it */ + if (strip->prev) + return 0; + + /* check other tracks to see if they have a strip that's earlier */ + // TODO: or should we check that the strip's track is also the first? + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + /* only check the first strip, assuming that they're all in order */ + ns= nlt->strips.first; + if (ns) { + if (ns->start < strip->start) + return 0; + } + } + + /* should be first now */ + return 1; +} + +/* Animated Strips ------------------------------------------- */ + +/* Check if the given NLA-Track has any strips with own F-Curves */ +short BKE_nlatrack_has_animated_strips (NlaTrack *nlt) +{ + NlaStrip *strip; + + /* sanity checks */ + if ELEM(NULL, nlt, nlt->strips.first) + return 0; + + /* check each strip for F-Curves only (don't care about whether the flags are set) */ + for (strip= nlt->strips.first; strip; strip= strip->next) { + if (strip->fcurves.first) + return 1; } + /* none found */ + return 0; } -void free_nlastrips (ListBase *nlalist) +/* Check if given NLA-Tracks have any strips with own F-Curves */ +short BKE_nlatracks_have_animated_strips (ListBase *tracks) { - bActionStrip *strip; + NlaTrack *nlt; + + /* sanity checks */ + if ELEM(NULL, tracks, tracks->first) + return 0; + + /* check each track, stopping on the first hit */ + for (nlt= tracks->first; nlt; nlt= nlt->next) { + if (BKE_nlatrack_has_animated_strips(nlt)) + return 1; + } + + /* none found */ + return 0; +} - if (!nlalist->first) +/* Validate the NLA-Strips 'control' F-Curves based on the flags set*/ +void BKE_nlastrip_validate_fcurves (NlaStrip *strip) +{ + FCurve *fcu; + + /* sanity checks */ + if (strip == NULL) return; + + /* if controlling influence... */ + if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) { + /* try to get F-Curve */ + fcu= list_find_fcurve(&strip->fcurves, "influence", 0); + + /* add one if not found */ + if (fcu == NULL) { + /* make new F-Curve */ + fcu= MEM_callocN(sizeof(FCurve), "NlaStrip FCurve"); + BLI_addtail(&strip->fcurves, fcu); + + /* set default flags */ + fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); + + /* store path - make copy, and store that */ + fcu->rna_path= BLI_strdupn("influence", 9); + + // TODO: insert a few keyframes to ensure default behaviour? + } + } + + /* if controlling time... */ + if (strip->flag & NLASTRIP_FLAG_USR_TIME) { + /* try to get F-Curve */ + fcu= list_find_fcurve(&strip->fcurves, "strip_time", 0); + + /* add one if not found */ + if (fcu == NULL) { + /* make new F-Curve */ + fcu= MEM_callocN(sizeof(FCurve), "NlaStrip FCurve"); + BLI_addtail(&strip->fcurves, fcu); + + /* set default flags */ + fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED); + + /* store path - make copy, and store that */ + fcu->rna_path= BLI_strdupn("strip_time", 10); + + // TODO: insert a few keyframes to ensure default behaviour? + } + } +} - /* Do any specific freeing */ - for (strip=nlalist->first; strip; strip=strip->next) +/* Sanity Validation ------------------------------------ */ + +/* Find (and set) a unique name for a strip from the whole AnimData block + * Uses a similar method to the BLI method, but is implemented differently + * as we need to ensure that the name is unique over several lists of tracks, + * not just a single track. + */ +void BKE_nlastrip_validate_name (AnimData *adt, NlaStrip *strip) +{ + GHash *gh; + NlaStrip *tstrip; + NlaTrack *nlt; + + /* sanity checks */ + if ELEM(NULL, adt, strip) + return; + + /* give strip a default name if none already */ + if (strip->name[0]==0) { + switch (strip->type) { + case NLASTRIP_TYPE_CLIP: /* act-clip */ + sprintf(strip->name, "Act: %s", (strip->act)?(strip->act->id.name+2):("<None>")); + break; + case NLASTRIP_TYPE_TRANSITION: /* transition */ + sprintf(strip->name, "Transition"); + break; + case NLASTRIP_TYPE_META: /* meta */ + sprintf(strip->name, "Meta"); + break; + default: + sprintf(strip->name, "NLA Strip"); + break; + } + } + + /* build a hash-table of all the strips in the tracks + * - this is easier than iterating over all the tracks+strips hierarchy everytime + * (and probably faster) + */ + gh= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp); + + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + for (tstrip= nlt->strips.first; tstrip; tstrip= tstrip->next) { + /* don't add the strip of interest */ + if (tstrip == strip) + continue; + + /* use the name of the strip as the key, and the strip as the value, since we're mostly interested in the keys */ + BLI_ghash_insert(gh, tstrip->name, tstrip); + } + } + + /* if the hash-table has a match for this name, try other names... + * - in an extreme case, it might not be able to find a name, but then everything else in Blender would fail too :) + */ + if (BLI_ghash_haskey(gh, strip->name)) { + char tempname[128]; + int number = 1; + char *dot; + + /* Strip off the suffix */ + dot = strchr(strip->name, '.'); + if (dot) *dot=0; + + /* Try different possibilities */ + for (number = 1; number <= 999; number++) { + /* assemble alternative name */ + BLI_snprintf(tempname, 128, "%s%c%03d", strip->name, ".", number); + + /* if hash doesn't have this, set it */ + if (BLI_ghash_haskey(gh, tempname) == 0) { + BLI_strncpy(strip->name, tempname, sizeof(strip->name)); + break; + } + } + } + + /* free the hash... */ + BLI_ghash_free(gh, NULL, NULL); +} + +/* ---- */ + +/* Get strips which overlap the given one at the start/end of its range + * - strip: strip that we're finding overlaps for + * - track: nla-track that the overlapping strips should be found from + * - start, end: frames for the offending endpoints + */ +static void nlastrip_get_endpoint_overlaps (NlaStrip *strip, NlaTrack *track, float **start, float **end) +{ + NlaStrip *nls; + + /* find strips that overlap over the start/end of the given strip, + * but which don't cover the entire length + */ + // TODO: this scheme could get quite slow for doing this on many strips... + for (nls= track->strips.first; nls; nls= nls->next) { + /* check if strip overlaps (extends over or exactly on) the entire range of the strip we're validating */ + if ((nls->start <= strip->start) && (nls->end >= strip->end)) { + *start= NULL; + *end= NULL; + return; + } + + /* check if strip doesn't even occur anywhere near... */ + if (nls->end < strip->start) + continue; /* skip checking this strip... not worthy of mention */ + if (nls->start > strip->end) + return; /* the range we're after has already passed */ + + /* if this strip is not part of an island of continuous strips, it can be used + * - this check needs to be done for each end of the strip we try and use... + */ + if ((nls->next == NULL) || IS_EQ(nls->next->start, nls->end)==0) { + if ((nls->end > strip->start) && (nls->end < strip->end)) + *start= &nls->end; + } + if ((nls->prev == NULL) || IS_EQ(nls->prev->end, nls->start)==0) { + if ((nls->start < strip->end) && (nls->start > strip->start)) + *end= &nls->start; + } + } +} + +/* Determine auto-blending for the given strip */ +void BKE_nlastrip_validate_autoblends (NlaTrack *nlt, NlaStrip *nls) +{ + float *ps=NULL, *pe=NULL; + float *ns=NULL, *ne=NULL; + + /* sanity checks */ + if ELEM(NULL, nls, nlt) + return; + if ((nlt->prev == NULL) && (nlt->next == NULL)) + return; + if ((nls->flag & NLASTRIP_FLAG_AUTO_BLENDS)==0) + return; + + /* get test ranges */ + if (nlt->prev) + nlastrip_get_endpoint_overlaps(nls, nlt->prev, &ps, &pe); + if (nlt->next) + nlastrip_get_endpoint_overlaps(nls, nlt->next, &ns, &ne); + + /* set overlaps for this strip + * - don't use the values obtained though if the end in question + * is directly followed/preceeded by another strip, forming an + * 'island' of continuous strips + */ + if ( (ps || ns) && ((nls->prev == NULL) || IS_EQ(nls->prev->end, nls->start)==0) ) { - free_actionstrip (strip); - }; + /* start overlaps - pick the largest overlap */ + if ( ((ps && ns) && (*ps > *ns)) || (ps) ) + nls->blendin= *ps - nls->start; + else + nls->blendin= *ns - nls->start; + } + else /* no overlap allowed/needed */ + nls->blendin= 0.0f; + + if ( (pe || ne) && ((nls->next == NULL) || IS_EQ(nls->next->start, nls->end)==0) ) + { + /* end overlaps - pick the largest overlap */ + if ( ((pe && ne) && (*pe > *ne)) || (pe) ) + nls->blendout= nls->end - *pe; + else + nls->blendout= nls->end - *ne; + } + else /* no overlap allowed/needed */ + nls->blendout= 0.0f; +} - /* Free the whole list */ - BLI_freelistN(nlalist); +/* Ensure that auto-blending and other settings are set correctly */ +void BKE_nla_validate_state (AnimData *adt) +{ + NlaStrip *strip, *fstrip=NULL; + NlaTrack *nlt; + + /* sanity checks */ + if ELEM(NULL, adt, adt->nla_tracks.first) + return; + + /* adjust blending values for auto-blending, and also do an initial pass to find the earliest strip */ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + for (strip= nlt->strips.first; strip; strip= strip->next) { + /* auto-blending first */ + BKE_nlastrip_validate_autoblends(nlt, strip); + + /* extend mode - find first strip */ + if ((fstrip == NULL) || (strip->start < fstrip->start)) + fstrip= strip; + } + } + + /* second pass over the strips to adjust the extend-mode to fix any problems */ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + for (strip= nlt->strips.first; strip; strip= strip->next) { + /* apart from 'nothing' option which user has to explicitly choose, we don't really know if + * we should be overwriting the extend setting (but assume that's what the user wanted) + */ + // TODO: 1 solution is to tie this in with auto-blending... + if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) { + if (strip == fstrip) + strip->extendmode= NLASTRIP_EXTEND_HOLD; + else + strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD; + } + } + } } + +/* Core Tools ------------------------------------------- */ + +/* For the given AnimData block, add the active action to the NLA + * stack (i.e. 'push-down' action). The UI should only allow this + * for normal editing only (i.e. not in editmode for some strip's action), + * so no checks for this are performed. + */ +// TODO: maybe we should have checks for this too... +void BKE_nla_action_pushdown (AnimData *adt) +{ + NlaStrip *strip; + + /* sanity checks */ + // TODO: need to report the error for this + if ELEM(NULL, adt, adt->action) + return; + + /* if the action is empty, we also shouldn't try to add to stack, + * as that will cause us grief down the track + */ + // TODO: what about modifiers? + if (action_has_motion(adt->action) == 0) { + printf("BKE_nla_action_pushdown(): action has no data \n"); + return; + } + + /* add a new NLA strip to the track, which references the active action */ + strip= add_nlastrip_to_stack(adt, adt->action); + + /* do other necessary work on strip */ + if (strip) { + /* clear reference to action now that we've pushed it onto the stack */ + adt->action->id.us--; + adt->action= NULL; + + /* if the strip is the first one in the track it lives in, check if there + * are strips in any other tracks that may be before this, and set the extend + * mode accordingly + */ + if (nlastrip_is_first(adt, strip) == 0) { + /* not first, so extend mode can only be NLASTRIP_EXTEND_HOLD_FORWARD not NLASTRIP_EXTEND_HOLD, + * so that it doesn't override strips in previous tracks + */ + // FIXME: this needs to be more automated, since user can rearrange strips + strip->extendmode= NLASTRIP_EXTEND_HOLD_FORWARD; + } + + /* make strip the active one... */ + BKE_nlastrip_set_active(adt, strip); + } +} + + +/* Find the active strip + track combo, and set them up as the tweaking track, + * and return if successful or not. + */ +short BKE_nla_tweakmode_enter (AnimData *adt) +{ + NlaTrack *nlt, *activeTrack=NULL; + NlaStrip *strip, *activeStrip=NULL; + + /* verify that data is valid */ + if ELEM(NULL, adt, adt->nla_tracks.first) + return 0; + + /* if block is already in tweakmode, just leave, but we should report + * that this block is in tweakmode (as our returncode) + */ + if (adt->flag & ADT_NLA_EDIT_ON) + return 1; + + /* go over the tracks, finding the active one, and its active strip + * - if we cannot find both, then there's nothing to do + */ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + /* check if active */ + if (nlt->flag & NLATRACK_ACTIVE) { + /* store reference to this active track */ + activeTrack= nlt; + + /* now try to find active strip */ + activeStrip= BKE_nlastrip_find_active(nlt); + break; + } + } + if ELEM3(NULL, activeTrack, activeStrip, activeStrip->act) { + printf("NLA tweakmode enter - neither active requirement found \n"); + return 0; + } + + /* go over all the tracks up to the active one, tagging each strip that uses the same + * action as the active strip, but leaving everything else alone + */ + for (nlt= activeTrack->prev; nlt; nlt= nlt->prev) { + for (strip= nlt->strips.first; strip; strip= strip->next) { + if (strip->act == activeStrip->act) + strip->flag |= NLASTRIP_FLAG_TWEAKUSER; + else + strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER; + } + } + + + /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled + * - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on + */ + for (nlt= activeTrack; nlt; nlt= nlt->next) + nlt->flag |= NLATRACK_DISABLED; + + /* handle AnimData level changes: + * - 'real' active action to temp storage (no need to change user-counts) + * - action of active strip set to be the 'active action', and have its usercount incremented + * - editing-flag for this AnimData block should also get turned on (for more efficient restoring) + * - take note of the active strip for mapping-correction of keyframes in the action being edited + */ + adt->tmpact= adt->action; + adt->action= activeStrip->act; + adt->actstrip= activeStrip; + id_us_plus(&activeStrip->act->id); + adt->flag |= ADT_NLA_EDIT_ON; + + /* done! */ + return 1; +} + +/* Exit tweakmode for this AnimData block */ +void BKE_nla_tweakmode_exit (AnimData *adt) +{ + NlaStrip *strip; + NlaTrack *nlt; + + /* verify that data is valid */ + if ELEM(NULL, adt, adt->nla_tracks.first) + return; + + /* hopefully the flag is correct - skip if not on */ + if ((adt->flag & ADT_NLA_EDIT_ON) == 0) + return; + + // TODO: need to sync the user-strip with the new state of the action! + + /* for all Tracks, clear the 'disabled' flag + * for all Strips, clear the 'tweak-user' flag + */ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + nlt->flag &= ~NLATRACK_DISABLED; + + for (strip= nlt->strips.first; strip; strip= strip->next) + strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER; + } + + /* handle AnimData level changes: + * - 'temporary' active action needs its usercount decreased, since we're removing this reference + * - 'real' active action is restored from storage + * - storage pointer gets cleared (to avoid having bad notes hanging around) + * - editing-flag for this AnimData block should also get turned off + * - clear pointer to active strip + */ + if (adt->action) adt->action->id.us--; + adt->action= adt->tmpact; + adt->tmpact= NULL; + adt->actstrip= NULL; + adt->flag &= ~ADT_NLA_EDIT_ON; +} + +/* *************************************************** */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 62064799aca..0f42ba0d2e2 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -994,7 +994,7 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node, int internal) *nnode= *node; BLI_addtail(&ntree->nodes, nnode); - duplicatelist(&nnode->inputs, &node->inputs); + BLI_duplicatelist(&nnode->inputs, &node->inputs); oldsock= node->inputs.first; for(sock= nnode->inputs.first; sock; sock= sock->next, oldsock= oldsock->next) { oldsock->new_sock= sock; @@ -1002,7 +1002,7 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node, int internal) sock->own_index= 0; } - duplicatelist(&nnode->outputs, &node->outputs); + BLI_duplicatelist(&nnode->outputs, &node->outputs); oldsock= node->outputs.first; for(sock= nnode->outputs.first; sock; sock= sock->next, oldsock= oldsock->next) { if(internal) @@ -1012,8 +1012,7 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node, int internal) oldsock->new_sock= sock; } - if(nnode->id) - nnode->id->us++; + /* don't increase node->id users, freenode doesn't decrement either */ if(node->typeinfo->copystoragefunc) node->typeinfo->copystoragefunc(node, nnode); @@ -1056,6 +1055,14 @@ bNodeTree *ntreeAddTree(int type) ntree->type= type; ntree->alltypes.first = NULL; ntree->alltypes.last = NULL; + + /* this helps RNA identify ID pointers as nodetree */ + if(ntree->type==NTREE_SHADER) + BLI_strncpy(ntree->id.name, "NTShader Nodetree", sizeof(ntree->id.name)); + else if(ntree->type==NTREE_COMPOSIT) + BLI_strncpy(ntree->id.name, "NTComposit Nodetree", sizeof(ntree->id.name)); + else if(ntree->type==NTREE_TEXTURE) + BLI_strncpy(ntree->id.name, "NTTexture Nodetree", sizeof(ntree->id.name)); ntreeInitTypes(ntree); return ntree; @@ -1124,7 +1131,8 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select) /* check for copying links */ for(link= ntree->links.first; link; link= link->next) { - if(link->fromnode->new_node && link->tonode->new_node) { + if(link->fromnode==NULL || link->tonode==NULL); + else if(link->fromnode->new_node && link->tonode->new_node) { nlink= nodeAddLink(newtree, link->fromnode->new_node, NULL, link->tonode->new_node, NULL); /* sockets were copied in order */ for(a=0, sock= link->fromnode->outputs.first; sock; sock= sock->next, a++) { @@ -1158,6 +1166,104 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select) return newtree; } +/* *************** preview *********** */ +/* if node->preview, then we assume the rect to exist */ + +static void node_free_preview(bNode *node) +{ + if(node->preview) { + if(node->preview->rect) + MEM_freeN(node->preview->rect); + MEM_freeN(node->preview); + node->preview= NULL; + } +} + +static void node_init_preview(bNode *node, int xsize, int ysize) +{ + + if(node->preview==NULL) { + node->preview= MEM_callocN(sizeof(bNodePreview), "node preview"); + // printf("added preview %s\n", node->name); + } + + /* node previews can get added with variable size this way */ + if(xsize==0 || ysize==0) + return; + + /* sanity checks & initialize */ + if(node->preview->rect) { + if(node->preview->xsize!=xsize && node->preview->ysize!=ysize) { + MEM_freeN(node->preview->rect); + node->preview->rect= NULL; + } + } + + if(node->preview->rect==NULL) { + node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(float)*4, "node preview rect"); + node->preview->xsize= xsize; + node->preview->ysize= ysize; + } +} + +void ntreeInitPreview(bNodeTree *ntree, int xsize, int ysize) +{ + bNode *node; + + if(ntree==NULL) + return; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->flag & NODE_PREVIEW) /* hrms, check for closed nodes? */ + node_init_preview(node, xsize, ysize); + if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT)) + ntreeInitPreview((bNodeTree *)node->id, xsize, ysize); + } +} + +static void nodeClearPreview(bNode *node) +{ + if(node->preview && node->preview->rect) + memset(node->preview->rect, 0, MEM_allocN_len(node->preview->rect)); +} + +/* use it to enforce clear */ +void ntreeClearPreview(bNodeTree *ntree) +{ + bNode *node; + + if(ntree==NULL) + return; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->flag & NODE_PREVIEW) + nodeClearPreview(node); + if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT)) + ntreeClearPreview((bNodeTree *)node->id); + } +} + +/* hack warning! this function is only used for shader previews, and +since it gets called multiple times per pixel for Ztransp we only +add the color once. Preview gets cleared before it starts render though */ +void nodeAddToPreview(bNode *node, float *col, int x, int y) +{ + bNodePreview *preview= node->preview; + if(preview) { + if(x>=0 && y>=0) { + if(x<preview->xsize && y<preview->ysize) { + float *tar= preview->rect+ 4*((preview->xsize*y) + x); + //if(tar[0]==0.0f) { + QUATCOPY(tar, col); + //} + } + //else printf("prv out bound x y %d %d\n", x, y); + } + //else printf("prv out bound x y %d %d\n", x, y); + } +} + + /* ************** Free stuff ********** */ /* goes over entire tree */ @@ -1215,11 +1321,8 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node) BLI_freelistN(&node->inputs); BLI_freelistN(&node->outputs); - if(node->preview) { - if(node->preview->rect) - MEM_freeN(node->preview->rect); - MEM_freeN(node->preview); - } + node_free_preview(node); + if(node->typeinfo && node->typeinfo->freestoragefunc) { node->typeinfo->freestoragefunc(node); } @@ -1653,14 +1756,8 @@ void NodeTagChanged(bNodeTree *ntree, bNode *node) for(sock= node->outputs.first; sock; sock= sock->next) { if(sock->ns.data) { - free_compbuf(sock->ns.data); - sock->ns.data= NULL; - - //if(node->preview && node->preview->rect) { - // MEM_freeN(node->preview->rect); - // node->preview->rect= NULL; - //} - + //free_compbuf(sock->ns.data); + //sock->ns.data= NULL; } } node->need_exec= 1; @@ -1682,95 +1779,6 @@ void NodeTagIDChanged(bNodeTree *ntree, ID *id) } -/* *************** preview *********** */ - -/* if node->preview, then we assume the rect to exist */ - -static void nodeInitPreview(bNode *node, int xsize, int ysize) -{ - - if(node->preview==NULL) { - node->preview= MEM_callocN(sizeof(bNodePreview), "node preview"); -// printf("added preview %s\n", node->name); - } - - /* node previews can get added with variable size this way */ - if(xsize==0 || ysize==0) - return; - - /* sanity checks & initialize */ - if(node->preview->rect) { - if(node->preview->xsize!=xsize && node->preview->ysize!=ysize) { - MEM_freeN(node->preview->rect); - node->preview->rect= NULL; - } - } - - if(node->preview->rect==NULL) { - node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(float)*4, "node preview rect"); - node->preview->xsize= xsize; - node->preview->ysize= ysize; - } -} - -void ntreeInitPreview(bNodeTree *ntree, int xsize, int ysize) -{ - bNode *node; - - if(ntree==NULL) - return; - - for(node= ntree->nodes.first; node; node= node->next) { - if(node->typeinfo->flag & NODE_PREVIEW) /* hrms, check for closed nodes? */ - nodeInitPreview(node, xsize, ysize); - if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT)) - ntreeInitPreview((bNodeTree *)node->id, xsize, ysize); - } -} - -static void nodeClearPreview(bNode *node) -{ - if(node->preview && node->preview->rect) - memset(node->preview->rect, 0, MEM_allocN_len(node->preview->rect)); -} - -/* use it to enforce clear */ -void ntreeClearPreview(bNodeTree *ntree) -{ - bNode *node; - - if(ntree==NULL) - return; - - for(node= ntree->nodes.first; node; node= node->next) { - if(node->typeinfo->flag & NODE_PREVIEW) - nodeClearPreview(node); - if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT)) - ntreeClearPreview((bNodeTree *)node->id); - } -} - -/* hack warning! this function is only used for shader previews, and - since it gets called multiple times per pixel for Ztransp we only - add the color once. Preview gets cleared before it starts render though */ -void nodeAddToPreview(bNode *node, float *col, int x, int y) -{ - bNodePreview *preview= node->preview; - if(preview) { - if(x>=0 && y>=0) { - if(x<preview->xsize && y<preview->ysize) { - float *tar= preview->rect+ 4*((preview->xsize*y) + x); - if(tar[0]==0.0f) { - QUATCOPY(tar, col); - } - } - //else printf("prv out bound x y %d %d\n", x, y); - } - //else printf("prv out bound x y %d %d\n", x, y); - } -} - - /* ******************* executing ************* */ @@ -2223,7 +2231,7 @@ static void *exec_composite_node(void *node_v) bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ bNode *node= node_v; - ThreadData *thd= (ThreadData *)node->new_node; /* abuse */ + ThreadData *thd= (ThreadData *)node->threaddata; node_get_stack(node, thd->stack, nsin, nsout); @@ -2287,8 +2295,10 @@ static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd) /* is sock in use? */ else if(sock->link) { bNodeLink *link= sock->link; + /* this is the test for a cyclic case */ - if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) { + if(link->fromnode==NULL || link->tonode==NULL); + else if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) { if(link->fromnode->need_exec) { node->need_exec= 1; break; @@ -2318,7 +2328,7 @@ static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd) } else { /* tag for getExecutableNode() */ - node->exec= NODE_READY|NODE_FINISHED; + node->exec= NODE_READY|NODE_FINISHED|NODE_SKIPPED; } } @@ -2428,7 +2438,7 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview) /* sets need_exec tags in nodes */ totnode= setExecutableNodes(ntree, &thdata); - + BLI_init_threads(&threads, exec_composite_node, rd->threads); while(rendering) { @@ -2436,17 +2446,17 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview) if(BLI_available_threads(&threads)) { node= getExecutableNode(ntree); if(node) { - + if(ntree->timecursor) - ntree->timecursor(totnode); + ntree->timecursor(ntree->tch, totnode); if(ntree->stats_draw) { char str[64]; sprintf(str, "Compositing %d %s", totnode, node->name); - ntree->stats_draw(str); + ntree->stats_draw(ntree->sdh, str); } totnode--; - node->new_node = (bNode *)&thdata; + node->threaddata = &thdata; node->exec= NODE_PROCESSING; BLI_insert_thread(&threads, node); } @@ -2458,7 +2468,7 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview) rendering= 0; /* test for ESC */ - if(ntree->test_break && ntree->test_break()) { + if(ntree->test_break && ntree->test_break(ntree->tbh)) { for(node= ntree->nodes.first; node; node= node->next) node->exec |= NODE_READY; } @@ -2479,12 +2489,131 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview) } } - BLI_end_threads(&threads); ntreeEndExecTree(ntree); } + +/* ********** copy composite tree entirely, to allow threaded exec ******************* */ +/* ***************** do NOT execute this in a thread! ****************** */ + +/* returns localized composite tree for execution in threads */ +/* local tree then owns all compbufs */ +bNodeTree *ntreeLocalize(bNodeTree *ntree) +{ + bNodeTree *ltree= ntreeCopyTree(ntree, 0); + bNode *node; + bNodeSocket *sock; + + /* move over the compbufs */ + /* right after ntreeCopyTree() oldsock pointers are valid */ + for(node= ntree->nodes.first; node; node= node->next) { + + /* store new_node pointer to original */ + node->new_node->new_node= node; + /* ensure new user input gets handled ok */ + node->need_exec= 0; + + if(ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + if(node->id) { + if(node->flag & NODE_DO_OUTPUT) + node->new_node->id= (ID *)BKE_image_copy((Image *)node->id); + else + node->new_node->id= NULL; + } + } + + for(sock= node->outputs.first; sock; sock= sock->next) { + + sock->new_sock->ns.data= sock->ns.data; + sock->ns.data= NULL; + sock->new_sock->new_sock= sock; + } + } + + return ltree; +} + +static int node_exists(bNodeTree *ntree, bNode *testnode) +{ + bNode *node= ntree->nodes.first; + for(; node; node= node->next) + if(node==testnode) + return 1; + return 0; +} + +static int outsocket_exists(bNode *node, bNodeSocket *testsock) +{ + bNodeSocket *sock= node->outputs.first; + for(; sock; sock= sock->next) + if(sock==testsock) + return 1; + return 0; +} + + +/* sync local composite with real tree */ +/* local composite is supposed to be running, be careful moving previews! */ +void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree) +{ + bNode *lnode; + + /* move over the compbufs and previews */ + for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) { + if( (lnode->exec & NODE_READY) && !(lnode->exec & NODE_SKIPPED) ) { + if(node_exists(ntree, lnode->new_node)) { + + if(lnode->preview && lnode->preview->rect) { + node_free_preview(lnode->new_node); + lnode->new_node->preview= lnode->preview; + lnode->preview= NULL; + } + } + } + } +} + +/* merge local tree results back, and free local tree */ +/* we have to assume the editor already changed completely */ +void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree) +{ + bNode *lnode; + bNodeSocket *lsock; + + /* move over the compbufs and previews */ + for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) { + if(node_exists(ntree, lnode->new_node)) { + + if(lnode->preview && lnode->preview->rect) { + node_free_preview(lnode->new_node); + lnode->new_node->preview= lnode->preview; + lnode->preview= NULL; + } + + if(ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + if(lnode->id && (lnode->flag & NODE_DO_OUTPUT)) { + /* image_merge does sanity check for pointers */ + BKE_image_merge((Image *)lnode->new_node->id, (Image *)lnode->id); + } + } + + for(lsock= lnode->outputs.first; lsock; lsock= lsock->next) { + if(outsocket_exists(lnode->new_node, lsock->new_sock)) { + lsock->new_sock->ns.data= lsock->ns.data; + lsock->ns.data= NULL; + lsock->new_sock= NULL; + } + } + } + } + ntreeFreeTree(localtree); + MEM_freeN(localtree); +} + +/* *********************************************** */ + /* GPU material from shader nodes */ static void gpu_from_node_stack(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs) @@ -2646,7 +2775,7 @@ static void force_hidden_passes(bNode *node, int passflag) } /* based on rules, force sockets hidden always */ -void ntreeCompositForceHidden(bNodeTree *ntree) +void ntreeCompositForceHidden(bNodeTree *ntree, Scene *curscene) { bNode *node; @@ -2654,7 +2783,7 @@ void ntreeCompositForceHidden(bNodeTree *ntree) for(node= ntree->nodes.first; node; node= node->next) { if( node->type==CMP_NODE_R_LAYERS) { - Scene *sce= node->id?(Scene *)node->id:G.scene; /* G.scene is WEAK! */ + Scene *sce= node->id?(Scene *)node->id:curscene; SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1); if(srl) force_hidden_passes(node, srl->passflag); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index ec068c35c11..9423f80cba2 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -39,13 +39,14 @@ #include "MEM_guardedalloc.h" +#include "DNA_anim_types.h" #include "DNA_action_types.h" #include "DNA_armature_types.h" +#include "DNA_boid_types.h" #include "DNA_camera_types.h" #include "DNA_constraint_types.h" #include "DNA_curve_types.h" #include "DNA_group_types.h" -#include "DNA_ipo_types.h" #include "DNA_lamp_types.h" #include "DNA_lattice_types.h" #include "DNA_material_types.h" @@ -58,7 +59,7 @@ #include "DNA_object_types.h" #include "DNA_object_force.h" #include "DNA_object_fluidsim.h" -#include "DNA_oops_types.h" +#include "DNA_outliner_types.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -68,32 +69,31 @@ #include "DNA_view3d_types.h" #include "DNA_world_types.h" -#include "BKE_armature.h" -#include "BKE_action.h" -#include "BKE_bullet.h" -#include "BKE_colortools.h" -#include "BKE_deform.h" -#include "BKE_DerivedMesh.h" -#include "BKE_nla.h" - #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_editVert.h" #include "BKE_utildefines.h" -#include "BKE_bad_level_calls.h" #include "BKE_main.h" #include "BKE_global.h" +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_bullet.h" +#include "BKE_colortools.h" +#include "BKE_deform.h" +#include "BKE_DerivedMesh.h" +#include "BKE_nla.h" +#include "BKE_animsys.h" #include "BKE_anim.h" #include "BKE_blender.h" #include "BKE_constraint.h" #include "BKE_curve.h" #include "BKE_displist.h" +#include "BKE_fcurve.h" #include "BKE_group.h" #include "BKE_icons.h" -#include "BKE_ipo.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" @@ -117,25 +117,22 @@ #include "GPU_material.h" -#include "blendef.h" - /* Local function protos */ -static void solve_parenting (Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul); +static void solve_parenting (Scene *scene, Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul); float originmat[3][3]; /* after where_is_object(), can be used in other functions (bad!) */ -Object workob; -void clear_workob(void) +void clear_workob(Object *workob) { - memset(&workob, 0, sizeof(Object)); + memset(workob, 0, sizeof(Object)); - workob.size[0]= workob.size[1]= workob.size[2]= 1.0; + workob->size[0]= workob->size[1]= workob->size[2]= 1.0; } -void copy_baseflags() +void copy_baseflags(struct Scene *scene) { - Base *base= G.scene->base.first; + Base *base= scene->base.first; while(base) { base->object->flag= base->flag; @@ -143,9 +140,9 @@ void copy_baseflags() } } -void copy_objectflags() +void copy_objectflags(struct Scene *scene) { - Base *base= G.scene->base.first; + Base *base= scene->base.first; while(base) { base->flag= base->object->flag; @@ -153,9 +150,9 @@ void copy_objectflags() } } -void update_base_layer(Object *ob) +void update_base_layer(struct Scene *scene, Object *ob) { - Base *base= G.scene->base.first; + Base *base= scene->base.first; while (base) { if (base->object == ob) base->lay= ob->lay; @@ -248,13 +245,14 @@ void free_object(Object *ob) if(ob->mat[a]) ob->mat[a]->id.us--; } if(ob->mat) MEM_freeN(ob->mat); + if(ob->matbits) MEM_freeN(ob->matbits); ob->mat= 0; + ob->matbits= 0; if(ob->bb) MEM_freeN(ob->bb); ob->bb= 0; if(ob->path) free_path(ob->path); ob->path= 0; - if(ob->ipo) ob->ipo->id.us--; - if(ob->action) ob->action->id.us--; + if(ob->adt) BKE_free_animdata((ID *)ob); if(ob->poselib) ob->poselib->id.us--; if(ob->dup_group) ob->dup_group->id.us--; if(ob->defbase.first) @@ -269,12 +267,6 @@ void free_object(Object *ob) free_actuators(&ob->actuators); free_constraints(&ob->constraints); - free_constraint_channels(&ob->constraintChannels); - free_nlastrips(&ob->nlastrips); - -#ifndef DISABLE_PYTHON - BPY_free_scriptlink(&ob->scriptlink); -#endif if(ob->pd){ if(ob->pd->tex) @@ -295,7 +287,7 @@ static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Objec ob->recalc |= OB_RECALC; } } -void unlink_object(Object *ob) +void unlink_object(Scene *scene, Object *ob) { Object *obt; Material *mat; @@ -304,11 +296,10 @@ void unlink_object(Object *ob) Scene *sce; Curve *cu; Tex *tex; - Ipo *ipo; Group *group; Camera *camera; bConstraint *con; - bActionStrip *strip; + //bActionStrip *strip; // XXX animsys ModifierData *md; int a; @@ -418,6 +409,7 @@ void unlink_object(Object *ob) } /* strips */ +#if 0 // XXX old animation system for(strip= obt->nlastrips.first; strip; strip= strip->next) { if(strip->object==ob) strip->object= NULL; @@ -429,22 +421,22 @@ void unlink_object(Object *ob) amod->ob= NULL; } } +#endif // XXX old animation system /* particle systems */ if(obt->particlesystem.first) { ParticleSystem *tpsys= obt->particlesystem.first; for(; tpsys; tpsys=tpsys->next) { - if(tpsys->keyed_ob==ob) { - ParticleSystem *psys= BLI_findlink(&ob->particlesystem,tpsys->keyed_psys-1); + BoidState *state = NULL; + BoidRule *rule = NULL; - if(psys && psys->keyed_ob) { - tpsys->keyed_ob= psys->keyed_ob; - tpsys->keyed_psys= psys->keyed_psys; + ParticleTarget *pt = tpsys->targets.first; + for(; pt; pt=pt->next) { + if(pt->ob==ob) { + pt->ob = NULL; + obt->recalc |= OB_RECALC_DATA; + break; } - else - tpsys->keyed_ob= NULL; - - obt->recalc |= OB_RECALC_DATA; } if(tpsys->target_ob==ob) { @@ -466,6 +458,22 @@ void unlink_object(Object *ob) } } } + if(tpsys->part->boids) { + for(state = tpsys->part->boids->states.first; state; state=state->next) { + for(rule = state->rules.first; rule; rule=rule->next) { + if(rule->type==eBoidRuleType_Avoid) { + BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*)rule; + if(gabr->ob==ob) + gabr->ob= NULL; + } + else if(rule->type==eBoidRuleType_FollowLeader) { + BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader*)rule; + if(flbr->ob==ob) + flbr->ob= NULL; + } + } + } + } } if(ob->pd) obt->recalc |= OB_RECALC_DATA; @@ -497,9 +505,9 @@ void unlink_object(Object *ob) tex= tex->id.next; } - /* mballs */ - if(ob->type==OB_MBALL) { - obt= find_basis_mball(ob); + /* mballs (scene==NULL when called from library.c) */ + if(scene && ob->type==OB_MBALL) { + obt= find_basis_mball(scene, ob); if(obt) freedisplist(&obt->disp); } @@ -525,6 +533,8 @@ void unlink_object(Object *ob) } sce= sce->id.next; } + +#if 0 // XXX old animation system /* ipos */ ipo= G.main->ipo.first; while(ipo) { @@ -537,6 +547,7 @@ void unlink_object(Object *ob) } ipo= ipo->id.next; } +#endif // XXX old animation system /* screens */ sc= G.main->screen.first; @@ -551,26 +562,16 @@ void unlink_object(Object *ob) if(v3d->camera==ob) { v3d->camera= NULL; - if(v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; + // XXX if(v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; } if(v3d->localvd && v3d->localvd->camera==ob ) { v3d->localvd->camera= NULL; - if(v3d->localvd->persp==V3D_CAMOB) v3d->localvd->persp= V3D_PERSP; + // XXX if(v3d->localvd->persp==V3D_CAMOB) v3d->localvd->persp= V3D_PERSP; } } - else if(sl->spacetype==SPACE_IPO) { - SpaceIpo *sipo= (SpaceIpo *)sl; - if(sipo->from == (ID *)ob) sipo->from= NULL; - } - else if(sl->spacetype==SPACE_OOPS) { + else if(sl->spacetype==SPACE_OUTLINER) { SpaceOops *so= (SpaceOops *)sl; - Oops *oops; - oops= so->oops.first; - while(oops) { - if(oops->id==(ID *)ob) oops->id= NULL; - oops= oops->next; - } if(so->treestore) { TreeStoreElem *tselem= so->treestore->data; int a; @@ -578,7 +579,6 @@ void unlink_object(Object *ob) if(tselem->id==(ID *)ob) tselem->id= NULL; } } - so->lockpoin= NULL; } } @@ -641,10 +641,8 @@ Camera *copy_camera(Camera *cam) Camera *camn; camn= copy_libblock(cam); - id_us_plus((ID *)camn->ipo); -#ifndef DISABLE_PYTHON - BPY_copy_scriptlink(&camn->scriptlink); -#endif + camn->adt= BKE_copy_animdata(cam->adt); + return camn; } @@ -707,7 +705,7 @@ float dof_camera(Object *ob) { Camera *cam = (Camera *)ob->data; if (ob->type != OB_CAMERA) - return 0.0; + return 0.0f; if (cam->dof_ob) { /* too simple, better to return the distance on the view axis only * return VecLenf(ob->obmat[3], cam->dof_ob->obmat[3]); */ @@ -717,7 +715,7 @@ float dof_camera(Object *ob) Mat4Ortho(obmat); Mat4Invert(ob->imat, obmat); Mat4MulMat4(mat, cam->dof_ob->obmat, ob->imat); - return fabs(mat[3][2]); + return (float)fabs(mat[3][2]); } return cam->YF_dofdist; } @@ -728,40 +726,40 @@ void *add_lamp(char *name) la= alloc_libblock(&G.main->lamp, ID_LA, name); - la->r= la->g= la->b= la->k= 1.0; - la->haint= la->energy= 1.0; - la->dist= 20.0; - la->spotsize= 45.0; - la->spotblend= 0.15; - la->att2= 1.0; + la->r= la->g= la->b= la->k= 1.0f; + la->haint= la->energy= 1.0f; + la->dist= 25.0f; + la->spotsize= 45.0f; + la->spotblend= 0.15f; + la->att2= 1.0f; la->mode= LA_SHAD_BUF; la->bufsize= 512; - la->clipsta= 0.5; - la->clipend= 40.0; - la->shadspotsize= 45.0; + la->clipsta= 0.5f; + la->clipend= 40.0f; + la->shadspotsize= 45.0f; la->samp= 3; - la->bias= 1.0; - la->soft= 3.0; + la->bias= 1.0f; + la->soft= 3.0f; la->ray_samp= la->ray_sampy= la->ray_sampz= 1; - la->area_size=la->area_sizey=la->area_sizez= 1.0; + la->area_size=la->area_sizey=la->area_sizez= 1.0f; la->buffers= 1; la->buftype= LA_SHADBUF_HALFWAY; la->ray_samp_method = LA_SAMP_HALTON; - la->adapt_thresh = 0.001; + la->adapt_thresh = 0.001f; la->preview=NULL; - la->falloff_type = LA_FALLOFF_INVLINEAR; + la->falloff_type = LA_FALLOFF_INVSQUARE; la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f); la->sun_effect_type = 0; la->horizon_brightness = 1.0; la->spread = 1.0; la->sun_brightness = 1.0; la->sun_size = 1.0; - la->backscattered_light = 1.0; - la->atm_turbidity = 2.0; - la->atm_inscattering_factor = 1.0; - la->atm_extinction_factor = 1.0; - la->atm_distance_factor = 1.0; - la->sun_intensity = 1.0; + la->backscattered_light = 1.0f; + la->atm_turbidity = 2.0f; + la->atm_inscattering_factor = 1.0f; + la->atm_extinction_factor = 1.0f; + la->atm_distance_factor = 1.0f; + la->sun_intensity = 1.0f; la->skyblendtype= MA_RAMP_ADD; la->skyblendfac= 1.0f; la->sky_colorspace= BLI_CS_CIE; @@ -788,12 +786,12 @@ Lamp *copy_lamp(Lamp *la) lan->curfalloff = curvemapping_copy(la->curfalloff); +#if 0 // XXX old animation system id_us_plus((ID *)lan->ipo); +#endif // XXX old animation system if (la->preview) lan->preview = BKE_previewimg_copy(la->preview); -#ifndef DISABLE_PYTHON - BPY_copy_scriptlink(&la->scriptlink); -#endif + return lan; } @@ -851,9 +849,7 @@ void make_local_lamp(Lamp *la) void free_camera(Camera *ca) { -#ifndef DISABLE_PYTHON - BPY_free_scriptlink(&ca->scriptlink); -#endif + BKE_free_animdata((ID *)ca); } void free_lamp(Lamp *la) @@ -861,17 +857,13 @@ void free_lamp(Lamp *la) MTex *mtex; int a; - /* scriptlinks */ -#ifndef DISABLE_PYTHON - BPY_free_scriptlink(&la->scriptlink); -#endif - for(a=0; a<MAX_MTEX; a++) { mtex= la->mtex[a]; if(mtex && mtex->tex) mtex->tex->id.us--; if(mtex) MEM_freeN(mtex); } - la->ipo= 0; + + BKE_free_animdata((ID *)la); curvemapping_free(la->curfalloff); @@ -891,13 +883,13 @@ void *add_wave() static void *add_obdata_from_type(int type) { switch (type) { - case OB_MESH: G.totmesh++; return add_mesh("Mesh"); - case OB_CURVE: G.totcurve++; return add_curve("Curve", OB_CURVE); - case OB_SURF: G.totcurve++; return add_curve("Surf", OB_SURF); + case OB_MESH: return add_mesh("Mesh"); + case OB_CURVE: return add_curve("Curve", OB_CURVE); + case OB_SURF: return add_curve("Surf", OB_SURF); case OB_FONT: return add_curve("Text", OB_FONT); case OB_MBALL: return add_mball("Meta"); case OB_CAMERA: return add_camera("Camera"); - case OB_LAMP: G.totlamp++; return add_lamp("Lamp"); + case OB_LAMP: return add_lamp("Lamp"); case OB_LATTICE: return add_lattice("Lattice"); case OB_WAVE: return add_wave(); case OB_ARMATURE: return add_armature("Armature"); @@ -934,7 +926,6 @@ Object *add_only_object(int type, char *name) Object *ob; ob= alloc_libblock(&G.main->object, ID_OB, name); - G.totobj++; /* default object vars */ ob->type= type; @@ -956,7 +947,6 @@ Object *add_only_object(int type, char *name) Mat4One(ob->parentinv); Mat4One(ob->obmat); ob->dt= OB_SHADED; - if(U.flag & USER_MAT_ON_OB) ob->colbits= -1; ob->empty_drawtype= OB_ARROWS; ob->empty_drawsize= 1.0; @@ -968,8 +958,12 @@ Object *add_only_object(int type, char *name) ob->trackflag= OB_POSY; ob->upflag= OB_POSZ; } + +#if 0 // XXX old animation system ob->ipoflag = OB_OFFS_OB+OB_OFFS_PARENT; ob->ipowin= ID_OB; /* the ipowin shown */ +#endif // XXX old animation system + ob->dupon= 1; ob->dupoff= 0; ob->dupsta= 1; ob->dupend= 100; ob->dupfacesca = 1.0; @@ -994,9 +988,9 @@ Object *add_only_object(int type, char *name) return ob; } -/* general add: to G.scene, with layer from area and default name */ +/* general add: to scene, with layer from area and default name */ /* creates minimum required data, but without vertices etc. */ -Object *add_object(int type) +Object *add_object(struct Scene *scene, int type) { Object *ob; Base *base; @@ -1007,47 +1001,15 @@ Object *add_object(int type) ob->data= add_obdata_from_type(type); - ob->lay= G.scene->lay; + ob->lay= scene->lay; - base= scene_add_base(G.scene, ob); - scene_select_base(G.scene, base); + base= scene_add_base(scene, ob); + scene_select_base(scene, base); ob->recalc |= OB_RECALC; return ob; } -void base_init_from_view3d(Base *base, View3D *v3d) -{ - Object *ob= base->object; - - if (!v3d) { - /* no 3d view, this wont happen often */ - base->lay = 1; - VECCOPY(ob->loc, G.scene->cursor); - - /* return now because v3d->viewquat isnt available */ - return; - } else if (v3d->localview) { - base->lay= ob->lay= v3d->layact + v3d->lay; - VECCOPY(ob->loc, v3d->cursor); - } else { - base->lay= ob->lay= v3d->layact; - VECCOPY(ob->loc, G.scene->cursor); - } - - if (U.flag & USER_ADD_VIEWALIGNED) { - v3d->viewquat[0]= -v3d->viewquat[0]; - - /* Quats arnt used yet */ - /*if (ob->transflag & OB_QUAT) { - QUATCOPY(ob->quat, v3d->viewquat); - } else {*/ - QuatToEul(v3d->viewquat, ob->rot); - /*}*/ - v3d->viewquat[0]= -v3d->viewquat[0]; - } -} - SoftBody *copy_softbody(SoftBody *sb) { SoftBody *sbn; @@ -1064,7 +1026,7 @@ SoftBody *copy_softbody(SoftBody *sb) sbn->scratch= NULL; - sbn->pointcache= BKE_ptcache_copy(sb->pointcache); + sbn->pointcache= BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches); return sbn; } @@ -1089,18 +1051,29 @@ ParticleSystem *copy_particlesystem(ParticleSystem *psys) psysn= MEM_dupallocN(psys); psysn->particles= MEM_dupallocN(psys->particles); psysn->child= MEM_dupallocN(psys->child); + if(psysn->particles->keys) + psysn->particles->keys = MEM_dupallocN(psys->particles->keys); for(a=0, pa=psysn->particles; a<psysn->totpart; a++, pa++) { if(pa->hair) pa->hair= MEM_dupallocN(pa->hair); - if(pa->keys) - pa->keys= MEM_dupallocN(pa->keys); + if(a) + pa->keys= (pa-1)->keys + (pa-1)->totkey; } if(psys->soft) { psysn->soft= copy_softbody(psys->soft); psysn->soft->particles = psysn; } + + if(psys->particles->boid) { + psysn->particles->boid = MEM_dupallocN(psys->particles->boid); + for(a=1, pa=psysn->particles+1; a<psysn->totpart; a++, pa++) + pa->boid = (pa-1)->boid + 1; + } + + if(psys->targets.first) + BLI_duplicatelist(&psysn->targets, &psys->targets); psysn->pathcache= NULL; psysn->childcache= NULL; @@ -1112,7 +1085,7 @@ ParticleSystem *copy_particlesystem(ParticleSystem *psys) psysn->reactevents.first = psysn->reactevents.last = NULL; psysn->renderdata = NULL; - psysn->pointcache= BKE_ptcache_copy(psys->pointcache); + psysn->pointcache= BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches); id_us_plus((ID *)psysn->part); @@ -1166,6 +1139,7 @@ static void copy_object_pose(Object *obn, Object *ob) ListBase targets = {NULL, NULL}; bConstraintTarget *ct; +#if 0 // XXX old animation system /* note that we can't change lib linked ipo blocks. for making * proxies this still works correct however because the object * is changed to object->proxy_from when evaluating the driver. */ @@ -1179,6 +1153,7 @@ static void copy_object_pose(Object *obn, Object *ob) icu->driver->ob= obn; } } +#endif // XXX old animation system if (cti && cti->get_constraint_targets) { cti->get_constraint_targets(con, &targets); @@ -1205,6 +1180,7 @@ Object *copy_object(Object *ob) if(ob->totcol) { obn->mat= MEM_dupallocN(ob->mat); + obn->matbits= MEM_dupallocN(ob->matbits); } if(ob->bb) obn->bb= MEM_dupallocN(ob->bb); @@ -1218,9 +1194,7 @@ Object *copy_object(Object *ob) modifier_copyData(md, nmd); BLI_addtail(&obn->modifiers, nmd); } -#ifndef DISABLE_PYTHON - BPY_copy_scriptlink(&ob->scriptlink); -#endif + obn->prop.first = obn->prop.last = NULL; copy_properties(&obn->prop, &ob->prop); @@ -1235,16 +1209,12 @@ Object *copy_object(Object *ob) armature_rebuild_pose(obn, obn->data); } copy_defgroups(&obn->defbase, &ob->defbase); - copy_nlastrips(&obn->nlastrips, &ob->nlastrips); - copy_constraints (&obn->constraints, &ob->constraints); - - clone_constraint_channels (&obn->constraintChannels, &ob->constraintChannels); + copy_constraints(&obn->constraints, &ob->constraints); /* increase user numbers */ id_us_plus((ID *)obn->data); - id_us_plus((ID *)obn->ipo); - id_us_plus((ID *)obn->action); id_us_plus((ID *)obn->dup_group); + // FIXME: add this for animdata too... for(a=0; a<obn->totcol; a++) id_us_plus((ID *)obn->mat[a]); @@ -1263,10 +1233,6 @@ Object *copy_object(Object *ob) obn->derivedDeform = NULL; obn->derivedFinal = NULL; -#ifdef WITH_VERSE - obn->vnode = NULL; -#endif - obn->gpulamp.first = obn->gpulamp.last = NULL; return obn; @@ -1274,21 +1240,25 @@ Object *copy_object(Object *ob) void expand_local_object(Object *ob) { - bActionStrip *strip; + //bActionStrip *strip; ParticleSystem *psys; int a; - + +#if 0 // XXX old animation system id_lib_extern((ID *)ob->action); id_lib_extern((ID *)ob->ipo); +#endif // XXX old animation system id_lib_extern((ID *)ob->data); id_lib_extern((ID *)ob->dup_group); for(a=0; a<ob->totcol; a++) { id_lib_extern((ID *)ob->mat[a]); } +#if 0 // XXX old animation system for (strip=ob->nlastrips.first; strip; strip=strip->next) { id_lib_extern((ID *)strip->act); } +#endif // XXX old animation system for(psys=ob->particlesystem.first; psys; psys=psys->next) id_lib_extern((ID *)psys->part); } @@ -1360,6 +1330,29 @@ void make_local_object(Object *ob) expand_local_object(ob); } +/* + * Returns true if the Object is a from an external blend file (libdata) + */ +int object_is_libdata(Object *ob) +{ + if (!ob) return 0; + if (ob->proxy) return 0; + if (ob->id.lib) return 1; + return 0; +} + +/* Returns true if the Object data is a from an external blend file (libdata) */ +int object_data_is_libdata(Object *ob) +{ + if(!ob) return 0; + if(ob->proxy) return 0; + if(ob->id.lib) return 1; + if(!ob->data) return 0; + if(((ID *)ob->data)->lib) return 1; + + return 0; +} + /* *************** PROXY **************** */ /* when you make proxy, ensure the exposed layers are extern */ @@ -1410,9 +1403,32 @@ void object_make_proxy(Object *ob, Object *target, Object *gob) ob->parent= target->parent; /* libdata */ Mat4CpyMat4(ob->parentinv, target->parentinv); - ob->ipo= target->ipo; /* libdata */ - /* skip constraints, constraintchannels, nla? */ + /* copy animdata stuff - drivers only for now... */ + if ((target->adt) && (target->adt->drivers.first)) { + FCurve *fcu; + + /* add new animdata block */ + ob->adt= BKE_id_add_animdata(&ob->id); + + /* make a copy of all the drivers (for now), then correct any links that need fixing */ + copy_fcurves(&ob->adt->drivers, &target->adt->drivers); + + for (fcu= ob->adt->drivers.first; fcu; fcu= fcu->next) { + ChannelDriver *driver= fcu->driver; + DriverTarget *dtar; + + for (dtar= driver->targets.first; dtar; dtar= dtar->next) { + if ((Object *)dtar->id == target) + dtar->id= (ID *)ob; + else + id_lib_extern((ID *)dtar->id); + } + } + } + + /* skip constraints? */ + // FIXME: this is considered by many as a bug /* set object type and link to data */ ob->type= target->type; @@ -1422,8 +1438,10 @@ void object_make_proxy(Object *ob, Object *target, Object *gob) /* copy material and index information */ ob->actcol= ob->totcol= 0; if(ob->mat) MEM_freeN(ob->mat); + if(ob->matbits) MEM_freeN(ob->matbits); ob->mat = NULL; - if ((target->totcol) && (target->mat) && OB_SUPPORT_MATERIAL(ob)) { + ob->matbits= NULL; + if ((target->totcol) && (target->mat) && ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { //XXX OB_SUPPORT_MATERIAL int i; ob->colbits = target->colbits; @@ -1431,6 +1449,7 @@ void object_make_proxy(Object *ob, Object *target, Object *gob) ob->totcol= target->totcol; ob->mat = MEM_dupallocN(target->mat); + ob->matbits = MEM_dupallocN(target->matbits); for(i=0; i<target->totcol; i++) { /* dont need to run test_object_materials since we know this object is new and not used elsewhere */ id_us_plus((ID *)ob->mat[i]); @@ -1445,6 +1464,9 @@ void object_make_proxy(Object *ob, Object *target, Object *gob) armature_set_id_extern(ob); } + + /* copy drawtype info */ + ob->dt= target->dt; } @@ -1471,8 +1493,9 @@ void disable_speed_curve(int val) no_speed_curve= val; } +// XXX THIS CRUFT NEEDS SERIOUS RECODING ASAP! /* ob can be NULL */ -float bsystem_time(Object *ob, float cfra, float ofs) +float bsystem_time(struct Scene *scene, Object *ob, float cfra, float ofs) { /* returns float ( see frame_to_float in ipo.c) */ @@ -1480,8 +1503,9 @@ float bsystem_time(Object *ob, float cfra, float ofs) cfra+= bluroffs+fieldoffs; /* global time */ - cfra*= G.scene->r.framelen; + cfra*= scene->r.framelen; +#if 0 // XXX old animation system if (ob) { if (no_speed_curve==0 && ob->ipo) cfra= calc_ipo_time(ob->ipo, cfra); @@ -1490,6 +1514,7 @@ float bsystem_time(Object *ob, float cfra, float ofs) if ((ob->ipoflag & OB_OFFS_PARENT) && (ob->partype & PARSLOW)==0) cfra-= give_timeoffset(ob); } +#endif // XXX old animation system cfra-= ofs; @@ -1568,7 +1593,7 @@ void object_to_mat4(Object *ob, float mat[][4]) int enable_cu_speed= 1; -static void ob_parcurve(Object *ob, Object *par, float mat[][4]) +static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[][4]) { Curve *cu; float q[4], vec[4], dir[3], quat[4], x1, ctime; @@ -1578,7 +1603,7 @@ static void ob_parcurve(Object *ob, Object *par, float mat[][4]) cu= par->data; if(cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */ - makeDispListCurveTypes(par, 0); + makeDispListCurveTypes(scene, par, 0); if(cu->path==NULL) return; /* exception, timeoffset is regarded as distance offset */ @@ -1593,15 +1618,17 @@ static void ob_parcurve(Object *ob, Object *par, float mat[][4]) } /* catch exceptions: curve paths used as a duplicator */ else if(enable_cu_speed) { - ctime= bsystem_time(ob, (float)G.scene->r.cfra, 0.0); - - if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) { - ctime /= cu->pathlen; - CLAMP(ctime, 0.0, 1.0); - } + /* ctime is now a proper var setting of Curve which gets set by Animato like any other var that's animated, + * but this will only work if it actually is animated... + * + * we firstly calculate the modulus of cu->ctime/cu->pathlen to clamp ctime within the 0.0 to 1.0 times pathlen + * range, then divide this (the modulus) by pathlen to get a value between 0.0 and 1.0 + */ + ctime= fmod(cu->ctime, cu->pathlen) / cu->pathlen; + CLAMP(ctime, 0.0, 1.0); } else { - ctime= G.scene->r.cfra - give_timeoffset(ob); + ctime= scene->r.cfra - give_timeoffset(ob); ctime /= cu->pathlen; CLAMP(ctime, 0.0, 1.0); @@ -1642,11 +1669,9 @@ static void ob_parcurve(Object *ob, Object *par, float mat[][4]) static void ob_parbone(Object *ob, Object *par, float mat[][4]) { bPoseChannel *pchan; - bArmature *arm; float vec[3]; - arm=get_armature(par); - if (!arm) { + if (par->type!=OB_ARMATURE) { Mat4One(mat); return; } @@ -1670,13 +1695,16 @@ static void ob_parbone(Object *ob, Object *par, float mat[][4]) static void give_parvert(Object *par, int nr, float *vec) { + EditMesh *em; int a, count; vec[0]=vec[1]=vec[2]= 0.0f; if(par->type==OB_MESH) { - if(G.obedit && (par->data==G.obedit->data)) { - EditMesh *em = G.editMesh; + Mesh *me= par->data; + em = BKE_mesh_get_editmesh(me); + + if(em) { EditVert *eve; for(eve= em->verts.first; eve; eve= eve->next) { @@ -1685,6 +1713,7 @@ static void give_parvert(Object *par, int nr, float *vec) break; } } + BKE_mesh_end_editmesh(me, em); } else { DerivedMesh *dm = par->derivedFinal; @@ -1714,7 +1743,7 @@ static void give_parvert(Object *par, int nr, float *vec) } } } - else if ELEM(par->type, OB_CURVE, OB_SURF) { + else if (ELEM(par->type, OB_CURVE, OB_SURF)) { Nurb *nu; Curve *cu; BPoint *bp; @@ -1722,8 +1751,10 @@ static void give_parvert(Object *par, int nr, float *vec) int found= 0; cu= par->data; - nu= cu->nurb.first; - if(par==G.obedit) nu= editNurb.first; + if(cu->editnurb) + nu= cu->editnurb->first; + else + nu= cu->nurb.first; count= 0; while(nu && !found) { @@ -1763,7 +1794,7 @@ static void give_parvert(Object *par, int nr, float *vec) DispList *dl = find_displist(&par->disp, DL_VERTS); float *co = dl?dl->verts:NULL; - if(par==G.obedit) latt= editLatt; + if(latt->editlatt) latt= latt->editlatt; a= latt->pntsu*latt->pntsv*latt->pntsw; count= 0; @@ -1790,7 +1821,7 @@ static void ob_parvert3(Object *ob, Object *par, float mat[][4]) /* in local ob space */ Mat4One(mat); - if ELEM4(par->type, OB_MESH, OB_SURF, OB_CURVE, OB_LATTICE) { + if (ELEM4(par->type, OB_MESH, OB_SURF, OB_CURVE, OB_LATTICE)) { give_parvert(par, ob->par1, v1); give_parvert(par, ob->par2, v2); @@ -1811,36 +1842,17 @@ static void ob_parvert3(Object *ob, Object *par, float mat[][4]) } } +// XXX what the hell is this? static int no_parent_ipo=0; void set_no_parent_ipo(int val) { no_parent_ipo= val; } -static int during_script_flag=0; -void disable_where_script(short on) -{ - during_script_flag= on; -} - -int during_script(void) { - return during_script_flag; -} - -static int during_scriptlink_flag=0; -void disable_where_scriptlink(short on) -{ - during_scriptlink_flag= on; -} - -int during_scriptlink(void) { - return during_scriptlink_flag; -} - -void where_is_object_time(Object *ob, float ctime) +void where_is_object_time(Scene *scene, Object *ob, float ctime) { float *fp1, *fp2, slowmat[4][4] = MAT4_UNITY; - float stime, fac1, fac2, vec[3]; + float stime=ctime, fac1, fac2, vec[3]; int a; int pop; @@ -1850,8 +1862,9 @@ void where_is_object_time(Object *ob, float ctime) if(ob==NULL) return; +#if 0 // XXX old animation system /* this is needed to be able to grab objects with ipos, otherwise it always freezes them */ - stime= bsystem_time(ob, ctime, 0.0); + stime= bsystem_time(scene, ob, ctime, 0.0); if(stime != ob->ctime) { ob->ctime= stime; @@ -1861,7 +1874,7 @@ void where_is_object_time(Object *ob, float ctime) execute_ipo((ID *)ob, ob->ipo); } else - do_all_object_actions(ob); + do_all_object_actions(scene, ob); /* do constraint ipos ..., note it needs stime (0 = all ipos) */ do_constraint_channels(&ob->constraints, &ob->constraintChannels, stime, 0); @@ -1872,36 +1885,39 @@ void where_is_object_time(Object *ob, float ctime) /* do constraint ipos ..., note it needs stime (1 = only drivers ipos) */ do_constraint_channels(&ob->constraints, &ob->constraintChannels, stime, 1); } +#endif // XXX old animation system + + /* execute drivers only, as animation has already been done */ + BKE_animsys_evaluate_animdata(&ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS); if(ob->parent) { Object *par= ob->parent; + // XXX depreceated - animsys if(ob->ipoflag & OB_OFFS_PARENT) ctime-= give_timeoffset(ob); /* hurms, code below conflicts with depgraph... (ton) */ /* and even worse, it gives bad effects for NLA stride too (try ctime != par->ctime, with MBlur) */ pop= 0; if(no_parent_ipo==0 && stime != par->ctime) { - // only for ipo systems? pushdata(par, sizeof(Object)); pop= 1; if(par->proxy_from); // was a copied matrix, no where_is! bad... - else where_is_object_time(par, ctime); + else where_is_object_time(scene, par, ctime); } - solve_parenting(ob, par, ob->obmat, slowmat, 0); - + solve_parenting(scene, ob, par, ob->obmat, slowmat, 0); + if(pop) { poplast(par); } if(ob->partype & PARSLOW) { // include framerate - - fac1= (1.0f/(1.0f+ fabs(give_timeoffset(ob)))); - if(fac1>=1.0) return; + fac1= ( 1.0f / (1.0f + (float)fabs(give_timeoffset(ob))) ); + if(fac1 >= 1.0f) return; fac2= 1.0f-fac1; fp1= ob->obmat[0]; @@ -1910,7 +1926,6 @@ void where_is_object_time(Object *ob, float ctime) fp1[0]= fac1*fp1[0] + fac2*fp2[0]; } } - } else { object_to_mat4(ob, ob->obmat); @@ -1918,27 +1933,21 @@ void where_is_object_time(Object *ob, float ctime) /* Handle tracking */ if(ob->track) { - if( ctime != ob->track->ctime) where_is_object_time(ob->track, ctime); + if( ctime != ob->track->ctime) where_is_object_time(scene, ob->track, ctime); solve_tracking (ob, ob->track->obmat); - } /* solve constraints */ if (ob->constraints.first) { bConstraintOb *cob; - cob= constraints_make_evalob(ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + cob= constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); /* constraints need ctime, not stime. Some call where_is_object_time and bsystem_time */ solve_constraints (&ob->constraints, cob, ctime); constraints_clear_evalob(cob); } -#ifndef DISABLE_PYTHON - if(ob->scriptlink.totscript && !during_script()) { - if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript((ID *)ob, SCRIPT_REDRAW); - } -#endif /* set negative scale flag in object */ Crossf(vec, ob->obmat[0], ob->obmat[1]); @@ -1946,25 +1955,24 @@ void where_is_object_time(Object *ob, float ctime) else ob->transflag &= ~OB_NEG_SCALE; } -static void solve_parenting (Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul) +static void solve_parenting (Scene *scene, Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul) { float totmat[4][4]; float tmat[4][4]; float locmat[4][4]; float vec[3]; int ok; - + object_to_mat4(ob, locmat); if(ob->partype & PARSLOW) Mat4CpyMat4(slowmat, obmat); - switch(ob->partype & PARTYPE) { case PAROBJECT: ok= 0; if(par->type==OB_CURVE) { if( ((Curve *)par->data)->flag & CU_PATH ) { - ob_parcurve(ob, par, tmat); + ob_parcurve(scene, ob, par, tmat); ok= 1; } } @@ -2053,19 +2061,19 @@ void solve_tracking (Object *ob, float targetmat[][4]) } -void where_is_object(Object *ob) +void where_is_object(struct Scene *scene, Object *ob) { - where_is_object_time(ob, (float)G.scene->r.cfra); + where_is_object_time(scene, ob, (float)scene->r.cfra); } -void where_is_object_simul(Object *ob) +void where_is_object_simul(Scene *scene, Object *ob) /* was written for the old game engine (until 2.04) */ /* It seems that this function is only called for a lamp that is the child of another object */ { Object *par; - Ipo *ipo; + //Ipo *ipo; float *fp1, *fp2; float slowmat[4][4]; float fac1, fac2; @@ -2074,13 +2082,14 @@ for a lamp that is the child of another object */ /* NO TIMEOFFS */ /* no ipo! (because of dloc and realtime-ipos) */ - ipo= ob->ipo; - ob->ipo= NULL; + // XXX old animation system + //ipo= ob->ipo; + //ob->ipo= NULL; if(ob->parent) { par= ob->parent; - solve_parenting(ob, par, ob->obmat, slowmat, 1); + solve_parenting(scene, ob, par, ob->obmat, slowmat, 1); if(ob->partype & PARSLOW) { @@ -2105,45 +2114,47 @@ for a lamp that is the child of another object */ if (ob->constraints.first) { bConstraintOb *cob; - cob= constraints_make_evalob(ob, NULL, CONSTRAINT_OBTYPE_OBJECT); - solve_constraints (&ob->constraints, cob, G.scene->r.cfra); + cob= constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + solve_constraints(&ob->constraints, cob, (float)scene->r.cfra); constraints_clear_evalob(cob); } /* WATCH IT!!! */ - ob->ipo= ipo; + // XXX old animation system + //ob->ipo= ipo; } /* for calculation of the inverse parent transform, only used for editor */ -void what_does_parent(Object *ob) +void what_does_parent(Scene *scene, Object *ob, Object *workob) { - clear_workob(); - Mat4One(workob.obmat); - Mat4One(workob.parentinv); - Mat4One(workob.constinv); - workob.parent= ob->parent; - workob.track= ob->track; + clear_workob(workob); + + Mat4One(workob->obmat); + Mat4One(workob->parentinv); + Mat4One(workob->constinv); + workob->parent= ob->parent; + workob->track= ob->track; - workob.trackflag= ob->trackflag; - workob.upflag= ob->upflag; + workob->trackflag= ob->trackflag; + workob->upflag= ob->upflag; - workob.partype= ob->partype; - workob.par1= ob->par1; - workob.par2= ob->par2; - workob.par3= ob->par3; + workob->partype= ob->partype; + workob->par1= ob->par1; + workob->par2= ob->par2; + workob->par3= ob->par3; - workob.constraints.first = ob->constraints.first; - workob.constraints.last = ob->constraints.last; + workob->constraints.first = ob->constraints.first; + workob->constraints.last = ob->constraints.last; - strcpy(workob.parsubstr, ob->parsubstr); + strcpy(workob->parsubstr, ob->parsubstr); - where_is_object(&workob); + where_is_object(scene, workob); } BoundBox *unit_boundbox() { BoundBox *bb; - float min[3] = {-1,-1,-1}, max[3] = {-1,-1,-1}; + float min[3] = {-1.0f,-1.0f,-1.0f}, max[3] = {-1.0f,-1.0f,-1.0f}; bb= MEM_callocN(sizeof(BoundBox), "bb"); boundbox_set_from_min_max(bb, min, max); @@ -2170,7 +2181,7 @@ BoundBox *object_get_boundbox(Object *ob) if(ob->type==OB_MESH) { bb = mesh_get_bb(ob); } - else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) { + else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { bb= ( (Curve *)ob->data )->bb; } else if(ob->type==OB_MBALL) { @@ -2256,7 +2267,7 @@ void minmax_object(Object *ob, float *min, float *max) } /* TODO - use dupli objects bounding boxes */ -void minmax_object_duplis(Object *ob, float *min, float *max) +void minmax_object_duplis(Scene *scene, Object *ob, float *min, float *max) { if ((ob->transflag & OB_DUPLI)==0) { return; @@ -2264,7 +2275,7 @@ void minmax_object_duplis(Object *ob, float *min, float *max) ListBase *lb; DupliObject *dob; - lb= object_duplilist(G.scene, ob); + lb= object_duplilist(scene, ob); for(dob= lb->first; dob; dob= dob->next) { if(dob->no_draw); else { @@ -2284,13 +2295,16 @@ void minmax_object_duplis(Object *ob, float *min, float *max) /* the main object update call, for object matrix, constraints, keys and displist (modifiers) */ /* requires flags to be set! */ -void object_handle_update(Object *ob) +void object_handle_update(Scene *scene, Object *ob) { if(ob->recalc & OB_RECALC) { - if(ob->recalc & OB_RECALC_OB) { - - // printf("recalcob %s\n", ob->id.name+2); + /* XXX new animsys warning: depsgraph tag OB_RECALC_DATA should not skip drivers, + which is only in where_is_object now */ + if(ob->recalc & OB_RECALC) { + + if (G.f & G_DEBUG) + printf("recalcob %s\n", ob->id.name+2); /* handle proxy copy for target */ if(ob->id.lib && ob->proxy_from) { @@ -2304,41 +2318,45 @@ void object_handle_update(Object *ob) Mat4CpyMat4(ob->obmat, ob->proxy_from->obmat); } else - where_is_object(ob); -#ifndef DISABLE_PYTHON - if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript((ID *)ob, SCRIPT_OBJECTUPDATE); -#endif + where_is_object(scene, ob); } if(ob->recalc & OB_RECALC_DATA) { - // printf("recalcdata %s\n", ob->id.name+2); + if (G.f & G_DEBUG) + printf("recalcdata %s\n", ob->id.name+2); /* includes all keys and modifiers */ if(ob->type==OB_MESH) { - makeDerivedMesh(ob, get_viewedit_datamask()); + EditMesh *em = BKE_mesh_get_editmesh(ob->data); + + // here was vieweditdatamask? XXX + if(ob==scene->obedit) { + makeDerivedMesh(scene, ob, em, CD_MASK_BAREMESH); + BKE_mesh_end_editmesh(ob->data, em); + } else + makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH); } else if(ob->type==OB_MBALL) { - makeDispListMBall(ob); + makeDispListMBall(scene, ob); } else if(ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - makeDispListCurveTypes(ob, 0); + makeDispListCurveTypes(scene, ob, 0); } - else if(ob->type==OB_LATTICE) { - lattice_calc_modifiers(ob); - } - else if(ob->type==OB_CAMERA) { - Camera *cam = (Camera *)ob->data; - calc_ipo(cam->ipo, frame_to_float(G.scene->r.cfra)); - execute_ipo(&cam->id, cam->ipo); + else if(ELEM(ob->type, OB_CAMERA, OB_LAMP)) { + ID *data_id= (ID *)ob->data; + AnimData *adt= BKE_animdata_from_id(data_id); + float ctime= (float)scene->r.cfra; // XXX this is bad... + + /* evaluate drivers */ + BKE_animsys_evaluate_animdata(data_id, adt, ctime, ADT_RECALC_DRIVERS); } - else if(ob->type==OB_LAMP) { - Lamp *la = (Lamp *)ob->data; - calc_ipo(la->ipo, frame_to_float(G.scene->r.cfra)); - execute_ipo(&la->id, la->ipo); + else if(ob->type==OB_LATTICE) { + lattice_calc_modifiers(scene, ob); } else if(ob->type==OB_ARMATURE) { /* this happens for reading old files and to match library armatures with poses */ + // XXX this won't screw up the pose set already... if(ob->pose==NULL || (ob->pose->flag & POSE_RECALC)) armature_rebuild_pose(ob, ob->data); @@ -2347,19 +2365,25 @@ void object_handle_update(Object *ob) // printf("pose proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name); } else { - do_all_pose_actions(ob); - where_is_pose(ob); + where_is_pose(scene, ob); } } if(ob->particlesystem.first) { ParticleSystem *tpsys, *psys; DerivedMesh *dm; + ob->transflag &= ~OB_DUPLIPARTS; psys= ob->particlesystem.first; while(psys) { if(psys_check_enabled(ob, psys)) { - particle_system_update(ob, psys); + /* check use of dupli objects here */ + if(psys->part && psys->part->draw_as == PART_DRAW_REND && + ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) + || (psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group))) + ob->transflag |= OB_DUPLIPARTS; + + particle_system_update(scene, ob, psys); psys= psys->next; } else if(psys->flag & PSYS_DELETE) { @@ -2376,16 +2400,13 @@ void object_handle_update(Object *ob) /* this is to make sure we get render level duplis in groups: * the derivedmesh must be created before init_render_mesh, * since object_duplilist does dupliparticles before that */ - dm = mesh_create_derived_render(ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); + dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); dm->release(dm); for(psys=ob->particlesystem.first; psys; psys=psys->next) psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated; } } -#ifndef DISABLE_PYTHON - if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript((ID *)ob, SCRIPT_OBDATAUPDATE); -#endif } /* the no-group proxy case, we call update */ @@ -2393,7 +2414,7 @@ void object_handle_update(Object *ob) /* set pointer in library proxy target, for copying, but restore it */ ob->proxy->proxy_from= ob; // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name); - object_handle_update(ob->proxy); + object_handle_update(scene, ob->proxy); } ob->recalc &= ~OB_RECALC; diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index d0925a641e3..8c77ed92aa1 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -61,9 +61,9 @@ #include "BKE_image.h" #include "BKE_font.h" #include "BKE_packedFile.h" -#include "BKE_bad_level_calls.h" /* <- waitcursor */ +#include "BKE_report.h" -int seekPackedFile(PackedFile * pf, int offset, int whence) +int seekPackedFile(PackedFile *pf, int offset, int whence) { int oldseek = -1, seek = 0; @@ -93,12 +93,12 @@ int seekPackedFile(PackedFile * pf, int offset, int whence) return(oldseek); } -void rewindPackedFile(PackedFile * pf) +void rewindPackedFile(PackedFile *pf) { seekPackedFile(pf, 0, SEEK_SET); } -int readPackedFile(PackedFile * pf, void * data, int size) +int readPackedFile(PackedFile *pf, void *data, int size) { if ((pf != NULL) && (size >= 0) && (data != NULL)) { if (size + pf->seek > pf->size) { @@ -119,68 +119,56 @@ int readPackedFile(PackedFile * pf, void * data, int size) return(size); } -int countPackedFiles() +int countPackedFiles(Main *bmain) { - int count = 0; Image *ima; VFont *vf; - bSample *sample; + bSound *sound; + int count = 0; // let's check if there are packed files... - ima = G.main->image.first; - while (ima) { - if (ima->packedfile) { + for(ima=bmain->image.first; ima; ima=ima->id.next) + if(ima->packedfile) count++; - } - ima= ima->id.next; - } - vf = G.main->vfont.first; - while (vf) { - if (vf->packedfile) { + for(vf=bmain->vfont.first; vf; vf=vf->id.next) + if(vf->packedfile) count++; - } - vf = vf->id.next; - } - sample = samples->first; - while (sample) { - if (sample->packedfile) { + for(sound=bmain->sound.first; sound; sound=sound->id.next) + if(sound->packedfile) count++; - } - sample = sample->id.next; - } - return(count); + return count; } -void freePackedFile(PackedFile * pf) +void freePackedFile(PackedFile *pf) { - if (pf) { + if(pf) { MEM_freeN(pf->data); MEM_freeN(pf); - } else { - printf("freePackedFile: Trying to free a NULL pointer\n"); } + else + printf("freePackedFile: Trying to free a NULL pointer\n"); } -PackedFile * newPackedFileMemory(void *mem, int memlen) +PackedFile *newPackedFileMemory(void *mem, int memlen) { - PackedFile * pf = MEM_callocN(sizeof(*pf), "PackedFile"); + PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile"); pf->data = mem; pf->size = memlen; return pf; } -PackedFile * newPackedFile(char * filename) +PackedFile *newPackedFile(ReportList *reports, char *filename) { - PackedFile * pf = NULL; + PackedFile *pf = NULL; int file, filelen; char name[FILE_MAXDIR+FILE_MAXFILE]; - void * data; + void *data; - waitcursor(1); + //XXX waitcursor(1); // convert relative filenames to absolute filenames @@ -192,7 +180,7 @@ PackedFile * newPackedFile(char * filename) file= open(name, O_BINARY|O_RDONLY); if (file <= 0) { - // error("Can't open file: %s", name); + BKE_reportf(reports, RPT_ERROR, "Can't open file: %s", name); } else { filelen = BLI_filesize(file); @@ -210,41 +198,28 @@ PackedFile * newPackedFile(char * filename) close(file); } - waitcursor(0); + //XXX waitcursor(0); return (pf); } -void packAll() +void packAll(Main *bmain, ReportList *reports) { Image *ima; VFont *vf; - bSample *sample; - - ima = G.main->image.first; - while (ima) { - if (ima->packedfile == NULL) { - ima->packedfile = newPackedFile(ima->name); - } - ima= ima->id.next; - } - - vf = G.main->vfont.first; - while (vf) { - if (vf->packedfile == NULL) { - vf->packedfile = newPackedFile(vf->name); - } - vf = vf->id.next; - } + bSound *sound; + for(ima=bmain->image.first; ima; ima=ima->id.next) + if(ima->packedfile == NULL) + ima->packedfile = newPackedFile(reports, ima->name); - sample = samples->first; - while (sample) { - if (sample->packedfile == NULL) { - sound_set_packedfile(sample, newPackedFile(sample->name)); - } - sample = sample->id.next; - } + for(vf=bmain->vfont.first; vf; vf=vf->id.next) + if(vf->packedfile == NULL) + vf->packedfile = newPackedFile(reports, vf->name); + + for(sound=bmain->sound.first; sound; sound=sound->id.next) + if(sound->packedfile == NULL) + sound->packedfile = newPackedFile(reports, sound->name); } @@ -253,10 +228,10 @@ void packAll() // attempt to create a function that generates an unique filename // this will work when all funtions in fileops.c understand relative filenames... -char * find_new_name(char * name) +char *find_new_name(char *name) { char tempname[FILE_MAXDIR + FILE_MAXFILE]; - char * newname; + char *newname; if (fop_exists(name)) { for (number = 1; number <= 999; number++) { @@ -275,15 +250,15 @@ char * find_new_name(char * name) */ -int writePackedFile(char * filename, PackedFile *pf, int guimode) +int writePackedFile(ReportList *reports, char *filename, PackedFile *pf, int guimode) { int file, number, remove_tmp = FALSE; int ret_value = RET_OK; char name[FILE_MAXDIR + FILE_MAXFILE]; char tempname[FILE_MAXDIR + FILE_MAXFILE]; -/* void * data; */ +/* void *data; */ - if (guimode) waitcursor(1); + if (guimode); //XXX waitcursor(1); strcpy(name, filename); BLI_convertstringcode(name, G.sce); @@ -306,28 +281,28 @@ int writePackedFile(char * filename, PackedFile *pf, int guimode) file = open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666); if (file >= 0) { if (write(file, pf->data, pf->size) != pf->size) { - if(guimode) error("Error writing file: %s", name); + BKE_reportf(reports, RPT_ERROR, "Error writing file: %s", name); ret_value = RET_ERROR; } close(file); } else { - if(guimode) error("Error creating file: %s", name); + BKE_reportf(reports, RPT_ERROR, "Error creating file: %s", name); ret_value = RET_ERROR; } if (remove_tmp) { if (ret_value == RET_ERROR) { if (BLI_rename(tempname, name) != 0) { - if(guimode) error("Error restoring tempfile. Check files: '%s' '%s'", tempname, name); + BKE_reportf(reports, RPT_ERROR, "Error restoring tempfile. Check files: '%s' '%s'", tempname, name); } } else { if (BLI_delete(tempname, 0, 0) != 0) { - if(guimode) error("Error deleting '%s' (ignored)"); + BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname); } } } - if(guimode) waitcursor(0); + if(guimode); //XXX waitcursor(0); return (ret_value); } @@ -343,7 +318,7 @@ PF_NOFILE - the original file doens't exist */ -int checkPackedFile(char * filename, PackedFile * pf) +int checkPackedFile(char *filename, PackedFile *pf) { struct stat st; int ret_val, i, len, file; @@ -393,68 +368,21 @@ int checkPackedFile(char * filename, PackedFile * pf) /* -unpackFile() looks at the existing files (abs_name, local_name) and a packed file. -If how == PF_ASK it offers the user a couple of options what to do with the packed file. + unpackFile() looks at the existing files (abs_name, local_name) and a packed file. -It returns a char * to the existing file name / new file name or NULL when +It returns a char *to the existing file name / new file name or NULL when there was an error or when the user desides to cancel the operation. */ -char *unpackFile(char * abs_name, char * local_name, PackedFile * pf, int how) +char *unpackFile(ReportList *reports, char *abs_name, char *local_name, PackedFile *pf, int how) { - char menu[6 * (FILE_MAXDIR + FILE_MAXFILE + 100)]; - char line[FILE_MAXDIR + FILE_MAXFILE + 100]; - char * newname = NULL, * temp = NULL; + char *newname = NULL, *temp = NULL; // char newabs[FILE_MAXDIR + FILE_MAXFILE]; // char newlocal[FILE_MAXDIR + FILE_MAXFILE]; if (pf != NULL) { - if (how == PF_ASK) { - sprintf(menu, "UnPack file%%t|Remove Pack %%x%d", PF_REMOVE); - - if (strcmp(abs_name, local_name)) { - switch (checkPackedFile(local_name, pf)) { - case PF_NOFILE: - sprintf(line, "|Create %s%%x%d", local_name, PF_WRITE_LOCAL); - strcat(menu, line); - break; - case PF_EQUAL: - sprintf(line, "|Use %s (identical)%%x%d", local_name, PF_USE_LOCAL); - strcat(menu, line); - break; - case PF_DIFFERS: - sprintf(line, "|Use %s (differs)%%x%d", local_name, PF_USE_LOCAL); - strcat(menu, line); - sprintf(line, "|Overwrite %s%%x%d", local_name, PF_WRITE_LOCAL); - strcat(menu, line); - break; - } - // sprintf(line, "|%%x%d", PF_INVALID); - // strcat(menu, line); - } - - switch (checkPackedFile(abs_name, pf)) { - case PF_NOFILE: - sprintf(line, "|Create %s%%x%d", abs_name, PF_WRITE_ORIGINAL); - strcat(menu, line); - break; - case PF_EQUAL: - sprintf(line, "|Use %s (identical)%%x%d", abs_name, PF_USE_ORIGINAL); - strcat(menu, line); - break; - case PF_DIFFERS: - sprintf(line, "|Use %s (differs)%%x%d", abs_name, PF_USE_ORIGINAL); - strcat(menu, line); - sprintf(line, "|Overwrite %s%%x%d", abs_name, PF_WRITE_ORIGINAL); - strcat(menu, line); - break; - } - - how = pupmenu(menu); - } - switch (how) { case -1: case PF_KEEP: @@ -470,7 +398,7 @@ char *unpackFile(char * abs_name, char * local_name, PackedFile * pf, int how) } // else fall through and create it case PF_WRITE_LOCAL: - if (writePackedFile(local_name, pf, 1) == RET_OK) { + if (writePackedFile(reports, local_name, pf, 1) == RET_OK) { temp = local_name; } break; @@ -482,7 +410,7 @@ char *unpackFile(char * abs_name, char * local_name, PackedFile * pf, int how) } // else fall through and create it case PF_WRITE_ORIGINAL: - if (writePackedFile(abs_name, pf, 1) == RET_OK) { + if (writePackedFile(reports, abs_name, pf, 1) == RET_OK) { temp = abs_name; } break; @@ -501,10 +429,10 @@ char *unpackFile(char * abs_name, char * local_name, PackedFile * pf, int how) } -int unpackVFont(VFont * vfont, int how) +int unpackVFont(ReportList *reports, VFont *vfont, int how) { char localname[FILE_MAXDIR + FILE_MAXFILE], fi[FILE_MAXFILE]; - char * newname; + char *newname; int ret_value = RET_ERROR; if (vfont != NULL) { @@ -513,7 +441,7 @@ int unpackVFont(VFont * vfont, int how) sprintf(localname, "//fonts/%s", fi); - newname = unpackFile(vfont->name, localname, vfont->packedfile, how); + newname = unpackFile(reports, vfont->name, localname, vfont->packedfile, how); if (newname != NULL) { ret_value = RET_OK; freePackedFile(vfont->packedfile); @@ -526,28 +454,26 @@ int unpackVFont(VFont * vfont, int how) return (ret_value); } -int unpackSample(bSample *sample, int how) +int unpackSound(ReportList *reports, bSound *sound, int how) { char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; - char * newname; + char *newname; int ret_value = RET_ERROR; - PackedFile *pf; - - if (sample != NULL) { - strcpy(localname, sample->name); + + if (sound != NULL) { + strcpy(localname, sound->name); BLI_splitdirstring(localname, fi); - sprintf(localname, "//samples/%s", fi); - - newname = unpackFile(sample->name, localname, sample->packedfile, how); + sprintf(localname, "//sounds/%s", fi); + + newname = unpackFile(reports, sound->name, localname, sound->packedfile, how); if (newname != NULL) { - strcpy(sample->name, newname); + strcpy(sound->name, newname); MEM_freeN(newname); - pf = sample->packedfile; - // because samples and sounds can point to the - // same packedfile we have to check them all - sound_set_packedfile(sample, NULL); - freePackedFile(pf); + freePackedFile(sound->packedfile); + sound->packedfile = 0; + + sound_load(sound); ret_value = RET_OK; } @@ -556,10 +482,10 @@ int unpackSample(bSample *sample, int how) return(ret_value); } -int unpackImage(Image * ima, int how) +int unpackImage(ReportList *reports, Image *ima, int how) { char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; - char * newname; + char *newname; int ret_value = RET_ERROR; if (ima != NULL) { @@ -567,7 +493,7 @@ int unpackImage(Image * ima, int how) BLI_splitdirstring(localname, fi); sprintf(localname, "//textures/%s", fi); - newname = unpackFile(ima->name, localname, ima->packedfile, how); + newname = unpackFile(reports, ima->name, localname, ima->packedfile, how); if (newname != NULL) { ret_value = RET_OK; freePackedFile(ima->packedfile); @@ -581,33 +507,22 @@ int unpackImage(Image * ima, int how) return(ret_value); } -void unpackAll(int how) +void unpackAll(Main *bmain, ReportList *reports, int how) { Image *ima; VFont *vf; - bSample *sample; - - ima = G.main->image.first; - while (ima) { - if (ima->packedfile) { - unpackImage(ima, how); - } - ima= ima->id.next; - } - - vf = G.main->vfont.first; - while (vf) { - if (vf->packedfile) { - unpackVFont(vf, how); - } - vf = vf->id.next; - } + bSound *sound; - sample = samples->first; - while (sample) { - if (sample->packedfile) { - unpackSample(sample, how); - } - sample = sample->id.next; - } + for(ima=bmain->image.first; ima; ima=ima->id.next) + if(ima->packedfile) + unpackImage(reports, ima, how); + + for(vf=bmain->vfont.first; vf; vf=vf->id.next) + if(vf->packedfile) + unpackVFont(reports, vf, how); + + for(sound=bmain->sound.first; sound; sound=sound->id.next) + if(sound->packedfile) + unpackSound(reports, sound, how); } + diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index b5b2c07af9c..c8aa440e2da 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -36,6 +36,7 @@ #include "MEM_guardedalloc.h" #include "DNA_scene_types.h" +#include "DNA_boid_types.h" #include "DNA_particle_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -46,7 +47,7 @@ #include "DNA_object_types.h" #include "DNA_curve_types.h" #include "DNA_key_types.h" -#include "DNA_ipo_types.h" +#include "DNA_ipo_types.h" // XXX old animation system stuff to remove! #include "BLI_arithb.h" #include "BLI_blenlib.h" @@ -58,6 +59,7 @@ #include "BKE_anim.h" +#include "BKE_boids.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_lattice.h" @@ -65,25 +67,27 @@ #include "BKE_displist.h" #include "BKE_particle.h" #include "BKE_DerivedMesh.h" -#include "BKE_ipo.h" #include "BKE_object.h" #include "BKE_softbody.h" #include "BKE_material.h" #include "BKE_key.h" #include "BKE_library.h" #include "BKE_depsgraph.h" -#include "BKE_bad_level_calls.h" #include "BKE_modifier.h" #include "BKE_mesh.h" #include "BKE_cdderivedmesh.h" #include "BKE_pointcache.h" -#include "blendef.h" #include "RE_render_ext.h" static void key_from_object(Object *ob, ParticleKey *key); static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float *fuv, float *orco, ParticleTexture *ptex, int event); +static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, + ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex); +static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, + ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, + float *orco, float mat[4][4], ParticleKey *state, float t); /* few helpers for countall etc. */ int count_particles(ParticleSystem *psys){ @@ -225,6 +229,34 @@ short psys_get_current_num(Object *ob) return i; } +void psys_set_current_num(Object *ob, int index) +{ + ParticleSystem *psys; + short i; + + if(ob==0) return; + + for(psys=ob->particlesystem.first, i=0; psys; psys=psys->next, i++) { + if(i == index) + psys->flag |= PSYS_CURRENT; + else + psys->flag &= ~PSYS_CURRENT; + } +} +Object *psys_find_object(Scene *scene, ParticleSystem *psys) +{ + Base *base = scene->base.first; + ParticleSystem *tpsys; + + for(base = scene->base.first; base; base = base->next) { + for(tpsys = base->object->particlesystem.first; psys; psys=psys->next) { + if(tpsys == psys) + return base->object; + } + } + + return NULL; +} /* change object's active particle system */ void psys_change_act(void *ob_v, void *act_v) { @@ -242,11 +274,11 @@ void psys_change_act(void *ob_v, void *act_v) npsys->flag |= PSYS_CURRENT; } } -Object *psys_get_lattice(Object *ob, ParticleSystem *psys) +Object *psys_get_lattice(Scene *scene, Object *ob, ParticleSystem *psys) { Object *lattice=0; - if(psys_in_edit_mode(psys)==0){ + if(psys_in_edit_mode(scene, psys)==0){ ModifierData *md = (ModifierData*)psys_get_modifier(ob,psys); @@ -287,16 +319,16 @@ int psys_ob_has_hair(Object *ob) return 0; } -int psys_in_edit_mode(ParticleSystem *psys) +int psys_in_edit_mode(Scene *scene, ParticleSystem *psys) { - return ((G.f & G_PARTICLEEDIT) && psys==psys_get_current(OBACT) && psys->edit); + return ((G.f & G_PARTICLEEDIT) && psys==psys_get_current((scene->basact)->object) && psys->edit); } int psys_check_enabled(Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd; Mesh *me; - if(psys->flag & PSYS_DISABLED || psys->flag & PSYS_DELETE) + if(psys->flag & PSYS_DISABLED || psys->flag & PSYS_DELETE || !psys->part) return 0; if(ob->type == OB_MESH) { @@ -325,10 +357,13 @@ void psys_free_settings(ParticleSettings *part) MEM_freeN(part->pd); part->pd = NULL; } + if(part->pd2) { MEM_freeN(part->pd2); part->pd2 = NULL; } + + boid_free_settings(part->boids); } void free_hair(ParticleSystem *psys, int softbody) @@ -357,10 +392,11 @@ void free_keyed_keys(ParticleSystem *psys) if(psys->particles && psys->particles->keys) { MEM_freeN(psys->particles->keys); - for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++) - if(pa->keys) { - pa->keys= NULL; - pa->totkey= 0; + for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++) { + if(pa->keys) { + pa->keys= NULL; + pa->totkey= 0; + } } } } @@ -404,9 +440,13 @@ void psys_free(Object *ob, ParticleSystem * psys) free_keyed_keys(psys); - PE_free_particle_edit(psys); + if(psys->edit && psys->free_edit) + psys->free_edit(psys); if(psys->particles){ + if(psys->particles->boid) + MEM_freeN(psys->particles->boid); + MEM_freeN(psys->particles); psys->particles = 0; psys->totpart = 0; @@ -425,7 +465,7 @@ void psys_free(Object *ob, ParticleSystem * psys) for(tpsys=ob->particlesystem.first; tpsys; tpsys=tpsys->next){ if(tpsys->part) { - if(ELEM(tpsys->part->draw_as,PART_DRAW_OB,PART_DRAW_GR)) + if(ELEM(tpsys->part->ren_as,PART_DRAW_OB,PART_DRAW_GR)) { nr++; break; @@ -444,13 +484,21 @@ void psys_free(Object *ob, ParticleSystem * psys) if(psys->reactevents.first) BLI_freelistN(&psys->reactevents); - if(psys->pointcache) - BKE_ptcache_free(psys->pointcache); + BKE_ptcache_free_list(&psys->ptcaches); + psys->pointcache = NULL; + if(psys->targets.first) + BLI_freelistN(&psys->targets); + + BLI_kdtree_free(psys->tree); + MEM_freeN(psys); } } +/************************************************/ +/* Rendering */ +/************************************************/ /* these functions move away particle data and bring it back after * rendering, to make different render settings possible without * removing the previous data. this should be solved properly once */ @@ -464,6 +512,7 @@ typedef struct ParticleRenderData { ChildParticle *child; ParticleCacheKey **pathcache; ParticleCacheKey **childcache; + ListBase pathcachebufs, childcachebufs; int totchild, totcached, totchildcache; DerivedMesh *dm; int totdmvert, totdmedge, totdmface; @@ -550,8 +599,12 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float data->child= psys->child; data->totchild= psys->totchild; data->pathcache= psys->pathcache; + data->pathcachebufs.first = psys->pathcachebufs.first; + data->pathcachebufs.last = psys->pathcachebufs.last; data->totcached= psys->totcached; data->childcache= psys->childcache; + data->childcachebufs.first = psys->childcachebufs.first; + data->childcachebufs.last = psys->childcachebufs.last; data->totchildcache= psys->totchildcache; if(psmd->dm) @@ -564,6 +617,8 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[][4], float psys->pathcache= NULL; psys->childcache= NULL; psys->totchild= psys->totcached= psys->totchildcache= 0; + psys->pathcachebufs.first = psys->pathcachebufs.last = NULL; + psys->childcachebufs.first = psys->childcachebufs.last = NULL; Mat4CpyMat4(data->winmat, winmat); Mat4MulMat4(data->viewmat, ob->obmat, viewmat); @@ -604,8 +659,12 @@ void psys_render_restore(Object *ob, ParticleSystem *psys) psys->child= data->child; psys->totchild= data->totchild; psys->pathcache= data->pathcache; + psys->pathcachebufs.first = data->pathcachebufs.first; + psys->pathcachebufs.last = data->pathcachebufs.last; psys->totcached= data->totcached; psys->childcache= data->childcache; + psys->childcachebufs.first = data->childcachebufs.first; + psys->childcachebufs.last = data->childcachebufs.last; psys->totchildcache= data->totchildcache; psmd->dm= data->dm; @@ -636,7 +695,7 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) int *origindex, *facetotvert; int a, b, totorigface, totface, newtot, skipped; - if(part->draw_as!=PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND)) + if(part->ren_as!=PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND)) return tot; if(!ctx->psys->renderdata) return tot; @@ -847,7 +906,7 @@ int psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float } /************************************************/ -/* Interpolated Particles */ +/* Interpolation */ /************************************************/ static float interpolate_particle_value(float v1, float v2, float v3, float v4, float *w, int four) { @@ -865,7 +924,7 @@ static void weighted_particle_vector(float *v1, float *v2, float *v3, float *v4, vec[1]= weights[0]*v1[1] + weights[1]*v2[1] + weights[2]*v3[1] + weights[3]*v4[1]; vec[2]= weights[0]*v1[2] + weights[1]*v2[2] + weights[2]*v3[2] + weights[3]*v4[2]; } -static void interpolate_particle(short type, ParticleKey keys[4], float dt, ParticleKey *result, int velocity) +void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, ParticleKey *result, int velocity) { float t[4]; @@ -896,6 +955,214 @@ static void interpolate_particle(short type, ParticleKey keys[4], float dt, Part +typedef struct ParticleInterpolationData { + ParticleKey *kkey[2]; + HairKey *hkey[2]; + BodyPoint *bp[2]; + SoftBody *soft; + int keyed, cached; + float birthtime, dietime; +} ParticleInterpolationData; +/* Assumes pointcache->mem_cache exists, so for disk cached particles call psys_make_temp_pointcache() before use */ +static void get_pointcache_keys_for_time(Object *ob, ParticleSystem *psys, int index, float t, ParticleKey *key1, ParticleKey *key2) +{ + PointCache *cache = psys->pointcache; + static PTCacheMem *pm = NULL; /* not thread safe */ + + if(index < 0) { /* initialize */ + pm = cache->mem_cache.first; + + if(pm) + pm = pm->next; + } + else { + if(pm) { + while(pm && pm->next && (float)pm->frame < t) + pm = pm->next; + + BKE_ptcache_make_particle_key(key2, pm->index_array ? pm->index_array[index] : index, pm->data, (float)pm->frame); + BKE_ptcache_make_particle_key(key1, pm->prev->index_array ? pm->prev->index_array[index] : index, pm->prev->data, (float)pm->prev->frame); + } + else if(cache->mem_cache.first) { + PTCacheMem *pm2 = cache->mem_cache.first; + BKE_ptcache_make_particle_key(key2, pm2->index_array ? pm2->index_array[index] : index, pm2->data, (float)pm2->frame); + copy_particle_key(key1, key2, 1); + } + } +} +static void init_particle_interpolation(Object *ob, ParticleSystem *psys, ParticleData *pa, ParticleInterpolationData *pind) +{ + + if(pind->keyed) { + pind->kkey[0] = pa->keys; + + if(pa->totkey > 1) + pind->kkey[1] = pa->keys + 1; + else + pind->kkey[1] = NULL; + + pind->birthtime = pa->keys->time; + pind->dietime = (pa->keys + pa->totkey - 1)->time; + } + else if(pind->cached) { + get_pointcache_keys_for_time(ob, psys, -1, 0.0f, NULL, NULL); + + pind->birthtime = pa->time; + pind->dietime = pa->dietime; + } + else { + pind->hkey[0] = pa->hair; + pind->hkey[1] = pa->hair + 1; + + pind->birthtime = pa->hair->time; + pind->dietime = (pa->hair + pa->totkey - 1)->time; + } + + if(pind->soft) { + pind->bp[0] = pind->soft->bpoint + pa->bpi; + pind->bp[1] = pind->soft->bpoint + pa->bpi + 1; + } +} +static void hair_to_particle(ParticleKey *key, HairKey *hkey) +{ + VECCOPY(key->co, hkey->co); + key->time = hkey->time; +} +static void bp_to_particle(ParticleKey *key, BodyPoint *bp, HairKey *hkey) +{ + VECCOPY(key->co, bp->pos); + key->time = hkey->time; +} + +static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData *pa, float t, float frs_sec, ParticleInterpolationData *pind, ParticleKey *result) +{ + ParticleKey keys[4]; + float real_t, dfra, keytime; + + /* interpret timing and find keys */ + if(pind->keyed) { + /* we have only one key, so let's use that */ + if(pind->kkey[1]==NULL) { + copy_particle_key(result, pind->kkey[0], 1); + return; + } + + if(result->time < 0.0f) + real_t = -result->time; + else + real_t = pind->kkey[0]->time + t * (pind->kkey[0][pa->totkey-1].time - pind->kkey[0]->time); + + if(psys->part->phystype==PART_PHYS_KEYED && psys->flag & PSYS_KEYED_TIMING) { + ParticleTarget *pt = psys->targets.first; + + pt=pt->next; + + while(pt && pa->time + pt->time < real_t) + pt= pt->next; + + if(pt) { + pt=pt->prev; + + if(pa->time + pt->time + pt->duration > real_t) + real_t = pa->time + pt->time; + } + else + real_t = pa->time + ((ParticleTarget*)psys->targets.last)->time; + } + + CLAMP(real_t, pa->time, pa->dietime); + + while(pind->kkey[1]->time < real_t) + pind->kkey[1]++; + + pind->kkey[0] = pind->kkey[1] - 1; + } + else if(pind->cached) { + if(result->time < 0.0f) /* flag for time in frames */ + real_t = -result->time; + else + real_t = pa->time + t * (pa->dietime - pa->time); + } + else { + if(result->time < 0.0f) + real_t = -result->time; + else + real_t = pind->hkey[0]->time + t * (pind->hkey[0][pa->totkey-1].time - pind->hkey[0]->time); + + while(pind->hkey[1]->time < real_t) { + pind->hkey[1]++; + pind->bp[1]++; + } + + pind->hkey[0] = pind->hkey[1] - 1; + } + + /* set actual interpolation keys */ + if(pind->soft) { + pind->bp[0] = pind->bp[1] - 1; + bp_to_particle(keys + 1, pind->bp[0], pind->hkey[0]); + bp_to_particle(keys + 2, pind->bp[1], pind->hkey[1]); + } + else if(pind->keyed) { + memcpy(keys + 1, pind->kkey[0], sizeof(ParticleKey)); + memcpy(keys + 2, pind->kkey[1], sizeof(ParticleKey)); + } + else if(pind->cached) { + get_pointcache_keys_for_time(NULL, psys, p, real_t, keys+1, keys+2); + } + else { + hair_to_particle(keys + 1, pind->hkey[0]); + hair_to_particle(keys + 2, pind->hkey[1]); + } + + /* set secondary interpolation keys for hair */ + if(!pind->keyed && !pind->cached) { + if(pind->soft) { + if(pind->hkey[0] != pa->hair) + bp_to_particle(keys, pind->bp[0] - 1, pind->hkey[0] - 1); + else + bp_to_particle(keys, pind->bp[0], pind->hkey[0]); + } + else { + if(pind->hkey[0] != pa->hair) + hair_to_particle(keys, pind->hkey[0] - 1); + else + hair_to_particle(keys, pind->hkey[0]); + } + + if(pind->soft) { + if(pind->hkey[1] != pa->hair + pa->totkey - 1) + bp_to_particle(keys + 3, pind->bp[1] + 1, pind->hkey[1] + 1); + else + bp_to_particle(keys + 3, pind->bp[1], pind->hkey[1]); + } + else { + if(pind->hkey[1] != pa->hair + pa->totkey - 1) + hair_to_particle(keys + 3, pind->hkey[1] + 1); + else + hair_to_particle(keys + 3, pind->hkey[1]); + } + } + + dfra = keys[2].time - keys[1].time; + keytime = (real_t - keys[1].time) / dfra; + + /* convert velocity to timestep size */ + if(pind->keyed || pind->cached){ + VecMulf(keys[1].vel, dfra / frs_sec); + VecMulf(keys[2].vel, dfra / frs_sec); + QuatInterpol(result->rot,keys[1].rot,keys[2].rot,keytime); + } + + /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0,1]->[k2,k3] (k1 & k4 used for cardinal & bspline interpolation)*/ + psys_interpolate_particle((pind->keyed || pind->cached) ? -1 /* signal for cubic interpolation */ + : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL) + ,keys, keytime, result, 1); + + /* the velocity needs to be converted back from cubic interpolation */ + if(pind->keyed || pind->cached) + VecMulf(result->vel, frs_sec / dfra); +} /************************************************/ /* Particles on a dm */ /************************************************/ @@ -1396,16 +1663,6 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in /************************************************/ /* Path Cache */ /************************************************/ -static void hair_to_particle(ParticleKey *key, HairKey *hkey) -{ - VECCOPY(key->co, hkey->co); - key->time = hkey->time; -} -static void bp_to_particle(ParticleKey *key, BodyPoint *bp, HairKey *hkey) -{ - VECCOPY(key->co, bp->pos); - key->time = hkey->time; -} static float vert_weight(MDeformVert *dvert, int group) { MDeformWeight *dw; @@ -1420,6 +1677,7 @@ static float vert_weight(MDeformVert *dvert, int group) } return 0.0; } + static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, short type, short axis, float obmat[][4]) { float vec[3]={0.0,0.0,0.0}, q1[4]={1,0,0,0},q2[4]; @@ -1554,6 +1812,7 @@ static void do_prekink(ParticleKey *state, ParticleKey *par, float *par_rot, flo break; } } + static void do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump) { if(par && clumpfac!=0.0){ @@ -1571,7 +1830,8 @@ static void do_clump(ParticleKey *state, ParticleKey *par, float time, float clu VecLerpf(state->co,state->co,par->co,clump); } } -int do_guide(ParticleKey *state, int pa_num, float time, ListBase *lb) + +int do_guide(Scene *scene, ParticleKey *state, int pa_num, float time, ListBase *lb) { PartDeflect *pd; ParticleEffectorCache *ec; @@ -1654,7 +1914,7 @@ int do_guide(ParticleKey *state, int pa_num, float time, ListBase *lb) /* curve taper */ if(cu->taperobj) - VecMulf(pa_loc,calc_taper(cu->taperobj,(int)(f_force*guidetime*100.0),100)); + VecMulf(pa_loc, calc_taper(scene, cu->taperobj, (int)(f_force*guidetime*100.0), 100)); /* TODO */ //else{ ///* curve size*/ @@ -1689,7 +1949,7 @@ int do_guide(ParticleKey *state, int pa_num, float time, ListBase *lb) } return 0; } -static void do_rough(float *loc, float t, float fac, float size, float thres, ParticleKey *state) +static void do_rough(float *loc, float mat[4][4], float t, float fac, float size, float thres, ParticleKey *state) { float rough[3]; float rco[3]; @@ -1702,34 +1962,26 @@ static void do_rough(float *loc, float t, float fac, float size, float thres, Pa rough[0]=-1.0f+2.0f*BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2,0,2); rough[1]=-1.0f+2.0f*BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2,0,2); rough[2]=-1.0f+2.0f*BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2,0,2); - VECADDFAC(state->co,state->co,rough,fac); + + VECADDFAC(state->co,state->co,mat[0],fac*rough[0]); + VECADDFAC(state->co,state->co,mat[1],fac*rough[1]); + VECADDFAC(state->co,state->co,mat[2],fac*rough[2]); } -static void do_rough_end(float *loc, float t, float fac, float shape, ParticleKey *state, ParticleKey *par) +static void do_rough_end(float *loc, float mat[4][4], float t, float fac, float shape, ParticleKey *state) { - float rough[3], rnor[3]; + float rough[2]; float roughfac; roughfac=fac*(float)pow((double)t,shape); VECCOPY(rough,loc); rough[0]=-1.0f+2.0f*rough[0]; rough[1]=-1.0f+2.0f*rough[1]; - rough[2]=-1.0f+2.0f*rough[2]; VecMulf(rough,roughfac); - - if(par){ - VECCOPY(rnor,par->vel); - } - else{ - VECCOPY(rnor,state->vel); - } - Normalize(rnor); - Projf(rnor,rough,rnor); - VECSUB(rough,rough,rnor); - - VECADD(state->co,state->co,rough); + VECADDFAC(state->co,state->co,mat[0],rough[0]); + VECADDFAC(state->co,state->co,mat[1],rough[1]); } -static void do_path_effectors(Object *ob, ParticleSystem *psys, int i, ParticleCacheKey *ca, int k, int steps, float *rootco, float effector, float dfra, float cfra, float *length, float *vec) +static void do_path_effectors(Scene *scene, Object *ob, ParticleSystem *psys, int i, ParticleCacheKey *ca, int k, int steps, float *rootco, float effector, float dfra, float cfra, float *length, float *vec) { float force[3] = {0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}; ParticleKey eff_key; @@ -1740,7 +1992,7 @@ static void do_path_effectors(Object *ob, ParticleSystem *psys, int i, ParticleC QUATCOPY(eff_key.rot,(ca-1)->rot); pa= psys->particles+i; - do_effectors(i, pa, &eff_key, ob, psys, rootco, force, vel, dfra, cfra); + do_effectors(i, pa, &eff_key, scene, ob, psys, rootco, force, vel, dfra, cfra); VecMulf(force, effector*pow((float)k / (float)steps, 100.0f * psys->part->eff_hair) / (float)steps); @@ -1748,12 +2000,12 @@ static void do_path_effectors(Object *ob, ParticleSystem *psys, int i, ParticleC Normalize(force); + VECADDFAC(ca->co, (ca-1)->co, force, *length); + if(k < steps) { VecSubf(vec, (ca+1)->co, ca->co); *length = VecLength(vec); } - - VECADDFAC(ca->co, (ca-1)->co, force, *length); } static int check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *state, float max_length, float *cur_length, float length, float *dvec) { @@ -1866,20 +2118,20 @@ static void get_strand_normal(Material *ma, float *surfnor, float surfdist, floa VECCOPY(nor, vnor); } -int psys_threads_init_path(ParticleThread *threads, float cfra, int editupdate) +int psys_threads_init_path(ParticleThread *threads, Scene *scene, float cfra, int editupdate) { ParticleThreadContext *ctx= threads[0].ctx; Object *ob= ctx->ob; ParticleSystem *psys= ctx->psys; ParticleSettings *part = psys->part; - ParticleEditSettings *pset = &G.scene->toolsettings->particle; + ParticleEditSettings *pset = &scene->toolsettings->particle; int totparent=0, between=0; int steps = (int)pow(2.0,(double)part->draw_step); int totchild = psys->totchild; int i, seed, totthread= threads[0].tot; /*---start figuring out what is actually wanted---*/ - if(psys_in_edit_mode(psys)) + if(psys_in_edit_mode(scene, psys)) if(psys->renderdata==0 && (psys->edit==NULL || pset->flag & PE_SHOW_CHILD)==0) totchild=0; @@ -1924,7 +2176,7 @@ int psys_threads_init_path(ParticleThread *threads, float cfra, int editupdate) ctx->parent_pass= 0; ctx->cfra= cfra; - psys->lattice = psys_get_lattice(ob, psys); + psys->lattice = psys_get_lattice(scene, ob, psys); /* cache all relevant vertex groups if they exist */ if(part->from!=PART_FROM_PARTICLE){ @@ -1939,10 +2191,12 @@ int psys_threads_init_path(ParticleThread *threads, float cfra, int editupdate) } /* set correct ipo timing */ +#if 0 // XXX old animation system if(part->flag&PART_ABS_TIME && part->ipo){ calc_ipo(part->ipo, cfra); execute_ipo((ID *)part, part->ipo); } +#endif // XXX old animation system return 1; } @@ -1960,13 +2214,11 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleData *pa=NULL; ParticleTexture ptex; float *cpa_fuv=0, *par_rot=0; - float co[3], orco[3], ornor[3], t, rough_t, cpa_1st[3], dvec[3]; - float branch_begin, branch_end, branch_prob, branchfac, rough_rand; - float pa_rough1, pa_rough2, pa_roughe; - float length, pa_length, pa_clump, pa_kink, pa_effector; - float max_length = 1.0f, cur_length = 0.0f; + float co[3], orco[3], ornor[3], hairmat[4][4], t, cpa_1st[3], dvec[3]; + float branch_begin, branch_end, branch_prob, rough_rand; + float length, max_length = 1.0f, cur_length = 0.0f; float eff_length, eff_vec[3]; - int k, cpa_num, guided = 0; + int k, cpa_num; short cpa_from; if(part->flag & PART_BRANCHING) { @@ -2020,16 +2272,20 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, cpa_num = cpa->num; foffset= cpa->foffset; - if(part->childtype == PART_CHILD_FACES) - foffset = -(2.0f + part->childspread); cpa_fuv = cpa->fuv; cpa_from = PART_FROM_FACE; psys_particle_on_emitter(ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa->fuv,foffset,co,ornor,0,0,orco,0); - /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */ - VECCOPY(cpa_1st,co); - Mat4MulVecfl(ob->obmat,cpa_1st); + if(part->path_start==0.0f) { + /* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */ + VECCOPY(cpa_1st,co); + Mat4MulVecfl(ob->obmat,cpa_1st); + } + + pa = psys->particles + cpa->parent; + + psys_mat_hair_to_global(ob, ctx->psmd->dm, psys->part->from, pa, hairmat); pa=0; } @@ -2052,55 +2308,29 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, cpa_fuv=pa->fuv; psys_particle_on_emitter(ctx->psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,ornor,0,0,orco,0); + + psys_mat_hair_to_global(ob, ctx->psmd->dm, psys->part->from, pa, hairmat); } keys->steps = ctx->steps; /* correct child ipo timing */ +#if 0 // XXX old animation system if((part->flag&PART_ABS_TIME)==0 && part->ipo){ float dsta=part->end-part->sta; calc_ipo(part->ipo, 100.0f*(ctx->cfra-(part->sta+dsta*cpa->rand[1]))/(part->lifetime*(1.0f - part->randlife*cpa->rand[0]))); execute_ipo((ID *)part, part->ipo); } +#endif // XXX old animation system /* get different child parameters from textures & vgroups */ - ptex.length=part->length*(1.0f - part->randlength*cpa->rand[0]); - ptex.clump=1.0; - ptex.kink=1.0; - ptex.rough= 1.0; - ptex.exist= 1.0; - - get_cpa_texture(ctx->dm,ctx->ma,cpa_num,cpa_fuv,orco,&ptex, - MAP_PA_DENS|MAP_PA_LENGTH|MAP_PA_CLUMP|MAP_PA_KINK|MAP_PA_ROUGH); - - pa_length=ptex.length; - pa_clump=ptex.clump; - pa_kink=ptex.kink; - pa_rough1=ptex.rough; - pa_rough2=ptex.rough; - pa_roughe=ptex.rough; - pa_effector= 1.0f; + get_child_modifier_parameters(part, ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex); if(ptex.exist < cpa->rand[1]) { keys->steps = -1; return; } - if(ctx->vg_length) - pa_length*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_length); - if(ctx->vg_clump) - pa_clump*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_clump); - if(ctx->vg_kink) - pa_kink*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_kink); - if(ctx->vg_rough1) - pa_rough1*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough1); - if(ctx->vg_rough2) - pa_rough2*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough2); - if(ctx->vg_roughe) - pa_roughe*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_roughe); - if(ctx->vg_effector) - pa_effector*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_effector); - /* create the child path */ for(k=0,state=keys; k<=ctx->steps; k++,state++){ if(ctx->between){ @@ -2124,12 +2354,14 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, key[w]++; w++; } - if(k==0){ - /* calculate the offset between actual child root position and first position interpolated from parents */ - VECSUB(cpa_1st,cpa_1st,state->co); + if(part->path_start==0.0f) { + if(k==0){ + /* calculate the offset between actual child root position and first position interpolated from parents */ + VECSUB(cpa_1st,cpa_1st,state->co); + } + /* apply offset for correct positioning */ + VECADD(state->co,state->co,cpa_1st); } - /* apply offset for correct positioning */ - VECADD(state->co,state->co,cpa_1st); } else{ /* offset the child from the parent position */ @@ -2143,7 +2375,7 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, if(part->flag & PART_CHILD_EFFECT) { for(k=0,state=keys; k<=ctx->steps; k++,state++) { if(k) { - do_path_effectors(ob, psys, cpa->pa[0], state, k, ctx->steps, keys->co, pa_effector, 0.0f, ctx->cfra, &eff_length, eff_vec); + do_path_effectors(ctx->scene, ob, psys, cpa->pa[0], state, k, ctx->steps, keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec); } else { VecSubf(eff_vec,(state+1)->co,state->co); @@ -2169,67 +2401,50 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, } /* apply different deformations to the child path */ - if(part->flag & PART_CHILD_EFFECT) - /* state is safe to cast, since only co and vel are used */ - guided = do_guide((ParticleKey*)state, cpa->parent, t, &(psys->effectors)); - - if(guided==0){ - if(part->kink) - do_prekink((ParticleKey*)state, (ParticleKey*)par, par_rot, t, - part->kink_freq * pa_kink, part->kink_shape, part->kink_amp, part->kink, part->kink_axis, ob->obmat); - - do_clump((ParticleKey*)state, (ParticleKey*)par, t, part->clumpfac, part->clumppow, pa_clump); - } - - if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING) - rough_t = t * rough_rand; - else - rough_t = t; - - if(part->rough1 != 0.0 && pa_rough1 != 0.0) - do_rough(orco, rough_t, pa_rough1*part->rough1, part->rough1_size, 0.0, (ParticleKey*)state); - - if(part->rough2 != 0.0 && pa_rough2 != 0.0) - do_rough(cpa->rand, rough_t, pa_rough2*part->rough2, part->rough2_size, part->rough2_thres, (ParticleKey*)state); + do_child_modifiers(ctx->scene, ob, psys, part, &ptex, (ParticleKey *)par, par_rot, cpa, orco, hairmat, (ParticleKey *)state, t); - if(part->rough_end != 0.0 && pa_roughe != 0.0) - do_rough_end(cpa->rand, rough_t, pa_roughe*part->rough_end, part->rough_end_shape, (ParticleKey*)state, (ParticleKey*)par); - - if(part->flag & PART_BRANCHING && ctx->between==0){ - if(branch_prob > part->branch_thres){ - branchfac=0.0f; - } - else{ - if(part->flag & PART_SYMM_BRANCHING){ - if(t < branch_begin || t > branch_end) - branchfac=0.0f; - else{ - if((t-branch_begin)/(branch_end-branch_begin)<0.5) - branchfac=2.0f*(t-branch_begin)/(branch_end-branch_begin); - else - branchfac=2.0f*(branch_end-t)/(branch_end-branch_begin); + /* TODO: better branching */ + //if(part->flag & PART_BRANCHING && ctx->between == 0 && part->flag & PART_ANIM_BRANCHING) + // rough_t = t * rough_rand; + //else + // rough_t = t; - CLAMP(branchfac,0.0f,1.0f); - } - } - else{ - if(t < branch_begin){ - branchfac=0.0f; - } - else{ - branchfac=(t-branch_begin)/((1.0f-branch_begin)*0.5f); - CLAMP(branchfac,0.0f,1.0f); - } - } - } + /* TODO: better branching */ + //if(part->flag & PART_BRANCHING && ctx->between==0){ + // if(branch_prob > part->branch_thres){ + // branchfac=0.0f; + // } + // else{ + // if(part->flag & PART_SYMM_BRANCHING){ + // if(t < branch_begin || t > branch_end) + // branchfac=0.0f; + // else{ + // if((t-branch_begin)/(branch_end-branch_begin)<0.5) + // branchfac=2.0f*(t-branch_begin)/(branch_end-branch_begin); + // else + // branchfac=2.0f*(branch_end-t)/(branch_end-branch_begin); + + // CLAMP(branchfac,0.0f,1.0f); + // } + // } + // else{ + // if(t < branch_begin){ + // branchfac=0.0f; + // } + // else{ + // branchfac=(t-branch_begin)/((1.0f-branch_begin)*0.5f); + // CLAMP(branchfac,0.0f,1.0f); + // } + // } + // } - if(i<psys->totpart) - VecLerpf(state->co, (pcache[i] + k)->co, state->co, branchfac); - else - /* this is not threadsafe, but should only happen for - * branching particles particles, which are not threaded */ - VecLerpf(state->co, (cache[i - psys->totpart] + k)->co, state->co, branchfac); - } + // if(i<psys->totpart) + // VecLerpf(state->co, (pcache[i] + k)->co, state->co, branchfac); + // else + // /* this is not threadsafe, but should only happen for + // * branching particles particles, which are not threaded */ + // VecLerpf(state->co, (cache[i - psys->totpart] + k)->co, state->co, branchfac); + //} /* we have to correct velocity because of kink & clump */ if(k>1){ @@ -2243,20 +2458,12 @@ void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, /* check if path needs to be cut before actual end of data points */ if(k){ VECSUB(dvec,state->co,(state-1)->co); - if(part->flag&PART_ABS_LENGTH) - length=VecLength(dvec); - else - length=1.0f/(float)ctx->steps; - + length=1.0f/(float)ctx->steps; k=check_path_length(k,keys,state,max_length,&cur_length,length,dvec); } else{ /* initialize length calculation */ - if(part->flag&PART_ABS_LENGTH) - max_length= part->abslength*pa_length; - else - max_length= pa_length; - + max_length= ptex.length; cur_length= 0.0f; } @@ -2288,7 +2495,7 @@ static void *exec_child_path_cache(void *data) return 0; } -void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int editupdate) +void psys_cache_child_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra, int editupdate) { ParticleSettings *part = psys->part; ParticleThread *pthreads; @@ -2297,9 +2504,9 @@ void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int ed ListBase threads; int i, totchild, totparent, totthread; - pthreads= psys_threads_create(ob, psys); + pthreads= psys_threads_create(scene, ob, psys); - if(!psys_threads_init_path(pthreads, cfra, editupdate)) { + if(!psys_threads_init_path(pthreads, scene, cfra, editupdate)) { psys_threads_free(pthreads); return; } @@ -2349,21 +2556,19 @@ void psys_cache_child_paths(Object *ob, ParticleSystem *psys, float cfra, int ed psys_threads_free(pthreads); } - /* Calculates paths ready for drawing/rendering. */ /* -Usefull for making use of opengl vertex arrays for super fast strand drawing. */ /* -Makes child strands possible and creates them too into the cache. */ /* -Cached path data is also used to determine cut position for the editmode tool. */ -void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupdate) +void psys_cache_paths(Scene *scene, Object *ob, ParticleSystem *psys, float cfra, int editupdate) { ParticleCacheKey *ca, **cache=psys->pathcache; ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - ParticleEditSettings *pset = &G.scene->toolsettings->particle; + ParticleEditSettings *pset = &scene->toolsettings->particle; ParticleSettings *part = psys->part; ParticleData *pa; - ParticleKey keys[4], result, *kkey[2] = {NULL, NULL}; - HairKey *hkey[2] = {NULL, NULL}; + ParticleKey result; ParticleEdit *edit = 0; ParticleEditKey *ekey = 0; @@ -2372,45 +2577,52 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda BodyPoint *bp[2] = {NULL, NULL}; Material *ma; + + ParticleInterpolationData pind; float birthtime = 0.0, dietime = 0.0; - float t, time = 0.0, keytime = 0.0, dfra = 1.0, frs_sec = G.scene->r.frs_sec; - float col[3] = {0.5f, 0.5f, 0.5f}; + float t, time = 0.0, keytime = 0.0, dfra = 1.0, frs_sec = scene->r.frs_sec; + float col[4] = {0.5f, 0.5f, 0.5f, 1.0f}; float prev_tangent[3], hairmat[4][4]; + float rotmat[3][3]; int k,i; int steps = (int)pow(2.0, (double)psys->part->draw_step); int totpart = psys->totpart; - char nosel[4], sel[4]; float sel_col[3]; float nosel_col[3]; float length, vec[3]; float *vg_effector= NULL, effector=0.0f; - float *vg_length= NULL, pa_length=1.0f, max_length=1.0f, cur_length=0.0f; - float len, dvec[3]; + float *vg_length= NULL, pa_length=1.0f; + int keyed, baked; /* we don't have anything valid to create paths from so let's quit here */ - if((psys->flag & PSYS_HAIR_DONE)==0 && (psys->flag & PSYS_KEYED)==0) + if((psys->flag & PSYS_HAIR_DONE)==0 && (psys->flag & PSYS_KEYED)==0 && (psys->pointcache->flag & PTCACHE_BAKED)==0) return; - if(psys->renderdata) + BLI_srandom(psys->seed); + + keyed = psys->flag & PSYS_KEYED; + baked = psys->pointcache->flag & PTCACHE_BAKED; + + if(psys->renderdata) { steps = (int)pow(2.0, (double)psys->part->ren_step); - else if(psys_in_edit_mode(psys)){ + } + else if(psys_in_edit_mode(scene, psys)) { edit=psys->edit; //timed = edit->draw_timed; - PE_get_colors(sel,nosel); - if(pset->brushtype == PE_BRUSH_WEIGHT){ + if(pset->brushtype == PE_BRUSH_WEIGHT) { sel_col[0] = sel_col[1] = sel_col[2] = 1.0f; nosel_col[0] = nosel_col[1] = nosel_col[2] = 0.0f; } else{ - sel_col[0] = (float)sel[0] / 255.0f; - sel_col[1] = (float)sel[1] / 255.0f; - sel_col[2] = (float)sel[2] / 255.0f; - nosel_col[0] = (float)nosel[0] / 255.0f; - nosel_col[1] = (float)nosel[1] / 255.0f; - nosel_col[2] = (float)nosel[2] / 255.0f; + sel_col[0] = (float)edit->sel_col[0] / 255.0f; + sel_col[1] = (float)edit->sel_col[1] / 255.0f; + sel_col[2] = (float)edit->sel_col[2] / 255.0f; + nosel_col[0] = (float)edit->nosel_col[0] / 255.0f; + nosel_col[1] = (float)edit->nosel_col[1] / 255.0f; + nosel_col[2] = (float)edit->nosel_col[2] / 255.0f; } } @@ -2430,7 +2642,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda soft= NULL; } - psys->lattice = psys_get_lattice(ob, psys); + psys->lattice = psys_get_lattice(scene, ob, psys); ma= give_current_material(ob, psys->part->omat); if(ma && (psys->part->draw & PART_DRAW_MAT_COL)) VECCOPY(col, &ma->r) @@ -2455,7 +2667,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda else memset(cache[i], 0, sizeof(*cache[i])*(steps+1)); if(!edit && !psys->totchild) { - pa_length = part->length * (1.0f - part->randlength*pa->r_ave[0]); + pa_length = 1.0f - part->randlength * 0.5 * (1.0f + pa->r_ave[0]); if(vg_length) pa_length *= psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_length); } @@ -2466,27 +2678,40 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda ekey = edit->keys[i]; /*--get the first data points--*/ - if(psys->flag & PSYS_KEYED) { - kkey[0] = pa->keys; - kkey[1] = kkey[0] + 1; - - birthtime = kkey[0]->time; - dietime = kkey[0][pa->totkey-1].time; - } - else { - hkey[0] = pa->hair; - hkey[1] = hkey[0] + 1; - - birthtime = hkey[0]->time; - dietime = hkey[0][pa->totkey-1].time; + pind.keyed = keyed; + pind.cached = baked; + pind.soft = soft; + init_particle_interpolation(ob, psys, pa, &pind); + + + /* hairmat is needed for for non-hair particle too so we get proper rotations */ + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); + VECCOPY(rotmat[0], hairmat[2]); + VECCOPY(rotmat[1], hairmat[1]); + VECCOPY(rotmat[2], hairmat[0]); + + if(!edit) { + if(part->draw & PART_ABS_PATH_TIME) { + birthtime = MAX2(pind.birthtime, part->path_start); + dietime = MIN2(pind.dietime, part->path_end); + } + else { + float tb = pind.birthtime; + birthtime = tb + part->path_start * (pind.dietime - tb); + dietime = tb + part->path_end * (pind.dietime - tb); + } - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); - } + if(birthtime >= dietime) { + cache[i]->steps = -1; + continue; + } - if(soft){ - bp[0] = soft->bpoint + pa->bpi; - bp[1] = bp[0] + 1; + dietime = birthtime + pa_length * (dietime - birthtime); } + else + /* XXX brecht: don't know if this code from 2.4 is correct + * still, but makes hair appear again in particle mode */ + dietime= pind.hkey[0][pa->totkey-1].time; /*--interpolate actual path from data points--*/ for(k=0, ca=cache[i]; k<=steps; k++, ca++){ @@ -2494,85 +2719,12 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda t = birthtime + time * (dietime - birthtime); - if(psys->flag & PSYS_KEYED) { - while(kkey[1]->time < t) { - kkey[1]++; - } - - kkey[0] = kkey[1] - 1; - } - else { - while(hkey[1]->time < t) { - hkey[1]++; - bp[1]++; - } - - hkey[0] = hkey[1] - 1; - } - - if(soft) { - bp[0] = bp[1] - 1; - bp_to_particle(keys + 1, bp[0], hkey[0]); - bp_to_particle(keys + 2, bp[1], hkey[1]); - } - else if(psys->flag & PSYS_KEYED) { - memcpy(keys + 1, kkey[0], sizeof(ParticleKey)); - memcpy(keys + 2, kkey[1], sizeof(ParticleKey)); - } - else { - hair_to_particle(keys + 1, hkey[0]); - hair_to_particle(keys + 2, hkey[1]); - } - + result.time = -t; - if((psys->flag & PSYS_KEYED)==0) { - if(soft) { - if(hkey[0] != pa->hair) - bp_to_particle(keys, bp[0] - 1, hkey[0] - 1); - else - bp_to_particle(keys, bp[0], hkey[0]); - } - else { - if(hkey[0] != pa->hair) - hair_to_particle(keys, hkey[0] - 1); - else - hair_to_particle(keys, hkey[0]); - } - - if(soft) { - if(hkey[1] != pa->hair + pa->totkey - 1) - bp_to_particle(keys + 3, bp[1] + 1, hkey[1] + 1); - else - bp_to_particle(keys + 3, bp[1], hkey[1]); - } - else { - if(hkey[1] != pa->hair + pa->totkey - 1) - hair_to_particle(keys + 3, hkey[1] + 1); - else - hair_to_particle(keys + 3, hkey[1]); - } - } + do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result); - dfra = keys[2].time - keys[1].time; - - keytime = (t - keys[1].time) / dfra; - - /* convert velocity to timestep size */ - if(psys->flag & PSYS_KEYED){ - VecMulf(keys[1].vel, dfra / frs_sec); - VecMulf(keys[2].vel, dfra / frs_sec); - } - - /* now we should have in chronologiacl order k1<=k2<=t<=k3<=k4 with keytime between [0,1]->[k2,k3] (k1 & k4 used for cardinal & bspline interpolation)*/ - interpolate_particle((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */ - : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL) - ,keys, keytime, &result, 0); - - /* the velocity needs to be converted back from cubic interpolation */ - if(psys->flag & PSYS_KEYED){ - VecMulf(result.vel, frs_sec / dfra); - } - else if(soft==NULL) { /* softbody and keyed are allready in global space */ + /* keyed, baked and softbody are allready in global space */ + if(!keyed && !baked && !soft) { Mat4MulVecfl(hairmat, result.co); } @@ -2582,14 +2734,14 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda if(edit){ if(pset->brushtype==PE_BRUSH_WEIGHT){ if(k==steps) - VecLerpf(ca->col, nosel_col, sel_col, hkey[0]->weight); + VecLerpf(ca->col, nosel_col, sel_col, pind.hkey[0]->weight); else VecLerpf(ca->col, nosel_col, sel_col, - (1.0f - keytime) * hkey[0]->weight + keytime * hkey[1]->weight); + (1.0f - keytime) * pind.hkey[0]->weight + keytime * pind.hkey[1]->weight); } else{ - if((ekey + (hkey[0] - pa->hair))->flag & PEK_SELECT){ - if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){ + if((ekey + (pind.hkey[0] - pa->hair))->flag & PEK_SELECT){ + if((ekey + (pind.hkey[1] - pa->hair))->flag & PEK_SELECT){ VECCOPY(ca->col, sel_col); } else{ @@ -2597,7 +2749,7 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda } } else{ - if((ekey + (hkey[1] - pa->hair))->flag & PEK_SELECT){ + if((ekey + (pind.hkey[1] - pa->hair))->flag & PEK_SELECT){ VecLerpf(ca->col, nosel_col, sel_col, keytime); } else{ @@ -2610,8 +2762,9 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda VECCOPY(ca->col, col); } } + - /*--modify paths--*/ + /*--modify paths and calculate rotation & velocity--*/ VecSubf(vec,(cache[i]+1)->co,cache[i]->co); length = VecLength(vec); @@ -2623,16 +2776,16 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda for(k=0, ca=cache[i]; k<=steps; k++, ca++) { /* apply effectors */ if(!(psys->part->flag & PART_CHILD_EFFECT) && edit==0 && k) - do_path_effectors(ob, psys, i, ca, k, steps, cache[i]->co, effector, dfra, cfra, &length, vec); + do_path_effectors(scene, ob, psys, i, ca, k, steps, cache[i]->co, effector, dfra, cfra, &length, vec); /* apply guide curves to path data */ if(edit==0 && psys->effectors.first && (psys->part->flag & PART_CHILD_EFFECT)==0) /* ca is safe to cast, since only co and vel are used */ - do_guide((ParticleKey*)ca, i, (float)k/(float)steps, &psys->effectors); + do_guide(scene, (ParticleKey*)ca, i, (float)k/(float)steps, &psys->effectors); /* apply lattice */ if(psys->lattice && edit==0) - calc_latt_deform(ca->co, 1.0f); + calc_latt_deform(psys->lattice, ca->co, 1.0f); /* figure out rotation */ @@ -2640,12 +2793,18 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda float cosangle, angle, tangent[3], normal[3], q[4]; if(k == 1) { + /* calculate initial tangent for incremental rotations */ VECSUB(tangent, ca->co, (ca - 1)->co); - - vectoquat(tangent, OB_POSX, OB_POSZ, (ca-1)->rot); - VECCOPY(prev_tangent, tangent); Normalize(prev_tangent); + + /* First rotation is based on emitting face orientation. */ + /* This is way better than having flipping rotations resulting */ + /* from using a global axis as a rotation pole (vec_to_quat()). */ + /* It's not an ideal solution though since it disregards the */ + /* initial tangent, but taking that in to account will allow */ + /* the possibility of flipping again. -jahka */ + Mat3ToQuat_is_ok(rotmat, (ca-1)->rot); } else { VECSUB(tangent, ca->co, (ca - 1)->co); @@ -2684,36 +2843,14 @@ void psys_cache_paths(Object *ob, ParticleSystem *psys, float cfra, int editupda } } - - if(!edit && !psys->totchild) { - /* check if path needs to be cut before actual end of data points */ - if(k){ - VECSUB(dvec,ca->co,(ca-1)->co); - if(part->flag&PART_ABS_LENGTH) - len=VecLength(dvec); - else - len=1.0f/(float)steps; - - k=check_path_length(k,cache[i],ca,max_length,&cur_length,len,dvec); - } - else{ - /* initialize length calculation */ - if(part->flag&PART_ABS_LENGTH) - max_length= part->abslength*pa_length; - else - max_length= pa_length; - - cur_length= 0.0f; - } - } } } psys->totcached = totpart; if(psys && psys->lattice){ - end_latt_deform(); - psys->lattice=0; + end_latt_deform(psys->lattice); + psys->lattice= NULL; } if(vg_effector) @@ -2734,15 +2871,6 @@ void copy_particle_key(ParticleKey *to, ParticleKey *from, int time){ memcpy(to,from,sizeof(ParticleKey)); to->time=to_time; } - /* - VECCOPY(to->co,from->co); - VECCOPY(to->vel,from->vel); - QUATCOPY(to->rot,from->rot); - if(time) - to->time=from->time; - to->flag=from->flag; - to->sbw=from->sbw; - */ } void psys_get_from_key(ParticleKey *key, float *loc, float *vel, float *rot, float *time){ if(loc) VECCOPY(loc,key->co); @@ -2896,17 +3024,78 @@ void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleDa /************************************************/ /* ParticleSettings handling */ /************************************************/ +void object_add_particle_system(Scene *scene, Object *ob) +{ + ParticleSystem *psys; + ModifierData *md; + ParticleSystemModifierData *psmd; + + if(!ob || ob->type != OB_MESH) + return; + + psys = ob->particlesystem.first; + for(; psys; psys=psys->next) + psys->flag &= ~PSYS_CURRENT; + + psys = MEM_callocN(sizeof(ParticleSystem), "particle_system"); + psys->pointcache = BKE_ptcache_add(&psys->ptcaches); + BLI_addtail(&ob->particlesystem, psys); + + psys->part = psys_new_settings("ParticleSettings", NULL); + + if(BLI_countlist(&ob->particlesystem)>1) + sprintf(psys->name, "ParticleSystem %i", BLI_countlist(&ob->particlesystem)); + else + strcpy(psys->name, "ParticleSystem"); + + md= modifier_new(eModifierType_ParticleSystem); + sprintf(md->name, "ParticleSystem %i", BLI_countlist(&ob->particlesystem)); + psmd= (ParticleSystemModifierData*) md; + psmd->psys=psys; + BLI_addtail(&ob->modifiers, md); + + psys->totpart=0; + psys->flag = PSYS_ENABLED|PSYS_CURRENT; + psys->cfra=bsystem_time(scene,ob,scene->r.cfra+1,0.0); + + DAG_scene_sort(scene); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); +} +void object_remove_particle_system(Scene *scene, Object *ob) +{ + ParticleSystem *psys = psys_get_current(ob); + ParticleSystemModifierData *psmd; + + if(!psys) + return; + + /* clear modifier */ + psmd= psys_get_modifier(ob, psys); + BLI_remlink(&ob->modifiers, psmd); + modifier_free((ModifierData *)psmd); + + /* clear particle system */ + BLI_remlink(&ob->particlesystem, psys); + psys_free(ob,psys); + + if(ob->particlesystem.first) + ((ParticleSystem *) ob->particlesystem.first)->flag |= PSYS_CURRENT; + + DAG_scene_sort(scene); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); +} static void default_particle_settings(ParticleSettings *part) { int i; part->type= PART_EMITTER; part->distr= PART_DISTR_JIT; - part->draw_as=PART_DRAW_DOT; + part->draw_as = PART_DRAW_REND; + part->ren_as = PART_DRAW_HALO; part->bb_uv_split=1; part->bb_align=PART_BB_VIEW; part->bb_split_offset=PART_BB_OFF_LINEAR; - part->flag=PART_REACT_MULTIPLE|PART_HAIR_GEOMETRY; + part->flag=PART_REACT_MULTIPLE|PART_HAIR_GEOMETRY|PART_EDISTR|PART_TRAND; part->sta= 1.0; part->end= 100.0; @@ -2915,8 +3104,6 @@ static void default_particle_settings(ParticleSettings *part) part->totpart= 1000; part->grid_res= 10; part->timetweak= 1.0; - part->keyed_time= 0.5; - //part->userjit; part->integrator= PART_INT_MIDPOINT; part->phystype= PART_PHYS_NEWTON; @@ -2930,19 +3117,13 @@ static void default_particle_settings(ParticleSettings *part) part->reactevent= PART_EVENT_DEATH; part->disp=100; part->from= PART_FROM_FACE; - part->length= 1.0; - part->nbetween= 4; - part->boidneighbours= 5; - part->max_vel = 10.0f; - part->average_vel = 0.3f; - part->max_tan_acc = 0.2f; - part->max_lat_acc = 1.0f; + part->normfac= 1.0f; part->reactshape=1.0f; part->mass=1.0; - part->size=1.0; + part->size=0.05; part->childsize=1.0; part->child_nbr=10; @@ -2957,17 +3138,23 @@ static void default_particle_settings(ParticleSettings *part) part->rough2_size=1.0; part->rough_end_shape=1.0; + part->clength=1.0f; + part->clength_thres=0.0f; + + part->draw= PART_DRAW_EMITTER|PART_DRAW_MAT_COL; part->draw_line[0]=0.5; + part->path_start = 0.0f; + part->path_end = 1.0f; - part->banking=1.0; - part->max_bank=1.0; + part->keyed_loops = 1; + + for(i=0; i<10; i++) + part->effector_weight[i]=1.0f; - for(i=0; i<BOID_TOT_RULES; i++){ - part->boidrule[i]=(char)i; - part->boidfac[i]=0.5; - } +#if 0 // XXX old animation system part->ipo = NULL; +#endif // XXX old animation system part->simplify_refsize= 1920; part->simplify_rate= 1.0f; @@ -2980,6 +3167,9 @@ ParticleSettings *psys_new_settings(char *name, Main *main) { ParticleSettings *part; + if(main==NULL) + main = G.main; + part= alloc_libblock(&main->particle, ID_PA, name); default_particle_settings(part); @@ -2994,6 +3184,8 @@ ParticleSettings *psys_copy_settings(ParticleSettings *part) partn= copy_libblock(part); if(partn->pd) partn->pd= MEM_dupallocN(part->pd); if(partn->pd2) partn->pd2= MEM_dupallocN(part->pd2); + + partn->boids = boid_copy_settings(part->boids); return partn; } @@ -3055,47 +3247,26 @@ void make_local_particlesettings(ParticleSettings *part) } } } - -/* should be integrated to depgraph signals */ -void psys_flush_settings(ParticleSettings *part, int event, int hair_recalc) +void psys_flush_particle_settings(Scene *scene, ParticleSettings *part, int recalc) { - Base *base; - Object *ob, *tob; + Base *base = scene->base.first; ParticleSystem *psys; int flush; - /* update all that have same particle settings */ - for(base = G.scene->base.first; base; base= base->next) { - if(base->object->particlesystem.first) { - ob=base->object; - flush=0; - for(psys=ob->particlesystem.first; psys; psys=psys->next){ - if(psys->part==part){ - psys->recalc |= event; - if(hair_recalc) - psys->recalc |= PSYS_RECALC_HAIR; - flush++; - } - else if(psys->part->type==PART_REACTOR){ - ParticleSystem *tpsys; - tob=psys->target_ob; - if(tob==0) - tob=ob; - tpsys=BLI_findlink(&tob->particlesystem,psys->target_psys-1); - - if(tpsys && tpsys->part==part){ - psys->recalc |= event; - flush++; - } - } + for(base = scene->base.first; base; base = base->next) { + flush = 0; + for(psys = base->object->particlesystem.first; psys; psys=psys->next) { + if(psys->part == part) { + psys->recalc |= recalc; + flush++; } - if(flush) - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); } + if(flush) + DAG_object_flush_update(scene, base->object, OB_RECALC_DATA); } } -LinkNode *psys_using_settings(ParticleSettings *part, int flush_update) +LinkNode *psys_using_settings(struct Scene *scene, ParticleSettings *part, int flush_update) { Object *ob, *tob; ParticleSystem *psys, *tpsys; @@ -3123,7 +3294,7 @@ LinkNode *psys_using_settings(ParticleSettings *part, int flush_update) } if(flush_update && found) - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); } return node; @@ -3210,7 +3381,7 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float if((event & mtex->pmapto) & MAP_PA_KINK) ptex->kink= texture_value_blend(def,ptex->kink,value,var,blend,neg & MAP_PA_KINK); if((event & mtex->pmapto) & MAP_PA_ROUGH) - ptex->rough= texture_value_blend(def,ptex->rough,value,var,blend,neg & MAP_PA_ROUGH); + ptex->rough1= ptex->rough2= ptex->roughe= texture_value_blend(def,ptex->rough1,value,var,blend,neg & MAP_PA_ROUGH); if((event & mtex->pmapto) & MAP_PA_DENS) ptex->exist= texture_value_blend(def,ptex->exist,value,var,blend,neg & MAP_PA_DENS); } @@ -3219,7 +3390,11 @@ static void get_cpa_texture(DerivedMesh *dm, Material *ma, int face_index, float if(event & MAP_PA_LENGTH) { CLAMP(ptex->length,0.0,1.0); } if(event & MAP_PA_CLUMP) { CLAMP(ptex->clump,0.0,1.0); } if(event & MAP_PA_KINK) { CLAMP(ptex->kink,0.0,1.0); } - if(event & MAP_PA_ROUGH) { CLAMP(ptex->rough,0.0,1.0); } + if(event & MAP_PA_ROUGH) { + CLAMP(ptex->rough1,0.0,1.0); + CLAMP(ptex->rough2,0.0,1.0); + CLAMP(ptex->roughe,0.0,1.0); + } if(event & MAP_PA_DENS) { CLAMP(ptex->exist,0.0,1.0); } } void psys_get_texture(Object *ob, Material *ma, ParticleSystemModifierData *psmd, ParticleSystem *psys, ParticleData *pa, ParticleTexture *ptex, int event) @@ -3305,10 +3480,12 @@ float psys_get_size(Object *ob, Material *ma, ParticleSystemModifierData *psmd, size=ptex.size; } +#if 0 // XXX old animation system if(icu_size){ calc_icu(icu_size,pa->time); size*=icu_size->curval; } +#endif // XXX old animation system if(vg_size) size*=psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_size); @@ -3318,12 +3495,12 @@ float psys_get_size(Object *ob, Material *ma, ParticleSystemModifierData *psmd, return size*part->size; } -float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra) +float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra, float *birthtime, float *dietime) { ParticleSettings *part = psys->part; + float time, life; if(part->childtype==PART_CHILD_FACES){ - float time; int w=0; time=0.0; while(w<4 && cpa->pa[w]>=0){ @@ -3331,28 +3508,38 @@ float psys_get_child_time(ParticleSystem *psys, ChildParticle *cpa, float cfra) w++; } - return (cfra-time)/(part->lifetime*(1.0f-part->randlife*cpa->rand[1])); + life = part->lifetime*(1.0f-part->randlife*cpa->rand[1]); } else{ ParticleData *pa = psys->particles + cpa->parent; - return (cfra-pa->time)/pa->lifetime; + + time = pa->time; + life = pa->lifetime; } + + if(birthtime) + *birthtime = time; + if(dietime) + *dietime = time+life; + + return (cfra-time)/life; } float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, float *pa_time) { ParticleSettings *part = psys->part; - float size, time; + float size; // time XXX if(part->childtype==PART_CHILD_FACES){ size=part->size; +#if 0 // XXX old animation system if((part->flag&PART_ABS_TIME)==0 && part->ipo){ IpoCurve *icu; if(pa_time) time=*pa_time; else - time=psys_get_child_time(psys,cpa,cfra); + time=psys_get_child_time(psys,cpa,cfra,NULL,NULL); /* correction for lifetime */ calc_ipo(part->ipo, 100*time); @@ -3362,6 +3549,7 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, size = icu->curval; } } +#endif // XXX old animation system } else size=psys->particles[cpa->parent].size; @@ -3373,8 +3561,68 @@ float psys_get_child_size(ParticleSystem *psys, ChildParticle *cpa, float cfra, return size; } +static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx, ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex) +{ + ptex->length= 1.0f - part->randlength*cpa->rand[0]; + ptex->clump=1.0; + ptex->kink=1.0; + ptex->rough1= 1.0; + ptex->rough2= 1.0; + ptex->roughe= 1.0; + ptex->exist= 1.0; + ptex->effector= 1.0; + + ptex->length*= part->clength_thres < cpa->rand[1] ? part->clength : 1.0f; + + get_cpa_texture(ctx->dm,ctx->ma,cpa_num,cpa_fuv,orco,ptex, + MAP_PA_DENS|MAP_PA_LENGTH|MAP_PA_CLUMP|MAP_PA_KINK|MAP_PA_ROUGH); + + + if(ptex->exist < cpa->rand[1]) + return; + + if(ctx->vg_length) + ptex->length*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_length); + if(ctx->vg_clump) + ptex->clump*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_clump); + if(ctx->vg_kink) + ptex->kink*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_kink); + if(ctx->vg_rough1) + ptex->rough1*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough1); + if(ctx->vg_rough2) + ptex->rough2*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_rough2); + if(ctx->vg_roughe) + ptex->roughe*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_roughe); + if(ctx->vg_effector) + ptex->effector*=psys_interpolate_value_from_verts(ctx->dm,cpa_from,cpa_num,cpa_fuv,ctx->vg_effector); +} +static void do_child_modifiers(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSettings *part, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, float mat[4][4], ParticleKey *state, float t) +{ + int guided = 0; + + if(part->flag & PART_CHILD_EFFECT) + /* state is safe to cast, since only co and vel are used */ + guided = do_guide(scene, (ParticleKey*)state, cpa->parent, t, &(psys->effectors)); + + if(guided==0){ + if(part->kink) + do_prekink(state, par, par_rot, t, part->kink_freq * ptex->kink, part->kink_shape, + part->kink_amp, part->kink, part->kink_axis, ob->obmat); + + do_clump(state, par, t, part->clumpfac, part->clumppow, ptex->clump); + } + + if(part->rough1 != 0.0 && ptex->rough1 != 0.0) + do_rough(orco, mat, t, ptex->rough1*part->rough1, part->rough1_size, 0.0, state); + + if(part->rough2 != 0.0 && ptex->rough2 != 0.0) + do_rough(cpa->rand, mat, t, ptex->rough2*part->rough2, part->rough2_size, part->rough2_thres, state); + + if(part->rough_end != 0.0 && ptex->roughe != 0.0) + do_rough_end(cpa->rand, mat, t, ptex->roughe*part->rough_end, part->rough_end_shape, state); +} /* get's hair (or keyed) particles state at the "path time" specified in state->time */ -void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, ParticleKey *state, int vel) +void psys_get_particle_on_path(Scene *scene, Object *ob, ParticleSystem *psys, int p, ParticleKey *state, int vel) { ParticleSettings *part = psys->part; ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); @@ -3382,33 +3630,29 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle ParticleData *pa; ChildParticle *cpa; ParticleTexture ptex; - ParticleKey *kkey[2] = {NULL, NULL}; - HairKey *hkey[2] = {NULL, NULL}; - ParticleKey *par=0, keys[4]; + ParticleKey *par=0, keys[4], tstate; + ParticleThreadContext ctx; /* fake thread context for child modifiers */ + ParticleInterpolationData pind; - float t, real_t, dfra, keytime, frs_sec = G.scene->r.frs_sec; + float t, frs_sec = scene->r.frs_sec; float co[3], orco[3]; float hairmat[4][4]; - float pa_clump = 0.0, pa_kink = 0.0; int totparent = 0; int totpart = psys->totpart; int totchild = psys->totchild; short between = 0, edit = 0; + int keyed = part->phystype & PART_PHYS_KEYED && psys->flag & PSYS_KEYED; + int cached = !keyed && part->type != PART_HAIR; + float *cpa_fuv; int cpa_num; short cpa_from; - //if(psys_in_edit_mode(psys)){ + //if(psys_in_edit_mode(scene, psys)){ // if((psys->edit_path->flag & PSYS_EP_SHOW_CHILD)==0) // totchild=0; // edit=1; //} - /* user want's cubic interpolation but only without sb it possible */ - //if(interpolation==PART_INTER_CUBIC && baked && psys->softflag==OB_SB_ENABLE) - // interpolation=PART_INTER_BSPLINE; - //else if(baked==0) /* it doesn't make sense to use other types for keyed */ - // interpolation=PART_INTER_CUBIC; - t=state->time; CLAMP(t, 0.0, 1.0); @@ -3420,118 +3664,36 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle key_from_object(pa->stick_ob,state); return; } - - if(psys->flag & PSYS_KEYED) { - kkey[0] = pa->keys; - kkey[1] = kkey[0] + 1; - - real_t = kkey[0]->time + t * (kkey[0][pa->totkey-1].time - kkey[0]->time); - } - else { - hkey[0] = pa->hair; - hkey[1] = pa->hair + 1; - - real_t = hkey[0]->time + (hkey[0][pa->totkey-1].time - hkey[0]->time) * t; - } - - if(psys->flag & PSYS_KEYED) { - while(kkey[1]->time < real_t) { - kkey[1]++; - } - kkey[0] = kkey[1] - 1; - memcpy(keys + 1, kkey[0], sizeof(ParticleKey)); - memcpy(keys + 2, kkey[1], sizeof(ParticleKey)); - } - else { - while(hkey[1]->time < real_t) - hkey[1]++; + pind.keyed = keyed; + pind.cached = cached; + pind.soft = NULL; + init_particle_interpolation(ob, psys, pa, &pind); + do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, state); - hkey[0] = hkey[1] - 1; - - hair_to_particle(keys + 1, hkey[0]); - hair_to_particle(keys + 2, hkey[1]); - } - - if((psys->flag & PSYS_KEYED)==0) { - //if(soft){ - // if(key[0] != sbel.keys) - // DB_copy_key(&k1,key[0]-1); - // else - // DB_copy_key(&k1,&k2); - //} - //else{ - if(hkey[0] != pa->hair) - hair_to_particle(keys, hkey[0] - 1); - else - hair_to_particle(keys, hkey[0]); - //} - - //if(soft){ - // if(key[1] != sbel.keys + sbel.totkey-1) - // DB_copy_key(&k4,key[1]+1); - // else - // DB_copy_key(&k4,&k3); - //} - //else { - if(hkey[1] != pa->hair + pa->totkey - 1) - hair_to_particle(keys + 3, hkey[1] + 1); - else - hair_to_particle(keys + 3, hkey[1]); - } - //} - - //psys_get_particle_on_path(bsys,p,t,bkey,ckey[0]); - - //if(part->rotfrom==PART_ROT_KEYS) - // QuatInterpol(state->rot,k2.rot,k3.rot,keytime); - //else{ - // /* TODO: different rotations */ - // float nvel[3]; - // VECCOPY(nvel,state->vel); - // VecMulf(nvel,-1.0f); - // vectoquat(nvel, OB_POSX, OB_POSZ, state->rot); - //} - - dfra = keys[2].time - keys[1].time; - - keytime = (real_t - keys[1].time) / dfra; - - /* convert velocity to timestep size */ - if(psys->flag & PSYS_KEYED){ - VecMulf(keys[1].vel, dfra / frs_sec); - VecMulf(keys[2].vel, dfra / frs_sec); - QuatInterpol(state->rot,keys[1].rot,keys[2].rot,keytime); - } - - interpolate_particle((psys->flag & PSYS_KEYED) ? -1 /* signal for cubic interpolation */ - : ((psys->part->flag & PART_HAIR_BSPLINE) ? KEY_BSPLINE : KEY_CARDINAL) - ,keys, keytime, state, 1); - - /* the velocity needs to be converted back from cubic interpolation */ - if(psys->flag & PSYS_KEYED){ - VecMulf(state->vel, frs_sec / dfra); - } - else { + if(!keyed && !cached) { if((pa->flag & PARS_REKEY)==0) { psys_mat_hair_to_global(ob, psmd->dm, part->from, pa, hairmat); Mat4MulVecfl(hairmat, state->co); Mat4Mul3Vecfl(hairmat, state->vel); if(psys->effectors.first && (part->flag & PART_CHILD_GUIDE)==0) { - do_guide(state, p, state->time, &psys->effectors); + do_guide(scene, state, p, state->time, &psys->effectors); /* TODO: proper velocity handling */ } if(psys->lattice && edit==0) - calc_latt_deform(state->co,1.0f); + calc_latt_deform(psys->lattice, state->co,1.0f); } } } else if(totchild){ //Mat4Invert(imat,ob->obmat); - + cpa=psys->child+p-totpart; + + if(state->time < 0.0f) + t = psys_get_child_time(psys, cpa, -state->time, NULL, NULL); if(totchild && part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){ totparent=(int)(totchild*part->parents*0.3); @@ -3548,8 +3710,8 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle /* get parent states */ while(w<4 && cpa->pa[w]>=0){ - keys[w].time = t; - psys_get_particle_on_path(ob, psys, cpa->pa[w], keys+w, 1); + keys[w].time = state->time; + psys_get_particle_on_path(scene, ob, psys, cpa->pa[w], keys+w, 1); w++; } @@ -3557,8 +3719,6 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle cpa_num=cpa->num; foffset= cpa->foffset; - if(part->childtype == PART_CHILD_FACES) - foffset = -(2.0f + part->childspread); cpa_fuv = cpa->fuv; cpa_from = PART_FROM_FACE; @@ -3569,13 +3729,16 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle //Mat4MulVecfl(ob->obmat,cpa_1st); + pa = psys->particles + cpa->parent; + + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); + pa=0; } else{ /* get the parent state */ - - keys->time = t; - psys_get_particle_on_path(ob,psys,cpa->parent,keys,1); + keys->time = state->time; + psys_get_particle_on_path(scene, ob, psys, cpa->parent, keys,1); /* get the original coordinates (orco) for texture usage */ pa=psys->particles+cpa->parent; @@ -3585,24 +3748,24 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle cpa_fuv=pa->fuv; psys_particle_on_emitter(psmd,cpa_from,cpa_num,DMCACHE_ISCHILD,cpa_fuv,pa->foffset,co,0,0,0,orco,0); + + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); } /* correct child ipo timing */ +#if 0 // XXX old animation system if((part->flag&PART_ABS_TIME)==0 && part->ipo){ calc_ipo(part->ipo, 100.0f*t); execute_ipo((ID *)part, part->ipo); } - - /* get different child parameters from textures & vgroups */ - ptex.clump=1.0; - ptex.kink=1.0; - - get_cpa_texture(psmd->dm,ma,cpa_num,cpa_fuv,orco,&ptex,MAP_PA_CLUMP|MAP_PA_KINK); +#endif // XXX old animation system - pa_clump=ptex.clump; - pa_kink=ptex.kink; - - /* TODO: vertex groups */ + /* get different child parameters from textures & vgroups */ + memset(&ctx, 0, sizeof(ParticleThreadContext)); + ctx.dm = psmd->dm; + ctx.ma = ma; + /* TODO: assign vertex groups */ + get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex); if(between){ int w=0; @@ -3630,50 +3793,37 @@ void psys_get_particle_on_path(Object *ob, ParticleSystem *psys, int p, Particle } par = keys; - //if(totparent){ - // if(p-totpart>=totparent){ - // key.time=t; - // psys_get_particle_on_path(ob,psys,totpart+cpa->parent,&key,1); - // bti->convert_dynamic_key(bsys,&key,par,cpar); - // } - // else - // par=0; - //} - //else - // DB_get_key_on_path(bsys,cpa->parent,t,par,cpar); - - /* apply different deformations to the child path */ - if(part->kink) - do_prekink(state, par, par->rot, t, part->kink_freq * pa_kink, part->kink_shape, - part->kink_amp, part->kink, part->kink_axis, ob->obmat); - - do_clump(state, par, t, part->clumpfac, part->clumppow, 1.0f); - - if(part->rough1 != 0.0) - do_rough(orco, t, part->rough1, part->rough1_size, 0.0, state); - if(part->rough2 != 0.0) - do_rough(cpa->rand, t, part->rough2, part->rough2_size, part->rough2_thres, state); + if(vel) + copy_particle_key(&tstate, state, 1); - if(part->rough_end != 0.0) - do_rough_end(cpa->rand, t, part->rough_end, part->rough_end_shape, state, par); + /* apply different deformations to the child path */ + do_child_modifiers(scene, ob, psys, part, &ptex, par, par->rot, cpa, orco, hairmat, state, t); + + /* try to estimate correct velocity */ + if(vel){ + ParticleKey tstate; + float length = VecLength(state->vel); + + if(t>=0.001f){ + tstate.time=t-0.001f; + psys_get_particle_on_path(scene,ob,psys,p,&tstate,0); + VECSUB(state->vel,state->co,tstate.co); + Normalize(state->vel); + } + else{ + tstate.time=t+0.001f; + psys_get_particle_on_path(scene, ob,psys,p,&tstate,0); + VECSUB(state->vel,tstate.co,state->co); + Normalize(state->vel); + } - //if(vel){ - // if(t>=0.001f){ - // tstate.time=t-0.001f; - // psys_get_particle_on_path(ob,psys,p,&tstate,0); - // VECSUB(state->vel,state->co,tstate.co); - // } - // else{ - // tstate.time=t+0.001f; - // psys_get_particle_on_path(ob,psys,p,&tstate,0); - // VECSUB(state->vel,tstate.co,state->co); - // } - //} + VecMulf(state->vel, length); + } } } /* gets particle's state at a time, returns 1 if particle exists and can be seen and 0 if not */ -int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey *state, int always){ +int psys_get_particle_state(struct Scene *scene, Object *ob, ParticleSystem *psys, int p, ParticleKey *state, int always){ ParticleSettings *part=psys->part; ParticleData *pa=0; float cfra; @@ -3683,7 +3833,7 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey if(state->time>0) cfra=state->time; else - cfra=bsystem_time(0,(float)G.scene->r.cfra,0.0); + cfra= bsystem_time(scene, 0, (float)scene->r.cfra,0.0); if(psys->totchild && p>=totpart){ if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES){ @@ -3696,7 +3846,7 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey pa=psys->particles+p; if(between){ - state->time = psys_get_child_time(psys,&psys->child[p-totpart],cfra); + state->time = psys_get_child_time(psys,&psys->child[p-totpart],cfra,NULL,NULL); if(always==0) if((state->time<0.0 && (part->flag & PART_UNBORN)==0) @@ -3709,6 +3859,8 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey if((pa->alive==PARS_UNBORN && (part->flag & PART_UNBORN)==0) || (pa->alive==PARS_DEAD && (part->flag & PART_DIED)==0)) return 0; + + state->time = MIN2(state->time, pa->dietime); } if(psys->flag & PSYS_KEYED){ @@ -3717,9 +3869,9 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey state->time= (cfra-(part->sta+(part->end-part->sta)*cpa->rand[0]))/(part->lifetime*cpa->rand[1]); } else - state->time= (cfra-pa->time)/(pa->dietime-pa->time); + state->time= -cfra; - psys_get_particle_on_path(ob,psys,p,state,1); + psys_get_particle_on_path(scene, ob, psys, p, state,1); return 1; } else{ @@ -3751,60 +3903,58 @@ int psys_get_particle_state(Object *ob, ParticleSystem *psys, int p, ParticleKey do_clump(state,key1,t,part->clumpfac,part->clumppow,1.0); if(psys->lattice) - calc_latt_deform(state->co,1.0f); + calc_latt_deform(psys->lattice, state->co,1.0f); } else{ - if (pa) { /* TODO PARTICLE - should this ever be NULL? - Campbell */ - if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)) - copy_particle_key(state, &pa->state, 1); - else if(pa->prev_state.time==state->time) - copy_particle_key(state, &pa->prev_state, 1); - else { - /* let's interpolate to try to be as accurate as possible */ - if(pa->state.time + 1.0f > state->time && pa->prev_state.time - 1.0f < state->time) { - ParticleKey keys[4]; - float dfra, keytime, frs_sec = G.scene->r.frs_sec; + if(pa->state.time==state->time || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED)) + copy_particle_key(state, &pa->state, 1); + else if(pa->prev_state.time==state->time) + copy_particle_key(state, &pa->prev_state, 1); + else { + /* let's interpolate to try to be as accurate as possible */ + if(pa->state.time + 1.0f > state->time && pa->prev_state.time - 1.0f < state->time) { + ParticleKey keys[4]; + float dfra, keytime, frs_sec = scene->r.frs_sec; - if(pa->prev_state.time >= pa->state.time) { - /* prev_state is wrong so let's not use it, this can happen at frame 1 or particle birth */ - copy_particle_key(state, &pa->state, 1); + if(pa->prev_state.time >= pa->state.time) { + /* prev_state is wrong so let's not use it, this can happen at frame 1 or particle birth */ + copy_particle_key(state, &pa->state, 1); - VECADDFAC(state->co, state->co, state->vel, (state->time-pa->state.time)/frs_sec); - } - else { - copy_particle_key(keys+1, &pa->prev_state, 1); - copy_particle_key(keys+2, &pa->state, 1); + VECADDFAC(state->co, state->co, state->vel, (state->time-pa->state.time)/frs_sec); + } + else { + copy_particle_key(keys+1, &pa->prev_state, 1); + copy_particle_key(keys+2, &pa->state, 1); - dfra = keys[2].time - keys[1].time; + dfra = keys[2].time - keys[1].time; - keytime = (state->time - keys[1].time) / dfra; + keytime = (state->time - keys[1].time) / dfra; - /* convert velocity to timestep size */ - VecMulf(keys[1].vel, dfra / frs_sec); - VecMulf(keys[2].vel, dfra / frs_sec); - - interpolate_particle(-1, keys, keytime, state, 1); - - /* convert back to real velocity */ - VecMulf(state->vel, frs_sec / dfra); + /* convert velocity to timestep size */ + VecMulf(keys[1].vel, dfra / frs_sec); + VecMulf(keys[2].vel, dfra / frs_sec); + + psys_interpolate_particle(-1, keys, keytime, state, 1); + + /* convert back to real velocity */ + VecMulf(state->vel, frs_sec / dfra); - VecLerpf(state->ave, keys[1].ave, keys[2].ave, keytime); - QuatInterpol(state->rot, keys[1].rot, keys[2].rot, keytime); - } - } - else { - /* extrapolating over big ranges is not accurate so let's just give something close to reasonable back */ - copy_particle_key(state, &pa->state, 0); + VecLerpf(state->ave, keys[1].ave, keys[2].ave, keytime); + QuatInterpol(state->rot, keys[1].rot, keys[2].rot, keytime); } } - - if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){ - key_from_object(pa->stick_ob,state); + else { + /* extrapolating over big ranges is not accurate so let's just give something close to reasonable back */ + copy_particle_key(state, &pa->state, 0); } + } - if(psys->lattice) - calc_latt_deform(state->co,1.0f); + if(pa->alive==PARS_DEAD && part->flag&PART_STICKY && pa->flag&PARS_STICKY && pa->stick_ob){ + key_from_object(pa->stick_ob,state); } + + if(psys->lattice) + calc_latt_deform(psys->lattice, state->co,1.0f); } return 1; @@ -3985,3 +4135,4 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3] VECADDFAC(center, bb->vec, xvec, bb->offset[0]); VECADDFAC(center, center, yvec, bb->offset[1]); } + diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 6ac57934670..2f4a5c28385 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -29,12 +29,15 @@ * ***** END GPL LICENSE BLOCK ***** */ +#include "BLI_storage.h" /* _LARGEFILE_SOURCE */ + #include <stdlib.h> #include <math.h> #include <string.h> #include "MEM_guardedalloc.h" +#include "DNA_boid_types.h" #include "DNA_particle_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -42,11 +45,12 @@ #include "DNA_object_force.h" #include "DNA_object_types.h" #include "DNA_material_types.h" -#include "DNA_ipo_types.h" #include "DNA_curve_types.h" #include "DNA_group_types.h" #include "DNA_scene_types.h" #include "DNA_texture_types.h" +#include "DNA_ipo_types.h" // XXX old animation system stuff... to be removed! +#include "DNA_listBase.h" #include "BLI_rand.h" #include "BLI_jitter.h" @@ -58,7 +62,7 @@ #include "BLI_threads.h" #include "BKE_anim.h" -#include "BKE_bad_level_calls.h" +#include "BKE_boids.h" #include "BKE_cdderivedmesh.h" #include "BKE_collision.h" #include "BKE_displist.h" @@ -69,7 +73,6 @@ #include "BKE_DerivedMesh.h" #include "BKE_object.h" #include "BKE_material.h" -#include "BKE_ipo.h" #include "BKE_softbody.h" #include "BKE_depsgraph.h" #include "BKE_lattice.h" @@ -81,17 +84,12 @@ #include "PIL_time.h" -#include "BSE_headerbuttons.h" - -#include "blendef.h" - #include "RE_shader_ext.h" /* fluid sim particle import */ #ifndef DISABLE_ELBEEM #include "DNA_object_fluidsim.h" #include "LBM_fluidsim.h" -#include "elbeem.h" #include <zlib.h> #include <string.h> @@ -111,14 +109,12 @@ static int get_current_display_percentage(ParticleSystem *psys) { ParticleSettings *part=psys->part; - if(psys->renderdata || (part->child_nbr && part->childtype)) + if(psys->renderdata || (part->child_nbr && part->childtype) + || (psys->pointcache->flag & PTCACHE_BAKING)) return 100; if(part->phystype==PART_PHYS_KEYED){ - if(psys->flag & PSYS_FIRST_KEYED) - return psys->part->disp; - else - return 100; + return psys->part->disp; } else return psys->part->disp; @@ -179,6 +175,7 @@ void psys_reset(ParticleSystem *psys, int mode) static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) { ParticleData *newpars = 0, *pa; + BoidData *newboids = 0; int i, totpart, totsaved = 0; if(new_totpart<0) { @@ -192,22 +189,34 @@ static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) else totpart=new_totpart; - if(totpart) + if(totpart) { newpars= MEM_callocN(totpart*sizeof(ParticleData), "particles"); + + if(psys->part->phystype == PART_PHYS_BOIDS) + newboids = MEM_callocN(totpart*sizeof(BoidData), "Boid Data"); + } if(psys->particles) { totsaved=MIN2(psys->totpart,totpart); /*save old pars*/ - if(totsaved) + if(totsaved) { memcpy(newpars,psys->particles,totsaved*sizeof(ParticleData)); + if(newboids) + memcpy(newboids, psys->particles->boid, totsaved*sizeof(BoidData)); + } + if(psys->particles->keys) MEM_freeN(psys->particles->keys); - for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++) + if(psys->particles->boid) + MEM_freeN(psys->particles->boid); + + for(i=0, pa=newpars; i<totsaved; i++, pa++) { if(pa->keys) { pa->keys= NULL; pa->totkey= 0; } + } for(i=totsaved, pa=psys->particles+totsaved; i<psys->totpart; i++, pa++) if(pa->hair) MEM_freeN(pa->hair); @@ -216,6 +225,13 @@ static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) } psys->particles=newpars; + if(newboids) { + pa = psys->particles; + pa->boid = newboids; + for(i=1, pa++; i<totpart; i++,pa++) + pa->boid = (pa-1)->boid + 1; + } + if(psys->child) { MEM_freeN(psys->child); psys->child=0; @@ -225,7 +241,7 @@ static void realloc_particles(Object *ob, ParticleSystem *psys, int new_totpart) psys->totpart=totpart; } -static int get_psys_child_number(ParticleSystem *psys) +static int get_psys_child_number(struct Scene *scene, ParticleSystem *psys) { int nbr; @@ -234,15 +250,15 @@ static int get_psys_child_number(ParticleSystem *psys) if(psys->renderdata) { nbr= psys->part->ren_child_nbr; - return get_render_child_particle_number(&G.scene->r, nbr); + return get_render_child_particle_number(&scene->r, nbr); } else return psys->part->child_nbr; } -static int get_psys_tot_child(ParticleSystem *psys) +static int get_psys_tot_child(struct Scene *scene, ParticleSystem *psys) { - return psys->totpart*get_psys_child_number(psys); + return psys->totpart*get_psys_child_number(scene, psys); } static void alloc_child_particles(ParticleSystem *psys, int tot) @@ -938,7 +954,7 @@ static int compare_orig_index(const void *p1, const void *p2) /* 6. and we're done! */ /* This is to denote functionality that does not yet work with mesh - only derived mesh */ -int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm, int from) +int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, DerivedMesh *finaldm, int from) { ParticleThreadContext *ctx= threads[0].ctx; Object *ob= ctx->ob; @@ -969,7 +985,7 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm return 0; if (!finaldm->deformedOnly && !CustomData_has_layer( &finaldm->faceData, CD_ORIGINDEX ) ) { - error("Can't paint with the current modifier stack, disable destructive modifiers"); +// XXX error("Can't paint with the current modifier stack, disable destructive modifiers"); return 0; } @@ -991,7 +1007,7 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm BLI_kdtree_balance(tree); - totpart=get_psys_tot_child(psys); + totpart=get_psys_tot_child(scene, psys); cfrom=from=PART_FROM_FACE; if(part->flag&PART_CHILD_SEAMS){ @@ -1040,9 +1056,9 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm } else{ /* no need to figure out distribution */ - int child_nbr= get_psys_child_number(psys); + int child_nbr= get_psys_child_number(scene, psys); - totpart= get_psys_tot_child(psys); + totpart= get_psys_tot_child(scene, psys); alloc_child_particles(psys, totpart); cpa=psys->child; for(i=0; i<child_nbr; i++){ @@ -1389,16 +1405,16 @@ int psys_threads_init_distribution(ParticleThread *threads, DerivedMesh *finaldm return 1; } -static void distribute_particles_on_dm(DerivedMesh *finaldm, Object *ob, ParticleSystem *psys, int from) +static void distribute_particles_on_dm(DerivedMesh *finaldm, Scene *scene, Object *ob, ParticleSystem *psys, int from) { ListBase threads; ParticleThread *pthreads; ParticleThreadContext *ctx; int i, totthread; - pthreads= psys_threads_create(ob, psys); + pthreads= psys_threads_create(scene, ob, psys); - if(!psys_threads_init_distribution(pthreads, finaldm, from)) { + if(!psys_threads_init_distribution(pthreads, scene, finaldm, from)) { psys_threads_free(pthreads); return; } @@ -1438,7 +1454,7 @@ static void distribute_particles_on_shape(Object *ob, ParticleSystem *psys, int pa->num= -1; } } -static void distribute_particles(Object *ob, ParticleSystem *psys, int from) +static void distribute_particles(Scene *scene, Object *ob, ParticleSystem *psys, int from) { ParticleSystemModifierData *psmd=0; int distr_error=0; @@ -1446,7 +1462,7 @@ static void distribute_particles(Object *ob, ParticleSystem *psys, int from) if(psmd){ if(psmd->dm) - distribute_particles_on_dm(psmd->dm,ob,psys,from); + distribute_particles_on_dm(psmd->dm, scene, ob, psys, from); else distr_error=1; } @@ -1468,20 +1484,21 @@ static void distribute_particles(Object *ob, ParticleSystem *psys, int from) } /* threaded child particle distribution and path caching */ -ParticleThread *psys_threads_create(struct Object *ob, struct ParticleSystem *psys) +ParticleThread *psys_threads_create(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys) { ParticleThread *threads; ParticleThreadContext *ctx; int i, totthread; - if(G.scene->r.mode & R_FIXED_THREADS) - totthread= G.scene->r.threads; + if(scene->r.mode & R_FIXED_THREADS) + totthread= scene->r.threads; else totthread= BLI_system_thread_count(); threads= MEM_callocN(sizeof(ParticleThread)*totthread, "ParticleThread"); ctx= MEM_callocN(sizeof(ParticleThreadContext), "ParticleThreadContext"); + ctx->scene= scene; ctx->ob= ob; ctx->psys= psys; ctx->psmd= psys_get_modifier(ob, psys); @@ -1519,8 +1536,8 @@ void psys_threads_free(ParticleThread *threads) MEM_freeN(ctx->vg_roughe); if(ctx->psys->lattice){ - end_latt_deform(); - ctx->psys->lattice=0; + end_latt_deform(ctx->psys->lattice); + ctx->psys->lattice= NULL; } /* distribution */ @@ -1551,7 +1568,7 @@ void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *ps ParticleSettings *part; ParticleTexture ptex; Material *ma=0; - IpoCurve *icu=0; + //IpoCurve *icu=0; // XXX old animation system int totpart; float rand,length; @@ -1574,9 +1591,9 @@ void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *ps pa->lifetime= part->lifetime*ptex.life; if(part->type==PART_HAIR) - pa->time=0.0f; + pa->time= 0.0f; else if(part->type==PART_REACTOR && (part->flag&PART_REACT_STA_END)==0) - pa->time=MAXFRAMEF; + pa->time= 300000.0f; /* max frame */ else{ //icu=find_ipocurve(psys->part->ipo,PART_EMIT_TIME); //if(icu){ @@ -1592,13 +1609,15 @@ void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *ps pa->lifetime=100.0f; } else{ +#if 0 // XXX old animation system icu=find_ipocurve(psys->part->ipo,PART_EMIT_LIFE); if(icu){ calc_icu(icu,100*ptex.time); pa->lifetime*=icu->curval; } +#endif // XXX old animation system - /* need to get every rand even if we don't use them so that randoms don't affect eachother */ + /* need to get every rand even if we don't use them so that randoms don't affect each other */ rand= BLI_frand(); if(part->randlife!=0.0) pa->lifetime*= 1.0f - part->randlife*rand; @@ -1611,12 +1630,15 @@ void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *ps rand= BLI_frand(); /* while loops are to have a spherical distribution (avoid cubic distribution) */ - length=2.0f; - while(length>1.0){ - pa->r_ve[0]=2.0f*(BLI_frand()-0.5f); - pa->r_ve[1]=2.0f*(BLI_frand()-0.5f); - pa->r_ve[2]=2.0f*(BLI_frand()-0.5f); - length=VecLength(pa->r_ve); + if(part->phystype != PART_PHYS_BOIDS) { + /* boids store gravity in r_ve, so skip here */ + length=2.0f; + while(length>1.0){ + pa->r_ve[0]=2.0f*(BLI_frand()-0.5f); + pa->r_ve[1]=2.0f*(BLI_frand()-0.5f); + pa->r_ve[2]=2.0f*(BLI_frand()-0.5f); + length=VecLength(pa->r_ve); + } } length=2.0f; @@ -1649,7 +1671,7 @@ void initialize_particle(ParticleData *pa, int p, Object *ob, ParticleSystem *ps } static void initialize_all_particles(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd) { - IpoCurve *icu=0; + //IpoCurve *icu=0; // XXX old animation system ParticleData *pa; int p, totpart=psys->totpart; @@ -1657,6 +1679,7 @@ static void initialize_all_particles(Object *ob, ParticleSystem *psys, ParticleS initialize_particle(pa,p,ob,psys,psmd); if(psys->part->type != PART_FLUID) { +#if 0 // XXX old animation system icu=find_ipocurve(psys->part->ipo,PART_EMIT_FREQ); if(icu){ float time=psys->part->sta, end=psys->part->end; @@ -1665,6 +1688,7 @@ static void initialize_all_particles(Object *ob, ParticleSystem *psys, ParticleS p=0; pa=psys->particles; + calc_icu(icu,time); v1=icu->curval; if(v1<0.0f) v1=0.0f; @@ -1705,16 +1729,17 @@ static void initialize_all_particles(Object *ob, ParticleSystem *psys, ParticleS pa->flag |= PARS_UNEXIST; } } +#endif // XXX old animation system } } /* sets particle to the emitter surface with initial velocity & rotation */ -void reset_particle(ParticleData *pa, ParticleSystem *psys, ParticleSystemModifierData *psmd, Object *ob, +void reset_particle(Scene *scene, ParticleData *pa, ParticleSystem *psys, ParticleSystemModifierData *psmd, Object *ob, float dtime, float cfra, float *vg_vel, float *vg_tan, float *vg_rot) { ParticleSettings *part; ParticleTexture ptex; ParticleKey state; - IpoCurve *icu=0; + //IpoCurve *icu=0; // XXX old animation system float fac, phasefac, nor[3]={0,0,0},loc[3],tloc[3],vel[3]={0.0,0.0,0.0},rot[4],q2[4]; float r_vel[3],r_ave[3],r_rot[4],p_vel[3]={0.0,0.0,0.0}; float x_vec[3]={1.0,0.0,0.0}, utan[3]={0.0,1.0,0.0}, vtan[3]={0.0,0.0,1.0}, rot_vec[3]={0.0,0.0,0.0}; @@ -1738,7 +1763,7 @@ void reset_particle(ParticleData *pa, ParticleSystem *psys, ParticleSystemModifi if(pa->num == -1) memset(&state, 0, sizeof(state)); else - psys_get_particle_state(tob,tpsys,pa->num,&state,1); + psys_get_particle_state(scene, tob,tpsys,pa->num,&state,1); psys_get_from_key(&state,loc,nor,rot,0); QuatMulVecf(rot,vtan); @@ -1759,7 +1784,7 @@ void reset_particle(ParticleData *pa, ParticleSystem *psys, ParticleSystemModifi else{ /* get precise emitter matrix if particle is born */ if(part->type!=PART_HAIR && pa->time < cfra && pa->time >= psys->cfra) - where_is_object_time(ob,pa->time); + where_is_object_time(scene, ob,pa->time); /* get birth location from object */ if(part->tanfac!=0.0) @@ -1829,117 +1854,163 @@ void reset_particle(ParticleData *pa, ParticleSystem *psys, ParticleSystemModifi QuatMul(r_rot,r_rot,rot); } } - /* conversion done so now we apply new: */ - /* -velocity from: */ - /* *reactions */ - if(dtime>0.0f){ - VECSUB(vel,pa->state.vel,pa->prev_state.vel); - } + if(part->phystype==PART_PHYS_BOIDS) { + float dvec[3], q[4], mat[3][3]; + + VECCOPY(pa->state.co,loc); + + /* boids don't get any initial velocity */ + pa->state.vel[0]=pa->state.vel[1]=pa->state.vel[2]=0.0f; + + /* boids store direction in ave */ + if(fabs(nor[2])==1.0f) { + VecSubf(pa->state.ave, loc, ob->obmat[3]); + Normalize(pa->state.ave); + } + else { + VECCOPY(pa->state.ave, nor); + } + /* and gravity in r_ve */ + pa->r_ve[0] = pa->r_ve[1] = 0.0f; + pa->r_ve[2] = -1.0f; + if(part->acc[2]!=0.0f) + pa->r_ve[2] = part->acc[2]; + + /* calculate rotation matrix */ + Projf(dvec, pa->r_ve, pa->state.ave); + VecSubf(mat[0], pa->state.ave, dvec); + Normalize(mat[0]); + VECCOPY(mat[2], pa->r_ve); + VecMulf(mat[2], -1.0f); + Normalize(mat[2]); + Crossf(mat[1], mat[2], mat[0]); + + /* apply rotation */ + Mat3ToQuat_is_ok(mat, q); + QuatCopy(pa->state.rot, q); - /* *emitter velocity */ - if(dtime!=0.0 && part->obfac!=0.0){ - VECSUB(vel,loc,pa->state.co); - VecMulf(vel,part->obfac/dtime); + pa->boid->health = part->boids->health; + pa->boid->mode = eBoidMode_InAir; + pa->boid->state_id = ((BoidState*)part->boids->states.first)->id; + pa->boid->acc[0]=pa->boid->acc[1]=pa->boid->acc[2]=0.0f; } - - /* *emitter normal */ - if(part->normfac!=0.0) - VECADDFAC(vel,vel,nor,part->normfac); - - /* *emitter tangent */ - if(part->tanfac!=0.0) - VECADDFAC(vel,vel,vtan,part->tanfac*(vg_tan?psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_tan):1.0f)); + else { + /* conversion done so now we apply new: */ + /* -velocity from: */ - /* *texture */ - /* TODO */ + /* *reactions */ + if(dtime>0.0f){ + VECSUB(vel,pa->state.vel,pa->prev_state.vel); + } - /* *random */ - if(part->randfac!=0.0) - VECADDFAC(vel,vel,r_vel,part->randfac); + /* *emitter velocity */ + if(dtime!=0.0 && part->obfac!=0.0){ + VECSUB(vel,loc,pa->state.co); + VecMulf(vel,part->obfac/dtime); + } + + /* *emitter normal */ + if(part->normfac!=0.0) + VECADDFAC(vel,vel,nor,part->normfac); + + /* *emitter tangent */ + if(psmd && part->tanfac!=0.0) + VECADDFAC(vel,vel,vtan,part->tanfac*(vg_tan?psys_particle_value_from_verts(psmd->dm,part->from,pa,vg_tan):1.0f)); - /* *particle */ - if(part->partfac!=0.0) - VECADDFAC(vel,vel,p_vel,part->partfac); + /* *texture */ + /* TODO */ - icu=find_ipocurve(psys->part->ipo,PART_EMIT_VEL); - if(icu){ - calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta))); - ptex.ivel*=icu->curval; - } + /* *random */ + if(part->randfac!=0.0) + VECADDFAC(vel,vel,r_vel,part->randfac); - VecMulf(vel,ptex.ivel); - - VECCOPY(pa->state.vel,vel); + /* *particle */ + if(part->partfac!=0.0) + VECADDFAC(vel,vel,p_vel,part->partfac); - /* -location from emitter */ - VECCOPY(pa->state.co,loc); + //icu=find_ipocurve(psys->part->ipo,PART_EMIT_VEL); + //if(icu){ + // calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta))); + // ptex.ivel*=icu->curval; + //} - /* -rotation */ - pa->state.rot[0]=1.0; - pa->state.rot[1]=pa->state.rot[2]=pa->state.rot[3]=0.0; + VecMulf(vel,ptex.ivel); - if(part->rotmode){ - /* create vector into which rotation is aligned */ - switch(part->rotmode){ - case PART_ROT_NOR: - VecCopyf(rot_vec, nor); - break; - case PART_ROT_VEL: - VecCopyf(rot_vec, vel); - break; - case PART_ROT_GLOB_X: - case PART_ROT_GLOB_Y: - case PART_ROT_GLOB_Z: - rot_vec[part->rotmode - PART_ROT_GLOB_X] = 1.0f; - break; - case PART_ROT_OB_X: - case PART_ROT_OB_Y: - case PART_ROT_OB_Z: - VecCopyf(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]); - break; - } + //if(ELEM(part->phystype, PART_PHYS_GRADU_EX, PART_PHYS_GRADU_SIM)) + // VecAddf(vel,vel,part->acc); - /* create rotation quat */ - VecNegf(rot_vec); - vectoquat(rot_vec, OB_POSX, OB_POSZ, q2); - - /* randomize rotation quat */ - if(part->randrotfac!=0.0f) - QuatInterpol(rot, q2, r_rot, part->randrotfac); - else - QuatCopy(rot,q2); + VECCOPY(pa->state.vel,vel); - /* rotation phase */ - phasefac = part->phasefac; - if(part->randphasefac != 0.0f) /* abuse r_ave[0] as a random number */ - phasefac += part->randphasefac * pa->r_ave[0]; - VecRotToQuat(x_vec, phasefac*(float)M_PI, q_phase); + /* -location from emitter */ + VECCOPY(pa->state.co,loc); - /* combine base rotation & phase */ - QuatMul(pa->state.rot, rot, q_phase); - } + /* -rotation */ + pa->state.rot[0]=1.0; + pa->state.rot[1]=pa->state.rot[2]=pa->state.rot[3]=0.0; + + if(part->rotmode){ + /* create vector into which rotation is aligned */ + switch(part->rotmode){ + case PART_ROT_NOR: + VecCopyf(rot_vec, nor); + break; + case PART_ROT_VEL: + VecCopyf(rot_vec, vel); + break; + case PART_ROT_GLOB_X: + case PART_ROT_GLOB_Y: + case PART_ROT_GLOB_Z: + rot_vec[part->rotmode - PART_ROT_GLOB_X] = 1.0f; + break; + case PART_ROT_OB_X: + case PART_ROT_OB_Y: + case PART_ROT_OB_Z: + VecCopyf(rot_vec, ob->obmat[part->rotmode - PART_ROT_OB_X]); + break; + } + + /* create rotation quat */ + VecNegf(rot_vec); + vectoquat(rot_vec, OB_POSX, OB_POSZ, q2); - /* -angular velocity */ + /* randomize rotation quat */ + if(part->randrotfac!=0.0f) + QuatInterpol(rot, q2, r_rot, part->randrotfac); + else + QuatCopy(rot,q2); - pa->state.ave[0] = pa->state.ave[1] = pa->state.ave[2] = 0.0; + /* rotation phase */ + phasefac = part->phasefac; + if(part->randphasefac != 0.0f) /* abuse r_ave[0] as a random number */ + phasefac += part->randphasefac * pa->r_ave[0]; + VecRotToQuat(x_vec, phasefac*(float)M_PI, q_phase); - if(part->avemode){ - switch(part->avemode){ - case PART_AVE_SPIN: - VECCOPY(pa->state.ave,vel); - break; - case PART_AVE_RAND: - VECCOPY(pa->state.ave,r_ave); - break; + /* combine base rotation & phase */ + QuatMul(pa->state.rot, rot, q_phase); } - Normalize(pa->state.ave); - VecMulf(pa->state.ave,part->avefac); - icu=find_ipocurve(psys->part->ipo,PART_EMIT_AVE); - if(icu){ - calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta))); - VecMulf(pa->state.ave,icu->curval); + /* -angular velocity */ + + pa->state.ave[0] = pa->state.ave[1] = pa->state.ave[2] = 0.0; + + if(part->avemode){ + switch(part->avemode){ + case PART_AVE_SPIN: + VECCOPY(pa->state.ave,vel); + break; + case PART_AVE_RAND: + VECCOPY(pa->state.ave,r_ave); + break; + } + Normalize(pa->state.ave); + VecMulf(pa->state.ave,part->avefac); + + //icu=find_ipocurve(psys->part->ipo,PART_EMIT_AVE); + //if(icu){ + // calc_icu(icu,100*((pa->time-part->sta)/(part->end-part->sta))); + // VecMulf(pa->state.ave,icu->curval); + //} } } @@ -1953,7 +2024,7 @@ void reset_particle(ParticleData *pa, ParticleSystem *psys, ParticleSystemModifi pa->stick_ob = 0; pa->flag &= ~PARS_STICKY; } -static void reset_all_particles(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float dtime, float cfra, int from) +static void reset_all_particles(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float dtime, float cfra, int from) { ParticleData *pa; int p, totpart=psys->totpart; @@ -1962,73 +2033,63 @@ static void reset_all_particles(Object *ob, ParticleSystem *psys, ParticleSystem float *vg_rot=psys_cache_vgroup(psmd->dm,psys,PSYS_VG_ROT); for(p=from, pa=psys->particles+from; p<totpart; p++, pa++) - reset_particle(pa, psys, psmd, ob, dtime, cfra, vg_vel, vg_tan, vg_rot); + reset_particle(scene, pa, psys, psmd, ob, dtime, cfra, vg_vel, vg_tan, vg_rot); if(vg_vel) MEM_freeN(vg_vel); } /************************************************/ -/* Keyed particles */ +/* Particle targets */ /************************************************/ -/* a bit of an unintuitive function :) counts objects in a keyed chain and returns 1 if some of them were selected (used in drawing) */ -int psys_count_keyed_targets(Object *ob, ParticleSystem *psys) +ParticleSystem *psys_get_target_system(Object *ob, ParticleTarget *pt) { - ParticleSystem *kpsys=psys,*tpsys; - ParticleSettings *tpart; - Object *kob=ob,*tob; - int select=ob->flag&SELECT; - short totkeyed=0; - Base *base; + ParticleSystem *psys = NULL; - ListBase lb; - lb.first=lb.last=0; - - tob=psys->keyed_ob; - while(tob){ - if((tpsys=BLI_findlink(&tob->particlesystem,kpsys->keyed_psys-1))){ - tpart=tpsys->part; - - if(tpart->phystype==PART_PHYS_KEYED){ - if(lb.first){ - for(base=lb.first;base;base=base->next){ - if(tob==base->object){ - fprintf(stderr,"Error: loop in keyed chain!\n"); - BLI_freelistN(&lb); - return select; - } - } - } - base=MEM_callocN(sizeof(Base), "keyed base"); - base->object=tob; - BLI_addtail(&lb,base); - - if(tob->flag&SELECT) - select++; - kob=tob; - kpsys=tpsys; - tob=tpsys->keyed_ob; - totkeyed++; - } - else{ - tob=0; - totkeyed++; - } + if(pt->ob == NULL || pt->ob == ob) + psys = BLI_findlink(&ob->particlesystem, pt->psys-1); + else + psys = BLI_findlink(&pt->ob->particlesystem, pt->psys-1); + + if(psys) + pt->flag |= PTARGET_VALID; + else + pt->flag &= ~PTARGET_VALID; + + return psys; +} +/************************************************/ +/* Keyed particles */ +/************************************************/ +/* Counts valid keyed targets */ +void psys_count_keyed_targets(Object *ob, ParticleSystem *psys) +{ + ParticleSystem *kpsys; + ParticleTarget *pt = psys->targets.first; + int keys_valid = 1; + psys->totkeyed = 0; + + for(; pt; pt=pt->next) { + kpsys = psys_get_target_system(ob, pt); + + if(kpsys && kpsys->totpart) { + psys->totkeyed += keys_valid; + if(psys->flag & PSYS_KEYED_TIMING && pt->duration != 0.0f) + psys->totkeyed += 1; + } + else { + keys_valid = 0; } - else - tob=0; } - psys->totkeyed=totkeyed; - BLI_freelistN(&lb); - return select; + + psys->totkeyed *= psys->flag & PSYS_KEYED_TIMING ? 1 : psys->part->keyed_loops; } -static void set_keyed_keys(Object *ob, ParticleSystem *psys) +static void set_keyed_keys(Scene *scene, Object *ob, ParticleSystem *psys) { - Object *kob = ob; ParticleSystem *kpsys = psys; + ParticleTarget *pt; ParticleData *pa; - int totpart = psys->totpart, i, k, totkeys = psys->totkeyed + 1; - float prevtime, nexttime, keyedtime; + int totpart = psys->totpart, i, k, totkeys = psys->totkeyed; /* no proper targets so let's clear and bail out */ if(psys->totkeyed==0) { @@ -2040,7 +2101,7 @@ static void set_keyed_keys(Object *ob, ParticleSystem *psys) if(totpart && psys->particles->totkey != totkeys) { free_keyed_keys(psys); - psys->particles->keys = MEM_callocN(psys->totpart*totkeys*sizeof(ParticleKey), "Keyed keys"); + psys->particles->keys = MEM_callocN(totpart*totkeys*sizeof(ParticleKey), "Keyed keys"); psys->particles->totkey = totkeys; for(i=1, pa=psys->particles+1; i<totpart; i++,pa++){ @@ -2051,32 +2112,36 @@ static void set_keyed_keys(Object *ob, ParticleSystem *psys) psys->flag &= ~PSYS_KEYED; + + pt = psys->targets.first; for(k=0; k<totkeys; k++) { + if(pt->ob) + kpsys = BLI_findlink(&pt->ob->particlesystem, pt->psys - 1); + else + kpsys = BLI_findlink(&ob->particlesystem, pt->psys - 1); + for(i=0,pa=psys->particles; i<totpart; i++, pa++) { (pa->keys + k)->time = -1.0; /* use current time */ - if(kpsys->totpart > 0) - psys_get_particle_state(kob, kpsys, i%kpsys->totpart, pa->keys + k, 1); + psys_get_particle_state(scene, pt->ob, kpsys, i%kpsys->totpart, pa->keys + k, 1); - if(k==0) - pa->keys->time = pa->time; - else if(k==totkeys-1) - (pa->keys + k)->time = pa->time + pa->lifetime; - else{ - if(psys->flag & PSYS_KEYED_TIME){ - prevtime = (pa->keys + k - 1)->time; - nexttime = pa->time + pa->lifetime; - keyedtime = kpsys->part->keyed_time; - (pa->keys + k)->time = (1.0f - keyedtime) * prevtime + keyedtime * nexttime; + if(psys->flag & PSYS_KEYED_TIMING){ + (pa->keys+k)->time = pa->time + pt->time; + if(pt->duration != 0.0f && k+1 < totkeys) { + copy_particle_key(pa->keys+k+1, pa->keys+k, 1); + (pa->keys+k+1)->time = pa->time + pt->time + pt->duration; } - else - (pa->keys+k)->time = pa->time + (float)k / (float)(totkeys - 1) * pa->lifetime; } + else if(totkeys > 1) + (pa->keys+k)->time = pa->time + (float)k / (float)(totkeys - 1) * pa->lifetime; + else + pa->keys->time = pa->time; } - if(kpsys->keyed_ob){ - kob = kpsys->keyed_ob; - kpsys = BLI_findlink(&kob->particlesystem, kpsys->keyed_psys - 1); - } + + if(psys->flag & PSYS_KEYED_TIMING && pt->duration!=0.0f) + k++; + + pt = (pt->next && pt->next->flag & PTARGET_VALID)? pt->next : psys->targets.first; } psys->flag |= PSYS_KEYED; @@ -2192,62 +2257,62 @@ void psys_get_reactor_target(Object *ob, ParticleSystem *psys, Object **target_o /************************************************/ /* Point Cache */ /************************************************/ - -static void write_particles_to_cache(Object *ob, ParticleSystem *psys, int cfra) +void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys) { + PointCache *cache = psys->pointcache; PTCacheID pid; - PTCacheFile *pf; - ParticleData *pa; - int i, totpart= psys->totpart; - if(totpart == 0) + if((cache->flag & PTCACHE_DISK_CACHE)==0 || cache->mem_cache.first) return; BKE_ptcache_id_from_particles(&pid, ob, psys); - pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, cfra); - if(!pf) - return; - /* assuming struct consists of tightly packed floats */ - for(i=0, pa=psys->particles; i<totpart; i++, pa++) - BKE_ptcache_file_write_floats(pf, (float*)&pa->state, sizeof(ParticleKey)/sizeof(float)); - - BKE_ptcache_file_close(pf); + BKE_ptcache_disk_to_mem(&pid); } - -static int get_particles_from_cache(Object *ob, ParticleSystem *psys, int cfra) +void psys_clear_temp_pointcache(ParticleSystem *psys) { - PTCacheID pid; - PTCacheFile *pf; - ParticleData *pa; - int i, totpart= psys->totpart; + PTCacheMem *pm = psys->pointcache->mem_cache.first; - if(totpart == 0) - return 0; - - BKE_ptcache_id_from_particles(&pid, ob, psys); - pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, cfra); - if(!pf) - return 0; - - /* assuming struct consists of tightly packed floats */ - for(i=0, pa=psys->particles; i<totpart; i++, pa++) { - if(cfra!=pa->state.time) - copy_particle_key(&pa->prev_state,&pa->state,1); - if(!BKE_ptcache_file_read_floats(pf, (float*)&pa->state, sizeof(ParticleKey)/sizeof(float))) { - BKE_ptcache_file_close(pf); - return 0; - } - } + if((psys->pointcache->flag & PTCACHE_DISK_CACHE)==0) + return; - BKE_ptcache_file_close(pf); + BKE_ptache_free_mem(psys->pointcache); +} +void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra, int *efra) +{ + ParticleSettings *part = psys->part; - return 1; + *sfra = MAX2(1, (int)part->sta); + *efra = MIN2((int)(part->end + part->lifetime + 1.0), scene->r.efra); } /************************************************/ /* Effectors */ /************************************************/ +static void update_particle_tree(ParticleSystem *psys) +{ + if(psys) { + ParticleData *pa = psys->particles; + int p, totpart = psys->totpart; + + if(!psys->tree || psys->tree_frame != psys->cfra) { + + BLI_kdtree_free(psys->tree); + + psys->tree = BLI_kdtree_new(totpart); + + for(p=0, pa=psys->particles; p<totpart; p++,pa++){ + if(pa->flag & (PARS_NO_DISP+PARS_UNEXIST) || pa->alive != PARS_ALIVE) + continue; + + BLI_kdtree_insert(psys->tree, p, pa->state.co, NULL); + } + BLI_kdtree_balance(psys->tree); + + psys->tree_frame = psys->cfra; + } + } +} static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, short object, float *pa_co, float obmat[4][4], float force_val, float falloff, float *field) { TexResult result[4]; @@ -2320,7 +2385,7 @@ static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, VecAddf(field,field,mag_vec); } -static void add_to_effectors(ListBase *lb, Object *ob, Object *obsrc, ParticleSystem *psys) +static void add_to_effectors(ListBase *lb, Scene *scene, Object *ob, Object *obsrc, ParticleSystem *psys) { ParticleEffectorCache *ec; PartDeflect *pd= ob->pd; @@ -2332,7 +2397,7 @@ static void add_to_effectors(ListBase *lb, Object *ob, Object *obsrc, ParticleSy Curve *cu= ob->data; if(cu->flag & CU_PATH) { if(cu->path==NULL || cu->path->data==NULL) - makeDispListCurveTypes(ob, 0); + makeDispListCurveTypes(scene, ob, 0); if(cu->path && cu->path->data) { type |= PSYS_EC_EFFECTOR; } @@ -2369,6 +2434,8 @@ static void add_to_effectors(ListBase *lb, Object *ob, Object *obsrc, ParticleSy Object *tob; for(i=0; epsys; epsys=epsys->next,i++){ + if(!psys_check_enabled(ob, epsys)) + continue; type=0; if(epsys!=psys || (psys->part->flag & PART_SELF_EFFECT)){ epart=epsys->part; @@ -2403,7 +2470,7 @@ static void add_to_effectors(ListBase *lb, Object *ob, Object *obsrc, ParticleSy } } -static void psys_init_effectors_recurs(Object *ob, Object *obsrc, ParticleSystem *psys, ListBase *listb, int level) +static void psys_init_effectors_recurs(Scene *scene, Object *ob, Object *obsrc, ParticleSystem *psys, ListBase *listb, int level) { Group *group; GroupObject *go; @@ -2413,17 +2480,17 @@ static void psys_init_effectors_recurs(Object *ob, Object *obsrc, ParticleSystem if(ob->lay & layer) { if(ob->pd || ob->particlesystem.first) - add_to_effectors(listb, ob, obsrc, psys); + add_to_effectors(listb, scene, ob, obsrc, psys); if(ob->dup_group) { group= ob->dup_group; for(go= group->gobject.first; go; go= go->next) - psys_init_effectors_recurs(go->ob, obsrc, psys, listb, level+1); + psys_init_effectors_recurs(scene, go->ob, obsrc, psys, listb, level+1); } } } -void psys_init_effectors(Object *obsrc, Group *group, ParticleSystem *psys) +void psys_init_effectors(Scene *scene, Object *obsrc, Group *group, ParticleSystem *psys) { ListBase *listb= &psys->effectors; Base *base; @@ -2434,11 +2501,11 @@ void psys_init_effectors(Object *obsrc, Group *group, ParticleSystem *psys) GroupObject *go; for(go= group->gobject.first; go; go= go->next) - psys_init_effectors_recurs(go->ob, obsrc, psys, listb, 0); + psys_init_effectors_recurs(scene, go->ob, obsrc, psys, listb, 0); } else { - for(base = G.scene->base.first; base; base= base->next) - psys_init_effectors_recurs(base->object, obsrc, psys, listb, 0); + for(base = scene->base.first; base; base= base->next) + psys_init_effectors_recurs(scene, base->object, obsrc, psys, listb, 0); } } @@ -2447,34 +2514,32 @@ void psys_end_effectors(ParticleSystem *psys) /* NOTE: ec->ob is not valid in here anymore! - dg */ - ListBase *lb=&psys->effectors; - if(lb->first) { - ParticleEffectorCache *ec; - for(ec= lb->first; ec; ec= ec->next){ - if(ec->distances) - MEM_freeN(ec->distances); + ParticleEffectorCache *ec = psys->effectors.first; - if(ec->locations) - MEM_freeN(ec->locations); + for(; ec; ec= ec->next){ + if(ec->distances) + MEM_freeN(ec->distances); - if(ec->face_minmax) - MEM_freeN(ec->face_minmax); + if(ec->locations) + MEM_freeN(ec->locations); - if(ec->vert_cos) - MEM_freeN(ec->vert_cos); + if(ec->face_minmax) + MEM_freeN(ec->face_minmax); - if(ec->tree) - BLI_kdtree_free(ec->tree); - - if(ec->rng) - rng_free(ec->rng); - } + if(ec->vert_cos) + MEM_freeN(ec->vert_cos); - BLI_freelistN(lb); + if(ec->tree) + BLI_kdtree_free(ec->tree); + + if(ec->rng) + rng_free(ec->rng); } + + BLI_freelistN(&psys->effectors); } -static void precalc_effectors(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra) +static void precalc_effectors(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra) { ListBase *lb=&psys->effectors; ParticleEffectorCache *ec; @@ -2538,7 +2603,7 @@ static void precalc_effectors(Object *ob, ParticleSystem *psys, ParticleSystemMo ec->tree=tree; for(p=0, epa=epsys->particles; p<totepart; p++,epa++) - if(epa->alive==PARS_ALIVE && psys_get_particle_state(eob,epsys,p,&state,0)) + if(epa->alive==PARS_ALIVE && psys_get_particle_state(scene, eob,epsys,p,&state,0)) BLI_kdtree_insert(tree, p, state.co, NULL); BLI_kdtree_balance(tree); @@ -2554,9 +2619,86 @@ static void precalc_effectors(Object *ob, ParticleSystem *psys, ParticleSystemMo } } +int effector_find_co(Scene *scene, float *pco, SurfaceModifierData *sur, Object *ob, PartDeflect *pd, float *co, float *nor, float *vel, int *index) +{ + SurfaceModifierData *surmd = NULL; + int ret = 0; + + if(sur) + surmd = sur; + else if(pd && pd->flag&PFIELD_SURFACE) + { + surmd = (SurfaceModifierData *)modifiers_findByType ( ob, eModifierType_Surface ); + } + + if(surmd) { + /* closest point in the object surface is an effector */ + BVHTreeNearest nearest; + + nearest.index = -1; + nearest.dist = FLT_MAX; + + BLI_bvhtree_find_nearest(surmd->bvhtree->tree, pco, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree); + if(nearest.index != -1) { + VECCOPY(co, nearest.co); + + if(nor) { + VECCOPY(nor, nearest.no); + } + + if(vel) { + MFace *mface = CDDM_get_face(surmd->dm, nearest.index); + + VECCOPY(vel, surmd->v[mface->v1].co); + VecAddf(vel, vel, surmd->v[mface->v2].co); + VecAddf(vel, vel, surmd->v[mface->v3].co); + if(mface->v4) + VecAddf(vel, vel, surmd->v[mface->v4].co); + + VecMulf(vel, mface->v4 ? 0.25f : 0.333f); + } + + if(index) + *index = nearest.index; + + ret = 1; + } + else { + co[0] = co[1] = co[2] = 0.0f; + + if(nor) + nor[0] = nor[1] = nor[2] = 0.0f; + + if(vel) + vel[0] = vel[1] = vel[2] = 0.0f; + } + } + else { + /* use center of object for distance calculus */ + VECCOPY(co, ob->obmat[3]); + + if(nor) { + VECCOPY(nor, ob->obmat[2]); + } + + if(vel) { + Object obcopy = *ob; + + VECCOPY(vel, ob->obmat[3]); + + where_is_object_time(scene, ob, scene->r.cfra - 1.0); + + VecSubf(vel, vel, ob->obmat[3]); + + *ob = obcopy; + } + } + + return ret; +} /* calculate forces that all effectors apply to a particle*/ -void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, ParticleSystem *psys, float *rootco, float *force_field, float *vel,float framestep, float cfra) +void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene, Object *ob, ParticleSystem *psys, float *rootco, float *force_field, float *vel,float framestep, float cfra) { Object *eob; ParticleSystem *epsys; @@ -2564,12 +2706,11 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P ParticleData *epa; ParticleKey estate; PartDeflect *pd; - SurfaceModifierData *surmd = NULL; ListBase *lb=&psys->effectors; ParticleEffectorCache *ec; - float distance, vec_to_part[3]; - float falloff, charge = 0.0f; - int p; + float distance, vec_to_part[3], pco[3], co[3]; + float falloff, charge = 0.0f, strength; + int p, face_index=-1; /* check all effector objects for interaction */ if(lb->first){ @@ -2590,48 +2731,36 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P if(ec->type & PSYS_EC_EFFECTOR){ pd=eob->pd; if(psys->part->type!=PART_HAIR && psys->part->integrator) - where_is_object_time(eob,cfra); + where_is_object_time(scene, eob,cfra); if(pd && pd->flag&PFIELD_SURFACE) { - surmd = (SurfaceModifierData *)modifiers_findByType ( eob, eModifierType_Surface ); - } - if(surmd) { - /* closest point in the object surface is an effector */ - BVHTreeNearest nearest; float velocity[3]; - - nearest.index = -1; - nearest.dist = FLT_MAX; - /* using velocity corrected location allows for easier sliding over effector surface */ VecCopyf(velocity, state->vel); VecMulf(velocity, psys_get_timestep(psys->part)); - VecAddf(vec_to_part, state->co, velocity); - - BLI_bvhtree_find_nearest(surmd->bvhtree->tree, vec_to_part, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree); - - if(nearest.index != -1) { - VecSubf(vec_to_part, state->co, nearest.co); - } - else - vec_to_part[0] = vec_to_part[1] = vec_to_part[2] = 0.0f; + VecAddf(pco, state->co, velocity); } else - /* use center of object for distance calculus */ - VecSubf(vec_to_part, state->co, eob->obmat[3]); + VECCOPY(pco, state->co); + + effector_find_co(scene, pco, NULL, eob, pd, co, NULL, NULL, &face_index); + + VecSubf(vec_to_part, state->co, co); distance = VecLength(vec_to_part); falloff=effector_falloff(pd,eob->obmat[2],vec_to_part); + strength = pd->f_strength * psys->part->effector_weight[0] * psys->part->effector_weight[pd->forcefield]; + if(falloff<=0.0f) ; /* don't do anything */ else if(pd->forcefield==PFIELD_TEXTURE) { do_texture_effector(pd->tex, pd->tex_mode, pd->flag&PFIELD_TEX_2D, pd->tex_nabla, pd->flag & PFIELD_TEX_OBJECT, (pd->flag & PFIELD_TEX_ROOTCO) ? rootco : state->co, eob->obmat, - pd->f_strength, falloff, force_field); + strength, falloff, force_field); } else { - do_physical_effector(eob, state->co, pd->forcefield,pd->f_strength,distance, + do_physical_effector(scene, eob, state->co, pd->forcefield,strength,distance, falloff,0.0,pd->f_damp,eob->obmat[2],vec_to_part, state->vel,force_field,pd->flag&PFIELD_PLANAR,ec->rng,pd->f_noise,charge,pa->size); } @@ -2655,7 +2784,7 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P p=0; } - epsys->lattice=psys_get_lattice(ob,psys); + epsys->lattice= psys_get_lattice(scene, ob, psys); for(; p<totepart; p++){ /* particle skips itself as effector */ @@ -2663,7 +2792,7 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P epa = epsys->particles + p; estate.time=cfra; - if(psys_get_particle_state(eob,epsys,p,&estate,0)){ + if(psys_get_particle_state(scene, eob,epsys,p,&estate,0)){ VECSUB(vec_to_part, state->co, estate.co); distance = VecLength(vec_to_part); @@ -2672,25 +2801,27 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P falloff=effector_falloff(pd,estate.vel,vec_to_part); + strength = pd->f_strength * psys->part->effector_weight[0] * psys->part->effector_weight[pd->forcefield]; + if(falloff<=0.0f) ; /* don't do anything */ else - do_physical_effector(eob, state->co, pd->forcefield,pd->f_strength,distance, + do_physical_effector(scene, eob, state->co, pd->forcefield,strength,distance, falloff,epart->size,pd->f_damp,estate.vel,vec_to_part, state->vel,force_field,0, ec->rng, pd->f_noise,charge,pa->size); } } else if(pd && pd->forcefield==PFIELD_HARMONIC && cfra-framestep <= epa->dietime && cfra>epa->dietime){ /* first step after key release */ - psys_get_particle_state(eob,epsys,p,&estate,1); + psys_get_particle_state(scene, eob,epsys,p,&estate,1); VECADD(vel,vel,estate.vel); /* TODO: add rotation handling here too */ } } if(epsys->lattice){ - end_latt_deform(); - epsys->lattice=0; + end_latt_deform(epsys->lattice); + epsys->lattice= NULL; } } } @@ -2701,7 +2832,7 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P /* Newtonian physics */ /************************************************/ /* gathers all forces that effect particles and calculates a new state for the particle */ -static void apply_particle_forces(int pa_no, ParticleData *pa, Object *ob, ParticleSystem *psys, ParticleSettings *part, float timestep, float dfra, float cfra) +static void apply_particle_forces(Scene *scene, int pa_no, ParticleData *pa, Object *ob, ParticleSystem *psys, ParticleSettings *part, float timestep, float dfra, float cfra) { ParticleKey states[5], tkey; float force[3],tvel[3],dx[4][3],dv[4][3]; @@ -2733,7 +2864,7 @@ static void apply_particle_forces(int pa_no, ParticleData *pa, Object *ob, Parti tvel[0]=tvel[1]=tvel[2]=0.0; /* add effectors */ if(part->type != PART_HAIR) - do_effectors(pa_no,pa,states+i,ob,psys,states->co,force,tvel,dfra,fra); + do_effectors(pa_no,pa,states+i,scene, ob, psys,states->co,force,tvel,dfra,fra); /* calculate air-particle interaction */ if(part->dragfac!=0.0f){ @@ -2837,7 +2968,7 @@ static void apply_particle_forces(int pa_no, ParticleData *pa, Object *ob, Parti tkey.time=pa->state.time; if(part->type != PART_HAIR) { - if(do_guide(&tkey,pa_no,time,&psys->effectors)) { + if(do_guide(scene, &tkey, pa_no, time, &psys->effectors)) { VECCOPY(pa->state.co,tkey.co); /* guides don't produce valid velocity */ VECSUB(pa->state.vel,tkey.co,pa->prev_state.co); @@ -2902,7 +3033,7 @@ static void intersect_dm_quad_weights(float *v1, float *v2, float *v3, float *v4 } /* check intersection with a derivedmesh */ -int psys_intersect_dm(Object *ob, DerivedMesh *dm, float *vert_cos, float *co1, float* co2, float *min_d, int *min_face, float *min_w, +int psys_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, float *vert_cos, float *co1, float* co2, float *min_d, int *min_face, float *min_w, float *face_minmax, float *pa_minmax, float radius, float *ipoint) { MFace *mface=0; @@ -2914,9 +3045,9 @@ int psys_intersect_dm(Object *ob, DerivedMesh *dm, float *vert_cos, float *co1, if(dm==0){ psys_disable_all(ob); - dm=mesh_get_derived_final(ob,0); + dm=mesh_get_derived_final(scene, ob, 0); if(dm==0) - dm=mesh_get_derived_deform(ob,0); + dm=mesh_get_derived_deform(scene, ob, 0); psys_enable_all(ob); @@ -3027,20 +3158,7 @@ int psys_intersect_dm(Object *ob, DerivedMesh *dm, float *vert_cos, float *co1, return intersect; } -/* container for moving data between deflet_particle and particle_intersect_face */ -typedef struct ParticleCollision -{ - struct Object *ob, *ob_t; // collided and current objects - struct CollisionModifierData *md; // collision modifier for ob_t; - float nor[3]; // normal at collision point - float vel[3]; // velocity of collision point - float co1[3], co2[3]; // ray start and end points - float ray_len; // original length of co2-co1, needed for collision time evaluation - float t; // time of previous collision, needed for substracting face velocity -} -ParticleCollision; - -static void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { ParticleCollision *col = (ParticleCollision *) userdata; MFace *face = col->md->mfaces + index; @@ -3114,21 +3232,28 @@ static void particle_intersect_face(void *userdata, int index, const BVHTreeRay /* angular momentum <-> linear momentum and swept sphere - mesh collisions */ /* 1. check for all possible deflectors for closest intersection on particle path */ /* 2. if deflection was found kill the particle or calculate new coordinates */ -static void deflect_particle(Object *pob, ParticleSystemModifierData *psmd, ParticleSystem *psys, ParticleSettings *part, ParticleData *pa, int p, float timestep, float dfra, float cfra){ - Object *ob = NULL; +static void deflect_particle(Scene *scene, Object *pob, ParticleSystemModifierData *psmd, ParticleSystem *psys, ParticleSettings *part, ParticleData *pa, int p, float timestep, float dfra, float cfra){ + Object *ob = NULL, *skip_ob = NULL; ListBase *lb=&psys->effectors; ParticleEffectorCache *ec; ParticleKey reaction_state; ParticleCollision col; BVHTreeRayHit hit; float ray_dir[3], zerovec[3]={0.0,0.0,0.0}; - float radius = ((part->flag & PART_SIZE_DEFL)?pa->size:0.0f); + float radius = ((part->flag & PART_SIZE_DEFL)?pa->size:0.0f), boid_z; int deflections=0, max_deflections=10; VECCOPY(col.co1, pa->prev_state.co); VECCOPY(col.co2, pa->state.co); col.t = 0.0f; + /* override for boids */ + if(part->phystype == PART_PHYS_BOIDS) { + radius = pa->size; + boid_z = pa->state.co[2]; + skip_ob = pa->stick_ob; + } + /* 10 iterations to catch multiple deflections */ if(lb->first) while(deflections < max_deflections){ /* 1. */ @@ -3146,13 +3271,17 @@ static void deflect_particle(Object *pob, ParticleSystemModifierData *psmd, Part if(ec->type & PSYS_EC_DEFLECT){ ob= ec->ob; - if(part->type!=PART_HAIR) - where_is_object_time(ob,cfra); + /* for boids: don't check with current ground object */ + if(ob==skip_ob) + continue; /* particles should not collide with emitter at birth */ if(ob==pob && pa->time < cfra && pa->time >= psys->cfra) continue; + if(part->type!=PART_HAIR) + where_is_object_time(scene,ob,cfra); + col.md = ( CollisionModifierData * ) ( modifiers_findByType ( ec->ob, eModifierType_Collision ) ); col.ob_t = ob; @@ -3284,6 +3413,13 @@ static void deflect_particle(Object *pob, ParticleSystemModifierData *psmd, Part /* make sure we don't hit the current face again */ VECADDFAC(co, co, col.nor, (through ? -0.0001f : 0.0001f)); + if(part->phystype == PART_PHYS_BOIDS && part->boids->options & BOID_ALLOW_LAND) { + if(pa->boid->mode == eBoidMode_OnLand || co[2] <= boid_z) { + co[2] = boid_z; + vel[2] = 0.0f; + } + } + /* store state for reactors */ VECCOPY(reaction_state.co, co); VecLerpf(reaction_state.vel, pa->prev_state.vel, pa->state.vel, dt); @@ -3317,622 +3453,9 @@ static void deflect_particle(Object *pob, ParticleSystemModifierData *psmd, Part } } /************************************************/ -/* Boid physics */ -/************************************************/ -static int boid_see_mesh(ListBase *lb, Object *pob, ParticleSystem *psys, float *vec1, float *vec2, float *loc, float *nor, float cfra) -{ - Object *ob, *min_ob; - DerivedMesh *dm; - MFace *mface; - MVert *mvert; - ParticleEffectorCache *ec; - ParticleSystemModifierData *psmd=psys_get_modifier(pob,psys); - float imat[4][4]; - float co1[3], co2[3], min_w[4], min_d; - int min_face=0, intersect=0; - - if(lb->first){ - intersect=0; - min_d=20000.0; - min_ob=NULL; - for(ec=lb->first; ec; ec=ec->next){ - if(ec->type & PSYS_EC_DEFLECT){ - ob= ec->ob; - - if(psys->part->type!=PART_HAIR) - where_is_object_time(ob,cfra); - - if(ob==pob) - dm=psmd->dm; - else - dm=0; - - VECCOPY(co1,vec1); - VECCOPY(co2,vec2); - - if(ec->vert_cos==0){ - /* convert particle coordinates to object coordinates */ - Mat4Invert(imat,ob->obmat); - - Mat4MulVecfl(imat,co1); - Mat4MulVecfl(imat,co2); - } - - if(psys_intersect_dm(ob,dm,ec->vert_cos,co1,co2,&min_d,&min_face,min_w,ec->face_minmax,0,0,0)) - min_ob=ob; - } - } - if(min_ob){ - ob=min_ob; - - if(ob==pob){ - dm=psmd->dm; - } - else{ - psys_disable_all(ob); - - dm=mesh_get_derived_final(ob,0); - if(dm==0) - dm=mesh_get_derived_deform(ob,0); - - psys_enable_all(ob); - } - - mface=dm->getFaceDataArray(dm,CD_MFACE); - mface+=min_face; - mvert=dm->getVertDataArray(dm,CD_MVERT); - - /* get deflection point & normal */ - psys_interpolate_face(mvert,mface,0,0,min_w,loc,nor,0,0,0,0); - - VECADD(nor,nor,loc); - Mat4MulVecfl(ob->obmat,loc); - Mat4MulVecfl(ob->obmat,nor); - VECSUB(nor,nor,loc); - return 1; - } - } - return 0; -} -/* vector calculus functions in 2d vs. 3d */ -static void set_boid_vec_func(BoidVecFunc *bvf, int is_2d) -{ - if(is_2d){ - bvf->Addf = Vec2Addf; - bvf->Subf = Vec2Subf; - bvf->Mulf = Vec2Mulf; - bvf->Length = Vec2Length; - bvf->Normalize = Normalize2; - bvf->Inpf = Inp2f; - bvf->Copyf = Vec2Copyf; - } - else{ - bvf->Addf = VecAddf; - bvf->Subf = VecSubf; - bvf->Mulf = VecMulf; - bvf->Length = VecLength; - bvf->Normalize = Normalize; - bvf->Inpf = Inpf; - bvf->Copyf = VecCopyf; - } -} -/* boids have limited processing capability so once there's too much information (acceleration) no more is processed */ -static int add_boid_acc(BoidVecFunc *bvf, float lat_max, float tan_max, float *lat_accu, float *tan_accu, float *acc, float *dvec, float *vel) -{ - static float tangent[3]; - static float tan_length; - - if(vel){ - bvf->Copyf(tangent,vel); - tan_length=bvf->Normalize(tangent); - return 1; - } - else{ - float cur_tan, cur_lat; - float tan_acc[3], lat_acc[3]; - int ret=0; - - bvf->Copyf(tan_acc,tangent); - - if(tan_length>0.0){ - bvf->Mulf(tan_acc,Inpf(tangent,dvec)); - - bvf->Subf(lat_acc,dvec,tan_acc); - } - else{ - bvf->Copyf(tan_acc,dvec); - lat_acc[0]=lat_acc[1]=lat_acc[2]=0.0f; - *lat_accu=lat_max; - } - - cur_tan=bvf->Length(tan_acc); - cur_lat=bvf->Length(lat_acc); - - /* add tangential acceleration */ - if(*lat_accu+cur_lat<=lat_max){ - bvf->Addf(acc,acc,lat_acc); - *lat_accu+=cur_lat; - ret=1; - } - else{ - bvf->Mulf(lat_acc,(lat_max-*lat_accu)/cur_lat); - bvf->Addf(acc,acc,lat_acc); - *lat_accu=lat_max; - } - - /* add lateral acceleration */ - if(*tan_accu+cur_tan<=tan_max){ - bvf->Addf(acc,acc,tan_acc); - *tan_accu+=cur_tan; - ret=1; - } - else{ - bvf->Mulf(tan_acc,(tan_max-*tan_accu)/cur_tan); - bvf->Addf(acc,acc,tan_acc); - *tan_accu=tan_max; - } - - return ret; - } -} -/* determines the acceleration that the boid tries to acchieve */ -static void boid_brain(BoidVecFunc *bvf, ParticleData *pa, Object *ob, ParticleSystem *psys, ParticleSettings *part, KDTree *tree, float timestep, float cfra, float *acc) -{ - ParticleData *pars=psys->particles; - KDTreeNearest ptn[MAX_BOIDNEIGHBOURS+1]; - ParticleEffectorCache *ec=0; - float dvec[3]={0.0,0.0,0.0}, ob_co[3], ob_nor[3]; - float avoid[3]={0.0,0.0,0.0}, velocity[3]={0.0,0.0,0.0}, center[3]={0.0,0.0,0.0}; - float cubedist[MAX_BOIDNEIGHBOURS+1]; - int i, n, neighbours=0, near, not_finished=1; - - float cur_vel; - float lat_accu=0.0f, max_lat_acc=part->max_vel*part->max_lat_acc; - float tan_accu=0.0f, max_tan_acc=part->max_vel*part->max_tan_acc; - float avg_vel=part->average_vel*part->max_vel; - - acc[0]=acc[1]=acc[2]=0.0f; - /* the +1 neighbour is because boid itself is in the tree */ - neighbours=BLI_kdtree_find_n_nearest(tree,part->boidneighbours+1,pa->state.co,NULL,ptn); - - for(n=1; n<neighbours; n++){ - cubedist[n]=(float)pow((double)(ptn[n].dist/pa->size),3.0); - cubedist[n]=1.0f/MAX2(cubedist[n],1.0f); - } - - /* initialize tangent */ - add_boid_acc(bvf,0.0,0.0,0,0,0,0,pa->state.vel); - - for(i=0; i<BOID_TOT_RULES && not_finished; i++){ - switch(part->boidrule[i]){ - case BOID_COLLIDE: - /* collision avoidance */ - bvf->Copyf(dvec,pa->prev_state.vel); - bvf->Mulf(dvec,5.0f); - bvf->Addf(dvec,dvec,pa->prev_state.co); - if(boid_see_mesh(&psys->effectors,ob,psys,pa->prev_state.co,dvec,ob_co,ob_nor,cfra)){ - float probelen = bvf->Length(dvec); - float proj; - float oblen; - - Normalize(ob_nor); - proj = bvf->Inpf(ob_nor,pa->prev_state.vel); - - bvf->Subf(dvec,pa->prev_state.co,ob_co); - oblen=bvf->Length(dvec); - - bvf->Copyf(dvec,ob_nor); - bvf->Mulf(dvec,-proj); - bvf->Mulf(dvec,((probelen/oblen)-1.0f)*100.0f*part->boidfac[BOID_COLLIDE]); - - not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0); - } - break; - case BOID_AVOID: - /* predator avoidance */ - if(psys->effectors.first){ - for(ec=psys->effectors.first; ec; ec=ec->next){ - if(ec->type & PSYS_EC_EFFECTOR){ - Object *eob = ec->ob; - PartDeflect *pd = eob->pd; - - if(pd->forcefield==PFIELD_FORCE && pd->f_strength<0.0){ - float distance; - VECSUB(dvec,eob->obmat[3],pa->prev_state.co); - - distance=Normalize(dvec); - - if(part->flag & PART_DIE_ON_COL && distance < pd->mindist){ - pa->alive = PARS_DYING; - pa->dietime=cfra; - i=BOID_TOT_RULES; - break; - } - - if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist) - ; - else{ - bvf->Mulf(dvec,part->boidfac[BOID_AVOID]*pd->f_strength/(float)pow((double)distance,(double)pd->f_power)); - - not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0); - } - } - } - else if(ec->type & PSYS_EC_PARTICLE){ - Object *eob = ec->ob; - ParticleSystem *epsys; - ParticleSettings *epart; - ParticleKey state; - PartDeflect *pd; - KDTreeNearest ptn2[MAX_BOIDNEIGHBOURS]; - int totepart, p, count; - float distance; - epsys= BLI_findlink(&eob->particlesystem,ec->psys_nbr); - epart= epsys->part; - pd= epart->pd; - totepart= epsys->totpart; - - if(pd->forcefield==PFIELD_FORCE && pd->f_strength<0.0 && ec->tree){ - count=BLI_kdtree_find_n_nearest(ec->tree,epart->boidneighbours,pa->prev_state.co,NULL,ptn2); - for(p=0; p<count; p++){ - state.time=-1.0; - if(psys_get_particle_state(eob,epsys,ptn2[p].index,&state,0)){ - VECSUB(dvec, state.co, pa->prev_state.co); - - distance = Normalize(dvec); - - if(part->flag & PART_DIE_ON_COL && distance < (epsys->particles+ptn2[p].index)->size){ - pa->alive = PARS_DYING; - pa->dietime=cfra; - i=BOID_TOT_RULES; - break; - } - - if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist) - ; - else{ - bvf->Mulf(dvec,part->boidfac[BOID_AVOID]*pd->f_strength/(float)pow((double)distance,(double)pd->f_power)); - - not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0); - } - } - } - } - } - } - } - break; - case BOID_CROWD: - /* crowd avoidance */ - near=0; - for(n=1; n<neighbours; n++){ - if(ptn[n].dist<2.0f*pa->size){ - if(ptn[n].dist!=0.0f) { - bvf->Subf(dvec,pa->prev_state.co,pars[ptn[n].index].state.co); - bvf->Mulf(dvec,(2.0f*pa->size-ptn[n].dist)/ptn[n].dist); - bvf->Addf(avoid,avoid,dvec); - near++; - } - } - /* ptn[] is distance ordered so no need to check others */ - else break; - } - if(near){ - bvf->Mulf(avoid,part->boidfac[BOID_CROWD]*2.0f/timestep); - - not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,avoid,0); - } - break; - case BOID_CENTER: - /* flock centering */ - if(neighbours>1){ - for(n=1; n<neighbours; n++){ - bvf->Addf(center,center,pars[ptn[n].index].state.co); - } - bvf->Mulf(center,1.0f/((float)neighbours-1.0f)); - - bvf->Subf(dvec,center,pa->prev_state.co); - - bvf->Mulf(dvec,part->boidfac[BOID_CENTER]*2.0f); - - not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0); - } - break; - case BOID_AV_VEL: - /* average velocity */ - cur_vel=bvf->Length(pa->prev_state.vel); - if(cur_vel>0.0){ - bvf->Copyf(dvec,pa->prev_state.vel); - bvf->Mulf(dvec,part->boidfac[BOID_AV_VEL]*(avg_vel-cur_vel)/cur_vel); - not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0); - } - break; - case BOID_VEL_MATCH: - /* velocity matching */ - if(neighbours>1){ - for(n=1; n<neighbours; n++){ - bvf->Copyf(dvec,pars[ptn[n].index].state.vel); - bvf->Mulf(dvec,cubedist[n]); - bvf->Addf(velocity,velocity,dvec); - } - bvf->Mulf(velocity,1.0f/((float)neighbours-1.0f)); - - bvf->Subf(dvec,velocity,pa->prev_state.vel); - - bvf->Mulf(dvec,part->boidfac[BOID_VEL_MATCH]); - - not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0); - } - break; - case BOID_GOAL: - /* goal seeking */ - if(psys->effectors.first){ - for(ec=psys->effectors.first; ec; ec=ec->next){ - if(ec->type & PSYS_EC_EFFECTOR){ - Object *eob = ec->ob; - PartDeflect *pd = eob->pd; - float temp[4]; - - if(pd->forcefield==PFIELD_FORCE && pd->f_strength>0.0){ - float distance; - VECSUB(dvec,eob->obmat[3],pa->prev_state.co); - - distance=Normalize(dvec); - - if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist) - ; - else{ - VecMulf(dvec,pd->f_strength*part->boidfac[BOID_GOAL]/(float)pow((double)distance,(double)pd->f_power)); - - not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0); - } - } - else if(pd->forcefield==PFIELD_GUIDE){ - float distance; - - where_on_path(eob, (cfra-pa->time)/pa->lifetime, temp, dvec); - - VECSUB(dvec,temp,pa->prev_state.co); - - distance=Normalize(dvec); - - if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist) - ; - else{ - VecMulf(dvec,pd->f_strength*part->boidfac[BOID_GOAL]/(float)pow((double)distance,(double)pd->f_power)); - - not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0); - } - } - } - else if(ec->type & PSYS_EC_PARTICLE){ - Object *eob = ec->ob; - ParticleSystem *epsys; - ParticleSettings *epart; - ParticleKey state; - PartDeflect *pd; - KDTreeNearest ptn2[MAX_BOIDNEIGHBOURS]; - int totepart, p, count; - float distance; - epsys= BLI_findlink(&eob->particlesystem,ec->psys_nbr); - epart= epsys->part; - pd= epart->pd; - totepart= epsys->totpart; - - if(pd->forcefield==PFIELD_FORCE && pd->f_strength>0.0 && ec->tree){ - count=BLI_kdtree_find_n_nearest(ec->tree,epart->boidneighbours,pa->prev_state.co,NULL,ptn2); - for(p=0; p<count; p++){ - state.time=-1.0; - if(psys_get_particle_state(eob,epsys,ptn2[p].index,&state,0)){ - VECSUB(dvec, state.co, pa->prev_state.co); - - distance = Normalize(dvec); - - if(pd->flag&PFIELD_USEMAX && distance > pd->maxdist) - ; - else{ - bvf->Mulf(dvec,part->boidfac[BOID_AVOID]*pd->f_strength/(float)pow((double)distance,(double)pd->f_power)); - - not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0); - } - } - } - } - } - } - } - break; - case BOID_LEVEL: - /* level flight */ - if((part->flag & PART_BOIDS_2D)==0){ - dvec[0]=dvec[1]=0.0; - dvec[2]=-pa->prev_state.vel[2]; - - VecMulf(dvec,part->boidfac[BOID_LEVEL]); - not_finished=add_boid_acc(bvf,max_lat_acc,max_tan_acc,&lat_accu,&tan_accu,acc,dvec,0); - } - break; - } - } -} -/* tries to realize the wanted acceleration */ -static void boid_body(BoidVecFunc *bvf, ParticleData *pa, ParticleSystem *psys, ParticleSettings *part, float timestep, float *acc) -{ - float dvec[3], bvec[3], length, max_vel=part->max_vel; - float q2[4], q[4]; - float g=9.81f, pa_mass=part->mass; - float yvec[3]={0.0,1.0,0.0}, zvec[3]={0.0,0.0,-1.0}, bank; - - /* apply new velocity, location & rotation */ - copy_particle_key(&pa->state,&pa->prev_state,0); - - if(part->flag & PART_SIZEMASS) - pa_mass*=pa->size; - - /* by regarding the acceleration as a force at this stage we*/ - /* can get better controll allthough it's a bit unphysical */ - bvf->Mulf(acc,1.0f/pa_mass); - - bvf->Copyf(dvec,acc); - bvf->Mulf(dvec,timestep*timestep*0.5f); - - bvf->Copyf(bvec,pa->state.vel); - bvf->Mulf(bvec,timestep); - bvf->Addf(dvec,dvec,bvec); - bvf->Addf(pa->state.co,pa->state.co,dvec); - - /* air speed from wind and vortex effectors */ - if(psys->effectors.first) { - ParticleEffectorCache *ec; - for(ec=psys->effectors.first; ec; ec=ec->next) { - if(ec->type & PSYS_EC_EFFECTOR) { - Object *eob = ec->ob; - PartDeflect *pd = eob->pd; - float direction[3], vec_to_part[3]; - float falloff; - - if(pd->f_strength != 0.0f) { - VecCopyf(direction, eob->obmat[2]); - VecSubf(vec_to_part, pa->state.co, eob->obmat[3]); - - falloff=effector_falloff(pd, direction, vec_to_part); - - switch(pd->forcefield) { - case PFIELD_WIND: - if(falloff <= 0.0f) - ; /* don't do anything */ - else { - Normalize(direction); - VecMulf(direction, pd->f_strength * falloff); - bvf->Addf(pa->state.co, pa->state.co, direction); - } - break; - case PFIELD_VORTEX: - { - float distance, mag_vec[3]; - Crossf(mag_vec, direction, vec_to_part); - Normalize(mag_vec); - - distance = VecLength(vec_to_part); - - VecMulf(mag_vec, pd->f_strength * distance * falloff); - bvf->Addf(pa->state.co, pa->state.co, mag_vec); - break; - } - } - } - } - } - } - - - if((part->flag & PART_BOIDS_2D)==0 && pa->prev_state.vel[0]!=0.0 && pa->prev_state.vel[0]!=0.0 && pa->prev_state.vel[0]!=0.0){ - Crossf(yvec,pa->state.vel,zvec); - - Normalize(yvec); - - bank=Inpf(yvec,acc); - - bank=-(float)atan((double)(bank/g)); - - bank*=part->banking; - - bank-=pa->bank; - if(bank>M_PI*part->max_bank){ - bank=pa->bank+(float)M_PI*part->max_bank; - } - else if(bank<-M_PI*part->max_bank){ - bank=pa->bank-(float)M_PI*part->max_bank; - } - else - bank+=pa->bank; - - pa->bank=bank; - } - else{ - bank=0.0; - } - - - VecRotToQuat(pa->state.vel,bank,q); - - VECCOPY(dvec,pa->state.vel); - VecNegf(dvec); - vectoquat(dvec, OB_POSX, OB_POSZ, q2); - - QuatMul(pa->state.rot,q,q2); - - bvf->Mulf(acc,timestep); - bvf->Addf(pa->state.vel,pa->state.vel,acc); - - if(part->flag & PART_BOIDS_2D){ - pa->state.vel[2]=0.0; - pa->state.co[2]=part->groundz; - - if(psys->keyed_ob && (psys->keyed_ob->type == OB_MESH)){ - Object *zob=psys->keyed_ob; - int min_face; - float co1[3],co2[3],min_d=2.0,min_w[4],imat[4][4]; - VECCOPY(co1,pa->state.co); - VECCOPY(co2,pa->state.co); - - co1[2]=1000.0f; - co2[2]=-1000.0f; - - Mat4Invert(imat,zob->obmat); - Mat4MulVecfl(imat,co1); - Mat4MulVecfl(imat,co2); - - if(psys_intersect_dm(zob,0,0,co1,co2,&min_d,&min_face,min_w,0,0,0,0)){ - DerivedMesh *dm; - MFace *mface; - MVert *mvert; - float loc[3],nor[3],q1[4]; - - psys_disable_all(zob); - dm=mesh_get_derived_final(zob,0); - psys_enable_all(zob); - - mface=dm->getFaceDataArray(dm,CD_MFACE); - mface+=min_face; - mvert=dm->getVertDataArray(dm,CD_MVERT); - - /* get deflection point & normal */ - psys_interpolate_face(mvert,mface,0,0,min_w,loc,nor,0,0,0,0); - - Mat4MulVecfl(zob->obmat,loc); - Mat4Mul3Vecfl(zob->obmat,nor); - - Normalize(nor); - - VECCOPY(pa->state.co,loc); - - zvec[2]=1.0; - - Crossf(loc,zvec,nor); - - bank=VecLength(loc); - if(bank>0.0){ - bank=saasin(bank); - - VecRotToQuat(loc,bank,q); - - QUATCOPY(q1,pa->state.rot); - - QuatMul(pa->state.rot,q,q1); - } - } - } - } - - length=bvf->Length(pa->state.vel); - if(length > max_vel) - bvf->Mulf(pa->state.vel,max_vel/length); -} -/************************************************/ /* Hair */ /************************************************/ -static void save_hair(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra){ +static void save_hair(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra){ ParticleData *pa; HairKey *key; int totpart; @@ -3940,7 +3463,7 @@ static void save_hair(Object *ob, ParticleSystem *psys, ParticleSystemModifierDa Mat4Invert(ob->imat,ob->obmat); - psys->lattice=psys_get_lattice(ob,psys); + psys->lattice= psys_get_lattice(scene, ob, psys); if(psys->totpart==0) return; @@ -3980,19 +3503,19 @@ static void save_hair(Object *ob, ParticleSystem *psys, ParticleSystemModifierDa /* System Core */ /************************************************/ /* unbaked particles are calculated dynamically */ -static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra, +static void dynamics_step(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra, float *vg_vel, float *vg_tan, float *vg_rot, float *vg_size) { ParticleData *pa; ParticleSettings *part=psys->part; KDTree *tree=0; - BoidVecFunc bvf; - IpoCurve *icu_esize=find_ipocurve(part->ipo,PART_EMIT_SIZE); + IpoCurve *icu_esize= NULL; //=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system Material *ma=give_current_material(ob,part->omat); + BoidBrainData bbd; float timestep; int p, totpart; /* current time */ - float ctime, ipotime; + float ctime, ipotime; // XXX old animation system /* frame & time changes */ float dfra, dtime, pa_dtime, pa_dfra=0.0; float birthtime, dietime; @@ -4005,12 +3528,14 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi timestep=psys_get_timestep(part); dtime= dfra*timestep; ctime= cfra*timestep; - ipotime= cfra; + ipotime= cfra; // XXX old animation system +#if 0 // XXX old animation system if(part->flag&PART_ABS_TIME && part->ipo){ calc_ipo(part->ipo, cfra); execute_ipo((ID *)part, part->ipo); } +#endif // XXX old animation system if(dfra<0.0){ float *vg_size=0; @@ -4021,14 +3546,16 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi if(pa->flag & PARS_UNEXIST) continue; /* set correct ipo timing */ +#if 0 // XXX old animation system if((part->flag&PART_ABS_TIME)==0 && part->ipo){ ipotime=100.0f*(cfra-pa->time)/pa->lifetime; calc_ipo(part->ipo, ipotime); execute_ipo((ID *)part, part->ipo); } +#endif // XXX old animation system pa->size=psys_get_size(ob,ma,psmd,icu_esize,psys,part,pa,vg_size); - reset_particle(pa,psys,psmd,ob,dtime,cfra,vg_vel,vg_tan,vg_rot); + reset_particle(scene, pa,psys,psmd,ob,dtime,cfra,vg_vel,vg_tan,vg_rot); if(cfra>pa->time && part->flag & PART_LOOP && part->type!=PART_HAIR){ pa->loop=(short)((cfra-pa->time)/pa->lifetime); @@ -4058,36 +3585,45 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi if(psys->effectors.first) psys_end_effectors(psys); - psys_init_effectors(ob,part->eff_group,psys); + psys_init_effectors(scene, ob, part->eff_group, psys); if(psys->effectors.first) - precalc_effectors(ob,psys,psmd,cfra); + precalc_effectors(scene, ob,psys,psmd,cfra); if(part->phystype==PART_PHYS_BOIDS){ - /* create particle tree for fast inter-particle comparisons */ - tree=BLI_kdtree_new(totpart); - for(p=0, pa=psys->particles; p<totpart; p++,pa++){ - if(pa->flag & (PARS_NO_DISP+PARS_UNEXIST) || pa->alive!=PARS_ALIVE) - continue; - - BLI_kdtree_insert(tree, p, pa->state.co, NULL); + ParticleTarget *pt = psys->targets.first; + bbd.scene = scene; + bbd.ob = ob; + bbd.psys = psys; + bbd.part = part; + bbd.cfra = cfra; + bbd.dfra = dfra; + bbd.timestep = timestep; + + update_particle_tree(psys); + + boids_precalc_rules(part, cfra); + + for(; pt; pt=pt->next) { + if(pt->ob) + update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1)); } - BLI_kdtree_balance(tree); - set_boid_vec_func(&bvf,part->flag&PART_BOIDS_2D); } /* main loop: calculate physics for all particles */ for(p=0, pa=psys->particles; p<totpart; p++,pa++){ - if(pa->flag & PARS_UNEXIST) continue; + if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue; copy_particle_key(&pa->prev_state,&pa->state,1); /* set correct ipo timing */ +#if 0 // XXX old animation system if((part->flag&PART_ABS_TIME)==0 && part->ipo){ ipotime=100.0f*(cfra-pa->time)/pa->lifetime; calc_ipo(part->ipo, ipotime); execute_ipo((ID *)part, part->ipo); } +#endif // XXX old animation system pa->size=psys_get_size(ob,ma,psmd,icu_esize,psys,part,pa,vg_size); /* reactions can change birth time so they need to be checked first */ @@ -4101,25 +3637,26 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi if(pa->alive==PARS_UNBORN || pa->alive==PARS_KILLED || ELEM(part->phystype,PART_PHYS_NO,PART_PHYS_KEYED) - || birthtime >= cfra){ - reset_particle(pa,psys,psmd,ob,dtime,cfra,vg_vel,vg_tan,vg_rot); + || birthtime >= psys->cfra){ + reset_particle(scene, pa,psys,psmd,ob,dtime,cfra,vg_vel,vg_tan,vg_rot); } pa_dfra = dfra; pa_dtime = dtime; - if(birthtime <= cfra && birthtime >= psys->cfra){ + + if(dietime <= cfra && psys->cfra < dietime){ + /* particle dies some time between this and last step */ + pa_dfra = dietime - ((birthtime > psys->cfra) ? birthtime : psys->cfra); + pa_dtime = pa_dfra * timestep; + pa->alive = PARS_DYING; + } + else if(birthtime <= cfra && birthtime >= psys->cfra){ /* particle is born some time between this and last step*/ pa->alive = PARS_ALIVE; pa_dfra = cfra - birthtime; pa_dtime = pa_dfra*timestep; } - else if(dietime <= cfra && psys->cfra < dietime){ - /* particle dies some time between this and last step */ - pa_dfra = dietime - psys->cfra; - pa_dtime = pa_dfra * timestep; - pa->alive = PARS_DYING; - } else if(dietime < cfra){ /* nothing to be done when particle is dead */ } @@ -4129,20 +3666,24 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi switch(part->phystype){ case PART_PHYS_NEWTON: /* do global forces & effectors */ - apply_particle_forces(p,pa,ob,psys,part,timestep,pa_dfra,cfra); + apply_particle_forces(scene, p, pa, ob, psys, part, timestep,pa_dfra,cfra); /* deflection */ - deflect_particle(ob,psmd,psys,part,pa,p,timestep,pa_dfra,cfra); + deflect_particle(scene, ob,psmd,psys,part,pa,p,timestep,pa_dfra,cfra); /* rotations */ rotate_particle(part,pa,pa_dfra,timestep); break; case PART_PHYS_BOIDS: { - float acc[3]; - boid_brain(&bvf,pa,ob,psys,part,tree,timestep,cfra,acc); - if(pa->alive != PARS_DYING) - boid_body(&bvf,pa,psys,part,timestep,acc); + bbd.goal_ob = NULL; + boid_brain(&bbd, p, pa); + if(pa->alive != PARS_DYING) { + boid_body(&bbd, pa); + + /* deflection */ + deflect_particle(scene,ob,psmd,psys,part,pa,p,timestep,pa_dfra,cfra); + } break; } } @@ -4152,7 +3693,7 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi if(part->flag & PART_LOOP && part->type!=PART_HAIR){ pa->loop++; - reset_particle(pa,psys,psmd,ob,0.0,cfra,vg_vel,vg_tan,vg_rot); + reset_particle(scene, pa,psys,psmd,ob,0.0,cfra,vg_vel,vg_tan,vg_rot); pa->alive=PARS_ALIVE; } else{ @@ -4178,26 +3719,26 @@ static void dynamics_step(Object *ob, ParticleSystem *psys, ParticleSystemModifi } /* check if path cache or children need updating and do it if needed */ -static void psys_update_path_cache(Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) +static void psys_update_path_cache(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) { ParticleSettings *part=psys->part; - ParticleEditSettings *pset=&G.scene->toolsettings->particle; + ParticleEditSettings *pset=&scene->toolsettings->particle; int distr=0,alloc=0; - if((psys->part->childtype && psys->totchild != get_psys_tot_child(psys)) || psys->recalc&PSYS_ALLOC) + if((psys->part->childtype && psys->totchild != get_psys_tot_child(scene, psys)) || psys->recalc&PSYS_RECALC_RESET) alloc=1; - if(alloc || psys->recalc&PSYS_DISTR || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT))) + if(alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (G.f & G_WEIGHTPAINT))) distr=1; if(distr){ if(alloc) realloc_particles(ob,psys,psys->totpart); - if(get_psys_tot_child(psys)) { + if(get_psys_tot_child(scene, psys)) { /* don't generate children while computing the hair keys */ if(!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) { - distribute_particles(ob,psys,PART_FROM_CHILD); + distribute_particles(scene, ob, psys, PART_FROM_CHILD); if(part->from!=PART_FROM_PARTICLE && part->childtype==PART_CHILD_FACES && part->parents!=0.0) psys_find_parents(ob,psmd,psys); @@ -4205,22 +3746,47 @@ static void psys_update_path_cache(Object *ob, ParticleSystemModifierData *psmd, } } - if((part->type==PART_HAIR || psys->flag&PSYS_KEYED) && (psys_in_edit_mode(psys) - || (part->type==PART_HAIR || part->draw_as==PART_DRAW_PATH))){ - psys_cache_paths(ob, psys, cfra, 0); + if((part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED) && ( psys_in_edit_mode(scene, psys) || (part->type==PART_HAIR + || (part->ren_as == PART_DRAW_PATH && (part->draw_as == PART_DRAW_REND || psys->renderdata))))){ + + psys_cache_paths(scene, ob, psys, cfra, 0); /* for render, child particle paths are computed on the fly */ if(part->childtype) { - if(((psys->totchild!=0)) || (psys_in_edit_mode(psys) && (pset->flag&PE_SHOW_CHILD))) + if(((psys->totchild!=0)) || (psys_in_edit_mode(scene, psys) && (pset->flag&PE_SHOW_CHILD))) if(!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) - psys_cache_child_paths(ob, psys, cfra, 0); + psys_cache_child_paths(scene, ob, psys, cfra, 0); } } else if(psys->pathcache) psys_free_path_cache(psys); } -static void hair_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) +/* calculate and store key locations in world coordinates */ +void psys_update_world_cos(Object *ob, ParticleSystem *psys) +{ + ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); + ParticleData *pa; + ParticleEditKey *key; + int i, k, totpart; + float hairmat[4][4]; + + if(psys==0 || psys->edit==0) + return; + + totpart= psys->totpart; + + for(i=0, pa=psys->particles; i<totpart; i++, pa++) { + psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat); + + for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++) { + VECCOPY(key->world_co,key->co); + Mat4MulVecfl(hairmat, key->world_co); + } + } +} + +static void hair_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) { ParticleSettings *part = psys->part; ParticleData *pa; @@ -4234,33 +3800,33 @@ static void hair_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSyst pa->flag &= ~PARS_NO_DISP; } - if(psys->recalc & PSYS_DISTR) + if(psys->recalc & PSYS_RECALC_RESET) /* need this for changing subsurf levels */ psys_calc_dmcache(ob, psmd->dm, psys); if(psys->effectors.first) psys_end_effectors(psys); - psys_init_effectors(ob,part->eff_group,psys); + psys_init_effectors(scene, ob, part->eff_group, psys); if(psys->effectors.first) - precalc_effectors(ob,psys,psmd,cfra); + precalc_effectors(scene, ob,psys,psmd,cfra); - if(psys_in_edit_mode(psys)) - PE_recalc_world_cos(ob, psys); + if(psys_in_edit_mode(scene, psys)) + psys_update_world_cos(ob, psys); - psys_update_path_cache(ob,psmd,psys,cfra); + psys_update_path_cache(scene, ob,psmd,psys,cfra); } /* updates cached particles' alive & other flags etc..*/ -static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) +static void cached_step(Scene *scene, Object *ob, ParticleSystemModifierData *psmd, ParticleSystem *psys, float cfra) { ParticleSettings *part=psys->part; ParticleData *pa; ParticleKey state; - IpoCurve *icu_esize=find_ipocurve(part->ipo,PART_EMIT_SIZE); + IpoCurve *icu_esize= NULL; //=find_ipocurve(part->ipo,PART_EMIT_SIZE); // XXX old animation system Material *ma=give_current_material(ob,part->omat); int p; - float ipotime=cfra, disp, birthtime, dietime, *vg_size= NULL; + float disp, birthtime, dietime, *vg_size= NULL; // XXX ipotime=cfra if(part->from!=PART_FROM_PARTICLE) vg_size= psys_cache_vgroup(psmd->dm,psys,PSYS_VG_SIZE); @@ -4269,22 +3835,24 @@ static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSy psys_end_effectors(psys); //if(part->flag & (PART_BAKED_GUIDES+PART_BAKED_DEATHS)){ - psys_init_effectors(ob,part->eff_group,psys); + psys_init_effectors(scene, ob, part->eff_group, psys); if(psys->effectors.first) - precalc_effectors(ob,psys,psmd,cfra); + precalc_effectors(scene, ob,psys,psmd,cfra); //} disp= (float)get_current_display_percentage(psys)/50.0f-1.0f; for(p=0, pa=psys->particles; p<psys->totpart; p++,pa++){ +#if 0 // XXX old animation system if((part->flag&PART_ABS_TIME)==0 && part->ipo){ ipotime=100.0f*(cfra-pa->time)/pa->lifetime; calc_ipo(part->ipo, ipotime); execute_ipo((ID *)part, part->ipo); } +#endif // XXX old animation system pa->size= psys_get_size(ob,ma,psmd,icu_esize,psys,part,pa,vg_size); - psys->lattice=psys_get_lattice(ob,psys); + psys->lattice= psys_get_lattice(scene, ob, psys); if(part->flag & PART_LOOP && part->type!=PART_HAIR) pa->loop = (short)((cfra - pa->time) / pa->lifetime); @@ -4295,12 +3863,15 @@ static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSy dietime = birthtime + (1 + pa->loop) * (pa->dietime - pa->time); /* update alive status and push events */ - if(pa->time > cfra) - pa->alive = PARS_UNBORN; + if(pa->time >= cfra) { + pa->alive = pa->time==cfra ? PARS_ALIVE : PARS_UNBORN; + if((psys->pointcache->flag & PTCACHE_EXTERNAL) == 0) + reset_particle(scene, pa, psys, psmd, ob, 0.0f, cfra, NULL, NULL, NULL); + } else if(dietime <= cfra){ if(dietime > psys->cfra){ - state.time = pa->dietime; - psys_get_particle_state(ob,psys,p,&state,1); + state.time = dietime; + psys_get_particle_state(scene, ob,psys,p,&state,1); push_reaction(ob,psys,p,PART_EVENT_DEATH,&state); } pa->alive = PARS_DEAD; @@ -4308,14 +3879,14 @@ static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSy else{ pa->alive = PARS_ALIVE; state.time = cfra; - psys_get_particle_state(ob,psys,p,&state,1); + psys_get_particle_state(scene, ob,psys,p,&state,1); state.time = cfra; push_reaction(ob,psys,p,PART_EVENT_NEAR,&state); } if(psys->lattice){ - end_latt_deform(); - psys->lattice=0; + end_latt_deform(psys->lattice); + psys->lattice= NULL; } if(pa->r_rot[0] > disp) @@ -4325,21 +3896,26 @@ static void cached_step(Object *ob, ParticleSystemModifierData *psmd, ParticleSy } /* make sure that children are up to date */ - if(psys->part->childtype && psys->totchild != get_psys_tot_child(psys)) { + if(psys->part->childtype && psys->totchild != get_psys_tot_child(scene, psys)) { realloc_particles(ob, psys, psys->totpart); - distribute_particles(ob, psys, PART_FROM_CHILD); + distribute_particles(scene, ob, psys, PART_FROM_CHILD); } + psys_update_path_cache(scene, ob,psmd,psys,cfra); + if(vg_size) MEM_freeN(vg_size); } -void psys_changed_type(ParticleSystem *psys) +static void psys_changed_type(Object *ob, ParticleSystem *psys) { ParticleSettings *part; + PTCacheID pid; part= psys->part; + BKE_ptcache_id_from_particles(&pid, ob, psys); + /* system type has changed so set sensible defaults and clear non applicable flags */ if(part->from == PART_FROM_PARTICLE) { if(part->type != PART_REACTOR) @@ -4348,27 +3924,87 @@ void psys_changed_type(ParticleSystem *psys) part->distr = PART_DISTR_JIT; } - if(psys->part->phystype != PART_PHYS_KEYED) + if(part->phystype != PART_PHYS_KEYED) psys->flag &= ~PSYS_KEYED; if(part->type == PART_HAIR) { - part->draw_as = PART_DRAW_PATH; - part->rotfrom = PART_ROT_IINCR; + if(ELEM4(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)==0) + part->ren_as = PART_DRAW_PATH; + + if(ELEM3(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0) + part->draw_as = PART_DRAW_REND; + + CLAMP(part->path_start, 0.0f, 100.0f); + CLAMP(part->path_end, 0.0f, 100.0f); + + BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); } else { free_hair(psys, 1); - if(part->draw_as == PART_DRAW_PATH) - if(psys->part->phystype != PART_PHYS_KEYED) - part->draw_as = PART_DRAW_DOT; + CLAMP(part->path_start, part->sta, part->end + part->lifetime); + CLAMP(part->path_end, part->sta, part->end + part->lifetime); } psys->softflag= 0; psys_reset(psys, PSYS_RESET_ALL); } +void psys_check_boid_data(ParticleSystem *psys) +{ + ParticleData *pa = psys->particles; + int p = 1; + + if(!pa) + return; + + if(psys->part && psys->part->phystype==PART_PHYS_BOIDS) { + if(!pa->boid) { + pa->boid = MEM_callocN(psys->totpart * sizeof(BoidData), "Boid Data"); + + for(pa++; p<psys->totpart; p++, pa++) + pa->boid = (pa-1)->boid + 1; + } + } + else if(pa->boid){ + MEM_freeN(pa->boid); + for(; p<psys->totpart; p++, pa++) + pa->boid = NULL; + } +} +static void psys_changed_physics(Object *ob, ParticleSystem *psys) +{ + ParticleSettings *part = psys->part; + + if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)) { + PTCacheID pid; + BKE_ptcache_id_from_particles(&pid, ob, psys); + BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); + } + else { + free_keyed_keys(psys); + psys->flag &= ~PSYS_KEYED; + } + + if(part->phystype == PART_PHYS_BOIDS && part->boids == NULL) { + BoidState *state; + + psys_check_boid_data(psys); + + part->boids = MEM_callocN(sizeof(BoidSettings), "Boid Settings"); + boid_default_settings(part->boids); -static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) + state = boid_new_state(part->boids); + BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Separate)); + BLI_addtail(&state->rules, boid_new_rule(eBoidRuleType_Flock)); + + ((BoidRule*)state->rules.first)->flag |= BOIDRULE_CURRENT; + + state->flag |= BOIDSTATE_CURRENT; + BLI_addtail(&part->boids->states, state); + } +} +static void particles_fluid_step(Scene *scene, Object *ob, ParticleSystem *psys, int cfra) { if(psys->particles){ MEM_freeN(psys->particles); @@ -4389,13 +4025,13 @@ static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) char *suffix2 = ".gz"; char filename[256]; char debugStrBuffer[256]; - int curFrame = G.scene->r.cfra -1; // warning - sync with derived mesh fsmesh loading + int curFrame = scene->r.cfra -1; // warning - sync with derived mesh fsmesh loading int p, j, numFileParts, totpart; int readMask, activeParts = 0, fileParts = 0; gzFile gzf; - if(ob==G.obedit) // off... - return; +// XXX if(ob==G.obedit) // off... +// return; // ok, start loading strcpy(filename, fss->surfdataPath); @@ -4407,7 +4043,7 @@ static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) gzf = gzopen(filename, "rb"); if (!gzf) { snprintf(debugStrBuffer,256,"readFsPartData::error - Unable to open file for reading '%s' \n", filename); - //elbeemDebugOut(debugStrBuffer); + // XXX bad level call elbeemDebugOut(debugStrBuffer); return; } @@ -4417,7 +4053,7 @@ static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) part->totpart= totpart; part->sta=part->end = 1.0f; - part->lifetime = G.scene->r.efra + 1; + part->lifetime = scene->r.efra + 1; /* initialize particles */ realloc_particles(ob, psys, part->totpart); @@ -4467,7 +4103,9 @@ static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) totpart = psys->totpart = activeParts; snprintf(debugStrBuffer,256,"readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d \n", psys->totpart,activeParts,fileParts,readMask); - elbeemDebugOut(debugStrBuffer); + // bad level call + // XXX elbeemDebugOut(debugStrBuffer); + } // fluid sim particles done } #endif // DISABLE_ELBEEM @@ -4475,7 +4113,7 @@ static void particles_fluid_step(Object *ob, ParticleSystem *psys, int cfra) /* Calculates the next state for all particles of the system */ /* In particles code most fra-ending are frames, time-ending are fra*timestep (seconds)*/ -static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra) +static void system_step(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystemModifierData *psmd, float cfra) { ParticleSettings *part; ParticleData *pa; @@ -4489,28 +4127,36 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier part= psys->part; cache= psys->pointcache; - framenr= (int)CFRA; + framenr= (int)scene->r.cfra; framedelta= framenr - cache->simframe; + /* set suitable cache range automatically */ + if((cache->flag & (PTCACHE_BAKING|PTCACHE_BAKED))==0) + psys_get_pointcache_start_end(scene, psys, &cache->startframe, &cache->endframe); + BKE_ptcache_id_from_particles(&pid, ob, psys); - BKE_ptcache_id_time(&pid, 0.0f, &startframe, &endframe, NULL); + BKE_ptcache_id_time(&pid, scene, 0.0f, &startframe, &endframe, NULL); + + psys_clear_temp_pointcache(psys); /* update ipo's */ +#if 0 // XXX old animation system if((part->flag & PART_ABS_TIME) && part->ipo) { calc_ipo(part->ipo, cfra); execute_ipo((ID *)part, part->ipo); } +#endif // XXX old animation system /* hair if it's already done is handled separate */ if(part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DONE)) { - hair_step(ob, psmd, psys, cfra); + hair_step(scene, ob, psmd, psys, cfra); psys->cfra = cfra; psys->recalc = 0; return; } /* fluid is also handled separate */ else if(part->type == PART_FLUID) { - particles_fluid_step(ob, psys, framenr); + particles_fluid_step(scene, ob, psys, framenr); psys->cfra = cfra; psys->recalc = 0; return; @@ -4541,44 +4187,56 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier oldtotpart = psys->totpart; oldtotchild = psys->totchild; - if(part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT) + if(psys->pointcache->flag & PTCACHE_EXTERNAL) + totpart = pid.cache->totpoint; + else if(part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT) totpart = part->grid_res*part->grid_res*part->grid_res; else totpart = psys->part->totpart; - totchild = get_psys_tot_child(psys); + totchild = get_psys_tot_child(scene, psys); - if(oldtotpart != totpart || (psys->part->childtype && oldtotchild != totchild)) { + if(oldtotpart != totpart || oldtotchild != totchild) { only_children_changed = (oldtotpart == totpart); - realloc_particles(ob, psys, totpart); alloc = 1; distr= 1; init= 1; } - if(psys->recalc & PSYS_DISTR) { + if(psys->recalc & PSYS_RECALC_RESET) { distr= 1; init= 1; } if(init) { if(distr) { - if(alloc) + if(alloc) { realloc_particles(ob, psys, totpart); - distribute_particles(ob, psys, part->from); + if(usecache && !only_children_changed) { + BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0); + BKE_ptcache_id_from_particles(&pid, ob, psys); + } + } + + if(!only_children_changed) + distribute_particles(scene, ob, psys, part->from); if((psys->part->type == PART_HAIR) && !(psys->flag & PSYS_HAIR_DONE)) /* don't generate children while growing hair - waste of time */ psys_free_children(psys); - else if(get_psys_tot_child(psys)) - distribute_particles(ob, psys, PART_FROM_CHILD); + else if(get_psys_tot_child(scene, psys)) + distribute_particles(scene, ob, psys, PART_FROM_CHILD); } - if(only_children_changed==0) { + if(!only_children_changed) { + free_keyed_keys(psys); + initialize_all_particles(ob, psys, psmd); + - if(alloc) - reset_all_particles(ob, psys, psmd, 0.0, cfra, oldtotpart); + if(alloc) { + reset_all_particles(scene, ob, psys, psmd, 0.0, cfra, oldtotpart); + } } /* flag for possible explode modifiers after this system */ @@ -4587,49 +4245,51 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier /* try to read from the cache */ if(usecache) { - if(get_particles_from_cache(ob, psys, framenr)) { - if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) { - psys_count_keyed_targets(ob,psys); - set_keyed_keys(ob, psys); - } + int result = BKE_ptcache_read_cache(&pid, cfra, scene->r.frs_sec); - cached_step(ob,psmd,psys,cfra); + if(result == PTCACHE_READ_EXACT || result == PTCACHE_READ_INTERPOLATED) { + cached_step(scene, ob, psmd, psys, cfra); psys->cfra=cfra; psys->recalc = 0; - if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) { - psys_update_path_cache(ob,psmd,psys,framenr); - } - cache->simframe= framenr; cache->flag |= PTCACHE_SIMULATION_VALID; + if(result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED) + BKE_ptcache_write_cache(&pid, (int)cfra); + return; } + else if(result==PTCACHE_READ_OLD) { + psys->cfra = (float)cache->simframe; + for(p=0, pa=psys->particles; p<totpart; p++, pa++) { + /* update alive status */ + if(pa->time > psys->cfra) + pa->alive = PARS_UNBORN; + else if(pa->dietime <= psys->cfra) + pa->alive = PARS_DEAD; + else + pa->alive = PARS_ALIVE; + } + } else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) { psys_reset(psys, PSYS_RESET_CACHE_MISS); psys->cfra=cfra; psys->recalc = 0; return; } - - if(framenr != startframe && framedelta != 1) { - psys_reset(psys, PSYS_RESET_CACHE_MISS); - psys->cfra = cfra; - psys->recalc = 0; - return; - } } else { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; + cache->last_exact= 0; } /* if on second frame, write cache for first frame */ - if(usecache && framenr == startframe+1) - write_particles_to_cache(ob, psys, startframe); + if(usecache && psys->cfra == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) + BKE_ptcache_write_cache(&pid, startframe); - if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED) + if(part->phystype==PART_PHYS_KEYED) psys_count_keyed_targets(ob,psys); /* initialize vertex groups */ @@ -4660,7 +4320,7 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier for(dframe=-totframesback; dframe<=0; dframe++) { /* ok now we're all set so let's go */ - dynamics_step(ob,psys,psmd,cfra+dframe,vg_vel,vg_tan,vg_rot,vg_size); + dynamics_step(scene, ob, psys, psmd, cfra+dframe, vg_vel, vg_tan, vg_rot, vg_size); psys->cfra = cfra+dframe; } } @@ -4673,12 +4333,12 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier /* only write cache starting from second frame */ if(usecache && framenr != startframe) - write_particles_to_cache(ob, psys, framenr); + BKE_ptcache_write_cache(&pid, (int)cfra); /* for keyed particles the path is allways known so it can be drawn */ - if(part->phystype==PART_PHYS_KEYED && psys->flag&PSYS_FIRST_KEYED){ - set_keyed_keys(ob, psys); - psys_update_path_cache(ob,psmd,psys,(int)cfra); + if(part->phystype==PART_PHYS_KEYED) { + set_keyed_keys(scene, ob, psys); + psys_update_path_cache(scene, ob, psmd, psys,(int)cfra); } else if(psys->pathcache) psys_free_path_cache(psys); @@ -4690,12 +4350,12 @@ static void system_step(Object *ob, ParticleSystem *psys, ParticleSystemModifier if(vg_size) MEM_freeN(vg_size); if(psys->lattice){ - end_latt_deform(); - psys->lattice=0; + end_latt_deform(psys->lattice); + psys->lattice= NULL; } } -static void psys_to_softbody(Object *ob, ParticleSystem *psys) +static void psys_to_softbody(Scene *scene, Object *ob, ParticleSystem *psys) { SoftBody *sb; short softflag; @@ -4715,7 +4375,7 @@ static void psys_to_softbody(Object *ob, ParticleSystem *psys) ob->softflag= psys->softflag; /* do softbody */ - sbObjectStep(ob, (float)G.scene->r.cfra, NULL, psys_count_keys(psys)); + sbObjectStep(scene, ob, (float)scene->r.cfra, NULL, psys_count_keys(psys)); /* return things back to normal */ psys->soft= ob->soft; @@ -4728,8 +4388,7 @@ static void psys_to_softbody(Object *ob, ParticleSystem *psys) static int hair_needs_recalc(ParticleSystem *psys) { if((psys->flag & PSYS_EDITED)==0 && - ((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & PSYS_RECALC_HAIR)) { - psys->recalc &= ~PSYS_RECALC_HAIR; + ((psys->flag & PSYS_HAIR_DONE)==0 || psys->recalc & PSYS_RECALC_RESET)) { return 1; } @@ -4737,7 +4396,7 @@ static int hair_needs_recalc(ParticleSystem *psys) } /* main particle update call, checks that things are ok on the large scale before actual particle calculations */ -void particle_system_update(Object *ob, ParticleSystem *psys) +void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) { ParticleSystemModifierData *psmd; float cfra; @@ -4745,7 +4404,7 @@ void particle_system_update(Object *ob, ParticleSystem *psys) if(!psys_check_enabled(ob, psys)) return; - cfra= bsystem_time(ob, CFRA, 0.0f); + cfra= bsystem_time(scene, ob, (float)scene->r.cfra, 0.0f); psmd= psys_get_modifier(ob, psys); /* system was already updated from modifier stack */ @@ -4759,6 +4418,11 @@ void particle_system_update(Object *ob, ParticleSystem *psys) if(!psmd->dm) return; + if(psys->recalc & PSYS_RECALC_TYPE) + psys_changed_type(ob, psys); + else if(psys->recalc & PSYS_RECALC_PHYS) + psys_changed_physics(ob, psys); + /* (re-)create hair */ if(psys->part->type==PART_HAIR && hair_needs_recalc(psys)) { float hcfra=0.0f; @@ -4771,8 +4435,8 @@ void particle_system_update(Object *ob, ParticleSystem *psys) for(i=0; i<=psys->part->hair_step; i++){ hcfra=100.0f*(float)i/(float)psys->part->hair_step; - system_step(ob, psys, psmd, hcfra); - save_hair(ob, psys, psmd, hcfra); + system_step(scene, ob, psys, psmd, hcfra); + save_hair(scene, ob, psys, psmd, hcfra); } psys->flag |= PSYS_HAIR_DONE; @@ -4780,10 +4444,10 @@ void particle_system_update(Object *ob, ParticleSystem *psys) /* handle softbody hair */ if(psys->part->type==PART_HAIR && psys->soft) - psys_to_softbody(ob, psys); + psys_to_softbody(scene, ob, psys); /* the main particle system step */ - system_step(ob, psys, psmd, cfra); + system_step(scene, ob, psys, psmd, cfra); /* save matrix for duplicators */ Mat4Invert(psys->imat, ob->obmat); diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index d4676653a4e..d326fa84ed4 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -39,6 +39,7 @@ #include "DNA_object_force.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" +#include "DNA_smoke_types.h" #include "BLI_blenlib.h" @@ -51,10 +52,14 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_pointcache.h" +#include "BKE_scene.h" +#include "BKE_smoke.h" #include "BKE_softbody.h" #include "BKE_utildefines.h" -#include "blendef.h" +#include "BLI_blenlib.h" + +#include "smoke_API.h" /* needed for directory lookup */ #ifndef WIN32 @@ -76,8 +81,308 @@ #endif #endif -/* Creating ID's */ +static void ptcache_data_to(void **data, int type, int index, void *to); +static void ptcache_data_from(void **data, int type, void *from); + +/* Common functions */ +static int ptcache_read_basic_header(PTCacheFile *pf) +{ + int error=0; + + /* Custom functions should read these basic elements too! */ + if(!error && !fread(&pf->totpoint, sizeof(int), 1, pf->fp)) + error = 1; + + if(!error && !fread(&pf->data_types, sizeof(int), 1, pf->fp)) + error = 1; + + return !error; +} +static int ptcache_write_basic_header(PTCacheFile *pf) +{ + /* Custom functions should write these basic elements too! */ + if(!fwrite(&pf->totpoint, sizeof(int), 1, pf->fp)) + return 0; + + if(!fwrite(&pf->data_types, sizeof(int), 1, pf->fp)) + return 0; + + return 1; +} +/* Softbody functions */ +static int ptcache_write_softbody(int index, void *soft_v, void **data) +{ + SoftBody *soft= soft_v; + BodyPoint *bp = soft->bpoint + index; + + ptcache_data_from(data, BPHYS_DATA_LOCATION, bp->pos); + ptcache_data_from(data, BPHYS_DATA_VELOCITY, bp->vec); + + return 1; +} +static void ptcache_read_softbody(int index, void *soft_v, void **data, float frs_sec, float cfra, float *old_data) +{ + SoftBody *soft= soft_v; + BodyPoint *bp = soft->bpoint + index; + + if(old_data) { + memcpy(bp->pos, data, 3 * sizeof(float)); + memcpy(bp->vec, data + 3, 3 * sizeof(float)); + } + else { + ptcache_data_to(data, BPHYS_DATA_LOCATION, 0, bp->pos); + ptcache_data_to(data, BPHYS_DATA_VELOCITY, 0, bp->vec); + } +} +static void ptcache_interpolate_softbody(int index, void *soft_v, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data) +{ + SoftBody *soft= soft_v; + BodyPoint *bp = soft->bpoint + index; + ParticleKey keys[4]; + float dfra; + + if(cfra1 == cfra2) + return; + + VECCOPY(keys[1].co, bp->pos); + VECCOPY(keys[1].vel, bp->vec); + + if(old_data) { + memcpy(keys[2].co, old_data, 3 * sizeof(float)); + memcpy(keys[2].vel, old_data + 3, 3 * sizeof(float)); + } + else + BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2); + + dfra = cfra2 - cfra1; + + VecMulf(keys[1].vel, dfra); + VecMulf(keys[2].vel, dfra); + + psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, 1); + + VecMulf(keys->vel, 1.0f / dfra); + + VECCOPY(bp->pos, keys->co); + VECCOPY(bp->vec, keys->vel); +} +static int ptcache_totpoint_softbody(void *soft_v) +{ + SoftBody *soft= soft_v; + return soft->totpoint; +} +/* Particle functions */ +static int ptcache_write_particle(int index, void *psys_v, void **data) +{ + ParticleSystem *psys= psys_v; + ParticleData *pa = psys->particles + index; + float times[3] = {pa->time, pa->dietime, pa->lifetime}; + + if(data[BPHYS_DATA_INDEX]) { + int step = psys->pointcache->step; + /* No need to store unborn or died particles */ + if(pa->time - step > pa->state.time || pa->dietime + step < pa->state.time) + return 0; + } + + ptcache_data_from(data, BPHYS_DATA_INDEX, &index); + ptcache_data_from(data, BPHYS_DATA_LOCATION, pa->state.co); + ptcache_data_from(data, BPHYS_DATA_VELOCITY, pa->state.vel); + ptcache_data_from(data, BPHYS_DATA_ROTATION, pa->state.rot); + ptcache_data_from(data, BPHYS_DATA_AVELOCITY, pa->state.ave); + ptcache_data_from(data, BPHYS_DATA_SIZE, &pa->size); + ptcache_data_from(data, BPHYS_DATA_TIMES, times); + + if(pa->boid) + ptcache_data_from(data, BPHYS_DATA_TIMES, &pa->boid); + + return 1; +} +void BKE_ptcache_make_particle_key(ParticleKey *key, int index, void **data, float time) +{ + ptcache_data_to(data, BPHYS_DATA_LOCATION, index, key->co); + ptcache_data_to(data, BPHYS_DATA_VELOCITY, index, key->vel); + ptcache_data_to(data, BPHYS_DATA_ROTATION, index, key->rot); + ptcache_data_to(data, BPHYS_DATA_AVELOCITY, index, key->ave); + key->time = time; +} +static void ptcache_read_particle(int index, void *psys_v, void **data, float frs_sec, float cfra, float *old_data) +{ + ParticleSystem *psys= psys_v; + ParticleData *pa = psys->particles + index; + + if(cfra > pa->state.time) + memcpy(&pa->prev_state, &pa->state, sizeof(ParticleKey)); + + if(old_data){ + /* old format cache */ + memcpy(&pa->state, old_data, sizeof(ParticleKey)); + return; + } + + BKE_ptcache_make_particle_key(&pa->state, 0, data, cfra); + + if(data[BPHYS_DATA_SIZE]) + ptcache_data_to(data, BPHYS_DATA_SIZE, 0, &pa->size); + + if(data[BPHYS_DATA_TIMES]) { + float times[3]; + ptcache_data_to(data, BPHYS_DATA_TIMES, 0, ×); + pa->time = times[0]; + pa->dietime = times[1]; + pa->lifetime = times[2]; + } + + if(pa->boid) + ptcache_data_to(data, BPHYS_DATA_BOIDS, 0, &pa->boid); + + /* determine velocity from previous location */ + if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_VELOCITY]) { + if(cfra > pa->prev_state.time) { + VecSubf(pa->state.vel, pa->state.co, pa->prev_state.co); + VecMulf(pa->state.vel, (cfra - pa->prev_state.time) / frs_sec); + } + else { + VecSubf(pa->state.vel, pa->prev_state.co, pa->state.co); + VecMulf(pa->state.vel, (pa->prev_state.time - cfra) / frs_sec); + } + } + + /* determine rotation from velocity */ + if(data[BPHYS_DATA_LOCATION] && !data[BPHYS_DATA_ROTATION]) { + vectoquat(pa->state.vel, OB_POSX, OB_POSZ, pa->state.rot); + } +} +static void ptcache_interpolate_particle(int index, void *psys_v, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data) +{ + ParticleSystem *psys= psys_v; + ParticleData *pa = psys->particles + index; + ParticleKey keys[4]; + float dfra; + + cfra = MIN2(cfra, pa->dietime); + cfra1 = MIN2(cfra1, pa->dietime); + cfra2 = MIN2(cfra2, pa->dietime); + + if(cfra1 == cfra2) + return; + + memcpy(keys+1, &pa->state, sizeof(ParticleKey)); + if(old_data) + memcpy(keys+2, old_data, sizeof(ParticleKey)); + else + BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2); + + dfra = cfra2 - cfra1; + + VecMulf(keys[1].vel, dfra / frs_sec); + VecMulf(keys[2].vel, dfra / frs_sec); + + psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &pa->state, 1); + QuatInterpol(pa->state.rot, keys[1].rot,keys[2].rot, (cfra - cfra1) / dfra); + + VecMulf(pa->state.vel, frs_sec / dfra); + + pa->state.time = cfra; +} + +static int ptcache_totpoint_particle(void *psys_v) +{ + ParticleSystem *psys = psys_v; + return psys->totpart; +} +static int ptcache_totwrite_particle(void *psys_v) +{ + ParticleSystem *psys = psys_v; + int totwrite = 0; + + /* TODO for later */ + //if((psys->part->flag & (PART_UNBORN|PART_DIED))==0) { + // ParticleData *pa= psys->particles; + // int p, step = psys->pointcache->step; + + // for(p=0; p<psys->totpart; p++,pa++) + // totwrite += (pa->time - step > pa->state.time || pa->dietime + step > pa->state.time); + //} + //else + totwrite= psys->totpart; + + return totwrite; +} + +/* Cloth functions */ +static int ptcache_write_cloth(int index, void *cloth_v, void **data) +{ + ClothModifierData *clmd= cloth_v; + Cloth *cloth= clmd->clothObject; + ClothVertex *vert = cloth->verts + index; + + ptcache_data_from(data, BPHYS_DATA_LOCATION, vert->x); + ptcache_data_from(data, BPHYS_DATA_VELOCITY, vert->v); + ptcache_data_from(data, BPHYS_DATA_XCONST, vert->xconst); + + return 1; +} +static void ptcache_read_cloth(int index, void *cloth_v, void **data, float frs_sec, float cfra, float *old_data) +{ + ClothModifierData *clmd= cloth_v; + Cloth *cloth= clmd->clothObject; + ClothVertex *vert = cloth->verts + index; + + if(old_data) { + memcpy(vert->x, data, 3 * sizeof(float)); + memcpy(vert->xconst, data + 3, 3 * sizeof(float)); + memcpy(vert->v, data + 6, 3 * sizeof(float)); + } + else { + ptcache_data_to(data, BPHYS_DATA_LOCATION, 0, vert->x); + ptcache_data_to(data, BPHYS_DATA_VELOCITY, 0, vert->v); + ptcache_data_to(data, BPHYS_DATA_XCONST, 0, vert->xconst); + } +} +static void ptcache_interpolate_cloth(int index, void *cloth_v, void **data, float frs_sec, float cfra, float cfra1, float cfra2, float *old_data) +{ + ClothModifierData *clmd= cloth_v; + Cloth *cloth= clmd->clothObject; + ClothVertex *vert = cloth->verts + index; + ParticleKey keys[4]; + float dfra; + + if(cfra1 == cfra2) + return; + VECCOPY(keys[1].co, vert->x); + VECCOPY(keys[1].vel, vert->v); + + if(old_data) { + memcpy(keys[2].co, old_data, 3 * sizeof(float)); + memcpy(keys[2].vel, old_data + 6, 3 * sizeof(float)); + } + else + BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2); + + dfra = cfra2 - cfra1; + + VecMulf(keys[1].vel, dfra); + VecMulf(keys[2].vel, dfra); + + psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, keys, 1); + + VecMulf(keys->vel, 1.0f / dfra); + + VECCOPY(vert->x, keys->co); + VECCOPY(vert->v, keys->vel); + + /* should vert->xconst be interpolated somehow too? - jahka */ +} + +static int ptcache_totpoint_cloth(void *cloth_v) +{ + ClothModifierData *clmd= cloth_v; + return clmd->clothObject->numverts; +} + +/* Creating ID's */ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) { ParticleSystemModifierData *psmd; @@ -87,9 +392,24 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb) memset(pid, 0, sizeof(PTCacheID)); pid->ob= ob; - pid->data= sb; + pid->calldata= sb; pid->type= PTCACHE_TYPE_SOFTBODY; pid->cache= sb->pointcache; + pid->cache_ptr= &sb->pointcache; + pid->ptcaches= &sb->ptcaches; + pid->totpoint= pid->totwrite= ptcache_totpoint_softbody; + + pid->write_elem= ptcache_write_softbody; + pid->write_stream = NULL; + pid->read_stream = NULL; + pid->read_elem= ptcache_read_softbody; + pid->interpolate_elem= ptcache_interpolate_softbody; + + pid->write_header= ptcache_write_basic_header; + pid->read_header= ptcache_read_basic_header; + + pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY); + pid->info_types= 0; if(sb->particles) { psmd= psys_get_modifier(ob, sb->particles); @@ -112,21 +432,173 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p memset(pid, 0, sizeof(PTCacheID)); pid->ob= ob; - pid->data= psys; + pid->calldata= psys; pid->type= PTCACHE_TYPE_PARTICLES; pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)psmd); pid->cache= psys->pointcache; + pid->cache_ptr= &psys->pointcache; + pid->ptcaches= &psys->ptcaches; + + pid->write_elem= ptcache_write_particle; + pid->write_stream = NULL; + pid->read_stream = NULL; + pid->read_elem= ptcache_read_particle; + pid->interpolate_elem= ptcache_interpolate_particle; + + pid->totpoint= ptcache_totpoint_particle; + pid->totwrite= ptcache_totwrite_particle; + + pid->write_header= ptcache_write_basic_header; + pid->read_header= ptcache_read_basic_header; + + pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY); + + /* TODO for later */ + //if((psys->part->flag & (PART_UNBORN|PART_DIED))==0) + // pid->data_types|= (1<<BPHYS_DATA_INDEX); + + if(psys->part->phystype == PART_PHYS_BOIDS) + pid->data_types|= (1<<BPHYS_DATA_AVELOCITY) | (1<<BPHYS_DATA_ROTATION) | (1<<BPHYS_DATA_BOIDS); + + if(psys->part->rotmode || psys->part->avemode) + pid->data_types|= (1<<BPHYS_DATA_AVELOCITY) | (1<<BPHYS_DATA_ROTATION); + + if(psys->part->flag & PART_ROT_DYN) + pid->data_types|= (1<<BPHYS_DATA_ROTATION); + + pid->info_types= (1<<BPHYS_DATA_TIMES); +} + +#if 0 // XXX smoke pointcache stuff breaks compiling now +/* Smoke functions */ +static int ptcache_totpoint_smoke(void *smoke_v) +{ + SmokeModifierData *smd= (SmokeModifierData *)smoke_v; + SmokeDomainSettings *sds = smd->domain; + + if(sds->fluid) + { + return sds->res[0]*sds->res[1]*sds->res[2]; + } + else + return 0; +} + +// forward decleration +static int ptcache_file_write(PTCacheFile *pf, void *f, size_t tot, int size); + +static int ptcache_write_smoke(PTCacheFile *pf, void *smoke_v) +{ + SmokeModifierData *smd= (SmokeModifierData *)smoke_v; + SmokeDomainSettings *sds = smd->domain; + + if(sds->fluid) + { + size_t res = sds->res[0]*sds->res[1]*sds->res[2]; + float *dens, *densold, *heat, *heatold, *vx, *vy, *vz; + + smoke_export(sds->fluid, &dens, &densold, &heat, &heatold, &vx, &vy, &vz); + + ptcache_file_write(pf, dens, res, sizeof(float)); + ptcache_file_write(pf, densold, res, sizeof(float)); + ptcache_file_write(pf, heat, res, sizeof(float)); + ptcache_file_write(pf, heatold, res, sizeof(float)); + ptcache_file_write(pf, vx, res, sizeof(float)); + ptcache_file_write(pf, vy, res, sizeof(float)); + ptcache_file_write(pf, vz, res, sizeof(float)); + + return 1; + } + + return 0; +} + +// forward decleration +static int ptcache_file_read(PTCacheFile *pf, void *f, size_t tot, int size); + +static void ptcache_read_smoke(PTCacheFile *pf, void *smoke_v) +{ + SmokeModifierData *smd= (SmokeModifierData *)smoke_v; + SmokeDomainSettings *sds = smd->domain; + + if(sds->fluid) + { + size_t res = sds->res[0]*sds->res[1]*sds->res[2]; + float *dens, *densold, *heat, *heatold, *vx, *vy, *vz; + + smoke_export(sds->fluid, &dens, &densold, &heat, &heatold, &vx, &vy, &vz); + + ptcache_file_read(pf, dens, res, sizeof(float)); + ptcache_file_read(pf, densold, res, sizeof(float)); + ptcache_file_read(pf, heat, res, sizeof(float)); + ptcache_file_read(pf, heatold, res, sizeof(float)); + ptcache_file_read(pf, vx, res, sizeof(float)); + ptcache_file_read(pf, vy, res, sizeof(float)); + ptcache_file_read(pf, vz, res, sizeof(float)); + + } +} +void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd, int num) +{ + SmokeDomainSettings *sds = smd->domain; + + memset(pid, 0, sizeof(PTCacheID)); + + pid->ob= ob; + pid->calldata= smd; + + // if(num == 0) + pid->type= PTCACHE_TYPE_SMOKE_DOMAIN_LOW; + // else if(num == 1) + // pid->type= PTCACHE_TYPE_SMOKE_DOMAIN_HIGH; + + pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)smd); + + pid->cache= sds->point_cache; + pid->cache_ptr= &sds->point_cache; + pid->ptcaches= &sds->ptcaches; + + + pid->totpoint= pid->totwrite= ptcache_totpoint_smoke; + + pid->write_elem= NULL; + pid->read_elem= NULL; + pid->read_stream = ptcache_read_smoke; + pid->write_stream = ptcache_write_smoke; + pid->interpolate_elem= NULL; + + pid->write_header= ptcache_write_basic_header; + pid->read_header= ptcache_read_basic_header; + + pid->data_types= (1<<BPHYS_DATA_LOCATION); // bogus values tot make pointcache happy + pid->info_types= 0; } +#endif // XXX smoke poitcache stuff breaks compiling void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd) { memset(pid, 0, sizeof(PTCacheID)); pid->ob= ob; - pid->data= clmd; + pid->calldata= clmd; pid->type= PTCACHE_TYPE_CLOTH; pid->stack_index= modifiers_indexInObject(ob, (ModifierData *)clmd); pid->cache= clmd->point_cache; + pid->cache_ptr= &clmd->point_cache; + pid->ptcaches= &clmd->ptcaches; + pid->totpoint= pid->totwrite= ptcache_totpoint_cloth; + + pid->write_elem= ptcache_write_cloth; + pid->write_stream = NULL; + pid->read_stream = NULL; + pid->read_elem= ptcache_read_cloth; + pid->interpolate_elem= ptcache_interpolate_cloth; + + pid->write_header= ptcache_write_basic_header; + pid->read_header= ptcache_read_basic_header; + + pid->data_types= (1<<BPHYS_DATA_LOCATION) | (1<<BPHYS_DATA_VELOCITY) | (1<<BPHYS_DATA_XCONST); + pid->info_types= 0; } void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob) @@ -161,9 +633,24 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob) BKE_ptcache_id_from_cloth(pid, ob, (ClothModifierData*)md); BLI_addtail(lb, pid); } + /* + // enabled on next commit + if(md->type == eModifierType_Smoke) { + SmokeModifierData *smd = (SmokeModifierData *)md; + if(smd->type & MOD_SMOKE_TYPE_DOMAIN) + { + pid= MEM_callocN(sizeof(PTCacheID), "PTCacheID"); + BKE_ptcache_id_from_smoke(pid, ob, (SmokeModifierData*)md, 0); + BLI_addtail(lb, pid); + } + } + */ } } + +/* File handling */ + /* Takes an Object ID and returns a unique name - id: object id - cfra: frame for the cache, can be negative @@ -176,11 +663,15 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob) static int ptcache_path(PTCacheID *pid, char *filename) { Library *lib; - int i; + size_t i; lib= (pid)? pid->ob->id.lib: NULL; - if (G.relbase_valid || lib) { + if(pid->cache->flag & PTCACHE_EXTERNAL) { + strcpy(filename, pid->cache->path); + return BLI_add_slash(filename); /* new strlen() */ + } + else if (G.relbase_valid || lib) { char file[MAX_PTCACHE_PATH]; /* we dont want the dir, only the file */ char *blendfilename; @@ -195,15 +686,14 @@ static int ptcache_path(PTCacheID *pid, char *filename) snprintf(filename, MAX_PTCACHE_PATH, "//"PTCACHE_PATH"%s", file); /* add blend file name to pointcache dir */ BLI_convertstringcode(filename, blendfilename); - BLI_add_slash(filename); - return strlen(filename); + return BLI_add_slash(filename); /* new strlen() */ } /* use the temp path. this is weak but better then not using point cache at all */ /* btempdir is assumed to exist and ALWAYS has a trailing slash */ snprintf(filename, MAX_PTCACHE_PATH, "%s"PTCACHE_PATH"%d", btempdir, abs(getpid())); - BLI_add_slash(filename); - return strlen(filename); + + return BLI_add_slash(filename); /* new strlen() */ } static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext) @@ -214,23 +704,39 @@ static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, sho filename[0] = '\0'; newname = filename; - /*if (!G.relbase_valid) return 0; *//* save blend file before using pointcache */ + if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL)==0) return 0; /* save blend file before using disk pointcache */ /* start with temp dir */ if (do_path) { len = ptcache_path(pid, filename); newname += len; } - idname = (pid->ob->id.name+2); - /* convert chars to hex so they are always a valid filename */ - while('\0' != *idname) { - snprintf(newname, MAX_PTCACHE_FILE, "%02X", (char)(*idname++)); - newname+=2; - len += 2; + if(strcmp(pid->cache->name, "")==0 && (pid->cache->flag & PTCACHE_EXTERNAL)==0) { + idname = (pid->ob->id.name+2); + /* convert chars to hex so they are always a valid filename */ + while('\0' != *idname) { + snprintf(newname, MAX_PTCACHE_FILE, "%02X", (char)(*idname++)); + newname+=2; + len += 2; + } } - + else { + int temp = (int)strlen(pid->cache->name); + strcpy(newname, pid->cache->name); + newname+=temp; + len += temp; + } + if (do_ext) { - snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ + if(pid->cache->flag & PTCACHE_EXTERNAL) { + if(pid->cache->index >= 0) + snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ + else + snprintf(newname, MAX_PTCACHE_FILE, "_%06d"PTCACHE_EXT, cfra); /* always 6 chars */ + } + else { + snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02d"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */ + } len += 16; } @@ -238,7 +744,7 @@ static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, sho } /* youll need to close yourself after! */ -PTCacheFile *BKE_ptcache_file_open(PTCacheID *pid, int mode, int cfra) +static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra) { PTCacheFile *pf; FILE *fp = NULL; @@ -248,7 +754,7 @@ PTCacheFile *BKE_ptcache_file_open(PTCacheID *pid, int mode, int cfra) if(pid->ob->id.lib && mode == PTCACHE_FILE_WRITE) return NULL; - /*if (!G.relbase_valid) return NULL; *//* save blend file before using pointcache */ + if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL)==0) return NULL; /* save blend file before using disk pointcache */ BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); @@ -271,27 +777,639 @@ PTCacheFile *BKE_ptcache_file_open(PTCacheID *pid, int mode, int cfra) return pf; } -void BKE_ptcache_file_close(PTCacheFile *pf) +static void ptcache_file_close(PTCacheFile *pf) { fclose(pf->fp); MEM_freeN(pf); } -int BKE_ptcache_file_read_floats(PTCacheFile *pf, float *f, int tot) +static int ptcache_file_read(PTCacheFile *pf, void *f, size_t tot, int size) +{ + return (fread(f, size, tot, pf->fp) == tot); +} +static int ptcache_file_write(PTCacheFile *pf, void *f, size_t tot, int size) +{ + return (fwrite(f, size, tot, pf->fp) == tot); +} +static int ptcache_file_read_data(PTCacheFile *pf) +{ + int i; + + for(i=0; i<BPHYS_TOT_DATA; i++) { + if(pf->data_types & (1<<i) && !ptcache_file_read(pf, pf->cur[i], 1, BKE_ptcache_data_size(i))) + return 0; + } + + return 1; +} +static int ptcache_file_write_data(PTCacheFile *pf) +{ + int i; + + for(i=0; i<BPHYS_TOT_DATA; i++) { + if(pf->data_types & (1<<i) && !ptcache_file_write(pf, pf->cur[i], 1, BKE_ptcache_data_size(i))) + return 0; + } + + return 1; +} +static int ptcache_file_read_header_begin(PTCacheFile *pf) +{ + int error=0; + char bphysics[8]; + + pf->data_types = 0; + + if(fread(bphysics, sizeof(char), 8, pf->fp) != 8) + error = 1; + + if(!error && strncmp(bphysics, "BPHYSICS", 8)) + error = 1; + + if(!error && !fread(&pf->type, sizeof(int), 1, pf->fp)) + error = 1; + + /* if there was an error set file as it was */ + if(error) + fseek(pf->fp, 0, SEEK_SET); + + return !error; +} + + +static int ptcache_file_write_header_begin(PTCacheFile *pf) +{ + char *bphysics = "BPHYSICS"; + + if(fwrite(bphysics, sizeof(char), 8, pf->fp) != 8) + return 0; + + if(!fwrite(&pf->type, sizeof(int), 1, pf->fp)) + return 0; + + return 1; +} + + +/* Data pointer handling */ +int BKE_ptcache_data_size(int data_type) +{ + switch(data_type) { + case BPHYS_DATA_INDEX: + return sizeof(int); + case BPHYS_DATA_LOCATION: + case BPHYS_DATA_VELOCITY: + case BPHYS_DATA_AVELOCITY: /* also BPHYS_DATA_XCONST */ + case BPHYS_DATA_TIMES: + return 3 * sizeof(float); + case BPHYS_DATA_ROTATION: + return 4 * sizeof(float); + case BPHYS_DATA_SIZE: + return sizeof(float); + case BPHYS_DATA_BOIDS: + return sizeof(BoidData); + default: + return 0; + } +} +static void ptcache_data_to(void **data, int type, int index, void *to) +{ + if(data[type]) { + if(index) + memcpy(to, (char*)data[type] + index * BKE_ptcache_data_size(type), BKE_ptcache_data_size(type)); + else + memcpy(to, data[type], BKE_ptcache_data_size(type)); + } +} + +static void ptcache_data_from(void **data, int type, void *from) +{ + if(data[type]) + memcpy(data[type], from, BKE_ptcache_data_size(type)); +} + +static void ptcache_file_init_pointers(PTCacheFile *pf) +{ + int data_types = pf->data_types; + + pf->cur[BPHYS_DATA_INDEX] = data_types & (1<<BPHYS_DATA_INDEX) ? &pf->data.index : NULL; + pf->cur[BPHYS_DATA_LOCATION] = data_types & (1<<BPHYS_DATA_LOCATION) ? &pf->data.loc : NULL; + pf->cur[BPHYS_DATA_VELOCITY] = data_types & (1<<BPHYS_DATA_VELOCITY) ? &pf->data.vel : NULL; + pf->cur[BPHYS_DATA_ROTATION] = data_types & (1<<BPHYS_DATA_ROTATION) ? &pf->data.rot : NULL; + pf->cur[BPHYS_DATA_AVELOCITY] = data_types & (1<<BPHYS_DATA_AVELOCITY) ? &pf->data.ave : NULL; + pf->cur[BPHYS_DATA_SIZE] = data_types & (1<<BPHYS_DATA_SIZE) ? &pf->data.size : NULL; + pf->cur[BPHYS_DATA_TIMES] = data_types & (1<<BPHYS_DATA_TIMES) ? &pf->data.times : NULL; + pf->cur[BPHYS_DATA_BOIDS] = data_types & (1<<BPHYS_DATA_BOIDS) ? &pf->data.boids : NULL; +} + +static void ptcache_mem_init_pointers(PTCacheMem *pm) +{ + int data_types = pm->data_types; + int i; + + for(i=0; i<BPHYS_TOT_DATA; i++) + pm->cur[i] = data_types & (1<<i) ? pm->data[i] : NULL; +} + +static void ptcache_mem_incr_pointers(PTCacheMem *pm) +{ + int i; + + for(i=0; i<BPHYS_TOT_DATA; i++) { + if(pm->cur[i]) + pm->cur[i] = (char*)pm->cur[i] + BKE_ptcache_data_size(i); + } +} +static void ptcache_alloc_data(PTCacheMem *pm) { - return (fread(f, sizeof(float), tot, pf->fp) == tot); + int data_types = pm->data_types; + int totpoint = pm->totpoint; + int i; + + for(i=0; i<BPHYS_TOT_DATA; i++) { + if(data_types & (1<<i)) + pm->data[i] = MEM_callocN(totpoint * BKE_ptcache_data_size(i), "PTCache Data"); + } +} +static void ptcache_free_data(void *data[]) +{ + int i; + + for(i=0; i<BPHYS_TOT_DATA; i++) { + if(data[i]) + MEM_freeN(data[i]); + } +} +static void ptcache_copy_data(void *from[], void *to[]) +{ + int i; + for(i=0; i<BPHYS_TOT_DATA; i++) { + if(from[i]) + memcpy(to[i], from[i], BKE_ptcache_data_size(i)); + } } -int BKE_ptcache_file_write_floats(PTCacheFile *pf, float *f, int tot) + + +static int ptcache_pid_old_elemsize(PTCacheID *pid) { - return (fwrite(f, sizeof(float), tot, pf->fp) == tot); + if(pid->type==PTCACHE_TYPE_SOFTBODY) + return 6 * sizeof(float); + else if(pid->type==PTCACHE_TYPE_PARTICLES) + return sizeof(ParticleKey); + else if(pid->type==PTCACHE_TYPE_CLOTH) + return 9 * sizeof(float); + + return 0; } +/* reads cache from disk or memory */ +/* possible to get old or interpolated result */ +int BKE_ptcache_read_cache(PTCacheID *pid, float cfra, float frs_sec) +{ + PTCacheFile *pf=NULL, *pf2=NULL; + PTCacheMem *pm=NULL, *pm2=NULL; + float old_data1[14], old_data2[14]; + int cfrai = (int)cfra; + int old_elemsize = ptcache_pid_old_elemsize(pid); + int i, incr = old_elemsize / sizeof(float); + + int cfra1 = 0, cfra2 = 0; + int totpoint = 0, totpoint2 = 0; + int *index = &i, *index2 = &i; + int use_old = 0, old_frame; + + int ret = 0, error = 0; + + /* nothing to read to */ + if(pid->totpoint(pid->calldata) == 0) + return 0; + + if(pid->cache->flag & PTCACHE_READ_INFO) { + pid->cache->flag &= ~PTCACHE_READ_INFO; + BKE_ptcache_read_cache(pid, 0, frs_sec); + } + + + /* first check if we have the actual frame cached */ + if(cfra == (float)cfrai) { + if(pid->cache->flag & PTCACHE_DISK_CACHE) { + pf= ptcache_file_open(pid, PTCACHE_FILE_READ, cfrai); + } + else { + pm = pid->cache->mem_cache.first; + + for(; pm; pm=pm->next) { + if(pm->frame == cfrai) + break; + } + } + } + + /* no exact cache frame found so try to find cached frames around cfra */ + if(!pm && !pf) { + if(pid->cache->flag & PTCACHE_DISK_CACHE) { + pf=NULL; + while(cfrai > pid->cache->startframe && !pf) { + cfrai--; + pf= ptcache_file_open(pid, PTCACHE_FILE_READ, cfrai); + cfra1 = cfrai; + } + + old_frame = cfrai; + + cfrai = (int)cfra; + while(cfrai < pid->cache->endframe && !pf2) { + cfrai++; + pf2= ptcache_file_open(pid, PTCACHE_FILE_READ, cfrai); + cfra2 = cfrai; + } + + if(pf && !pf2) { + pf2 = pf; + pf = NULL; + } + } + else if(pid->cache->mem_cache.first){ + pm = pid->cache->mem_cache.first; + + while(pm->next && pm->next->frame < cfra) + pm= pm->next; + + if(pm) { + old_frame = pm->frame; + cfra1 = pm->frame; + } + + pm2 = pid->cache->mem_cache.last; + + if(pm2 && pm2->frame < cfra) + pm2 = NULL; + else { + while(pm2->prev && pm2->prev->frame > cfra) + pm2= pm2->prev; + + if(pm2) + cfra2 = pm2->frame; + } + + if(pm && !pm2) { + pm2 = pm; + pm = NULL; + } + } + } + + if(!pm && !pm2 && !pf && !pf2) + return 0; + + if(pm) { + ptcache_mem_init_pointers(pm); + totpoint = pm->totpoint; + index = pm->data_types & (1<<BPHYS_DATA_INDEX) ? pm->cur[BPHYS_DATA_INDEX] : &i; + } + if(pm2) { + ptcache_mem_init_pointers(pm2); + totpoint2 = pm2->totpoint; + index2 = pm2->data_types & (1<<BPHYS_DATA_INDEX) ? pm2->cur[BPHYS_DATA_INDEX] : &i; + } + if(pf) { + if(ptcache_file_read_header_begin(pf)) { + if(pf->type != pid->type) { + /* todo report error */ + ptcache_file_close(pf); + pf = NULL; + } + else if(pid->read_header(pf)) { + ptcache_file_init_pointers(pf); + totpoint = pf->totpoint; + index = pf->data_types & BPHYS_DATA_INDEX ? &pf->data.index : &i; + } + } + else { + /* fall back to old cache file format */ + use_old = 1; + totpoint = pid->totpoint(pid->calldata); + } + } + if(pf2) { + if(ptcache_file_read_header_begin(pf2)) { + if(pf2->type != pid->type) { + /* todo report error */ + ptcache_file_close(pf2); + pf2 = NULL; + } + else if(pid->read_header(pf2)) { + ptcache_file_init_pointers(pf2); + totpoint2 = pf2->totpoint; + index2 = pf->data_types & BPHYS_DATA_INDEX ? &pf2->data.index : &i; + } + } + else { + /* fall back to old cache file format */ + use_old = 1; + totpoint2 = pid->totpoint(pid->calldata); + } + } + + /* don't read old cache if allready simulated past cached frame */ + if(!pm && !pf && cfra1 && cfra1 <= pid->cache->simframe) + error = 1; + if(cfra1 && cfra1==cfra2) + error = 1; + + if(!error) + { + if(pf && pid->read_stream) { + if(totpoint != pid->totpoint(pid->calldata)) + error = 1; + else + { + // we have stream writing here + pid->read_stream(pf, pid->calldata); + } + } + } + + totpoint = MIN2(totpoint, pid->totpoint(pid->calldata)); + + if(!error) + { + for(i=0; i<totpoint; i++) { + /* read old cache file format */ + if(use_old) { + if(pid->read_elem && ptcache_file_read(pf, (void*)old_data1, 1, old_elemsize)) + pid->read_elem(i, pid->calldata, NULL, frs_sec, cfra, old_data1); + else + { error = 1; break; } + } + else { + if(pid->read_elem && (pm || ptcache_file_read_data(pf))) + pid->read_elem(*index, pid->calldata, pm ? pm->cur : pf->cur, frs_sec, cfra1 ? (float)cfra1 : (float)cfrai, NULL); + else + { error = 1; break; } + } + + if(pm) { + ptcache_mem_incr_pointers(pm); + index = pm->data_types & (1<<BPHYS_DATA_INDEX) ? pm->cur[BPHYS_DATA_INDEX] : &i; + } + } + } + + if(!error) + { + if(pf2 && pid->read_stream) { + if(totpoint2 != pid->totpoint(pid->calldata)) + error = 1; + else + { + // we have stream writing here + pid->read_stream(pf2, pid->calldata); + } + } + } + + totpoint2 = MIN2(totpoint2, pid->totpoint(pid->calldata)); + + if(!error) + { + for(i=0; i<totpoint2; i++) { + /* read old cache file format */ + if(use_old) { + if(pid->read_elem && ptcache_file_read(pf2, (void*)old_data2, 1, old_elemsize)) { + if(!pf && pf2) + pid->read_elem(i, pid->calldata, NULL, frs_sec, (float)cfra2, old_data2); + else if(pid->interpolate_elem) + pid->interpolate_elem(i, pid->calldata, NULL, frs_sec, cfra, (float)cfra1, (float)cfra2, old_data2); + else + { error = 1; break; } + } + else + { error = 1; break; } + } + else { + if(pid->read_elem && (pm2 || ptcache_file_read_data(pf2))) { + if((!pf && pf2) || (!pm && pm2)) + pid->read_elem(*index2, pid->calldata, pm2 ? pm2->cur : pf2->cur, frs_sec, (float)cfra2, NULL); + else if(pid->interpolate_elem) + pid->interpolate_elem(*index2, pid->calldata, pm2 ? pm2->cur : pf2->cur, frs_sec, cfra, (float)cfra1, (float)cfra2, NULL); + else + { error = 1; break; } + } + else + { error = 1; break; } + } + + if(pm2) { + ptcache_mem_incr_pointers(pm2); + index2 = pm2->data_types & (1<<BPHYS_DATA_INDEX) ? pm2->cur[BPHYS_DATA_INDEX] : &i; + } + } + } + + if(pm || pf) + ret = (pm2 || pf2) ? PTCACHE_READ_INTERPOLATED : PTCACHE_READ_EXACT; + else if(pm2 || pf2) { + ret = PTCACHE_READ_OLD; + pid->cache->simframe = old_frame; + } + + if(pf) { + ptcache_file_close(pf); + pf = NULL; + } + + if(pf2) { + ptcache_file_close(pf2); + pf = NULL; + } + + if((pid->cache->flag & PTCACHE_QUICK_CACHE)==0) { + cfrai = (int)cfra; + /* clear invalid cache frames so that better stuff can be simulated */ + if(pid->cache->flag & PTCACHE_OUTDATED) { + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, cfrai); + } + else if(pid->cache->flag & PTCACHE_FRAMES_SKIPPED) { + if(cfra <= pid->cache->last_exact) + pid->cache->flag &= ~PTCACHE_FRAMES_SKIPPED; + + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, MAX2(cfrai,pid->cache->last_exact)); + } + } + + return (error ? 0 : ret); +} +/* TODO for later */ +//static void ptcache_make_index_array(PTCacheMem *pm, int totpoint) +//{ +// int i, *index; +// +// if(pm->index_array) { +// MEM_freeN(pm->index_array); +// pm->index_array = NULL; +// } +// +// if(!pm->data[BPHYS_DATA_INDEX]) +// return; +// +// pm->index_array = MEM_callocN(totpoint * sizeof(int), "PTCacheMem index_array"); +// index = pm->data[BPHYS_DATA_INDEX]; +// +// for(i=0; i<pm->totpoint; i++, index++) +// pm->index_array[*index] = i; +//} +/* writes cache to disk or memory */ +int BKE_ptcache_write_cache(PTCacheID *pid, int cfra) +{ + PointCache *cache = pid->cache; + PTCacheFile *pf= NULL; + int elemsize = ptcache_pid_old_elemsize(pid); + int i, incr = elemsize / sizeof(float); + int totpoint = pid->totpoint(pid->calldata); + int add = 0, overwrite = 0; + + if(totpoint == 0 || cfra < 0 + || (cfra ? pid->data_types == 0 : pid->info_types == 0)) + return 0; + + if(cache->flag & PTCACHE_DISK_CACHE) { + int efra = cache->endframe; + + if(cfra==0) + add = 1; + /* allways start from scratch on the first frame */ + else if(cfra == cache->startframe) { + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, cfra); + cache->flag &= ~PTCACHE_REDO_NEEDED; + add = 1; + } + else { + int ofra; + /* find last cached frame */ + while(efra > cache->startframe && !BKE_ptcache_id_exist(pid, efra)) + efra--; + + /* find second last cached frame */ + ofra = efra-1; + while(ofra > cache->startframe && !BKE_ptcache_id_exist(pid, ofra)) + ofra--; + + if(efra >= cache->startframe && cfra > efra) { + if(ofra >= cache->startframe && efra - ofra < cache->step) + overwrite = 1; + else + add = 1; + } + } + + if(add || overwrite) { + if(overwrite) + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, efra); + + pf = ptcache_file_open(pid, PTCACHE_FILE_WRITE, cfra); + if(!pf) + return 0; + + pf->type = pid->type; + pf->totpoint = cfra ? totpoint : pid->totwrite(pid->calldata); + pf->data_types = cfra ? pid->data_types : pid->info_types; + + if(!ptcache_file_write_header_begin(pf) || !pid->write_header(pf)) { + ptcache_file_close(pf); + return 0; + } + + ptcache_file_init_pointers(pf); + + if(pf && pid->write_stream) { + // we have stream writing here + pid->write_stream(pf, pid->calldata); + } + else + for(i=0; i<totpoint; i++) { + if(pid->write_elem && pid->write_elem(i, pid->calldata, pf->cur)) + if(!ptcache_file_write_data(pf)) { + ptcache_file_close(pf); + return 0; + } + } + } + } + else { + PTCacheMem *pm; + PTCacheMem *pm2; + + pm2 = cache->mem_cache.first; + + /* don't write info file in memory */ + if(cfra==0) + return 1; + /* allways start from scratch on the first frame */ + if(cfra == cache->startframe) { + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, cfra); + cache->flag &= ~PTCACHE_REDO_NEEDED; + add = 1; + } + else if (cache->mem_cache.last) { + pm2 = cache->mem_cache.last; + + if(pm2 && cfra > pm2->frame) { + if(pm2->prev && pm2->frame - pm2->prev->frame < cache->step) + overwrite = 1; + else + add = 1; + } + } + else + add = 1; + + if(add || overwrite) { + if(overwrite) + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, pm2->frame); + + pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache mem"); + + pm->totpoint = pid->totwrite(pid->calldata); + pm->data_types = cfra ? pid->data_types : pid->info_types; + + ptcache_alloc_data(pm); + ptcache_mem_init_pointers(pm); + + for(i=0; i<totpoint; i++) { + if(pid->write_elem && pid->write_elem(i, pid->calldata, pm->cur)) + ptcache_mem_incr_pointers(pm); + } + //ptcache_make_index_array(pm, pid->totpoint(pid->calldata)); + + pm->frame = cfra; + BLI_addtail(&cache->mem_cache, pm); + } + } + + if(add || overwrite) { + if(cfra - cache->last_exact == 1 + || cfra == cache->startframe) { + cache->last_exact = cfra; + cache->flag &= ~PTCACHE_FRAMES_SKIPPED; + } + else + cache->flag |= PTCACHE_FRAMES_SKIPPED; + } + + if(pf) + ptcache_file_close(pf); + + BKE_ptcache_update_info(pid); + + return 1; +} /* youll need to close yourself after! * mode - PTCACHE_CLEAR_ALL, */ - +/* Clears & resets */ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra) { int len; /* store the length of the string */ @@ -304,7 +1422,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra) char path_full[MAX_PTCACHE_FILE]; char ext[MAX_PTCACHE_PATH]; - if(!pid->cache) + if(!pid->cache || pid->cache->flag & PTCACHE_BAKED) return; /* don't allow clearing for linked objects */ @@ -318,70 +1436,127 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, int cfra) case PTCACHE_CLEAR_ALL: case PTCACHE_CLEAR_BEFORE: case PTCACHE_CLEAR_AFTER: - ptcache_path(pid, path); - - len = BKE_ptcache_id_filename(pid, filename, cfra, 0, 0); /* no path */ - - dir = opendir(path); - if (dir==NULL) - return; - - snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, pid->stack_index); - - while ((de = readdir(dir)) != NULL) { - if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ - if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */ - if (mode == PTCACHE_CLEAR_ALL) { - BLI_join_dirfile(path_full, path, de->d_name); - BLI_delete(path_full, 0, 0); - } else { - /* read the number of the file */ - int frame, len2 = strlen(de->d_name); - char num[7]; - - if (len2 > 15) { /* could crash if trying to copy a string out of this range*/ - BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num)); - frame = atoi(num); - - if((mode==PTCACHE_CLEAR_BEFORE && frame < cfra) || - (mode==PTCACHE_CLEAR_AFTER && frame > cfra) ) { + if(pid->cache->flag & PTCACHE_DISK_CACHE) { + ptcache_path(pid, path); + + len = BKE_ptcache_id_filename(pid, filename, cfra, 0, 0); /* no path */ + + dir = opendir(path); + if (dir==NULL) + return; + + snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, pid->stack_index); + + while ((de = readdir(dir)) != NULL) { + if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ + if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */ + if (mode == PTCACHE_CLEAR_ALL) { + pid->cache->last_exact = 0; + BLI_join_dirfile(path_full, path, de->d_name); + BLI_delete(path_full, 0, 0); + } else { + /* read the number of the file */ + int frame, len2 = (int)strlen(de->d_name); + char num[7]; + + if (len2 > 15) { /* could crash if trying to copy a string out of this range*/ + BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num)); + frame = atoi(num); - BLI_join_dirfile(path_full, path, de->d_name); - BLI_delete(path_full, 0, 0); + if((mode==PTCACHE_CLEAR_BEFORE && frame < cfra) || + (mode==PTCACHE_CLEAR_AFTER && frame > cfra) ) { + + BLI_join_dirfile(path_full, path, de->d_name); + BLI_delete(path_full, 0, 0); + } } } } } } + closedir(dir); + } + else { + PTCacheMem *pm= pid->cache->mem_cache.first; + PTCacheMem *link= NULL; + + if(mode == PTCACHE_CLEAR_ALL) { + pid->cache->last_exact = 0; + for(; pm; pm=pm->next) + ptcache_free_data(pm->data); + BLI_freelistN(&pid->cache->mem_cache); + } else { + while(pm) { + if((mode==PTCACHE_CLEAR_BEFORE && pm->frame < cfra) || + (mode==PTCACHE_CLEAR_AFTER && pm->frame > cfra) ) { + link = pm; + pm = pm->next; + ptcache_free_data(link->data); + BLI_freelinkN(&pid->cache->mem_cache, link); + } + else + pm = pm->next; + } + } } - closedir(dir); break; case PTCACHE_CLEAR_FRAME: - len = BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); /* no path */ - BLI_delete(filename, 0, 0); + if(pid->cache->flag & PTCACHE_DISK_CACHE) { + if(BKE_ptcache_id_exist(pid, cfra)) { + BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); /* no path */ + BLI_delete(filename, 0, 0); + } + } + else { + PTCacheMem *pm = pid->cache->mem_cache.first; + + for(; pm; pm=pm->next) { + if(pm->frame == cfra) { + ptcache_free_data(pm->data); + BLI_freelinkN(&pid->cache->mem_cache, pm); + break; + } + } + } break; } + + BKE_ptcache_update_info(pid); } int BKE_ptcache_id_exist(PTCacheID *pid, int cfra) { - char filename[MAX_PTCACHE_FILE]; - if(!pid->cache) return 0; - BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); + if(pid->cache->flag & PTCACHE_DISK_CACHE) { + char filename[MAX_PTCACHE_FILE]; + + BKE_ptcache_id_filename(pid, filename, cfra, 1, 1); + + return BLI_exists(filename); + } + else { + PTCacheMem *pm = pid->cache->mem_cache.first; - return BLI_exists(filename); + for(; pm; pm=pm->next) { + if(pm->frame==cfra) + return 1; + } + return 0; + } } -void BKE_ptcache_id_time(PTCacheID *pid, float cfra, int *startframe, int *endframe, float *timescale) +void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startframe, int *endframe, float *timescale) { Object *ob; PointCache *cache; float offset, time, nexttime; + /* TODO: this has to be sorter out once bsystem_time gets redone, */ + /* now caches can handle interpolating etc. too - jahka */ + /* time handling for point cache: * - simulation time is scaled by result of bsystem_time * - for offsetting time only time offset is taken into account, since @@ -395,8 +1570,8 @@ void BKE_ptcache_id_time(PTCacheID *pid, float cfra, int *startframe, int *endfr cache= pid->cache; if(timescale) { - time= bsystem_time(ob, cfra, 0.0f); - nexttime= bsystem_time(ob, cfra+1.0f, 0.0f); + time= bsystem_time(scene, ob, cfra, 0.0f); + nexttime= bsystem_time(scene, ob, cfra+1.0f, 0.0f); *timescale= MAX2(nexttime - time, 0.0f); } @@ -405,7 +1580,8 @@ void BKE_ptcache_id_time(PTCacheID *pid, float cfra, int *startframe, int *endfr *startframe= cache->startframe; *endframe= cache->endframe; - if ((ob->ipoflag & OB_OFFS_PARENT) && (ob->partype & PARSLOW)==0) { + // XXX ipoflag is depreceated - old animation system stuff + if (/*(ob->ipoflag & OB_OFFS_PARENT) &&*/ (ob->partype & PARSLOW)==0) { offset= give_timeoffset(ob); *startframe += (int)(offset+0.5f); @@ -414,10 +1590,10 @@ void BKE_ptcache_id_time(PTCacheID *pid, float cfra, int *startframe, int *endfr } } -int BKE_ptcache_id_reset(PTCacheID *pid, int mode) +int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode) { PointCache *cache; - int reset, clear; + int reset, clear, after; if(!pid->cache) return 0; @@ -425,14 +1601,17 @@ int BKE_ptcache_id_reset(PTCacheID *pid, int mode) cache= pid->cache; reset= 0; clear= 0; + after= 0; if(mode == PTCACHE_RESET_DEPSGRAPH) { if(!(cache->flag & PTCACHE_BAKED) && !BKE_ptcache_get_continue_physics()) { - reset= 1; - clear= 1; + if(cache->flag & PTCACHE_QUICK_CACHE) + clear= 1; + + after= 1; } - else - cache->flag |= PTCACHE_OUTDATED; + + cache->flag |= PTCACHE_OUTDATED; } else if(mode == PTCACHE_RESET_BAKED) { if(!BKE_ptcache_get_continue_physics()) { @@ -451,23 +1630,28 @@ int BKE_ptcache_id_reset(PTCacheID *pid, int mode) } if(reset) { - cache->flag &= ~(PTCACHE_OUTDATED|PTCACHE_SIMULATION_VALID); + cache->flag &= ~(PTCACHE_REDO_NEEDED|PTCACHE_SIMULATION_VALID); cache->simframe= 0; + cache->last_exact= 0; if(pid->type == PTCACHE_TYPE_CLOTH) - cloth_free_modifier(pid->ob, pid->data); + cloth_free_modifier(pid->ob, pid->calldata); else if(pid->type == PTCACHE_TYPE_SOFTBODY) - sbFreeSimulation(pid->data); + sbFreeSimulation(pid->calldata); else if(pid->type == PTCACHE_TYPE_PARTICLES) - psys_reset(pid->data, PSYS_RESET_DEPSGRAPH); + psys_reset(pid->calldata, PSYS_RESET_DEPSGRAPH); + else if(pid->type == PTCACHE_TYPE_SMOKE_DOMAIN_LOW) + smokeModifier_reset(pid->calldata); } if(clear) BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + else if(after) + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, CFRA); - return (reset || clear); + return (reset || clear || after); } -int BKE_ptcache_object_reset(Object *ob, int mode) +int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode) { PTCacheID pid; ParticleSystem *psys; @@ -479,7 +1663,7 @@ int BKE_ptcache_object_reset(Object *ob, int mode) if(ob->soft) { BKE_ptcache_id_from_softbody(&pid, ob, ob->soft); - reset |= BKE_ptcache_id_reset(&pid, mode); + reset |= BKE_ptcache_id_reset(scene, &pid, mode); } for(psys=ob->particlesystem.first; psys; psys=psys->next) { @@ -488,22 +1672,35 @@ int BKE_ptcache_object_reset(Object *ob, int mode) if(psys->soft) { BKE_ptcache_id_from_softbody(&pid, ob, psys->soft); if(mode == PSYS_RESET_ALL || !(psys->part->type == PART_HAIR && (pid.cache->flag & PTCACHE_BAKED))) - reset |= BKE_ptcache_id_reset(&pid, mode); + reset |= BKE_ptcache_id_reset(scene, &pid, mode); else skip = 1; } + else if(psys->recalc & PSYS_RECALC_REDO || psys->recalc & PSYS_RECALC_CHILD) + skip = 1; if(skip == 0) { BKE_ptcache_id_from_particles(&pid, ob, psys); - reset |= BKE_ptcache_id_reset(&pid, mode); + reset |= BKE_ptcache_id_reset(scene, &pid, mode); } } for(md=ob->modifiers.first; md; md=md->next) { if(md->type == eModifierType_Cloth) { BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData*)md); - reset |= BKE_ptcache_id_reset(&pid, mode); + reset |= BKE_ptcache_id_reset(scene, &pid, mode); + } + /* + // enabled on next commit + if(md->type == eModifierType_Smoke) { + SmokeModifierData *smd = (SmokeModifierData *)md; + if(smd->type & MOD_SMOKE_TYPE_DOMAIN) + { + BKE_ptcache_id_from_smoke(&pid, ob, (SmokeModifierData*)md, 0); + reset |= BKE_ptcache_id_reset(scene, &pid, mode); + } } + */ } return reset; @@ -553,7 +1750,7 @@ void BKE_ptcache_remove(void) static int CONTINUE_PHYSICS = 0; -void BKE_ptcache_set_continue_physics(int enable) +void BKE_ptcache_set_continue_physics(Scene *scene, int enable) { Object *ob; @@ -562,8 +1759,8 @@ void BKE_ptcache_set_continue_physics(int enable) if(CONTINUE_PHYSICS == 0) { for(ob=G.main->object.first; ob; ob=ob->id.next) - if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_OUTDATED)) - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); + if(BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_OUTDATED)) + DAG_object_flush_update(scene, ob, OB_RECALC_DATA); } } } @@ -573,33 +1770,572 @@ int BKE_ptcache_get_continue_physics() return CONTINUE_PHYSICS; } -/* Point Cache */ +/* Point Cache handling */ -PointCache *BKE_ptcache_add() +PointCache *BKE_ptcache_add(ListBase *ptcaches) { PointCache *cache; cache= MEM_callocN(sizeof(PointCache), "PointCache"); cache->startframe= 1; cache->endframe= 250; + cache->step= 10; + + BLI_addtail(ptcaches, cache); return cache; } +void BKE_ptache_free_mem(PointCache *cache) +{ + PTCacheMem *pm = cache->mem_cache.first; + + if(pm) { + for(; pm; pm=pm->next) { + ptcache_free_data(pm->data); + if(pm->index_array) + MEM_freeN(pm->index_array); + } + + BLI_freelistN(&cache->mem_cache); + } +} void BKE_ptcache_free(PointCache *cache) { + BKE_ptache_free_mem(cache); MEM_freeN(cache); } +void BKE_ptcache_free_list(ListBase *ptcaches) +{ + PointCache *cache = ptcaches->first; + + for(; cache; cache=cache->next) + BKE_ptache_free_mem(cache); -PointCache *BKE_ptcache_copy(PointCache *cache) + BLI_freelistN(ptcaches); +} + +static PointCache *ptcache_copy(PointCache *cache) { PointCache *ncache; ncache= MEM_dupallocN(cache); + /* hmm, should these be copied over instead? */ + ncache->mem_cache.first = NULL; + ncache->mem_cache.last = NULL; + ncache->flag= 0; ncache->simframe= 0; return ncache; } +/* returns first point cache */ +PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, ListBase *ptcaches_old) +{ + PointCache *cache = ptcaches_old->first; + + ptcaches_new->first = ptcaches_new->last = NULL; + + for(; cache; cache=cache->next) + BLI_addtail(ptcaches_new, ptcache_copy(cache)); + + return ptcaches_new->first; +} + + +/* Baking */ +static int count_quick_cache(Scene *scene, int *quick_step) +{ + Base *base = scene->base.first; + PTCacheID *pid; + ListBase pidlist; + int autocache_count= 0; + + for(base = scene->base.first; base; base = base->next) { + if(base->object) { + BKE_ptcache_ids_from_object(&pidlist, base->object); + + for(pid=pidlist.first; pid; pid=pid->next) { + if((pid->cache->flag & PTCACHE_BAKED) + || (pid->cache->flag & PTCACHE_QUICK_CACHE)==0) + continue; + + if(pid->cache->flag & PTCACHE_OUTDATED || (pid->cache->flag & PTCACHE_SIMULATION_VALID)==0) { + if(!autocache_count) + *quick_step = pid->cache->step; + else + *quick_step = MIN2(*quick_step, pid->cache->step); + + autocache_count++; + } + } + + BLI_freelistN(&pidlist); + } + } + + return autocache_count; +} +void BKE_ptcache_quick_cache_all(Scene *scene) +{ + PTCacheBaker baker; + + baker.bake=0; + baker.break_data=NULL; + baker.break_test=NULL; + baker.pid=NULL; + baker.progressbar=NULL; + baker.progresscontext=NULL; + baker.render=0; + baker.anim_init = 0; + baker.scene=scene; + + if(count_quick_cache(scene, &baker.quick_step)) + BKE_ptcache_make_cache(&baker); +} +/* if bake is not given run simulations to current frame */ +void BKE_ptcache_make_cache(PTCacheBaker* baker) +{ + Scene *scene = baker->scene; + Base *base; + ListBase pidlist; + PTCacheID *pid = baker->pid; + PointCache *cache; + float frameleno = scene->r.framelen; + int cfrao = CFRA; + int startframe = MAXFRAME; + int endframe = baker->anim_init ? scene->r.sfra : CFRA; + int bake = baker->bake; + int render = baker->render; + int step = baker->quick_step; + + G.afbreek = 0; + + /* set caches to baking mode and figure out start frame */ + if(pid) { + /* cache/bake a single object */ + cache = pid->cache; + if((cache->flag & PTCACHE_BAKED)==0) { + if(pid->type==PTCACHE_TYPE_PARTICLES) + psys_get_pointcache_start_end(scene, pid->calldata, &cache->startframe, &cache->endframe); + + if(bake || cache->flag & PTCACHE_REDO_NEEDED) + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + + startframe = MAX2(cache->last_exact, cache->startframe); + + if(bake) { + endframe = cache->endframe; + cache->flag |= PTCACHE_BAKING; + } + else { + endframe = MIN2(endframe, cache->endframe); + } + + cache->flag &= ~PTCACHE_BAKED; + } + } + else for(base=scene->base.first; base; base= base->next) { + /* cache/bake everything in the scene */ + BKE_ptcache_ids_from_object(&pidlist, base->object); + + for(pid=pidlist.first; pid; pid=pid->next) { + cache = pid->cache; + if((cache->flag & PTCACHE_BAKED)==0) { + if(pid->type==PTCACHE_TYPE_PARTICLES) { + ParticleSystem *psys = (ParticleSystem*)pid->calldata; + /* skip hair & keyed particles */ + if(psys->part->type == PART_HAIR || psys->part->phystype == PART_PHYS_KEYED) + continue; + + psys_get_pointcache_start_end(scene, pid->calldata, &cache->startframe, &cache->endframe); + } + + if((cache->flag & PTCACHE_REDO_NEEDED || (cache->flag & PTCACHE_SIMULATION_VALID)==0) + && ((cache->flag & PTCACHE_QUICK_CACHE)==0 || render || bake)) + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + + startframe = MIN2(startframe, cache->startframe); + + if(bake || render) { + cache->flag |= PTCACHE_BAKING; + + if(bake) + endframe = MAX2(endframe, cache->endframe); + } + + cache->flag &= ~PTCACHE_BAKED; + + } + } + BLI_freelistN(&pidlist); + } + + CFRA= startframe; + scene->r.framelen = 1.0; + + for(; CFRA <= endframe; CFRA+=step) { + int prog; + + if(bake) + prog = (int)(100.0f * (float)(CFRA - startframe)/(float)(endframe-startframe)); + else + prog = CFRA; + + /* NOTE: baking should not redraw whole ui as this slows things down */ + if(baker->progressbar) + baker->progressbar(baker->progresscontext, prog); + + scene_update_for_newframe(scene, scene->lay); + + /* NOTE: breaking baking should leave calculated frames in cache, not clear it */ + if(baker->break_test && baker->break_test(baker->break_data)) + break; + } + + /* clear baking flag */ + if(pid) { + cache->flag &= ~(PTCACHE_BAKING|PTCACHE_REDO_NEEDED); + cache->flag |= PTCACHE_SIMULATION_VALID; + if(bake) { + cache->flag |= PTCACHE_BAKED; + /* write info file */ + if(cache->flag & PTCACHE_DISK_CACHE) + BKE_ptcache_write_cache(pid, 0); + } + } + else for(base=scene->base.first; base; base= base->next) { + BKE_ptcache_ids_from_object(&pidlist, base->object); + + for(pid=pidlist.first; pid; pid=pid->next) { + /* skip hair particles */ + if(pid->type==PTCACHE_TYPE_PARTICLES && ((ParticleSystem*)pid->calldata)->part->type == PART_HAIR) + continue; + + cache = pid->cache; + + if(step > 1) + cache->flag &= ~(PTCACHE_BAKING|PTCACHE_OUTDATED); + else + cache->flag &= ~(PTCACHE_BAKING|PTCACHE_REDO_NEEDED); + + cache->flag |= PTCACHE_SIMULATION_VALID; + + if(bake) { + cache->flag |= PTCACHE_BAKED; + if(cache->flag & PTCACHE_DISK_CACHE) + BKE_ptcache_write_cache(pid, 0); + } + } + BLI_freelistN(&pidlist); + } + + scene->r.framelen = frameleno; + CFRA = cfrao; + + if(bake) /* already on cfra unless baking */ + scene_update_for_newframe(scene, scene->lay); + + /* TODO: call redraw all windows somehow */ +} +/* Helpers */ +void BKE_ptcache_disk_to_mem(PTCacheID *pid) +{ + PointCache *cache = pid->cache; + PTCacheFile *pf; + PTCacheMem *pm; + + int cfra, sfra = cache->startframe, efra = cache->endframe; + int i; + + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + + for(cfra=sfra; cfra <= efra; cfra++) { + pf = ptcache_file_open(pid, PTCACHE_FILE_READ, cfra); + + if(pf) { + if(!ptcache_file_read_header_begin(pf)) { + printf("Can't yet convert old cache format\n"); + cache->flag |= PTCACHE_DISK_CACHE; + ptcache_file_close(pf); + return; + } + + if(pf->type != pid->type || !pid->read_header(pf)) { + cache->flag |= PTCACHE_DISK_CACHE; + ptcache_file_close(pf); + return; + } + + pm = MEM_callocN(sizeof(PTCacheMem), "Pointcache mem"); + + pm->totpoint = pf->totpoint; + pm->data_types = pf->data_types; + pm->frame = cfra; + + ptcache_alloc_data(pm); + ptcache_mem_init_pointers(pm); + ptcache_file_init_pointers(pf); + + for(i=0; i<pm->totpoint; i++) { + if(!ptcache_file_read_data(pf)) { + printf("Error reading from disk cache\n"); + + cache->flag |= PTCACHE_DISK_CACHE; + + ptcache_free_data(pm->data); + MEM_freeN(pm); + ptcache_file_close(pf); + + return; + } + ptcache_copy_data(pf->cur, pm->cur); + ptcache_mem_incr_pointers(pm); + } + + //ptcache_make_index_array(pm, pid->totpoint(pid->calldata)); + + BLI_addtail(&pid->cache->mem_cache, pm); + + ptcache_file_close(pf); + } + } + +} +void BKE_ptcache_mem_to_disk(PTCacheID *pid) +{ + PointCache *cache = pid->cache; + PTCacheFile *pf; + PTCacheMem *pm; + int i; + + pm = cache->mem_cache.first; + + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + + for(; pm; pm=pm->next) { + pf = ptcache_file_open(pid, PTCACHE_FILE_WRITE, pm->frame); + + if(pf) { + pf->data_types = pm->data_types; + pf->totpoint = pm->totpoint; + pf->type = pid->type; + + ptcache_mem_init_pointers(pm); + ptcache_file_init_pointers(pf); + + if(!ptcache_file_write_header_begin(pf) || !pid->write_header(pf)) { + printf("Error writing to disk cache\n"); + cache->flag &= ~PTCACHE_DISK_CACHE; + + ptcache_file_close(pf); + return; + } + + for(i=0; i<pm->totpoint; i++) { + ptcache_copy_data(pm->cur, pf->cur); + if(!ptcache_file_write_data(pf)) { + printf("Error writing to disk cache\n"); + cache->flag &= ~PTCACHE_DISK_CACHE; + + ptcache_file_close(pf); + return; + } + ptcache_mem_incr_pointers(pm); + } + + ptcache_file_close(pf); + + /* write info file */ + if(cache->flag & PTCACHE_BAKED) + BKE_ptcache_write_cache(pid, 0); + } + else + printf("Error creating disk cache file\n"); + } +} +void BKE_ptcache_toggle_disk_cache(PTCacheID *pid) +{ + PointCache *cache = pid->cache; + int last_exact = cache->last_exact; + + if (!G.relbase_valid){ + cache->flag &= ~PTCACHE_DISK_CACHE; + printf("File must be saved before using disk cache!\n"); + return; + } + + if(cache->flag & PTCACHE_DISK_CACHE) + BKE_ptcache_mem_to_disk(pid); + else + BKE_ptcache_disk_to_mem(pid); + + cache->flag ^= PTCACHE_DISK_CACHE; + BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0); + cache->flag ^= PTCACHE_DISK_CACHE; + + cache->last_exact = last_exact; + + BKE_ptcache_update_info(pid); +} + +void BKE_ptcache_load_external(PTCacheID *pid) +{ + /*todo*/ + PointCache *cache = pid->cache; + int len; /* store the length of the string */ + int info = 0; + + /* mode is same as fopen's modes */ + DIR *dir; + struct dirent *de; + char path[MAX_PTCACHE_PATH]; + char filename[MAX_PTCACHE_FILE]; + char ext[MAX_PTCACHE_PATH]; + + if(!cache) + return; + + cache->startframe = MAXFRAME; + cache->endframe = -1; + cache->totpoint = 0; + + ptcache_path(pid, path); + + len = BKE_ptcache_id_filename(pid, filename, 1, 0, 0); /* no path */ + + dir = opendir(path); + if (dir==NULL) + return; + + if(cache->index >= 0) + snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, cache->index); + else + strcpy(ext, PTCACHE_EXT); + + while ((de = readdir(dir)) != NULL) { + if (strstr(de->d_name, ext)) { /* do we have the right extension?*/ + if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */ + /* read the number of the file */ + int frame, len2 = (int)strlen(de->d_name); + char num[7]; + + if (len2 > 15) { /* could crash if trying to copy a string out of this range*/ + BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num)); + frame = atoi(num); + + if(frame) { + cache->startframe = MIN2(cache->startframe, frame); + cache->endframe = MAX2(cache->endframe, frame); + } + else + info = 1; + } + } + } + } + closedir(dir); + + if(cache->startframe != MAXFRAME) { + PTCacheFile *pf; + + /* read totpoint from info file (frame 0) */ + if(info) { + pf= ptcache_file_open(pid, PTCACHE_FILE_READ, 0); + + if(pf) { + if(ptcache_file_read_header_begin(pf)) { + if(pf->type == pid->type && pid->read_header(pf)) { + cache->totpoint = pf->totpoint; + cache->flag |= PTCACHE_READ_INFO; + } + else { + cache->totpoint = 0; + } + } + ptcache_file_close(pf); + } + } + /* or from any old format cache file */ + else { + float old_data[14]; + int elemsize = ptcache_pid_old_elemsize(pid); + pf= ptcache_file_open(pid, PTCACHE_FILE_READ, cache->startframe); + + if(pf) { + while(ptcache_file_read(pf, old_data, 1, elemsize)) + cache->totpoint++; + + ptcache_file_close(pf); + } + } + } + + cache->flag &= ~(PTCACHE_OUTDATED|PTCACHE_FRAMES_SKIPPED); + + BKE_ptcache_update_info(pid); +} + +void BKE_ptcache_update_info(PTCacheID *pid) +{ + PointCache *cache = pid->cache; + int totframes = 0; + char mem_info[64]; + + if(cache->flag & PTCACHE_EXTERNAL) { + int cfra = cache->startframe; + + for(; cfra<=cache->endframe; cfra++) { + if(BKE_ptcache_id_exist(pid, cfra)) + totframes++; + } + + if(totframes && cache->totpoint) + sprintf(cache->info, "%i points found!", cache->totpoint); + else + sprintf(cache->info, "No valid data to read!"); + return; + } + + if(cache->flag & PTCACHE_DISK_CACHE) { + int cfra = cache->startframe; + + for(; cfra<=cache->endframe; cfra++) { + if(BKE_ptcache_id_exist(pid, cfra)) + totframes++; + } + + sprintf(mem_info, "%i frames on disk", totframes); + } + else { + PTCacheMem *pm = cache->mem_cache.first; + float framesize = 0.0f, bytes = 0.0f; + int mb; + + if(pm) + framesize = (float)ptcache_pid_old_elemsize(pid) * (float)pm->totpoint; + + for(; pm; pm=pm->next) + totframes++; + + bytes = totframes * framesize; + + mb = (bytes > 1024.0f * 1024.0f); + + sprintf(mem_info, "%i frames in memory (%.1f %s)", + totframes, + bytes / (mb ? 1024.0f * 1024.0f : 1024.0f), + mb ? "Mb" : "kb"); + } + + if(cache->flag & PTCACHE_OUTDATED) { + sprintf(cache->info, "%s, cache is outdated!", mem_info); + } + else if(cache->flag & PTCACHE_FRAMES_SKIPPED) { + sprintf(cache->info, "%s, not exact since frame %i.", mem_info, cache->last_exact); + } + else + sprintf(cache->info, "%s.", mem_info); +} diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c index d2eb058a9a0..5cae527957b 100644 --- a/source/blender/blenkernel/intern/property.c +++ b/source/blender/blenkernel/intern/property.c @@ -33,6 +33,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <ctype.h> #ifdef HAVE_CONFIG_H #include <config.h> @@ -44,9 +45,7 @@ #include "DNA_object_types.h" #include "DNA_listBase.h" - #include "BLI_blenlib.h" -#include "BKE_bad_level_calls.h" #include "BKE_property.h" void free_property(bProperty *prop) @@ -101,25 +100,18 @@ void init_property(bProperty *prop) if(prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin); prop->poin= 0; - prop->otype= prop->type; prop->data= 0; switch(prop->type) { - case PROP_BOOL: - prop->poin= &prop->data; - break; - case PROP_INT: + case GPROP_BOOL: + case GPROP_INT: + case GPROP_FLOAT: + case GPROP_TIME: prop->poin= &prop->data; break; - case PROP_FLOAT: - prop->poin= &prop->data; - break; - case PROP_STRING: + case GPROP_STRING: prop->poin= MEM_callocN(MAX_PROPSTRING, "property string"); break; - case PROP_TIME: - prop->poin= &prop->data; - break; } } @@ -138,6 +130,60 @@ bProperty *new_property(int type) return prop; } +/* used by unique_property() only */ +static bProperty *get_property__internal(bProperty *first, bProperty *self, const char *name) +{ + bProperty *p; + for(p= first; p; p= p->next) { + if (p!=self && (strcmp(p->name, name)==0)) + return p; + } + return NULL; +} +void unique_property(bProperty *first, bProperty *prop, int force) +{ + bProperty *p; + + /* set the first if its not set */ + if(first==NULL) { + first= prop; + while(first->prev) { + first= first->prev; + } + } + + if(force) { + /* change other names to make them unique */ + while((p = get_property__internal(first, prop, prop->name))) { + unique_property(first, p, 0); + } + }else { + /* change our own name until its unique */ + if(get_property__internal(first, prop, prop->name)) { + /* there is a collision */ + char new_name[sizeof(prop->name)]; + char base_name[sizeof(prop->name)]; + char num[sizeof(prop->name)]; + int i= 0; + + /* strip numbers */ + strcpy(base_name, prop->name); + for(i= strlen(base_name)-1; (i>=0 && isdigit(base_name[i])); i--) { + base_name[i]= '\0'; + } + i= 0; + + do { /* ensure we have enough chars for the new number in the name */ + sprintf(num, "%d", i++); + BLI_strncpy(new_name, base_name, sizeof(prop->name) - strlen(num)); + strcat(new_name, num); + } while(get_property__internal(first, prop, new_name)); + + strcpy(prop->name, new_name); + } + } +} + bProperty *get_ob_property(Object *ob, char *name) { bProperty *prop; @@ -170,7 +216,7 @@ int compare_property(bProperty *prop, char *str) float fvalue, ftest; switch(prop->type) { - case PROP_BOOL: + case GPROP_BOOL: if(BLI_strcasecmp(str, "true")==0) { if(prop->data==1) return 0; else return 1; @@ -179,14 +225,14 @@ int compare_property(bProperty *prop, char *str) if(prop->data==0) return 0; else return 1; } - /* no break, do prop_int too! */ + /* no break, do GPROP_int too! */ - case PROP_INT: + case GPROP_INT: return prop->data - atoi(str); - case PROP_FLOAT: - case PROP_TIME: - // WARNING: untested for PROP_TIME + case GPROP_FLOAT: + case GPROP_TIME: + // WARNING: untested for GPROP_TIME // function isn't used currently fvalue= *((float *)&prop->data); ftest= (float)atof(str); @@ -194,7 +240,7 @@ int compare_property(bProperty *prop, char *str) else if( fvalue < ftest) return -1; return 0; - case PROP_STRING: + case GPROP_STRING: return strcmp(prop->poin, str); } @@ -206,19 +252,19 @@ void set_property(bProperty *prop, char *str) // extern int Gdfra; /* sector.c */ switch(prop->type) { - case PROP_BOOL: + case GPROP_BOOL: if(BLI_strcasecmp(str, "true")==0) prop->data= 1; else if(BLI_strcasecmp(str, "false")==0) prop->data= 0; else prop->data= (atoi(str)!=0); break; - case PROP_INT: + case GPROP_INT: prop->data= atoi(str); break; - case PROP_FLOAT: - case PROP_TIME: + case GPROP_FLOAT: + case GPROP_TIME: *((float *)&prop->data)= (float)atof(str); break; - case PROP_STRING: + case GPROP_STRING: strcpy(prop->poin, str); break; } @@ -230,15 +276,15 @@ void add_property(bProperty *prop, char *str) // extern int Gdfra; /* sector.c */ switch(prop->type) { - case PROP_BOOL: - case PROP_INT: + case GPROP_BOOL: + case GPROP_INT: prop->data+= atoi(str); break; - case PROP_FLOAT: - case PROP_TIME: + case GPROP_FLOAT: + case GPROP_TIME: *((float *)&prop->data)+= (float)atof(str); break; - case PROP_STRING: + case GPROP_STRING: /* strcpy(prop->poin, str); */ break; } @@ -252,15 +298,15 @@ void set_property_valstr(bProperty *prop, char *str) if(str == NULL) return; switch(prop->type) { - case PROP_BOOL: - case PROP_INT: + case GPROP_BOOL: + case GPROP_INT: sprintf(str, "%d", prop->data); break; - case PROP_FLOAT: - case PROP_TIME: + case GPROP_FLOAT: + case GPROP_TIME: sprintf(str, "%f", *((float *)&prop->data)); break; - case PROP_STRING: + case GPROP_STRING: BLI_strncpy(str, prop->poin, MAX_PROPSTRING); break; } diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c new file mode 100644 index 00000000000..391adfb762a --- /dev/null +++ b/source/blender/blenkernel/intern/report.c @@ -0,0 +1,261 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation (2008). + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" + +#include "BLI_blenlib.h" +#include "BLI_dynstr.h" + +#include "BKE_report.h" + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#ifdef _WIN32 +#ifndef vsnprintf +#define vsnprintf _vsnprintf +#endif +#endif + +static char *report_type_str(int type) +{ + switch(type) { + case RPT_DEBUG: return "Debug"; + case RPT_INFO: return "Info"; + case RPT_OPERATOR: return "Operator"; + case RPT_WARNING: return "Warning"; + case RPT_ERROR: return "Error"; + case RPT_ERROR_INVALID_INPUT: return "Invalid Input Error"; + case RPT_ERROR_INVALID_CONTEXT: return "Invalid Context Error"; + case RPT_ERROR_OUT_OF_MEMORY: return "Out Of Memory Error"; + default: return "Undefined Type"; + } +} + +void BKE_reports_init(ReportList *reports, int flag) +{ + if(!reports) + return; + + memset(reports, 0, sizeof(ReportList)); + + reports->storelevel= RPT_INFO; + reports->printlevel= RPT_INFO; + reports->flag= flag; +} + +void BKE_reports_clear(ReportList *reports) +{ + Report *report, *report_next; + + if(!reports) + return; + + report= reports->list.first; + + while (report) { + report_next= report->next; + MEM_freeN(report->message); + MEM_freeN(report); + report= report_next; + } + + reports->list.first= reports->list.last= NULL; +} + +void BKE_report(ReportList *reports, ReportType type, const char *message) +{ + Report *report; + int len; + + if(!reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) { + printf("%s: %s\n", report_type_str(type), message); + fflush(stdout); /* this ensures the message is printed before a crash */ + } + + if(reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) { + report= MEM_callocN(sizeof(Report), "Report"); + report->type= type; + report->typestr= report_type_str(type); + + len= strlen(message); + report->message= MEM_callocN(sizeof(char)*(len+1), "ReportMessage"); + memcpy(report->message, message, sizeof(char)*(len+1)); + report->len= len; + BLI_addtail(&reports->list, report); + } +} + +void BKE_reportf(ReportList *reports, ReportType type, const char *format, ...) +{ + DynStr *ds; + Report *report; + va_list args; + + if(!reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) { + va_start(args, format); + vprintf(format, args); + va_end(args); + fflush(stdout); /* this ensures the message is printed before a crash */ + } + + if(reports && (reports->flag & RPT_STORE) && (type >= reports->storelevel)) { + report= MEM_callocN(sizeof(Report), "Report"); + + ds= BLI_dynstr_new(); + va_start(args, format); + BLI_dynstr_vappendf(ds, format, args); + va_end(args); + + report->message= BLI_dynstr_get_cstring(ds); + report->len= BLI_dynstr_get_len(ds); + BLI_dynstr_free(ds); + + report->type= type; + report->typestr= report_type_str(type); + + BLI_addtail(&reports->list, report); + } +} + +void BKE_reports_prepend(ReportList *reports, const char *prepend) +{ + Report *report; + DynStr *ds; + + if(!reports) + return; + + for(report=reports->list.first; report; report=report->next) { + ds= BLI_dynstr_new(); + + BLI_dynstr_append(ds, prepend); + BLI_dynstr_append(ds, report->message); + MEM_freeN(report->message); + + report->message= BLI_dynstr_get_cstring(ds); + report->len= BLI_dynstr_get_len(ds); + + BLI_dynstr_free(ds); + } +} + +void BKE_reports_prependf(ReportList *reports, const char *prepend, ...) +{ + Report *report; + DynStr *ds; + va_list args; + + if(!reports) + return; + + for(report=reports->list.first; report; report=report->next) { + ds= BLI_dynstr_new(); + va_start(args, prepend); + BLI_dynstr_vappendf(ds, prepend, args); + va_end(args); + + BLI_dynstr_append(ds, report->message); + MEM_freeN(report->message); + + report->message= BLI_dynstr_get_cstring(ds); + report->len= BLI_dynstr_get_len(ds); + + BLI_dynstr_free(ds); + } +} + +ReportType BKE_report_print_level(ReportList *reports) +{ + if(!reports) + return RPT_ERROR; + + return reports->printlevel; +} + +void BKE_report_print_level_set(ReportList *reports, ReportType level) +{ + if(!reports) + return; + + reports->printlevel= level; +} + +ReportType BKE_report_store_level(ReportList *reports) +{ + if(!reports) + return RPT_ERROR; + + return reports->storelevel; +} + +void BKE_report_store_level_set(ReportList *reports, ReportType level) +{ + if(!reports) + return; + + reports->storelevel= level; +} + +char *BKE_reports_string(ReportList *reports, ReportType level) +{ + Report *report; + DynStr *ds; + char *cstring; + + if(!reports) + return NULL; + + ds= BLI_dynstr_new(); + for(report=reports->list.first; report; report=report->next) + if(report->type >= level) + BLI_dynstr_appendf(ds, "%s: %s\n", report->typestr, report->message); + + if (BLI_dynstr_get_len(ds)) + cstring= BLI_dynstr_get_cstring(ds); + else + cstring= NULL; + + BLI_dynstr_free(ds); + return cstring; +} + +void BKE_reports_print(ReportList *reports, ReportType level) +{ + char *cstring = BKE_reports_string(reports, level); + + if (cstring == NULL) + return; + + printf("%s", cstring); + fflush(stdout); + MEM_freeN(cstring); +} + diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index ea7b566c3b5..139895bbdaf 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -35,9 +35,10 @@ #include <stdio.h> #include <string.h> +#include <float.h> + #include "MEM_guardedalloc.h" -#include "nla.h" /* For __NLA: Important, do not remove */ #include "DNA_text_types.h" #include "DNA_controller_types.h" #include "DNA_sensor_types.h" @@ -45,13 +46,14 @@ #include "DNA_object_types.h" #include "BLI_blenlib.h" -#include "BKE_bad_level_calls.h" #include "BKE_utildefines.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_blender.h" #include "BKE_sca.h" +//#include "wm_event_types.h" + void free_text_controllers(Text *txt) { Object *ob; @@ -158,7 +160,7 @@ void init_sensor(bSensor *sens) break; case SENS_MOUSE: ms=sens->data= MEM_callocN(sizeof(bMouseSensor), "mousesens"); - ms->type= LEFTMOUSE; + //XXX ms->type= LEFTMOUSE; break; case SENS_COLLISION: sens->data= MEM_callocN(sizeof(bCollisionSensor), "colsens"); @@ -195,7 +197,7 @@ bSensor *new_sensor(int type) init_sensor(sens); strcpy(sens->name, "sensor"); - make_unique_prop_names(sens->name); +// XXX make_unique_prop_names(sens->name); return sens; } @@ -319,7 +321,7 @@ bController *new_controller(int type) init_controller(cont); strcpy(cont->name, "cont"); - make_unique_prop_names(cont->name); +// XXX make_unique_prop_names(cont->name); return cont; } @@ -410,6 +412,7 @@ void init_actuator(bActuator *act) { /* also use when actuator changes type */ bObjectActuator *oa; + bSoundActuator *sa; if(act->data) MEM_freeN(act->data); act->data= 0; @@ -422,10 +425,14 @@ void init_actuator(bActuator *act) break; #endif case ACT_SOUND: - act->data= MEM_callocN(sizeof(bSoundActuator), "soundact"); - break; - case ACT_CD: - act->data= MEM_callocN(sizeof(bCDActuator), "cdact"); + sa = act->data= MEM_callocN(sizeof(bSoundActuator), "soundact"); + sa->volume = 1.0f; + sa->sound3D.rolloff_factor = 1.0f; + sa->sound3D.reference_distance = 1.0f; + sa->sound3D.max_gain = 1.0f; + sa->sound3D.cone_inner_angle = 360.0f; + sa->sound3D.cone_outer_angle = 360.0f; + sa->sound3D.max_distance = FLT_MAX; break; case ACT_OBJECT: act->data= MEM_callocN(sizeof(bObjectActuator), "objectact"); @@ -491,7 +498,7 @@ bActuator *new_actuator(int type) init_actuator(act); strcpy(act->name, "act"); - make_unique_prop_names(act->name); +// XXX make_unique_prop_names(act->name); return act; } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 2c71f07a97a..0e987850acd 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -43,6 +43,7 @@ #endif #include "MEM_guardedalloc.h" +#include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_color_types.h" #include "DNA_constraint_types.h" @@ -53,14 +54,14 @@ #include "DNA_meta_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "DNA_scriptlink_types.h" #include "DNA_texture_types.h" #include "DNA_userdef_types.h" #include "BKE_action.h" #include "BKE_anim.h" +#include "BKE_animsys.h" #include "BKE_armature.h" -#include "BKE_bad_level_calls.h" +#include "BKE_colortools.h" #include "BKE_colortools.h" #include "BKE_constraint.h" #include "BKE_depsgraph.h" @@ -76,11 +77,12 @@ #include "BKE_object.h" #include "BKE_scene.h" #include "BKE_sculpt.h" +#include "BKE_sequence.h" #include "BKE_world.h" #include "BKE_utildefines.h" -#include "BIF_previewrender.h" -#include "BIF_editseq.h" +//XXX #include "BIF_previewrender.h" +//XXX #include "BIF_editseq.h" #ifndef DISABLE_PYTHON #include "BPY_extern.h" @@ -89,7 +91,7 @@ #include "BLI_arithb.h" #include "BLI_blenlib.h" -#include "nla.h" +//XXX #include "nla.h" #ifdef WIN32 #else @@ -138,13 +140,10 @@ void free_scene(Scene *sce) /* do not free objects! */ BLI_freelistN(&sce->base); - free_editing(sce->ed); - if(sce->radio) MEM_freeN(sce->radio); - sce->radio= 0; - -#ifndef DISABLE_PYTHON - BPY_free_scriptlink(&sce->scriptlink); -#endif + seq_free_editing(sce); + + BKE_free_animdata((ID *)sce); + BKE_keyingsets_free(&sce->keyingsets); if (sce->r.avicodecdata) { free_avicodecdata(sce->r.avicodecdata); @@ -166,7 +165,16 @@ void free_scene(Scene *sce) BLI_freelistN(&sce->transform_spaces); BLI_freelistN(&sce->r.layers); - if(sce->toolsettings){ + if(sce->toolsettings) { + if(sce->toolsettings->vpaint) + MEM_freeN(sce->toolsettings->vpaint); + if(sce->toolsettings->wpaint) + MEM_freeN(sce->toolsettings->wpaint); + if(sce->toolsettings->sculpt) { + sculptsession_free(sce->toolsettings->sculpt); + MEM_freeN(sce->toolsettings->sculpt); + } + MEM_freeN(sce->toolsettings); sce->toolsettings = NULL; } @@ -180,8 +188,6 @@ void free_scene(Scene *sce) ntreeFreeTree(sce->nodetree); MEM_freeN(sce->nodetree); } - - sculptdata_free(sce); } Scene *add_scene(char *name) @@ -192,21 +198,18 @@ Scene *add_scene(char *name) sce= alloc_libblock(&G.main->scene, ID_SCE, name); sce->lay= 1; - sce->selectmode= SCE_SELECT_VERTEX; - sce->editbutsize= 0.1; - sce->autokey_mode= U.autokey_mode; - sce->r.mode= R_GAMMA; + sce->r.mode= R_GAMMA|R_OSA|R_SHADOW|R_SSS|R_ENVMAP|R_RAYTRACE; sce->r.cfra= 1; sce->r.sfra= 1; sce->r.efra= 250; - sce->r.xsch= 320; - sce->r.ysch= 256; + sce->r.xsch= 1920; + sce->r.ysch= 1080; sce->r.xasp= 1; sce->r.yasp= 1; - sce->r.xparts= 4; - sce->r.yparts= 4; - sce->r.size= 100; + sce->r.xparts= 8; + sce->r.yparts= 8; + sce->r.size= 25; sce->r.planes= 24; sce->r.quality= 90; sce->r.framapto= 100; @@ -215,26 +218,18 @@ Scene *add_scene(char *name) sce->r.frs_sec= 25; sce->r.frs_sec_base= 1; sce->r.ocres = 128; + sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT; sce->r.bake_mode= 1; /* prevent to include render stuff here */ - sce->r.bake_filter= 2; + sce->r.bake_filter= 8; sce->r.bake_osa= 5; sce->r.bake_flag= R_BAKE_CLEAR; sce->r.bake_normal_space= R_BAKE_SPACE_TANGENT; - - sce->r.xplay= 640; - sce->r.yplay= 480; - sce->r.freqplay= 60; - sce->r.depth= 32; + + sce->r.scemode= R_DOCOMP|R_DOSEQ|R_EXTENSION; + sce->r.stamp= R_STAMP_TIME|R_STAMP_FRAME|R_STAMP_DATE|R_STAMP_SCENE|R_STAMP_CAMERA; sce->r.threads= 1; - - sce->r.stereomode = 1; // no stereo - sce->r.domeangle = 180; - sce->r.domemode = 1; - sce->r.domeres = 4; - sce->r.domeresbuf = 1.0f; - sce->r.dometilt = 0; sce->r.simplify_subsurf= 6; sce->r.simplify_particles= 1.0f; @@ -264,6 +259,10 @@ Scene *add_scene(char *name) sce->toolsettings->select_thresh= 0.01f; sce->toolsettings->jointrilimit = 0.8f; + sce->toolsettings->selectmode= SCE_SELECT_VERTEX; + sce->toolsettings->normalsize= 0.1; + sce->toolsettings->autokey_mode= U.autokey_mode; + sce->toolsettings->skgen_resolution = 100; sce->toolsettings->skgen_threshold_internal = 0.01f; sce->toolsettings->skgen_threshold_external = 0.01f; @@ -279,6 +278,11 @@ Scene *add_scene(char *name) sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH; sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE; + sce->toolsettings->proportional_size = 1.0f; + + + sce->unit.scale_length = 1.0f; + pset= &sce->toolsettings->particle; pset->flag= PE_KEEP_LENGTHS|PE_LOCK_FIRST|PE_DEFLECT_EMITTER; pset->emitterdist= 0.25f; @@ -301,11 +305,32 @@ Scene *add_scene(char *name) BLI_init_rctf(&sce->r.safety, 0.1f, 0.9f, 0.1f, 0.9f); sce->r.osa= 8; - sculptdata_init(sce); - /* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */ scene_add_render_layer(sce); + /* game data */ + sce->gm.stereoflag = STEREO_NOSTEREO; + sce->gm.stereomode = STEREO_ANAGLYPH; + sce->gm.dome.angle = 180; + sce->gm.dome.mode = DOME_FISHEYE; + sce->gm.dome.res = 4; + sce->gm.dome.resbuf = 1.0f; + sce->gm.dome.tilt = 0; + + sce->gm.xplay= 800; + sce->gm.yplay= 600; + sce->gm.freqplay= 60; + sce->gm.depth= 32; + + sce->gm.gravity= 9.8f; + sce->gm.physicsEngine= WOPHY_BULLET; + sce->gm.mode = 32; //XXX ugly harcoding, still not sure we should drop mode. 32 == 1 << 5 == use_occlusion_culling + sce->gm.occlusionRes = 128; + sce->gm.ticrate = 60; + sce->gm.maxlogicstep = 5; + sce->gm.physubstep = 1; + sce->gm.maxphystep = 5; + return sce; } @@ -321,21 +346,17 @@ Base *object_in_scene(Object *ob, Scene *sce) return NULL; } -void set_scene_bg(Scene *sce) +void set_scene_bg(Scene *scene) { + Scene *sce; Base *base; Object *ob; Group *group; GroupObject *go; int flag; - // Note: this here is defined in editseq.c (BIF_editseq.h), NOT in blenkernel! - clear_last_seq(); - - G.scene= sce; - /* check for cyclic sets, for reading old files but also for definite security (py?) */ - scene_check_setscene(G.scene); + scene_check_setscene(scene); /* deselect objects (for dataselect) */ for(ob= G.main->object.first; ob; ob= ob->id.next) @@ -351,15 +372,15 @@ void set_scene_bg(Scene *sce) } /* sort baselist */ - DAG_scene_sort(sce); + DAG_scene_sort(scene); /* ensure dags are built for sets */ - for(sce= sce->set; sce; sce= sce->set) + for(sce= scene->set; sce; sce= sce->set) if(sce->theDag==NULL) DAG_scene_sort(sce); /* copy layers and flags from bases to objects */ - for(base= G.scene->base.first; base; base= base->next) { + for(base= scene->base.first; base; base= base->next) { ob= base->object; ob->lay= base->lay; @@ -375,9 +396,6 @@ void set_scene_bg(Scene *sce) ob->ctime= -1234567.0; /* force ipo to be calculated later */ } /* no full animation update, this to enable render code to work (render code calls own animation updates) */ - - /* do we need FRAMECHANGED in set_scene? */ -// if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED, 0); } /* called from creator.c */ @@ -392,13 +410,13 @@ void set_scene_name(char *name) } } - error("Can't find scene: %s", name); + //XXX error("Can't find scene: %s", name); } /* used by metaballs * doesnt return the original duplicated object, only dupli's */ -int next_object(int val, Base **base, Object **ob) +int next_object(Scene *scene, int val, Base **base, Object **ob) { static ListBase *duplilist= NULL; static DupliObject *dupob; @@ -427,15 +445,15 @@ int next_object(int val, Base **base, Object **ob) /* the first base */ if(fase==F_START) { - *base= G.scene->base.first; + *base= scene->base.first; if(*base) { *ob= (*base)->object; fase= F_SCENE; } else { /* exception: empty scene */ - if(G.scene->set && G.scene->set->base.first) { - *base= G.scene->set->base.first; + if(scene->set && scene->set->base.first) { + *base= scene->set->base.first; *ob= (*base)->object; fase= F_SET; } @@ -448,8 +466,8 @@ int next_object(int val, Base **base, Object **ob) else { if(fase==F_SCENE) { /* scene is finished, now do the set */ - if(G.scene->set && G.scene->set->base.first) { - *base= G.scene->set->base.first; + if(scene->set && scene->set->base.first) { + *base= scene->set->base.first; *ob= (*base)->object; fase= F_SET; } @@ -466,7 +484,7 @@ int next_object(int val, Base **base, Object **ob) this enters eternal loop because of makeDispListMBall getting called inside of group_duplilist */ if((*base)->object->dup_group == NULL) { - duplilist= object_duplilist(G.scene, (*base)->object); + duplilist= object_duplilist(scene, (*base)->object); dupob= duplilist->first; @@ -576,41 +594,66 @@ int scene_check_setscene(Scene *sce) return 1; } +/* This (evil) function is needed to cope with two legacy Blender rendering features +* mblur (motion blur that renders 'subframes' and blurs them together), and fields +* rendering. Thus, the use of ugly globals from object.c +*/ +// BAD... EVIL... JUJU...!!!! +// XXX moved here temporarily +float frame_to_float (Scene *scene, int cfra) /* see also bsystem_time in object.c */ +{ + extern float bluroffs; /* bad stuff borrowed from object.c */ + extern float fieldoffs; + float ctime; + + ctime= (float)cfra; + ctime+= bluroffs+fieldoffs; + ctime*= scene->r.framelen; + + return ctime; +} + static void scene_update(Scene *sce, unsigned int lay) { Base *base; Object *ob; + float ctime = frame_to_float(sce, sce->r.cfra); if(sce->theDag==NULL) DAG_scene_sort(sce); DAG_scene_update_flags(sce, lay); // only stuff that moves or needs display still + /* All 'standard' (i.e. without any dependencies) animation is handled here, + * with an 'local' to 'macro' order of evaluation. This should ensure that + * settings stored nestled within a hierarchy (i.e. settings in a Texture block + * can be overridden by settings from Scene, which owns the Texture through a hierarchy + * such as Scene->World->MTex/Texture) can still get correctly overridden. + */ + BKE_animsys_evaluate_all_animation(G.main, ctime); + for(base= sce->base.first; base; base= base->next) { ob= base->object; - object_handle_update(ob); // bke_object.h + object_handle_update(sce, ob); // bke_object.h /* only update layer when an ipo */ - if(ob->ipo && has_ipo_code(ob->ipo, OB_LAY) ) { - base->lay= ob->lay; - } + // XXX old animation system + //if(ob->ipo && has_ipo_code(ob->ipo, OB_LAY) ) { + // base->lay= ob->lay; + //} } } + /* applies changes right away, does all sets too */ void scene_update_for_newframe(Scene *sce, unsigned int lay) { Scene *scene= sce; - /* clears all BONE_UNKEYED flags for every pose's pchans */ - framechange_poses_clear_unkeyed(); + /* clear animation overrides */ + // XXX TODO... - /* object ipos are calculated in where_is_object */ - do_all_data_ipos(); -#ifndef DISABLE_PYTHON - if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED, 0); -#endif /* sets first, we allow per definition current scene to have dependencies on sets */ for(sce= sce->set; sce; sce= sce->set) scene_update(sce, lay); @@ -634,130 +677,33 @@ void scene_add_render_layer(Scene *sce) srl->passflag= SCE_PASS_COMBINED|SCE_PASS_Z; } -/* Initialize 'permanent' sculpt data that is saved with file kept after - switching out of sculptmode. */ -void sculptdata_init(Scene *sce) -{ - SculptData *sd; - - if(!sce) - return; - - sd= &sce->sculptdata; - - if(sd->cumap) { - curvemapping_free(sd->cumap); - sd->cumap = NULL; - } - - memset(sd, 0, sizeof(SculptData)); - - sd->drawbrush.size = sd->smoothbrush.size = sd->pinchbrush.size = - sd->inflatebrush.size = sd->grabbrush.size = - sd->layerbrush.size = sd->flattenbrush.size = 50; - sd->drawbrush.strength = sd->smoothbrush.strength = - sd->pinchbrush.strength = sd->inflatebrush.strength = - sd->grabbrush.strength = sd->layerbrush.strength = - sd->flattenbrush.strength = 25; - sd->drawbrush.dir = sd->pinchbrush.dir = sd->inflatebrush.dir = sd->layerbrush.dir= 1; - sd->drawbrush.flag = sd->smoothbrush.flag = - sd->pinchbrush.flag = sd->inflatebrush.flag = - sd->layerbrush.flag = sd->flattenbrush.flag = 0; - sd->drawbrush.view= 0; - sd->brush_type= DRAW_BRUSH; - sd->texact= -1; - sd->texfade= 1; - sd->averaging= 1; - sd->texsep= 0; - sd->texrept= SCULPTREPT_DRAG; - sd->flags= SCULPT_DRAW_BRUSH; - sd->tablet_size=3; - sd->tablet_strength=10; - sd->rake=0; - sculpt_reset_curve(sd); -} - -void sculptdata_free(Scene *sce) -{ - SculptData *sd= &sce->sculptdata; - int a; - - sculptsession_free(sce); - - for(a=0; a<MAX_MTEX; a++) { - MTex *mtex= sd->mtex[a]; - if(mtex) { - if(mtex->tex) mtex->tex->id.us--; - MEM_freeN(mtex); - } - } - - curvemapping_free(sd->cumap); - sd->cumap = NULL; -} - -void sculpt_vertexusers_free(SculptSession *ss) -{ - if(ss && ss->vertex_users){ - MEM_freeN(ss->vertex_users); - MEM_freeN(ss->vertex_users_mem); - ss->vertex_users= NULL; - ss->vertex_users_mem= NULL; - ss->vertex_users_size= 0; - } -} - -void sculptsession_free(Scene *sce) +void sculptsession_free(Sculpt *sculpt) { - SculptSession *ss= sce->sculptdata.session; + SculptSession *ss= sculpt->session; if(ss) { if(ss->projverts) MEM_freeN(ss->projverts); - if(ss->mats) - MEM_freeN(ss->mats); - if(ss->radialcontrol) - MEM_freeN(ss->radialcontrol); + if(ss->fmap) + MEM_freeN(ss->fmap); + + if(ss->fmap_mem) + MEM_freeN(ss->fmap_mem); - sculpt_vertexusers_free(ss); if(ss->texcache) MEM_freeN(ss->texcache); + + if(ss->layer_disps) + MEM_freeN(ss->layer_disps); + + if(ss->mesh_co_orig) + MEM_freeN(ss->mesh_co_orig); + MEM_freeN(ss); - sce->sculptdata.session= NULL; + sculpt->session= NULL; } } -/* Default curve approximates 0.5 * (cos(pi * x) + 1), with 0 <= x <= 1 */ -void sculpt_reset_curve(SculptData *sd) -{ - CurveMap *cm = NULL; - - if(!sd->cumap) - sd->cumap = curvemapping_add(1, 0, 0, 1, 1); - - cm = sd->cumap->cm; - - if(cm->curve) - MEM_freeN(cm->curve); - cm->curve= MEM_callocN(6*sizeof(CurveMapPoint), "curve points"); - cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE; - cm->totpoint= 6; - cm->curve[0].x= 0; - cm->curve[0].y= 1; - cm->curve[1].x= 0.1; - cm->curve[1].y= 0.97553; - cm->curve[2].x= 0.3; - cm->curve[2].y= 0.79389; - cm->curve[3].x= 0.9; - cm->curve[3].y= 0.02447; - cm->curve[4].x= 0.7; - cm->curve[4].y= 0.20611; - cm->curve[5].x= 1; - cm->curve[5].y= 0; - - curvemapping_changed(sd->cumap, 0); -} - /* render simplification */ int get_render_subsurf_level(RenderData *r, int lvl) diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 7a45493e1f4..cc740d7fb3d 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -1,6 +1,4 @@ - -/* screen.c - * +/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -33,22 +31,294 @@ #include <stdio.h> #include <math.h> +#include "MEM_guardedalloc.h" + #include "DNA_screen_types.h" -#include "BKE_bad_level_calls.h" +#include "DNA_space_types.h" + #include "BLI_blenlib.h" #include "BKE_screen.h" -#ifdef HAVE_CONFIG_H -#include <config.h> +#ifndef DISABLE_PYTHON +#include "BPY_extern.h" #endif +/* ************ Spacetype/regiontype handling ************** */ + +/* keep global; this has to be accessible outside of windowmanager */ +static ListBase spacetypes= {NULL, NULL}; + +/* not SpaceType itself */ +static void spacetype_free(SpaceType *st) +{ + ARegionType *art; + PanelType *pt; + HeaderType *ht; + MenuType *mt; + + for(art= st->regiontypes.first; art; art= art->next) { + BLI_freelistN(&art->drawcalls); + + for(pt= art->paneltypes.first; pt; pt= pt->next) + if(pt->ext.free) + pt->ext.free(pt->ext.data); + + for(ht= art->headertypes.first; ht; ht= ht->next) + if(ht->ext.free) + ht->ext.free(ht->ext.data); + + for(mt= art->menutypes.first; mt; mt= mt->next) + if(mt->ext.free) + mt->ext.free(mt->ext.data); + + BLI_freelistN(&art->paneltypes); + BLI_freelistN(&art->headertypes); + BLI_freelistN(&art->menutypes); + } + + BLI_freelistN(&st->regiontypes); + BLI_freelistN(&st->toolshelf); + +} + +void BKE_spacetypes_free(void) +{ + SpaceType *st; + + for(st= spacetypes.first; st; st= st->next) { + spacetype_free(st); + } + + BLI_freelistN(&spacetypes); +} + +SpaceType *BKE_spacetype_from_id(int spaceid) +{ + SpaceType *st; + + for(st= spacetypes.first; st; st= st->next) { + if(st->spaceid==spaceid) + return st; + } + return NULL; +} + +ARegionType *BKE_regiontype_from_id(SpaceType *st, int regionid) +{ + ARegionType *art; + + for(art= st->regiontypes.first; art; art= art->next) + if(art->regionid==regionid) + return art; + + printf("Error, region type missing in - name:\"%s\", id:%d\n", st->name, st->spaceid); + return st->regiontypes.first; +} + + +const ListBase *BKE_spacetypes_list() +{ + return &spacetypes; +} + +void BKE_spacetype_register(SpaceType *st) +{ + SpaceType *stype; + + /* sanity check */ + stype= BKE_spacetype_from_id(st->spaceid); + if(stype) { + printf("error: redefinition of spacetype %s\n", stype->name); + spacetype_free(stype); + MEM_freeN(stype); + } + + BLI_addtail(&spacetypes, st); +} + +/* ***************** Space handling ********************** */ + +void BKE_spacedata_freelist(ListBase *lb) +{ + SpaceLink *sl; + ARegion *ar; + + for (sl= lb->first; sl; sl= sl->next) { + SpaceType *st= BKE_spacetype_from_id(sl->spacetype); + + /* free regions for pushed spaces */ + for(ar=sl->regionbase.first; ar; ar=ar->next) + BKE_area_region_free(st, ar); + + BLI_freelistN(&sl->regionbase); + + if(st && st->free) + st->free(sl); + } + + BLI_freelistN(lb); +} + +ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar) +{ + ARegion *newar= MEM_dupallocN(ar); + Panel *pa, *newpa, *patab; + + newar->prev= newar->next= NULL; + newar->handlers.first= newar->handlers.last= NULL; + newar->uiblocks.first= newar->uiblocks.last= NULL; + newar->swinid= 0; + + /* use optional regiondata callback */ + if(ar->regiondata) { + ARegionType *art= BKE_regiontype_from_id(st, ar->regiontype); + + if(art && art->duplicate) + newar->regiondata= art->duplicate(ar->regiondata); + else + newar->regiondata= MEM_dupallocN(ar->regiondata); + } + + if(ar->v2d.tab_offset) + newar->v2d.tab_offset= MEM_dupallocN(ar->v2d.tab_offset); + + newar->panels.first= newar->panels.last= NULL; + BLI_duplicatelist(&newar->panels, &ar->panels); + + /* copy panel pointers */ + for(newpa= newar->panels.first; newpa; newpa= newpa->next) { + patab= newar->panels.first; + pa= ar->panels.first; + while(patab) { + if(newpa->paneltab == pa) { + newpa->paneltab = patab; + break; + } + patab= patab->next; + pa= pa->next; + } + } + + return newar; +} + + +/* from lb2 to lb1, lb1 is supposed to be free'd */ +static void region_copylist(SpaceType *st, ListBase *lb1, ListBase *lb2) +{ + ARegion *ar; + + /* to be sure */ + lb1->first= lb1->last= NULL; + + for(ar= lb2->first; ar; ar= ar->next) { + ARegion *arnew= BKE_area_region_copy(st, ar); + BLI_addtail(lb1, arnew); + } +} + + +/* lb1 should be empty */ +void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2) +{ + SpaceLink *sl; + + lb1->first= lb1->last= NULL; /* to be sure */ + + for (sl= lb2->first; sl; sl= sl->next) { + SpaceType *st= BKE_spacetype_from_id(sl->spacetype); + + if(st && st->duplicate) { + SpaceLink *slnew= st->duplicate(sl); + + BLI_addtail(lb1, slnew); + + region_copylist(st, &slnew->regionbase, &sl->regionbase); + } + } +} + +/* lb1 should be empty */ +void BKE_spacedata_copyfirst(ListBase *lb1, ListBase *lb2) +{ + SpaceLink *sl; + + lb1->first= lb1->last= NULL; /* to be sure */ + + sl= lb2->first; + if(sl) { + SpaceType *st= BKE_spacetype_from_id(sl->spacetype); + + if(st && st->duplicate) { + SpaceLink *slnew= st->duplicate(sl); + + BLI_addtail(lb1, slnew); + + region_copylist(st, &slnew->regionbase, &sl->regionbase); + } + } +} + +/* not region itself */ +void BKE_area_region_free(SpaceType *st, ARegion *ar) +{ + if(st) { + ARegionType *art= BKE_regiontype_from_id(st, ar->regiontype); + + if(art && art->free) + art->free(ar); + + if(ar->regiondata) + printf("regiondata free error\n"); + } + else if(ar->type && ar->type->free) + ar->type->free(ar); + + if(ar->v2d.tab_offset) { + MEM_freeN(ar->v2d.tab_offset); + ar->v2d.tab_offset= NULL; + } + + if(ar) + BLI_freelistN(&ar->panels); +} + +/* not area itself */ +void BKE_screen_area_free(ScrArea *sa) +{ + SpaceType *st= BKE_spacetype_from_id(sa->spacetype); + ARegion *ar; + + for(ar=sa->regionbase.first; ar; ar=ar->next) + BKE_area_region_free(st, ar); + + BLI_freelistN(&sa->regionbase); + + BKE_spacedata_freelist(&sa->spacedata); + + BLI_freelistN(&sa->actionzones); +} + /* don't free screen itself */ void free_screen(bScreen *sc) { - unlink_screen(sc); + ScrArea *sa, *san; + ARegion *ar; + + for(ar=sc->regionbase.first; ar; ar=ar->next) + BKE_area_region_free(NULL, ar); + BLI_freelistN(&sc->regionbase); + + for(sa= sc->areabase.first; sa; sa= san) { + san= sa->next; + BKE_screen_area_free(sa); + } + BLI_freelistN(&sc->vertbase); BLI_freelistN(&sc->edgebase); BLI_freelistN(&sc->areabase); } + + diff --git a/source/blender/blenkernel/intern/script.c b/source/blender/blenkernel/intern/script.c index 6145f6c3063..e34b1d0a1dd 100644 --- a/source/blender/blenkernel/intern/script.c +++ b/source/blender/blenkernel/intern/script.c @@ -35,7 +35,6 @@ #include "DNA_space_types.h" #include "MEM_guardedalloc.h" -#include "BKE_bad_level_calls.h" /* for BPY_clear_script */ /* #include "BLI_blenlib.h" @@ -47,15 +46,14 @@ #ifndef DISABLE_PYTHON #include "BPY_extern.h" // Blender Python library #endif - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif */ /* XXX this function and so also the file should not be needed anymore, * since we have to force clearing all Python related data before freeing * Blender's library. Still testing, will decide later (Willian). */ + +//XXX +#if 0 void free_script (Script *script) { if (!script) return; @@ -63,3 +61,4 @@ void free_script (Script *script) BPY_clear_script(script); #endif } +#endif diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c new file mode 100644 index 00000000000..2ee95ed928e --- /dev/null +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -0,0 +1,3155 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): + * - Blender Foundation, 2003-2009 + * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <math.h> +#include <stdlib.h> + +#include "MEM_guardedalloc.h" +#include "PIL_dynlib.h" + +#include "DNA_scene_types.h" +#include "DNA_sequence_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_global.h" +#include "BKE_plugin_types.h" +#include "BKE_sequence.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +/* **** XXX **** */ +static void error() {} + +#define INT 96 +#define FLO 128 + +/* **** XXX **** */ + +/* Glow effect */ +enum { + GlowR=0, + GlowG=1, + GlowB=2, + GlowA=3 +}; + + +/* ********************************************************************** + PLUGINS + ********************************************************************** */ + +static void open_plugin_seq(PluginSeq *pis, const char *seqname) +{ + int (*version)(); + void* (*alloc_private)(); + char *cp; + + /* to be sure: (is tested for) */ + pis->doit= 0; + pis->pname= 0; + pis->varstr= 0; + pis->cfra= 0; + pis->version= 0; + pis->instance_private_data = 0; + + /* clear the error list */ + PIL_dynlib_get_error_as_string(NULL); + + /* if(pis->handle) PIL_dynlib_close(pis->handle); */ + /* pis->handle= 0; */ + + /* open the needed object */ + pis->handle= PIL_dynlib_open(pis->name); + if(test_dlerr(pis->name, pis->name)) return; + + if (pis->handle != 0) { + /* find the address of the version function */ + version= (int (*)())PIL_dynlib_find_symbol(pis->handle, "plugin_seq_getversion"); + if (test_dlerr(pis->name, "plugin_seq_getversion")) return; + + if (version != 0) { + pis->version= version(); + if (pis->version >= 2 && pis->version <= 6) { + int (*info_func)(PluginInfo *); + PluginInfo *info= (PluginInfo*) MEM_mallocN(sizeof(PluginInfo), "plugin_info"); + + info_func= (int (*)(PluginInfo *))PIL_dynlib_find_symbol(pis->handle, "plugin_getinfo"); + + if(info_func == NULL) error("No info func"); + else { + info_func(info); + + pis->pname= info->name; + pis->vars= info->nvars; + pis->cfra= info->cfra; + + pis->varstr= info->varstr; + + pis->doit= (void(*)(void))info->seq_doit; + if (info->init) + info->init(); + } + MEM_freeN(info); + + cp= PIL_dynlib_find_symbol(pis->handle, "seqname"); + if(cp) strncpy(cp, seqname, 21); + } else { + printf ("Plugin returned unrecognized version number\n"); + return; + } + } + alloc_private = (void* (*)())PIL_dynlib_find_symbol( + pis->handle, "plugin_seq_alloc_private_data"); + if (alloc_private) { + pis->instance_private_data = alloc_private(); + } + + pis->current_private_data = (void**) + PIL_dynlib_find_symbol( + pis->handle, "plugin_private_data"); + } +} + +static PluginSeq *add_plugin_seq(const char *str, const char *seqname) +{ + PluginSeq *pis; + VarStruct *varstr; + int a; + + pis= MEM_callocN(sizeof(PluginSeq), "PluginSeq"); + + strncpy(pis->name, str, FILE_MAXDIR+FILE_MAXFILE); + open_plugin_seq(pis, seqname); + + if(pis->doit==0) { + if(pis->handle==0) error("no plugin: %s", str); + else error("in plugin: %s", str); + MEM_freeN(pis); + return 0; + } + + /* default values */ + varstr= pis->varstr; + for(a=0; a<pis->vars; a++, varstr++) { + if( (varstr->type & FLO)==FLO) + pis->data[a]= varstr->def; + else if( (varstr->type & INT)==INT) + *((int *)(pis->data+a))= (int) varstr->def; + } + + return pis; +} + +static void free_plugin_seq(PluginSeq *pis) +{ + if(pis==0) return; + + /* no PIL_dynlib_close: same plugin can be opened multiple times with 1 handle */ + + if (pis->instance_private_data) { + void (*free_private)(void *); + + free_private = (void (*)(void *))PIL_dynlib_find_symbol( + pis->handle, "plugin_seq_free_private_data"); + if (free_private) { + free_private(pis->instance_private_data); + } + } + + MEM_freeN(pis); +} + +static void init_plugin(Sequence * seq, const char * fname) +{ + seq->plugin= (PluginSeq *)add_plugin_seq(fname, seq->name+2); +} + +/* + * FIXME: should query plugin! Could be generator, that needs zero inputs... + */ +static int num_inputs_plugin() +{ + return 1; +} + +static void load_plugin(Sequence * seq) +{ + if (seq) { + open_plugin_seq(seq->plugin, seq->name+2); + } +} + +static void copy_plugin(Sequence * dst, Sequence * src) +{ + if(src->plugin) { + dst->plugin= MEM_dupallocN(src->plugin); + open_plugin_seq(dst->plugin, dst->name+2); + } +} + +static ImBuf * IMB_cast_away_list(ImBuf * i) +{ + if (!i) { + return 0; + } + return (ImBuf*) (((void**) i) + 2); +} + +static void do_plugin_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + char *cp; + int float_rendering; + int use_temp_bufs = 0; /* Are needed since blur.c (and maybe some other + old plugins) do very bad stuff + with imbuf-internals */ + + if(seq->plugin && seq->plugin->doit) { + + if(seq->plugin->cfra) + *(seq->plugin->cfra)= cfra; +// XXX *(seq->plugin->cfra)= frame_to_float(scene, cfra); + + cp = PIL_dynlib_find_symbol( + seq->plugin->handle, "seqname"); + + if(cp) strncpy(cp, seq->name+2, 22); + + if (seq->plugin->current_private_data) { + *seq->plugin->current_private_data + = seq->plugin->instance_private_data; + } + + float_rendering = (out->rect_float != NULL); + + if (seq->plugin->version<=3 && float_rendering) { + use_temp_bufs = 1; + + if (ibuf1) { + ibuf1 = IMB_dupImBuf(ibuf1); + IMB_rect_from_float(ibuf1); + imb_freerectfloatImBuf(ibuf1); + ibuf1->flags &= ~IB_rectfloat; + } + if (ibuf2) { + ibuf2 = IMB_dupImBuf(ibuf2); + IMB_rect_from_float(ibuf2); + imb_freerectfloatImBuf(ibuf2); + ibuf2->flags &= ~IB_rectfloat; + } + if (ibuf3) { + ibuf3 = IMB_dupImBuf(ibuf3); + IMB_rect_from_float(ibuf3); + imb_freerectfloatImBuf(ibuf3); + ibuf3->flags &= ~IB_rectfloat; + } + if (!out->rect) imb_addrectImBuf(out); + imb_freerectfloatImBuf(out); + out->flags &= ~IB_rectfloat; + } + + if (seq->plugin->version<=2) { + if(ibuf1) IMB_convert_rgba_to_abgr(ibuf1); + if(ibuf2) IMB_convert_rgba_to_abgr(ibuf2); + if(ibuf3) IMB_convert_rgba_to_abgr(ibuf3); + } + + if (seq->plugin->version<=4) { + ((SeqDoit)seq->plugin->doit)( + seq->plugin->data, facf0, facf1, x, y, + IMB_cast_away_list(ibuf1), + IMB_cast_away_list(ibuf2), + IMB_cast_away_list(out), + IMB_cast_away_list(ibuf3)); + } else { + ((SeqDoit)seq->plugin->doit)( + seq->plugin->data, facf0, facf1, x, y, + ibuf1, ibuf2, out, ibuf3); + } + + if (seq->plugin->version<=2) { + if (!use_temp_bufs) { + if(ibuf1) IMB_convert_rgba_to_abgr(ibuf1); + if(ibuf2) IMB_convert_rgba_to_abgr(ibuf2); + if(ibuf3) IMB_convert_rgba_to_abgr(ibuf3); + } + IMB_convert_rgba_to_abgr(out); + } + if (seq->plugin->version<=3 && float_rendering) { + IMB_float_from_rect(out); + } + + if (use_temp_bufs) { + if (ibuf1) IMB_freeImBuf(ibuf1); + if (ibuf2) IMB_freeImBuf(ibuf2); + if (ibuf3) IMB_freeImBuf(ibuf3); + } + } +} + +static int do_plugin_early_out(struct Sequence *seq, + float facf0, float facf1) +{ + return 0; +} + +static void free_plugin(struct Sequence * seq) +{ + free_plugin_seq(seq->plugin); + seq->plugin = 0; +} + +/* ********************************************************************** + ALPHA OVER + ********************************************************************** */ + +static void init_alpha_over_or_under(Sequence * seq) +{ + Sequence * seq1 = seq->seq1; + Sequence * seq2 = seq->seq2; + + seq->seq2= seq1; + seq->seq1= seq2; +} + +static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, + char * rect1, char *rect2, char *out) +{ + int fac2, mfac, fac, fac4; + int xo, tempc; + char *rt1, *rt2, *rt; + + xo= x; + rt1= (char *)rect1; + rt2= (char *)rect2; + rt= (char *)out; + + fac2= (int)(256.0*facf0); + fac4= (int)(256.0*facf1); + + while(y--) { + + x= xo; + while(x--) { + + /* rt = rt1 over rt2 (alpha from rt1) */ + + fac= fac2; + mfac= 256 - ( (fac2*rt1[3])>>8 ); + + if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else if(mfac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt1); + else { + tempc= ( fac*rt1[0] + mfac*rt2[0])>>8; + if(tempc>255) rt[0]= 255; else rt[0]= tempc; + tempc= ( fac*rt1[1] + mfac*rt2[1])>>8; + if(tempc>255) rt[1]= 255; else rt[1]= tempc; + tempc= ( fac*rt1[2] + mfac*rt2[2])>>8; + if(tempc>255) rt[2]= 255; else rt[2]= tempc; + tempc= ( fac*rt1[3] + mfac*rt2[3])>>8; + if(tempc>255) rt[3]= 255; else rt[3]= tempc; + } + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + fac= fac4; + mfac= 256 - ( (fac4*rt1[3])>>8 ); + + if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else if(mfac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt1); + else { + tempc= ( fac*rt1[0] + mfac*rt2[0])>>8; + if(tempc>255) rt[0]= 255; else rt[0]= tempc; + tempc= ( fac*rt1[1] + mfac*rt2[1])>>8; + if(tempc>255) rt[1]= 255; else rt[1]= tempc; + tempc= ( fac*rt1[2] + mfac*rt2[2])>>8; + if(tempc>255) rt[2]= 255; else rt[2]= tempc; + tempc= ( fac*rt1[3] + mfac*rt2[3])>>8; + if(tempc>255) rt[3]= 255; else rt[3]= tempc; + } + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_alphaover_effect_float(float facf0, float facf1, int x, int y, + float * rect1, float *rect2, float *out) +{ + float fac2, mfac, fac, fac4; + int xo; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= facf0; + fac4= facf1; + + while(y--) { + + x= xo; + while(x--) { + + /* rt = rt1 over rt2 (alpha from rt1) */ + + fac= fac2; + mfac= 1.0 - (fac2*rt1[3]) ; + + if(fac <= 0.0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else if(mfac <=0) { + memcpy(rt, rt1, 4 * sizeof(float)); + } else { + rt[0] = fac*rt1[0] + mfac*rt2[0]; + rt[1] = fac*rt1[1] + mfac*rt2[1]; + rt[2] = fac*rt1[2] + mfac*rt2[2]; + rt[3] = fac*rt1[3] + mfac*rt2[3]; + } + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + fac= fac4; + mfac= 1.0 - (fac4*rt1[3]); + + if(fac <= 0.0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else if(mfac <= 0.0) { + memcpy(rt, rt1, 4 * sizeof(float)); + } else { + rt[0] = fac*rt1[0] + mfac*rt2[0]; + rt[1] = fac*rt1[1] + mfac*rt2[1]; + rt[2] = fac*rt1[2] + mfac*rt2[2]; + rt[3] = fac*rt1[3] + mfac*rt2[3]; + } + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_alphaover_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_alphaover_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_alphaover_effect_byte( + facf0, facf1, x, y, + (char*) ibuf1->rect, (char*) ibuf2->rect, + (char*) out->rect); + } +} + + +/* ********************************************************************** + ALPHA UNDER + ********************************************************************** */ + +void do_alphaunder_effect_byte( + float facf0, float facf1, int x, int y, char *rect1, + char *rect2, char *out) +{ + int fac2, mfac, fac, fac4; + int xo; + char *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= (int)(256.0*facf0); + fac4= (int)(256.0*facf1); + + while(y--) { + + x= xo; + while(x--) { + + /* rt = rt1 under rt2 (alpha from rt2) */ + + /* this complex optimalisation is because the + * 'skybuf' can be crossed in + */ + if(rt2[3]==0 && fac2==256) *( (unsigned int *)rt) = *( (unsigned int *)rt1); + else if(rt2[3]==255) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else { + mfac= rt2[3]; + fac= (fac2*(256-mfac))>>8; + + if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else { + rt[0]= ( fac*rt1[0] + mfac*rt2[0])>>8; + rt[1]= ( fac*rt1[1] + mfac*rt2[1])>>8; + rt[2]= ( fac*rt1[2] + mfac*rt2[2])>>8; + rt[3]= ( fac*rt1[3] + mfac*rt2[3])>>8; + } + } + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + if(rt2[3]==0 && fac4==256) *( (unsigned int *)rt) = *( (unsigned int *)rt1); + else if(rt2[3]==255) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else { + mfac= rt2[3]; + fac= (fac4*(256-mfac))>>8; + + if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2); + else { + rt[0]= ( fac*rt1[0] + mfac*rt2[0])>>8; + rt[1]= ( fac*rt1[1] + mfac*rt2[1])>>8; + rt[2]= ( fac*rt1[2] + mfac*rt2[2])>>8; + rt[3]= ( fac*rt1[3] + mfac*rt2[3])>>8; + } + } + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + + +static void do_alphaunder_effect_float(float facf0, float facf1, int x, int y, + float *rect1, float *rect2, + float *out) +{ + float fac2, mfac, fac, fac4; + int xo; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= facf0; + fac4= facf1; + + while(y--) { + + x= xo; + while(x--) { + + /* rt = rt1 under rt2 (alpha from rt2) */ + + /* this complex optimalisation is because the + * 'skybuf' can be crossed in + */ + if( rt2[3]<=0 && fac2>=1.0) { + memcpy(rt, rt1, 4 * sizeof(float)); + } else if(rt2[3]>=1.0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else { + mfac = rt2[3]; + fac = fac2 * (1.0 - mfac); + + if(fac == 0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else { + rt[0]= fac*rt1[0] + mfac*rt2[0]; + rt[1]= fac*rt1[1] + mfac*rt2[1]; + rt[2]= fac*rt1[2] + mfac*rt2[2]; + rt[3]= fac*rt1[3] + mfac*rt2[3]; + } + } + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + if(rt2[3]<=0 && fac4 >= 1.0) { + memcpy(rt, rt1, 4 * sizeof(float)); + + } else if(rt2[3]>=1.0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else { + mfac= rt2[3]; + fac= fac4*(1.0-mfac); + + if(fac == 0) { + memcpy(rt, rt2, 4 * sizeof(float)); + } else { + rt[0]= fac * rt1[0] + mfac * rt2[0]; + rt[1]= fac * rt1[1] + mfac * rt2[1]; + rt[2]= fac * rt1[2] + mfac * rt2[2]; + rt[3]= fac * rt1[3] + mfac * rt2[3]; + } + } + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_alphaunder_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_alphaunder_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_alphaunder_effect_byte( + facf0, facf1, x, y, + (char*) ibuf1->rect, (char*) ibuf2->rect, + (char*) out->rect); + } +} + + +/* ********************************************************************** + CROSS + ********************************************************************** */ + +void do_cross_effect_byte(float facf0, float facf1, int x, int y, + char *rect1, char *rect2, + char *out) +{ + int fac1, fac2, fac3, fac4; + int xo; + char *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= (int)(256.0*facf0); + fac1= 256-fac2; + fac4= (int)(256.0*facf1); + fac3= 256-fac4; + + while(y--) { + + x= xo; + while(x--) { + + rt[0]= (fac1*rt1[0] + fac2*rt2[0])>>8; + rt[1]= (fac1*rt1[1] + fac2*rt2[1])>>8; + rt[2]= (fac1*rt1[2] + fac2*rt2[2])>>8; + rt[3]= (fac1*rt1[3] + fac2*rt2[3])>>8; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + rt[0]= (fac3*rt1[0] + fac4*rt2[0])>>8; + rt[1]= (fac3*rt1[1] + fac4*rt2[1])>>8; + rt[2]= (fac3*rt1[2] + fac4*rt2[2])>>8; + rt[3]= (fac3*rt1[3] + fac4*rt2[3])>>8; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + } +} + +void do_cross_effect_float(float facf0, float facf1, int x, int y, + float *rect1, float *rect2, float *out) +{ + float fac1, fac2, fac3, fac4; + int xo; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= facf0; + fac1= 1.0 - fac2; + fac4= facf1; + fac3= 1.0 - fac4; + + while(y--) { + + x= xo; + while(x--) { + + rt[0]= fac1*rt1[0] + fac2*rt2[0]; + rt[1]= fac1*rt1[1] + fac2*rt2[1]; + rt[2]= fac1*rt1[2] + fac2*rt2[2]; + rt[3]= fac1*rt1[3] + fac2*rt2[3]; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + rt[0]= fac3*rt1[0] + fac4*rt2[0]; + rt[1]= fac3*rt1[1] + fac4*rt2[1]; + rt[2]= fac3*rt1[2] + fac4*rt2[2]; + rt[3]= fac3*rt1[3] + fac4*rt2[3]; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + } +} + +/* carefull: also used by speed effect! */ + +static void do_cross_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_cross_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_cross_effect_byte( + facf0, facf1, x, y, + (char*) ibuf1->rect, (char*) ibuf2->rect, + (char*) out->rect); + } +} + + +/* ********************************************************************** + GAMMA CROSS + ********************************************************************** */ + +/* copied code from initrender.c */ +static unsigned short gamtab[65536]; +static unsigned short igamtab1[256]; +static int gamma_tabs_init = FALSE; + +#define RE_GAMMA_TABLE_SIZE 400 + +static float gamma_range_table[RE_GAMMA_TABLE_SIZE + 1]; +static float gamfactor_table[RE_GAMMA_TABLE_SIZE]; +static float inv_gamma_range_table[RE_GAMMA_TABLE_SIZE + 1]; +static float inv_gamfactor_table[RE_GAMMA_TABLE_SIZE]; +static float color_domain_table[RE_GAMMA_TABLE_SIZE + 1]; +static float color_step; +static float inv_color_step; +static float valid_gamma; +static float valid_inv_gamma; + +static void makeGammaTables(float gamma) +{ + /* we need two tables: one forward, one backward */ + int i; + + valid_gamma = gamma; + valid_inv_gamma = 1.0 / gamma; + color_step = 1.0 / RE_GAMMA_TABLE_SIZE; + inv_color_step = (float) RE_GAMMA_TABLE_SIZE; + + /* We could squeeze out the two range tables to gain some memory. */ + for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++) { + color_domain_table[i] = i * color_step; + gamma_range_table[i] = pow(color_domain_table[i], + valid_gamma); + inv_gamma_range_table[i] = pow(color_domain_table[i], + valid_inv_gamma); + } + + /* The end of the table should match 1.0 carefully. In order to avoid */ + /* rounding errors, we just set this explicitly. The last segment may */ + /* have a different lenght than the other segments, but our */ + /* interpolation is insensitive to that. */ + color_domain_table[RE_GAMMA_TABLE_SIZE] = 1.0; + gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0; + inv_gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0; + + /* To speed up calculations, we make these calc factor tables. They are */ + /* multiplication factors used in scaling the interpolation. */ + for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++ ) { + gamfactor_table[i] = inv_color_step + * (gamma_range_table[i + 1] - gamma_range_table[i]) ; + inv_gamfactor_table[i] = inv_color_step + * (inv_gamma_range_table[i + 1] - inv_gamma_range_table[i]) ; + } + +} /* end of void makeGammaTables(float gamma) */ + + +static float gammaCorrect(float c) +{ + int i; + float res = 0.0; + + i = floor(c * inv_color_step); + /* Clip to range [0,1]: outside, just do the complete calculation. */ + /* We may have some performance problems here. Stretching up the LUT */ + /* may help solve that, by exchanging LUT size for the interpolation. */ + /* Negative colors are explicitly handled. */ + if (i < 0) res = -pow(abs(c), valid_gamma); + else if (i >= RE_GAMMA_TABLE_SIZE ) res = pow(c, valid_gamma); + else res = gamma_range_table[i] + + ( (c - color_domain_table[i]) * gamfactor_table[i]); + + return res; +} /* end of float gammaCorrect(float col) */ + +/* ------------------------------------------------------------------------- */ + +static float invGammaCorrect(float col) +{ + int i; + float res = 0.0; + + i = floor(col*inv_color_step); + /* Negative colors are explicitly handled. */ + if (i < 0) res = -pow(abs(col), valid_inv_gamma); + else if (i >= RE_GAMMA_TABLE_SIZE) res = pow(col, valid_inv_gamma); + else res = inv_gamma_range_table[i] + + ( (col - color_domain_table[i]) * inv_gamfactor_table[i]); + + return res; +} /* end of float invGammaCorrect(float col) */ + + +static void gamtabs(float gamma) +{ + float val, igamma= 1.0f/gamma; + int a; + + /* gamtab: in short, out short */ + for(a=0; a<65536; a++) { + val= a; + val/= 65535.0; + + if(gamma==2.0) val= sqrt(val); + else if(gamma!=1.0) val= pow(val, igamma); + + gamtab[a]= (65535.99*val); + } + /* inverse gamtab1 : in byte, out short */ + for(a=1; a<=256; a++) { + if(gamma==2.0) igamtab1[a-1]= a*a-1; + else if(gamma==1.0) igamtab1[a-1]= 256*a-1; + else { + val= a/256.0; + igamtab1[a-1]= (65535.0*pow(val, gamma)) -1 ; + } + } + +} + +static void build_gammatabs() +{ + if (gamma_tabs_init == FALSE) { + gamtabs(2.0f); + makeGammaTables(2.0f); + gamma_tabs_init = TRUE; + } +} + +static void init_gammacross(Sequence * seq) +{ +} + +static void load_gammacross(Sequence * seq) +{ +} + +static void free_gammacross(Sequence * seq) +{ +} + +static void do_gammacross_effect_byte(float facf0, float facf1, + int x, int y, + unsigned char *rect1, + unsigned char *rect2, + unsigned char *out) +{ + int fac1, fac2, col; + int xo; + unsigned char *rt1, *rt2, *rt; + + xo= x; + rt1= (unsigned char *)rect1; + rt2= (unsigned char *)rect2; + rt= (unsigned char *)out; + + fac2= (int)(256.0*facf0); + fac1= 256-fac2; + + while(y--) { + + x= xo; + while(x--) { + + col= (fac1*igamtab1[rt1[0]] + fac2*igamtab1[rt2[0]])>>8; + if(col>65535) rt[0]= 255; else rt[0]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col=(fac1*igamtab1[rt1[1]] + fac2*igamtab1[rt2[1]])>>8; + if(col>65535) rt[1]= 255; else rt[1]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col= (fac1*igamtab1[rt1[2]] + fac2*igamtab1[rt2[2]])>>8; + if(col>65535) rt[2]= 255; else rt[2]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col= (fac1*igamtab1[rt1[3]] + fac2*igamtab1[rt2[3]])>>8; + if(col>65535) rt[3]= 255; else rt[3]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + col= (fac1*igamtab1[rt1[0]] + fac2*igamtab1[rt2[0]])>>8; + if(col>65535) rt[0]= 255; else rt[0]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col= (fac1*igamtab1[rt1[1]] + fac2*igamtab1[rt2[1]])>>8; + if(col>65535) rt[1]= 255; else rt[1]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col= (fac1*igamtab1[rt1[2]] + fac2*igamtab1[rt2[2]])>>8; + if(col>65535) rt[2]= 255; else rt[2]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + col= (fac1*igamtab1[rt1[3]] + fac2*igamtab1[rt2[3]])>>8; + if(col>65535) rt[3]= 255; else rt[3]= ( (char *)(gamtab+col))[MOST_SIG_BYTE]; + + rt1+= 4; rt2+= 4; rt+= 4; + } + } + +} + +static void do_gammacross_effect_float(float facf0, float facf1, + int x, int y, + float *rect1, float *rect2, + float *out) +{ + float fac1, fac2; + int xo; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac2= facf0; + fac1= 1.0 - fac2; + + while(y--) { + + x= xo * 4; + while(x--) { + + *rt= gammaCorrect( + fac1 * invGammaCorrect(*rt1) + + fac2 * invGammaCorrect(*rt2)); + rt1++; rt2++; rt++; + } + + if(y==0) break; + y--; + + x= xo * 4; + while(x--) { + + *rt= gammaCorrect( + fac1*invGammaCorrect(*rt1) + + fac2*invGammaCorrect(*rt2)); + + rt1++; rt2++; rt++; + } + } +} + +static void do_gammacross_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + build_gammatabs(); + + if (out->rect_float) { + do_gammacross_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_gammacross_effect_byte( + facf0, facf1, x, y, + (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect, + (unsigned char*) out->rect); + } +} + + +/* ********************************************************************** + ADD + ********************************************************************** */ + +static void do_add_effect_byte(float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, + unsigned char *out) +{ + int col, xo, fac1, fac3; + char *rt1, *rt2, *rt; + + xo= x; + rt1= (char *)rect1; + rt2= (char *)rect2; + rt= (char *)out; + + fac1= (int)(256.0*facf0); + fac3= (int)(256.0*facf1); + + while(y--) { + + x= xo; + while(x--) { + + col= rt1[0]+ ((fac1*rt2[0])>>8); + if(col>255) rt[0]= 255; else rt[0]= col; + col= rt1[1]+ ((fac1*rt2[1])>>8); + if(col>255) rt[1]= 255; else rt[1]= col; + col= rt1[2]+ ((fac1*rt2[2])>>8); + if(col>255) rt[2]= 255; else rt[2]= col; + col= rt1[3]+ ((fac1*rt2[3])>>8); + if(col>255) rt[3]= 255; else rt[3]= col; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + col= rt1[0]+ ((fac3*rt2[0])>>8); + if(col>255) rt[0]= 255; else rt[0]= col; + col= rt1[1]+ ((fac3*rt2[1])>>8); + if(col>255) rt[1]= 255; else rt[1]= col; + col= rt1[2]+ ((fac3*rt2[2])>>8); + if(col>255) rt[2]= 255; else rt[2]= col; + col= rt1[3]+ ((fac3*rt2[3])>>8); + if(col>255) rt[3]= 255; else rt[3]= col; + + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_add_effect_float(float facf0, float facf1, int x, int y, + float *rect1, float *rect2, + float *out) +{ + int xo; + float fac1, fac3; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac1= facf0; + fac3= facf1; + + while(y--) { + + x= xo * 4; + while(x--) { + *rt = *rt1 + fac1 * (*rt2); + + rt1++; rt2++; rt++; + } + + if(y==0) break; + y--; + + x= xo * 4; + while(x--) { + *rt = *rt1 + fac3 * (*rt2); + + rt1++; rt2++; rt++; + } + } +} + +static void do_add_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_add_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_add_effect_byte( + facf0, facf1, x, y, + (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect, + (unsigned char*) out->rect); + } +} + + +/* ********************************************************************** + SUB + ********************************************************************** */ + +static void do_sub_effect_byte(float facf0, float facf1, + int x, int y, + char *rect1, char *rect2, char *out) +{ + int col, xo, fac1, fac3; + char *rt1, *rt2, *rt; + + xo= x; + rt1= (char *)rect1; + rt2= (char *)rect2; + rt= (char *)out; + + fac1= (int)(256.0*facf0); + fac3= (int)(256.0*facf1); + + while(y--) { + + x= xo; + while(x--) { + + col= rt1[0]- ((fac1*rt2[0])>>8); + if(col<0) rt[0]= 0; else rt[0]= col; + col= rt1[1]- ((fac1*rt2[1])>>8); + if(col<0) rt[1]= 0; else rt[1]= col; + col= rt1[2]- ((fac1*rt2[2])>>8); + if(col<0) rt[2]= 0; else rt[2]= col; + col= rt1[3]- ((fac1*rt2[3])>>8); + if(col<0) rt[3]= 0; else rt[3]= col; + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + col= rt1[0]- ((fac3*rt2[0])>>8); + if(col<0) rt[0]= 0; else rt[0]= col; + col= rt1[1]- ((fac3*rt2[1])>>8); + if(col<0) rt[1]= 0; else rt[1]= col; + col= rt1[2]- ((fac3*rt2[2])>>8); + if(col<0) rt[2]= 0; else rt[2]= col; + col= rt1[3]- ((fac3*rt2[3])>>8); + if(col<0) rt[3]= 0; else rt[3]= col; + + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_sub_effect_float(float facf0, float facf1, int x, int y, + float *rect1, float *rect2, + float *out) +{ + int xo; + float fac1, fac3; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac1= facf0; + fac3= facf1; + + while(y--) { + + x= xo * 4; + while(x--) { + *rt = *rt1 - fac1 * (*rt2); + + rt1++; rt2++; rt++; + } + + if(y==0) break; + y--; + + x= xo * 4; + while(x--) { + *rt = *rt1 - fac3 * (*rt2); + + rt1++; rt2++; rt++; + } + } +} + +static void do_sub_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_sub_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_sub_effect_byte( + facf0, facf1, x, y, + (char*) ibuf1->rect, (char*) ibuf2->rect, + (char*) out->rect); + } +} + +/* ********************************************************************** + DROP + ********************************************************************** */ + +/* Must be > 0 or add precopy, etc to the function */ +#define XOFF 8 +#define YOFF 8 + +static void do_drop_effect_byte(float facf0, float facf1, int x, int y, + unsigned char *rect2i, unsigned char *rect1i, + unsigned char *outi) +{ + int height, width, temp, fac, fac1, fac2; + char *rt1, *rt2, *out; + int field= 1; + + width= x; + height= y; + + fac1= (int)(70.0*facf0); + fac2= (int)(70.0*facf1); + + rt2= (char*) (rect2i + YOFF*width); + rt1= (char*) rect1i; + out= (char*) outi; + for (y=0; y<height-YOFF; y++) { + if(field) fac= fac1; + else fac= fac2; + field= !field; + + memcpy(out, rt1, sizeof(int)*XOFF); + rt1+= XOFF*4; + out+= XOFF*4; + + for (x=XOFF; x<width; x++) { + temp= ((fac*rt2[3])>>8); + + *(out++)= MAX2(0, *rt1 - temp); rt1++; + *(out++)= MAX2(0, *rt1 - temp); rt1++; + *(out++)= MAX2(0, *rt1 - temp); rt1++; + *(out++)= MAX2(0, *rt1 - temp); rt1++; + rt2+=4; + } + rt2+=XOFF*4; + } + memcpy(out, rt1, sizeof(int)*YOFF*width); +} + +static void do_drop_effect_float(float facf0, float facf1, int x, int y, + float *rect2i, float *rect1i, + float *outi) +{ + int height, width; + float temp, fac, fac1, fac2; + float *rt1, *rt2, *out; + int field= 1; + + width= x; + height= y; + + fac1= 70.0*facf0; + fac2= 70.0*facf1; + + rt2= (rect2i + YOFF*width); + rt1= rect1i; + out= outi; + for (y=0; y<height-YOFF; y++) { + if(field) fac= fac1; + else fac= fac2; + field= !field; + + memcpy(out, rt1, 4 * sizeof(float)*XOFF); + rt1+= XOFF*4; + out+= XOFF*4; + + for (x=XOFF; x<width; x++) { + temp= fac * rt2[3]; + + *(out++)= MAX2(0.0, *rt1 - temp); rt1++; + *(out++)= MAX2(0.0, *rt1 - temp); rt1++; + *(out++)= MAX2(0.0, *rt1 - temp); rt1++; + *(out++)= MAX2(0.0, *rt1 - temp); rt1++; + rt2+=4; + } + rt2+=XOFF*4; + } + memcpy(out, rt1, 4 * sizeof(float)*YOFF*width); +} + + +static void do_drop_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf * ibuf3, + struct ImBuf *out) +{ + if (out->rect_float) { + do_drop_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_drop_effect_byte( + facf0, facf1, x, y, + (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect, + (unsigned char*) out->rect); + } +} + +/* ********************************************************************** + MUL + ********************************************************************** */ + +static void do_mul_effect_byte(float facf0, float facf1, int x, int y, + unsigned char *rect1, unsigned char *rect2, + unsigned char *out) +{ + int xo, fac1, fac3; + char *rt1, *rt2, *rt; + + xo= x; + rt1= (char *)rect1; + rt2= (char *)rect2; + rt= (char *)out; + + fac1= (int)(256.0*facf0); + fac3= (int)(256.0*facf1); + + /* formula: + * fac*(a*b) + (1-fac)*a => fac*a*(b-1)+axaux= c*px + py*s ;//+centx + yaux= -s*px + c*py;//+centy + */ + + while(y--) { + + x= xo; + while(x--) { + + rt[0]= rt1[0] + ((fac1*rt1[0]*(rt2[0]-256))>>16); + rt[1]= rt1[1] + ((fac1*rt1[1]*(rt2[1]-256))>>16); + rt[2]= rt1[2] + ((fac1*rt1[2]*(rt2[2]-256))>>16); + rt[3]= rt1[3] + ((fac1*rt1[3]*(rt2[3]-256))>>16); + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + rt[0]= rt1[0] + ((fac3*rt1[0]*(rt2[0]-256))>>16); + rt[1]= rt1[1] + ((fac3*rt1[1]*(rt2[1]-256))>>16); + rt[2]= rt1[2] + ((fac3*rt1[2]*(rt2[2]-256))>>16); + rt[3]= rt1[3] + ((fac3*rt1[3]*(rt2[3]-256))>>16); + + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_mul_effect_float(float facf0, float facf1, int x, int y, + float *rect1, float *rect2, + float *out) +{ + int xo; + float fac1, fac3; + float *rt1, *rt2, *rt; + + xo= x; + rt1= rect1; + rt2= rect2; + rt= out; + + fac1= facf0; + fac3= facf1; + + /* formula: + * fac*(a*b) + (1-fac)*a => fac*a*(b-1)+a + */ + + while(y--) { + + x= xo; + while(x--) { + + rt[0]= rt1[0] + fac1*rt1[0]*(rt2[0]-1.0); + rt[1]= rt1[1] + fac1*rt1[1]*(rt2[1]-1.0); + rt[2]= rt1[2] + fac1*rt1[2]*(rt2[2]-1.0); + rt[3]= rt1[3] + fac1*rt1[3]*(rt2[3]-1.0); + + rt1+= 4; rt2+= 4; rt+= 4; + } + + if(y==0) break; + y--; + + x= xo; + while(x--) { + + rt[0]= rt1[0] + fac3*rt1[0]*(rt2[0]-1.0); + rt[1]= rt1[1] + fac3*rt1[1]*(rt2[1]-1.0); + rt[2]= rt1[2] + fac3*rt1[2]*(rt2[2]-1.0); + rt[3]= rt1[3] + fac3*rt1[3]*(rt2[3]-1.0); + + rt1+= 4; rt2+= 4; rt+= 4; + } + } +} + +static void do_mul_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_mul_effect_float( + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_mul_effect_byte( + facf0, facf1, x, y, + (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect, + (unsigned char*) out->rect); + } +} + +/* ********************************************************************** + WIPE + ********************************************************************** */ + +typedef struct WipeZone { + float angle; + int flip; + int xo, yo; + int width; + float invwidth; + float pythangle; +} WipeZone; + +static void precalc_wipe_zone(WipeZone *wipezone, WipeVars *wipe, int xo, int yo) +{ + wipezone->flip = (wipe->angle < 0); + wipezone->angle = pow(fabs(wipe->angle)/45.0f, log(xo)/log(2.0f)); + wipezone->xo = xo; + wipezone->yo = yo; + wipezone->width = (int)(wipe->edgeWidth*((xo+yo)/2.0f)); + wipezone->pythangle = 1.0f/sqrt(wipe->angle*wipe->angle + 1.0f); + + if(wipe->wipetype == DO_SINGLE_WIPE) + wipezone->invwidth = 1.0f/wipezone->width; + else + wipezone->invwidth = 1.0f/(0.5f*wipezone->width); +} + +// This function calculates the blur band for the wipe effects +static float in_band(WipeZone *wipezone,float width,float dist,float perc,int side,int dir) +{ + float t1,t2,alpha,percwidth; + + if(width == 0) + return (float)side; + + if(side == 1) + percwidth = width * perc; + else + percwidth = width * (1 - perc); + + if(width < dist) + return side; + + t1 = dist * wipezone->invwidth; //percentange of width that is + t2 = wipezone->invwidth; //amount of alpha per % point + + if(side == 1) + alpha = (t1*t2*100) + (1-perc); // add point's alpha contrib to current position in wipe + else + alpha = (1-perc) - (t1*t2*100); + + if(dir == 0) + alpha = 1-alpha; + + return alpha; +} + +static float check_zone(WipeZone *wipezone, int x, int y, + Sequence *seq, float facf0) +{ + float posx, posy,hyp,hyp2,angle,hwidth,b1,b2,b3,pointdist; +/*some future stuff +float hyp3,hyp4,b4,b5 +*/ + float temp1,temp2,temp3,temp4; //some placeholder variables + int xo = wipezone->xo; + int yo = wipezone->yo; + float halfx = xo*0.5f; + float halfy = yo*0.5f; + float widthf,output=0; + WipeVars *wipe = (WipeVars *)seq->effectdata; + int width; + + if(wipezone->flip) x = xo - x; + angle = wipezone->angle; + + posy = facf0 * yo; + + if(wipe->forward){ + posx = facf0 * xo; + posy = facf0 * yo; + } else{ + posx = xo - facf0 * xo; + posy = yo - facf0 * yo; + } + + switch (wipe->wipetype) { + case DO_SINGLE_WIPE: + width = wipezone->width; + hwidth = width*0.5f; + + if(angle == 0.0f) { + b1 = posy; + b2 = y; + hyp = fabs(y - posy); + } + else { + b1 = posy - (-angle)*posx; + b2 = y - (-angle)*x; + hyp = fabs(angle*x+y+(-posy-angle*posx))*wipezone->pythangle; + } + + if(angle < 0) { + temp1 = b1; + b1 = b2; + b2 = temp1; + } + + if(wipe->forward) { + if(b1 < b2) + output = in_band(wipezone,width,hyp,facf0,1,1); + else + output = in_band(wipezone,width,hyp,facf0,0,1); + } + else { + if(b1 < b2) + output = in_band(wipezone,width,hyp,facf0,0,1); + else + output = in_band(wipezone,width,hyp,facf0,1,1); + } + break; + + case DO_DOUBLE_WIPE: + if(!wipe->forward) + facf0 = 1.0f-facf0; // Go the other direction + + width = wipezone->width; // calculate the blur width + hwidth = width*0.5f; + if (angle == 0) { + b1 = posy*0.5f; + b3 = yo-posy*0.5f; + b2 = y; + + hyp = abs(y - posy*0.5f); + hyp2 = abs(y - (yo-posy*0.5f)); + } + else { + b1 = posy*0.5f - (-angle)*posx*0.5f; + b3 = (yo-posy*0.5f) - (-angle)*(xo-posx*0.5f); + b2 = y - (-angle)*x; + + hyp = abs(angle*x+y+(-posy*0.5f-angle*posx*0.5f))*wipezone->pythangle; + hyp2 = abs(angle*x+y+(-(yo-posy*0.5f)-angle*(xo-posx*0.5f)))*wipezone->pythangle; + } + + temp1 = xo*(1-facf0*0.5f)-xo*facf0*0.5f; + temp2 = yo*(1-facf0*0.5f)-yo*facf0*0.5f; + pointdist = sqrt(temp1*temp1 + temp2*temp2); + + if(b2 < b1 && b2 < b3 ){ + if(hwidth < pointdist) + output = in_band(wipezone,hwidth,hyp,facf0,0,1); + } else if(b2 > b1 && b2 > b3 ){ + if(hwidth < pointdist) + output = in_band(wipezone,hwidth,hyp2,facf0,0,1); + } else { + if( hyp < hwidth && hyp2 > hwidth ) + output = in_band(wipezone,hwidth,hyp,facf0,1,1); + else if( hyp > hwidth && hyp2 < hwidth ) + output = in_band(wipezone,hwidth,hyp2,facf0,1,1); + else + output = in_band(wipezone,hwidth,hyp2,facf0,1,1) * in_band(wipezone,hwidth,hyp,facf0,1,1); + } + if(!wipe->forward)output = 1-output; + break; + case DO_CLOCK_WIPE: + /* + temp1: angle of effect center in rads + temp2: angle of line through (halfx,halfy) and (x,y) in rads + temp3: angle of low side of blur + temp4: angle of high side of blur + */ + output = 1.0f - facf0; + widthf = wipe->edgeWidth*2.0f*(float)M_PI; + temp1 = 2.0f * (float)M_PI * facf0; + + if(wipe->forward){ + temp1 = 2.0f*(float)M_PI - temp1; + } + + x = x - halfx; + y = y - halfy; + + temp2 = asin(abs(y)/sqrt(x*x + y*y)); + if(x <= 0 && y >= 0) temp2 = (float)M_PI - temp2; + else if(x<=0 && y <= 0) temp2 += (float)M_PI; + else if(x >= 0 && y <= 0) temp2 = 2.0f*(float)M_PI - temp2; + + if(wipe->forward){ + temp3 = temp1-(widthf*0.5f)*facf0; + temp4 = temp1+(widthf*0.5f)*(1-facf0); + } else{ + temp3 = temp1-(widthf*0.5f)*(1-facf0); + temp4 = temp1+(widthf*0.5f)*facf0; + } + if (temp3 < 0) temp3 = 0; + if (temp4 > 2.0f*(float)M_PI) temp4 = 2.0f*(float)M_PI; + + + if(temp2 < temp3) output = 0; + else if (temp2 > temp4) output = 1; + else output = (temp2-temp3)/(temp4-temp3); + if(x == 0 && y == 0) output = 1; + if(output != output) output = 1; + if(wipe->forward) output = 1 - output; + break; + /* BOX WIPE IS NOT WORKING YET */ + /* case DO_CROSS_WIPE: */ + /* BOX WIPE IS NOT WORKING YET */ + /* + case DO_BOX_WIPE: + if(invert)facf0 = 1-facf0; + + width = (int)(wipe->edgeWidth*((xo+yo)/2.0)); + hwidth = (float)width/2.0; + if (angle == 0)angle = 0.000001; + b1 = posy/2 - (-angle)*posx/2; + b3 = (yo-posy/2) - (-angle)*(xo-posx/2); + b2 = y - (-angle)*x; + + hyp = abs(angle*x+y+(-posy/2-angle*posx/2))*wipezone->pythangle; + hyp2 = abs(angle*x+y+(-(yo-posy/2)-angle*(xo-posx/2)))*wipezone->pythangle; + + temp1 = xo*(1-facf0/2)-xo*facf0/2; + temp2 = yo*(1-facf0/2)-yo*facf0/2; + pointdist = sqrt(temp1*temp1 + temp2*temp2); + + if(b2 < b1 && b2 < b3 ){ + if(hwidth < pointdist) + output = in_band(wipezone,hwidth,hyp,facf0,0,1); + } else if(b2 > b1 && b2 > b3 ){ + if(hwidth < pointdist) + output = in_band(wipezone,hwidth,hyp2,facf0,0,1); + } else { + if( hyp < hwidth && hyp2 > hwidth ) + output = in_band(wipezone,hwidth,hyp,facf0,1,1); + else if( hyp > hwidth && hyp2 < hwidth ) + output = in_band(wipezone,hwidth,hyp2,facf0,1,1); + else + output = in_band(wipezone,hwidth,hyp2,facf0,1,1) * in_band(wipezone,hwidth,hyp,facf0,1,1); + } + + if(invert)facf0 = 1-facf0; + angle = -1/angle; + b1 = posy/2 - (-angle)*posx/2; + b3 = (yo-posy/2) - (-angle)*(xo-posx/2); + b2 = y - (-angle)*x; + + hyp = abs(angle*x+y+(-posy/2-angle*posx/2))*wipezone->pythangle; + hyp2 = abs(angle*x+y+(-(yo-posy/2)-angle*(xo-posx/2)))*wipezone->pythangle; + + if(b2 < b1 && b2 < b3 ){ + if(hwidth < pointdist) + output *= in_band(wipezone,hwidth,hyp,facf0,0,1); + } else if(b2 > b1 && b2 > b3 ){ + if(hwidth < pointdist) + output *= in_band(wipezone,hwidth,hyp2,facf0,0,1); + } else { + if( hyp < hwidth && hyp2 > hwidth ) + output *= in_band(wipezone,hwidth,hyp,facf0,1,1); + else if( hyp > hwidth && hyp2 < hwidth ) + output *= in_band(wipezone,hwidth,hyp2,facf0,1,1); + else + output *= in_band(wipezone,hwidth,hyp2,facf0,1,1) * in_band(wipezone,hwidth,hyp,facf0,1,1); + } + + break; +*/ + case DO_IRIS_WIPE: + if(xo > yo) yo = xo; + else xo = yo; + + if(!wipe->forward) facf0 = 1-facf0; + + width = wipezone->width; + hwidth = width*0.5f; + + temp1 = (halfx-(halfx)*facf0); + pointdist = sqrt(temp1*temp1 + temp1*temp1); + + temp2 = sqrt((halfx-x)*(halfx-x) + (halfy-y)*(halfy-y)); + if(temp2 > pointdist) output = in_band(wipezone,hwidth,fabs(temp2-pointdist),facf0,0,1); + else output = in_band(wipezone,hwidth,fabs(temp2-pointdist),facf0,1,1); + + if(!wipe->forward) output = 1-output; + + break; + } + if (output < 0) output = 0; + else if(output > 1) output = 1; + return output; +} + +static void init_wipe_effect(Sequence *seq) +{ + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = MEM_callocN(sizeof(struct WipeVars), "wipevars"); +} + +static int num_inputs_wipe() +{ + return 1; +} + +static void free_wipe_effect(Sequence *seq) +{ + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = 0; +} + +static void copy_wipe_effect(Sequence *dst, Sequence *src) +{ + dst->effectdata = MEM_dupallocN(src->effectdata); +} + +static void do_wipe_effect_byte(Sequence *seq, float facf0, float facf1, + int x, int y, + unsigned char *rect1, + unsigned char *rect2, unsigned char *out) +{ + WipeZone wipezone; + WipeVars *wipe = (WipeVars *)seq->effectdata; + int xo, yo; + char *rt1, *rt2, *rt; + + precalc_wipe_zone(&wipezone, wipe, x, y); + + rt1 = (char *)rect1; + rt2 = (char *)rect2; + rt = (char *)out; + + xo = x; + yo = y; + for(y=0;y<yo;y++) { + for(x=0;x<xo;x++) { + float check = check_zone(&wipezone,x,y,seq,facf0); + if (check) { + if (rt1) { + rt[0] = (int)(rt1[0]*check)+ (int)(rt2[0]*(1-check)); + rt[1] = (int)(rt1[1]*check)+ (int)(rt2[1]*(1-check)); + rt[2] = (int)(rt1[2]*check)+ (int)(rt2[2]*(1-check)); + rt[3] = (int)(rt1[3]*check)+ (int)(rt2[3]*(1-check)); + } else { + rt[0] = 0; + rt[1] = 0; + rt[2] = 0; + rt[3] = 255; + } + } else { + if (rt2) { + rt[0] = rt2[0]; + rt[1] = rt2[1]; + rt[2] = rt2[2]; + rt[3] = rt2[3]; + } else { + rt[0] = 0; + rt[1] = 0; + rt[2] = 0; + rt[3] = 255; + } + } + + rt+=4; + if(rt1 !=NULL){ + rt1+=4; + } + if(rt2 !=NULL){ + rt2+=4; + } + } + } +} + +static void do_wipe_effect_float(Sequence *seq, float facf0, float facf1, + int x, int y, + float *rect1, + float *rect2, float *out) +{ + WipeZone wipezone; + WipeVars *wipe = (WipeVars *)seq->effectdata; + int xo, yo; + float *rt1, *rt2, *rt; + + precalc_wipe_zone(&wipezone, wipe, x, y); + + rt1 = rect1; + rt2 = rect2; + rt = out; + + xo = x; + yo = y; + for(y=0;y<yo;y++) { + for(x=0;x<xo;x++) { + float check = check_zone(&wipezone,x,y,seq,facf0); + if (check) { + if (rt1) { + rt[0] = rt1[0]*check+ rt2[0]*(1-check); + rt[1] = rt1[1]*check+ rt2[1]*(1-check); + rt[2] = rt1[2]*check+ rt2[2]*(1-check); + rt[3] = rt1[3]*check+ rt2[3]*(1-check); + } else { + rt[0] = 0; + rt[1] = 0; + rt[2] = 0; + rt[3] = 1.0; + } + } else { + if (rt2) { + rt[0] = rt2[0]; + rt[1] = rt2[1]; + rt[2] = rt2[2]; + rt[3] = rt2[3]; + } else { + rt[0] = 0; + rt[1] = 0; + rt[2] = 0; + rt[3] = 1.0; + } + } + + rt+=4; + if(rt1 !=NULL){ + rt1+=4; + } + if(rt2 !=NULL){ + rt2+=4; + } + } + } +} + +static void do_wipe_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_wipe_effect_float(seq, + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_wipe_effect_byte(seq, + facf0, facf1, x, y, + (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect, + (unsigned char*) out->rect); + } +} +/* ********************************************************************** + TRANSFORM + ********************************************************************** */ +static void init_transform_effect(Sequence *seq) +{ + TransformVars *scale; + + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = MEM_callocN(sizeof(struct TransformVars), "transformvars"); + + scale = (TransformVars *)seq->effectdata; + scale->ScalexIni = 1; + scale->ScaleyIni = 1; + scale->ScalexFin = 1; + scale->ScaleyFin = 1; + + scale->xIni=0; + scale->xFin=0; + scale->yIni=0; + scale->yFin=0; + + scale->rotIni=0; + scale->rotFin=0; + + scale->interpolation=1; + scale->percent=1; +} + +static int num_inputs_transform() +{ + return 1; +} + +static void free_transform_effect(Sequence *seq) +{ + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = 0; +} + +static void copy_transform_effect(Sequence *dst, Sequence *src) +{ + dst->effectdata = MEM_dupallocN(src->effectdata); +} + +static void do_transform(Sequence * seq,float facf0, int x, int y, + struct ImBuf *ibuf1,struct ImBuf *out) +{ + int xo, yo, xi, yi; + float xs,ys,factxScale,factyScale,tx,ty,rad,s,c,xaux,yaux,factRot,px,py; + TransformVars *scale; + + // XXX struct RenderData *rd = NULL; // 2.5 global: &G.scene->r; + + + scale = (TransformVars *)seq->effectdata; + xo = x; + yo = y; + + //factor scale + factxScale = scale->ScalexIni + (scale->ScalexFin - scale->ScalexIni) * facf0; + factyScale = scale->ScaleyIni + (scale->ScaleyFin - scale->ScaleyIni) * facf0; + + //Factor translate + if(!scale->percent){ + float rd_s = 0.0f; // XXX 2.5 global: (rd->size / 100.0f); + + tx = scale->xIni * rd_s+(xo / 2.0f) + (scale->xFin * rd_s -(xo / 2.0f) - scale->xIni * rd_s +(xo / 2.0f)) * facf0; + ty = scale->yIni * rd_s+(yo / 2.0f) + (scale->yFin * rd_s -(yo / 2.0f) - scale->yIni * rd_s +(yo / 2.0f)) * facf0; + }else{ + tx = xo*(scale->xIni/100.0f)+(xo / 2.0f) + (xo*(scale->xFin/100.0f)-(xo / 2.0f) - xo*(scale->xIni/100.0f)+(xo / 2.0f)) * facf0; + ty = yo*(scale->yIni/100.0f)+(yo / 2.0f) + (yo*(scale->yFin/100.0f)-(yo / 2.0f) - yo*(scale->yIni/100.0f)+(yo / 2.0f)) * facf0; + } + + //factor Rotate + factRot = scale->rotIni + (scale->rotFin - scale->rotIni) * facf0; + rad = (M_PI * factRot) / 180.0f; + s= sin(rad); + c= cos(rad); + + + for (yi = 0; yi < yo; yi++) { + for (xi = 0; xi < xo; xi++) { + //tranlate point + px = xi-tx; + py = yi-ty; + + //rotate point with center ref + xaux = c*px + py*s ; + yaux = -s*px + c*py; + + //scale point with center ref + xs = xaux / factxScale; + ys = yaux / factyScale; + + //undo reference center point + xs += (xo / 2.0f); + ys += (yo / 2.0f); + + //interpolate + switch(scale->interpolation) { + case 0: + neareast_interpolation(ibuf1,out, xs,ys,xi,yi); + break; + case 1: + bilinear_interpolation(ibuf1,out, xs,ys,xi,yi); + break; + case 2: + bicubic_interpolation(ibuf1,out, xs,ys,xi,yi); + break; + } + } + } + +} +static void do_transform_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + do_transform(seq, facf0, x, y, ibuf1, out); +} + + +/* ********************************************************************** + GLOW + ********************************************************************** */ + +static void RVBlurBitmap2_byte ( unsigned char* map, int width,int height, + float blur, + int quality) +/* MUUUCCH better than the previous blur. */ +/* We do the blurring in two passes which is a whole lot faster. */ +/* I changed the math arount to implement an actual Gaussian */ +/* distribution. */ +/* */ +/* Watch out though, it tends to misbehaven with large blur values on */ +/* a small bitmap. Avoid avoid avoid. */ +/*=============================== */ +{ + unsigned char* temp=NULL,*swap; + float *filter=NULL; + int x,y,i,fx,fy; + int index, ix, halfWidth; + float fval, k, curColor[3], curColor2[3], weight=0; + + /* If we're not really blurring, bail out */ + if (blur<=0) + return; + + /* Allocate memory for the tempmap and the blur filter matrix */ + temp= MEM_mallocN( (width*height*4), "blurbitmaptemp"); + if (!temp) + return; + + /* Allocate memory for the filter elements */ + halfWidth = ((quality+1)*blur); + filter = (float *)MEM_mallocN(sizeof(float)*halfWidth*2, "blurbitmapfilter"); + if (!filter){ + MEM_freeN (temp); + return; + } + + /* Apparently we're calculating a bell curve */ + /* based on the standard deviation (or radius) */ + /* This code is based on an example */ + /* posted to comp.graphics.algorithms by */ + /* Blancmange (bmange@airdmhor.gen.nz) */ + + k = -1.0/(2.0*3.14159*blur*blur); + fval=0; + for (ix = 0;ix< halfWidth;ix++){ + weight = (float)exp(k*(ix*ix)); + filter[halfWidth - ix] = weight; + filter[halfWidth + ix] = weight; + } + filter[0] = weight; + + /* Normalize the array */ + fval=0; + for (ix = 0;ix< halfWidth*2;ix++) + fval+=filter[ix]; + + for (ix = 0;ix< halfWidth*2;ix++) + filter[ix]/=fval; + + /* Blur the rows */ + for (y=0;y<height;y++){ + /* Do the left & right strips */ + for (x=0;x<halfWidth;x++){ + index=(x+y*width)*4; + fx=0; + curColor[0]=curColor[1]=curColor[2]=0; + curColor2[0]=curColor2[1]=curColor2[2]=0; + + for (i=x-halfWidth;i<x+halfWidth;i++){ + if ((i>=0)&&(i<width)){ + curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx]; + curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx]; + curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx]; + + curColor2[0]+=map[(width-1-i+y*width)*4+GlowR] * + filter[fx]; + curColor2[1]+=map[(width-1-i+y*width)*4+GlowG] * + filter[fx]; + curColor2[2]+=map[(width-1-i+y*width)*4+GlowB] * + filter[fx]; + } + fx++; + } + temp[index+GlowR]=curColor[0]; + temp[index+GlowG]=curColor[1]; + temp[index+GlowB]=curColor[2]; + + temp[((width-1-x+y*width)*4)+GlowR]=curColor2[0]; + temp[((width-1-x+y*width)*4)+GlowG]=curColor2[1]; + temp[((width-1-x+y*width)*4)+GlowB]=curColor2[2]; + + } + /* Do the main body */ + for (x=halfWidth;x<width-halfWidth;x++){ + index=(x+y*width)*4; + fx=0; + curColor[0]=curColor[1]=curColor[2]=0; + for (i=x-halfWidth;i<x+halfWidth;i++){ + curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx]; + curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx]; + curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx]; + fx++; + } + temp[index+GlowR]=curColor[0]; + temp[index+GlowG]=curColor[1]; + temp[index+GlowB]=curColor[2]; + } + } + + /* Swap buffers */ + swap=temp;temp=map;map=swap; + + + /* Blur the columns */ + for (x=0;x<width;x++){ + /* Do the top & bottom strips */ + for (y=0;y<halfWidth;y++){ + index=(x+y*width)*4; + fy=0; + curColor[0]=curColor[1]=curColor[2]=0; + curColor2[0]=curColor2[1]=curColor2[2]=0; + for (i=y-halfWidth;i<y+halfWidth;i++){ + if ((i>=0)&&(i<height)){ + /* Bottom */ + curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy]; + curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy]; + curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy]; + + /* Top */ + curColor2[0]+=map[(x+(height-1-i)*width) * + 4+GlowR]*filter[fy]; + curColor2[1]+=map[(x+(height-1-i)*width) * + 4+GlowG]*filter[fy]; + curColor2[2]+=map[(x+(height-1-i)*width) * + 4+GlowB]*filter[fy]; + } + fy++; + } + temp[index+GlowR]=curColor[0]; + temp[index+GlowG]=curColor[1]; + temp[index+GlowB]=curColor[2]; + temp[((x+(height-1-y)*width)*4)+GlowR]=curColor2[0]; + temp[((x+(height-1-y)*width)*4)+GlowG]=curColor2[1]; + temp[((x+(height-1-y)*width)*4)+GlowB]=curColor2[2]; + } + /* Do the main body */ + for (y=halfWidth;y<height-halfWidth;y++){ + index=(x+y*width)*4; + fy=0; + curColor[0]=curColor[1]=curColor[2]=0; + for (i=y-halfWidth;i<y+halfWidth;i++){ + curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy]; + curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy]; + curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy]; + fy++; + } + temp[index+GlowR]=curColor[0]; + temp[index+GlowG]=curColor[1]; + temp[index+GlowB]=curColor[2]; + } + } + + + /* Swap buffers */ + swap=temp;temp=map;map=swap; + + /* Tidy up */ + MEM_freeN (filter); + MEM_freeN (temp); +} + +static void RVBlurBitmap2_float ( float* map, int width,int height, + float blur, + int quality) +/* MUUUCCH better than the previous blur. */ +/* We do the blurring in two passes which is a whole lot faster. */ +/* I changed the math arount to implement an actual Gaussian */ +/* distribution. */ +/* */ +/* Watch out though, it tends to misbehaven with large blur values on */ +/* a small bitmap. Avoid avoid avoid. */ +/*=============================== */ +{ + float* temp=NULL,*swap; + float *filter=NULL; + int x,y,i,fx,fy; + int index, ix, halfWidth; + float fval, k, curColor[3], curColor2[3], weight=0; + + /* If we're not really blurring, bail out */ + if (blur<=0) + return; + + /* Allocate memory for the tempmap and the blur filter matrix */ + temp= MEM_mallocN( (width*height*4*sizeof(float)), "blurbitmaptemp"); + if (!temp) + return; + + /* Allocate memory for the filter elements */ + halfWidth = ((quality+1)*blur); + filter = (float *)MEM_mallocN(sizeof(float)*halfWidth*2, "blurbitmapfilter"); + if (!filter){ + MEM_freeN (temp); + return; + } + + /* Apparently we're calculating a bell curve */ + /* based on the standard deviation (or radius) */ + /* This code is based on an example */ + /* posted to comp.graphics.algorithms by */ + /* Blancmange (bmange@airdmhor.gen.nz) */ + + k = -1.0/(2.0*3.14159*blur*blur); + fval=0; + for (ix = 0;ix< halfWidth;ix++){ + weight = (float)exp(k*(ix*ix)); + filter[halfWidth - ix] = weight; + filter[halfWidth + ix] = weight; + } + filter[0] = weight; + + /* Normalize the array */ + fval=0; + for (ix = 0;ix< halfWidth*2;ix++) + fval+=filter[ix]; + + for (ix = 0;ix< halfWidth*2;ix++) + filter[ix]/=fval; + + /* Blur the rows */ + for (y=0;y<height;y++){ + /* Do the left & right strips */ + for (x=0;x<halfWidth;x++){ + index=(x+y*width)*4; + fx=0; + curColor[0]=curColor[1]=curColor[2]=0.0f; + curColor2[0]=curColor2[1]=curColor2[2]=0.0f; + + for (i=x-halfWidth;i<x+halfWidth;i++){ + if ((i>=0)&&(i<width)){ + curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx]; + curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx]; + curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx]; + + curColor2[0]+=map[(width-1-i+y*width)*4+GlowR] * + filter[fx]; + curColor2[1]+=map[(width-1-i+y*width)*4+GlowG] * + filter[fx]; + curColor2[2]+=map[(width-1-i+y*width)*4+GlowB] * + filter[fx]; + } + fx++; + } + temp[index+GlowR]=curColor[0]; + temp[index+GlowG]=curColor[1]; + temp[index+GlowB]=curColor[2]; + + temp[((width-1-x+y*width)*4)+GlowR]=curColor2[0]; + temp[((width-1-x+y*width)*4)+GlowG]=curColor2[1]; + temp[((width-1-x+y*width)*4)+GlowB]=curColor2[2]; + + } + /* Do the main body */ + for (x=halfWidth;x<width-halfWidth;x++){ + index=(x+y*width)*4; + fx=0; + curColor[0]=curColor[1]=curColor[2]=0; + for (i=x-halfWidth;i<x+halfWidth;i++){ + curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx]; + curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx]; + curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx]; + fx++; + } + temp[index+GlowR]=curColor[0]; + temp[index+GlowG]=curColor[1]; + temp[index+GlowB]=curColor[2]; + } + } + + /* Swap buffers */ + swap=temp;temp=map;map=swap; + + + /* Blur the columns */ + for (x=0;x<width;x++){ + /* Do the top & bottom strips */ + for (y=0;y<halfWidth;y++){ + index=(x+y*width)*4; + fy=0; + curColor[0]=curColor[1]=curColor[2]=0; + curColor2[0]=curColor2[1]=curColor2[2]=0; + for (i=y-halfWidth;i<y+halfWidth;i++){ + if ((i>=0)&&(i<height)){ + /* Bottom */ + curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy]; + curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy]; + curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy]; + + /* Top */ + curColor2[0]+=map[(x+(height-1-i)*width) * + 4+GlowR]*filter[fy]; + curColor2[1]+=map[(x+(height-1-i)*width) * + 4+GlowG]*filter[fy]; + curColor2[2]+=map[(x+(height-1-i)*width) * + 4+GlowB]*filter[fy]; + } + fy++; + } + temp[index+GlowR]=curColor[0]; + temp[index+GlowG]=curColor[1]; + temp[index+GlowB]=curColor[2]; + temp[((x+(height-1-y)*width)*4)+GlowR]=curColor2[0]; + temp[((x+(height-1-y)*width)*4)+GlowG]=curColor2[1]; + temp[((x+(height-1-y)*width)*4)+GlowB]=curColor2[2]; + } + /* Do the main body */ + for (y=halfWidth;y<height-halfWidth;y++){ + index=(x+y*width)*4; + fy=0; + curColor[0]=curColor[1]=curColor[2]=0; + for (i=y-halfWidth;i<y+halfWidth;i++){ + curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy]; + curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy]; + curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy]; + fy++; + } + temp[index+GlowR]=curColor[0]; + temp[index+GlowG]=curColor[1]; + temp[index+GlowB]=curColor[2]; + } + } + + + /* Swap buffers */ + swap=temp;temp=map;map=swap; + + /* Tidy up */ + MEM_freeN (filter); + MEM_freeN (temp); +} + + +/* Adds two bitmaps and puts the results into a third map. */ +/* C must have been previously allocated but it may be A or B. */ +/* We clamp values to 255 to prevent weirdness */ +/*=============================== */ +static void RVAddBitmaps_byte (unsigned char* a, unsigned char* b, unsigned char* c, int width, int height) +{ + int x,y,index; + + for (y=0;y<height;y++){ + for (x=0;x<width;x++){ + index=(x+y*width)*4; + c[index+GlowR]=MIN2(255,a[index+GlowR]+b[index+GlowR]); + c[index+GlowG]=MIN2(255,a[index+GlowG]+b[index+GlowG]); + c[index+GlowB]=MIN2(255,a[index+GlowB]+b[index+GlowB]); + c[index+GlowA]=MIN2(255,a[index+GlowA]+b[index+GlowA]); + } + } +} + +static void RVAddBitmaps_float (float* a, float* b, float* c, + int width, int height) +{ + int x,y,index; + + for (y=0;y<height;y++){ + for (x=0;x<width;x++){ + index=(x+y*width)*4; + c[index+GlowR]=MIN2(1.0,a[index+GlowR]+b[index+GlowR]); + c[index+GlowG]=MIN2(1.0,a[index+GlowG]+b[index+GlowG]); + c[index+GlowB]=MIN2(1.0,a[index+GlowB]+b[index+GlowB]); + c[index+GlowA]=MIN2(1.0,a[index+GlowA]+b[index+GlowA]); + } + } +} + +/* For each pixel whose total luminance exceeds the threshold, */ +/* Multiply it's value by BOOST and add it to the output map */ +static void RVIsolateHighlights_byte (unsigned char* in, unsigned char* out, + int width, int height, int threshold, + float boost, float clamp) +{ + int x,y,index; + int intensity; + + + for(y=0;y< height;y++) { + for (x=0;x< width;x++) { + index= (x+y*width)*4; + + /* Isolate the intensity */ + intensity=(in[index+GlowR]+in[index+GlowG]+in[index+GlowB]-threshold); + if (intensity>0){ + out[index+GlowR]=MIN2(255*clamp, (in[index+GlowR]*boost*intensity)/255); + out[index+GlowG]=MIN2(255*clamp, (in[index+GlowG]*boost*intensity)/255); + out[index+GlowB]=MIN2(255*clamp, (in[index+GlowB]*boost*intensity)/255); + out[index+GlowA]=MIN2(255*clamp, (in[index+GlowA]*boost*intensity)/255); + } else{ + out[index+GlowR]=0; + out[index+GlowG]=0; + out[index+GlowB]=0; + out[index+GlowA]=0; + } + } + } +} + +static void RVIsolateHighlights_float (float* in, float* out, + int width, int height, float threshold, + float boost, float clamp) +{ + int x,y,index; + float intensity; + + + for(y=0;y< height;y++) { + for (x=0;x< width;x++) { + index= (x+y*width)*4; + + /* Isolate the intensity */ + intensity=(in[index+GlowR]+in[index+GlowG]+in[index+GlowB]-threshold); + if (intensity>0){ + out[index+GlowR]=MIN2(clamp, (in[index+GlowR]*boost*intensity)); + out[index+GlowG]=MIN2(clamp, (in[index+GlowG]*boost*intensity)); + out[index+GlowB]=MIN2(clamp, (in[index+GlowB]*boost*intensity)); + out[index+GlowA]=MIN2(clamp, (in[index+GlowA]*boost*intensity)); + } else{ + out[index+GlowR]=0; + out[index+GlowG]=0; + out[index+GlowB]=0; + out[index+GlowA]=0; + } + } + } +} + +static void init_glow_effect(Sequence *seq) +{ + GlowVars *glow; + + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = MEM_callocN(sizeof(struct GlowVars), "glowvars"); + + glow = (GlowVars *)seq->effectdata; + glow->fMini = 0.25; + glow->fClamp = 1.0; + glow->fBoost = 0.5; + glow->dDist = 3.0; + glow->dQuality = 3; + glow->bNoComp = 0; +} + +static int num_inputs_glow() +{ + return 1; +} + +static void free_glow_effect(Sequence *seq) +{ + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = 0; +} + +static void copy_glow_effect(Sequence *dst, Sequence *src) +{ + dst->effectdata = MEM_dupallocN(src->effectdata); +} + +//void do_glow_effect(Cast *cast, float facf0, float facf1, int xo, int yo, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *outbuf, ImBuf *use) +static void do_glow_effect_byte(Sequence *seq, float facf0, float facf1, + int x, int y, char *rect1, + char *rect2, char *out) +{ + unsigned char *outbuf=(unsigned char *)out; + unsigned char *inbuf=(unsigned char *)rect1; + GlowVars *glow = (GlowVars *)seq->effectdata; + int size= 100; // renderdata XXX + + RVIsolateHighlights_byte(inbuf, outbuf , x, y, glow->fMini*765, glow->fBoost * facf0, glow->fClamp); + RVBlurBitmap2_byte (outbuf, x, y, glow->dDist * (size / 100.0f),glow->dQuality); + if (!glow->bNoComp) + RVAddBitmaps_byte (inbuf , outbuf, outbuf, x, y); +} + +static void do_glow_effect_float(Sequence *seq, float facf0, float facf1, + int x, int y, + float *rect1, float *rect2, float *out) +{ + float *outbuf = out; + float *inbuf = rect1; + GlowVars *glow = (GlowVars *)seq->effectdata; + int size= 100; // renderdata XXX + + RVIsolateHighlights_float(inbuf, outbuf , x, y, glow->fMini*3.0f, glow->fBoost * facf0, glow->fClamp); + RVBlurBitmap2_float (outbuf, x, y, glow->dDist * (size / 100.0f),glow->dQuality); + if (!glow->bNoComp) + RVAddBitmaps_float (inbuf , outbuf, outbuf, x, y); +} + +static void do_glow_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + if (out->rect_float) { + do_glow_effect_float(seq, + facf0, facf1, x, y, + ibuf1->rect_float, ibuf2->rect_float, + out->rect_float); + } else { + do_glow_effect_byte(seq, + facf0, facf1, x, y, + (char*) ibuf1->rect, (char*) ibuf2->rect, + (char*) out->rect); + } +} + +/* ********************************************************************** + SOLID COLOR + ********************************************************************** */ + +static void init_solid_color(Sequence *seq) +{ + SolidColorVars *cv; + + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = MEM_callocN(sizeof(struct SolidColorVars), "solidcolor"); + + cv = (SolidColorVars *)seq->effectdata; + cv->col[0] = cv->col[1] = cv->col[2] = 0.5; +} + +static int num_inputs_color() +{ + return 0; +} + +static void free_solid_color(Sequence *seq) +{ + if(seq->effectdata)MEM_freeN(seq->effectdata); + seq->effectdata = 0; +} + +static void copy_solid_color(Sequence *dst, Sequence *src) +{ + dst->effectdata = MEM_dupallocN(src->effectdata); +} + +static int early_out_color(struct Sequence *seq, + float facf0, float facf1) +{ + return -1; +} + +static void do_solid_color(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + SolidColorVars *cv = (SolidColorVars *)seq->effectdata; + + unsigned char *rect; + float *rect_float; + + if (out->rect) { + unsigned char col0[3]; + unsigned char col1[3]; + + col0[0] = facf0 * cv->col[0] * 255; + col0[1] = facf0 * cv->col[1] * 255; + col0[2] = facf0 * cv->col[2] * 255; + + col1[0] = facf1 * cv->col[0] * 255; + col1[1] = facf1 * cv->col[1] * 255; + col1[2] = facf1 * cv->col[2] * 255; + + rect = (unsigned char *)out->rect; + + for(y=0; y<out->y; y++) { + for(x=0; x<out->x; x++, rect+=4) { + rect[0]= col0[0]; + rect[1]= col0[1]; + rect[2]= col0[2]; + rect[3]= 255; + } + y++; + if (y<out->y) { + for(x=0; x<out->x; x++, rect+=4) { + rect[0]= col1[0]; + rect[1]= col1[1]; + rect[2]= col1[2]; + rect[3]= 255; + } + } + } + + } else if (out->rect_float) { + float col0[3]; + float col1[3]; + + col0[0] = facf0 * cv->col[0]; + col0[1] = facf0 * cv->col[1]; + col0[2] = facf0 * cv->col[2]; + + col1[0] = facf1 * cv->col[0]; + col1[1] = facf1 * cv->col[1]; + col1[2] = facf1 * cv->col[2]; + + rect_float = out->rect_float; + + for(y=0; y<out->y; y++) { + for(x=0; x<out->x; x++, rect_float+=4) { + rect_float[0]= col0[0]; + rect_float[1]= col0[1]; + rect_float[2]= col0[2]; + rect_float[3]= 1.0; + } + y++; + if (y<out->y) { + for(x=0; x<out->x; x++, rect_float+=4) { + rect_float[0]= col1[0]; + rect_float[1]= col1[1]; + rect_float[2]= col1[2]; + rect_float[3]= 1.0; + } + } + } + } +} + +/* ********************************************************************** + SPEED + ********************************************************************** */ +static void init_speed_effect(Sequence *seq) +{ + SpeedControlVars * v; + + if(seq->effectdata) MEM_freeN(seq->effectdata); + seq->effectdata = MEM_callocN(sizeof(struct SpeedControlVars), + "speedcontrolvars"); + + v = (SpeedControlVars *)seq->effectdata; + v->globalSpeed = 1.0; + v->frameMap = 0; + v->flags = SEQ_SPEED_COMPRESS_IPO_Y; + v->length = 0; +} + +static void load_speed_effect(Sequence * seq) +{ + SpeedControlVars * v = (SpeedControlVars *)seq->effectdata; + + v->frameMap = 0; + v->length = 0; +} + +static int num_inputs_speed() +{ + return 1; +} + +static void free_speed_effect(Sequence *seq) +{ + SpeedControlVars * v = (SpeedControlVars *)seq->effectdata; + if(v->frameMap) MEM_freeN(v->frameMap); + if(seq->effectdata) MEM_freeN(seq->effectdata); + seq->effectdata = 0; +} + +static void copy_speed_effect(Sequence *dst, Sequence *src) +{ + SpeedControlVars * v; + dst->effectdata = MEM_dupallocN(src->effectdata); + v = (SpeedControlVars *)dst->effectdata; + v->frameMap = 0; + v->length = 0; +} + +static int early_out_speed(struct Sequence *seq, + float facf0, float facf1) +{ + return 1; +} + +static void store_icu_yrange_speed(struct Sequence * seq, + short adrcode, float * ymin, float * ymax) +{ + SpeedControlVars * v = (SpeedControlVars *)seq->effectdata; + + /* if not already done, load / initialize data */ + get_sequence_effect(seq); + + if ((v->flags & SEQ_SPEED_INTEGRATE) != 0) { + *ymin = -100.0; + *ymax = 100.0; + } else { + if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) { + *ymin = 0.0; + *ymax = 1.0; + } else { + *ymin = 0.0; + *ymax = seq->len; + } + } +} + +void sequence_effect_speed_rebuild_map(Sequence * seq, int force) +{ + float facf0 = seq->facf0; + //float ctime, div; + int cfra; + float fallback_fac; + SpeedControlVars * v = (SpeedControlVars *)seq->effectdata; + + /* if not already done, load / initialize data */ + get_sequence_effect(seq); + + if (!(force || seq->len != v->length || !v->frameMap)) { + return; + } + + if (!v->frameMap || v->length != seq->len) { + if (v->frameMap) MEM_freeN(v->frameMap); + + v->length = seq->len; + + v->frameMap = MEM_callocN(sizeof(float) * v->length, + "speedcontrol frameMap"); + } + + fallback_fac = 1.0; + + /* if there is no IPO, try to make retiming easy by stretching the + strip */ + // XXX old animation system - seq + if (/*!seq->ipo &&*/ seq->seq1 && seq->seq1->enddisp != seq->seq1->start + && seq->seq1->len != 0) { + fallback_fac = (float) seq->seq1->len / + (float) (seq->seq1->enddisp - seq->seq1->start); + /* FIXME: this strip stretching gets screwed by stripdata + handling one layer up. + + So it currently works by enlarging, never by shrinking! + + (IPOs still work, if used correctly) + */ + if (fallback_fac > 1.0) { + fallback_fac = 1.0; + } + } + + if ((v->flags & SEQ_SPEED_INTEGRATE) != 0) { + float cursor = 0; + + v->frameMap[0] = 0; + v->lastValidFrame = 0; + + for (cfra = 1; cfra < v->length; cfra++) { +#if 0 // XXX old animation system + if(seq->ipo) { + if((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) { + ctime = frame_to_float(scene, seq->startdisp + cfra); + div = 1.0; + } else { + ctime= frame_to_float(scene, cfra); + div= v->length / 100.0f; + if(div==0.0) return; + } + + calc_ipo(seq->ipo, ctime/div); + execute_ipo((ID *)seq, seq->ipo); + } else +#endif // XXX old animation system + { + seq->facf0 = fallback_fac; + } + seq->facf0 *= v->globalSpeed; + + cursor += seq->facf0; + + if (cursor >= v->length) { + v->frameMap[cfra] = v->length - 1; + } else { + v->frameMap[cfra] = cursor; + v->lastValidFrame = cfra; + } + } + } else { + v->lastValidFrame = 0; + for (cfra = 0; cfra < v->length; cfra++) { +#if 0 // XXX old animation system + if(seq->ipo) { + if((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) { + ctime = frame_to_float(scene, seq->startdisp + cfra); + div = 1.0; + } else { + ctime= frame_to_float(scene, cfra); + div= v->length / 100.0f; + if(div==0.0) return; + } + + calc_ipo(seq->ipo, ctime/div); + execute_ipo((ID *)seq, seq->ipo); + } +#endif // XXX old animation system + + if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) { + seq->facf0 *= v->length; + } + if (/*!seq->ipo*/ 1) { // XXX old animation system - seq + seq->facf0 = (float) cfra * fallback_fac; + } + seq->facf0 *= v->globalSpeed; + if (seq->facf0 >= v->length) { + seq->facf0 = v->length - 1; + } else { + v->lastValidFrame = cfra; + } + v->frameMap[cfra] = seq->facf0; + } + } + seq->facf0 = facf0; +} + +/* + simply reuse do_cross_effect for blending... + +static void do_speed_effect(Sequence * seq,int cfra, + float facf0, float facf1, int x, int y, + struct ImBuf *ibuf1, struct ImBuf *ibuf2, + struct ImBuf *ibuf3, struct ImBuf *out) +{ + +} +*/ + + +/* ********************************************************************** + sequence effect factory + ********************************************************************** */ + + +static void init_noop(struct Sequence *seq) +{ + +} + +static void load_noop(struct Sequence *seq) +{ + +} + +static void init_plugin_noop(struct Sequence *seq, const char * fname) +{ + +} + +static void free_noop(struct Sequence *seq) +{ + +} + +static int num_inputs_default() +{ + return 2; +} + +static int early_out_noop(struct Sequence *seq, + float facf0, float facf1) +{ + return 0; +} + +static int early_out_fade(struct Sequence *seq, + float facf0, float facf1) +{ + if (facf0 == 0.0 && facf1 == 0.0) { + return 1; + } else if (facf0 == 1.0 && facf1 == 1.0) { + return 2; + } + return 0; +} + +static int early_out_mul_input2(struct Sequence *seq, + float facf0, float facf1) +{ + if (facf0 == 0.0 && facf1 == 0.0) { + return 1; + } + return 0; +} + +static void store_icu_yrange_noop(struct Sequence * seq, + short adrcode, float * ymin, float * ymax) +{ + /* defaults are fine */ +} + +static void get_default_fac_noop(struct Sequence *seq, int cfra, + float * facf0, float * facf1) +{ + *facf0 = *facf1 = 1.0; +} + +static void get_default_fac_fade(struct Sequence *seq, int cfra, + float * facf0, float * facf1) +{ + *facf0 = (float)(cfra - seq->startdisp); + *facf1 = (float)(*facf0 + 0.5); + *facf0 /= seq->len; + *facf1 /= seq->len; +} + +static void do_overdrop_effect(struct Sequence * seq, int cfra, + float fac, float facf, + int x, int y, struct ImBuf * ibuf1, + struct ImBuf * ibuf2, + struct ImBuf * ibuf3, + struct ImBuf * out) +{ + do_drop_effect(seq, cfra, fac, facf, x, y, + ibuf1, ibuf2, ibuf3, out); + do_alphaover_effect(seq, cfra, fac, facf, x, y, + ibuf1, ibuf2, ibuf3, out); +} + +static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) +{ + struct SeqEffectHandle rval; + int sequence_type = seq_type; + + rval.init = init_noop; + rval.init_plugin = init_plugin_noop; + rval.num_inputs = num_inputs_default; + rval.load = load_noop; + rval.free = free_noop; + rval.early_out = early_out_noop; + rval.get_default_fac = get_default_fac_noop; + rval.store_icu_yrange = store_icu_yrange_noop; + rval.execute = NULL; + rval.copy = NULL; + + switch (sequence_type) { + case SEQ_CROSS: + rval.execute = do_cross_effect; + rval.early_out = early_out_fade; + rval.get_default_fac = get_default_fac_fade; + break; + case SEQ_GAMCROSS: + rval.init = init_gammacross; + rval.load = load_gammacross; + rval.free = free_gammacross; + rval.early_out = early_out_fade; + rval.get_default_fac = get_default_fac_fade; + rval.execute = do_gammacross_effect; + break; + case SEQ_ADD: + rval.execute = do_add_effect; + rval.early_out = early_out_mul_input2; + break; + case SEQ_SUB: + rval.execute = do_sub_effect; + rval.early_out = early_out_mul_input2; + break; + case SEQ_MUL: + rval.execute = do_mul_effect; + rval.early_out = early_out_mul_input2; + break; + case SEQ_ALPHAOVER: + rval.init = init_alpha_over_or_under; + rval.execute = do_alphaover_effect; + break; + case SEQ_OVERDROP: + rval.execute = do_overdrop_effect; + break; + case SEQ_ALPHAUNDER: + rval.init = init_alpha_over_or_under; + rval.execute = do_alphaunder_effect; + break; + case SEQ_WIPE: + rval.init = init_wipe_effect; + rval.num_inputs = num_inputs_wipe; + rval.free = free_wipe_effect; + rval.copy = copy_wipe_effect; + rval.early_out = early_out_fade; + rval.get_default_fac = get_default_fac_fade; + rval.execute = do_wipe_effect; + break; + case SEQ_GLOW: + rval.init = init_glow_effect; + rval.num_inputs = num_inputs_glow; + rval.free = free_glow_effect; + rval.copy = copy_glow_effect; + rval.execute = do_glow_effect; + break; + case SEQ_TRANSFORM: + rval.init = init_transform_effect; + rval.num_inputs = num_inputs_transform; + rval.free = free_transform_effect; + rval.copy = copy_transform_effect; + rval.execute = do_transform_effect; + break; + case SEQ_SPEED: + rval.init = init_speed_effect; + rval.num_inputs = num_inputs_speed; + rval.load = load_speed_effect; + rval.free = free_speed_effect; + rval.copy = copy_speed_effect; + rval.execute = do_cross_effect; + rval.early_out = early_out_speed; + rval.store_icu_yrange = store_icu_yrange_speed; + break; + case SEQ_COLOR: + rval.init = init_solid_color; + rval.num_inputs = num_inputs_color; + rval.early_out = early_out_color; + rval.free = free_solid_color; + rval.copy = copy_solid_color; + rval.execute = do_solid_color; + break; + case SEQ_PLUGIN: + rval.init_plugin = init_plugin; + rval.num_inputs = num_inputs_plugin; + rval.load = load_plugin; + rval.free = free_plugin; + rval.copy = copy_plugin; + rval.execute = do_plugin_effect; + rval.early_out = do_plugin_early_out; + rval.get_default_fac = get_default_fac_fade; + break; + } + + return rval; +} + + +struct SeqEffectHandle get_sequence_effect(Sequence * seq) +{ + struct SeqEffectHandle rval; + + memset(&rval, 0, sizeof(struct SeqEffectHandle)); + + if (seq->type & SEQ_EFFECT) { + rval = get_sequence_effect_impl(seq->type); + if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) { + rval.load(seq); + seq->flag &= ~SEQ_EFFECT_NOT_LOADED; + } + } + + return rval; +} + +struct SeqEffectHandle get_sequence_blend(Sequence * seq) +{ + struct SeqEffectHandle rval; + + memset(&rval, 0, sizeof(struct SeqEffectHandle)); + + if (seq->blend_mode != 0) { + rval = get_sequence_effect_impl(seq->blend_mode); + if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) { + rval.load(seq); + seq->flag &= ~SEQ_EFFECT_NOT_LOADED; + } + } + + return rval; +} + +int get_sequence_effect_num_inputs(int seq_type) +{ + struct SeqEffectHandle rval = get_sequence_effect_impl(seq_type); + + int cnt = rval.num_inputs(); + if (rval.execute) { + return cnt; + } + return 0; +} diff --git a/source/blender/blenkernel/intern/sequence.c b/source/blender/blenkernel/intern/sequence.c new file mode 100644 index 00000000000..159a60ad3af --- /dev/null +++ b/source/blender/blenkernel/intern/sequence.c @@ -0,0 +1,3414 @@ +/** +* $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): + * - Blender Foundation, 2003-2009 + * - Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "MEM_guardedalloc.h" +#include "MEM_CacheLimiterC-Api.h" + +#include "DNA_listBase.h" +#include "DNA_sequence_types.h" +#include "DNA_scene_types.h" + +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_sequence.h" +#include "BKE_utildefines.h" + +#include "BLI_blenlib.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "BLI_threads.h" +#include <pthread.h> + +#include "BKE_context.h" +#include "BKE_sound.h" +#include "AUD_C-API.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +/* **** XXX ******** */ +static int seqrectx= 0; /* bad bad global! */ +static int seqrecty= 0; +static void waitcursor(int val) {} +static int blender_test_break() {return 0;} + +/* **** XXX ******** */ + + +/* ********************************************************************** + alloc / free functions + ********************************************************************** */ + +static void free_tstripdata(int len, TStripElem *se) +{ + TStripElem *seo; + int a; + + seo= se; + if (!se) + return; + + for(a=0; a<len; a++, se++) { + if(se->ibuf) { + IMB_freeImBuf(se->ibuf); + se->ibuf = 0; + } + if(se->ibuf_comp) { + IMB_freeImBuf(se->ibuf_comp); + se->ibuf_comp = 0; + } + } + + MEM_freeN(seo); +} + + +void new_tstripdata(Sequence *seq) +{ + if(seq->strip) { + free_tstripdata(seq->strip->len, seq->strip->tstripdata); + free_tstripdata(seq->strip->endstill, + seq->strip->tstripdata_endstill); + free_tstripdata(seq->strip->startstill, + seq->strip->tstripdata_startstill); + + seq->strip->tstripdata= 0; + seq->strip->tstripdata_endstill= 0; + seq->strip->tstripdata_startstill= 0; + + if(seq->strip->ibuf_startstill) { + IMB_freeImBuf(seq->strip->ibuf_startstill); + seq->strip->ibuf_startstill = 0; + } + + if(seq->strip->ibuf_endstill) { + IMB_freeImBuf(seq->strip->ibuf_endstill); + seq->strip->ibuf_endstill = 0; + } + + seq->strip->len= seq->len; + } +} + + +/* free */ + +void free_proxy_seq(Sequence *seq) +{ + if (seq->strip && seq->strip->proxy && seq->strip->proxy->anim) { + IMB_free_anim(seq->strip->proxy->anim); + seq->strip->proxy->anim = 0; + } +} + +void seq_free_strip(Strip *strip) +{ + strip->us--; + if(strip->us>0) return; + if(strip->us<0) { + printf("error: negative users in strip\n"); + return; + } + + if (strip->stripdata) { + MEM_freeN(strip->stripdata); + } + + if (strip->proxy) { + if (strip->proxy->anim) { + IMB_free_anim(strip->proxy->anim); + } + + MEM_freeN(strip->proxy); + } + if (strip->crop) { + MEM_freeN(strip->crop); + } + if (strip->transform) { + MEM_freeN(strip->transform); + } + if (strip->color_balance) { + MEM_freeN(strip->color_balance); + } + + free_tstripdata(strip->len, strip->tstripdata); + free_tstripdata(strip->endstill, strip->tstripdata_endstill); + free_tstripdata(strip->startstill, strip->tstripdata_startstill); + + if(strip->ibuf_startstill) { + IMB_freeImBuf(strip->ibuf_startstill); + strip->ibuf_startstill = 0; + } + + if(strip->ibuf_endstill) { + IMB_freeImBuf(strip->ibuf_endstill); + strip->ibuf_endstill = 0; + } + + MEM_freeN(strip); +} + +void seq_free_sequence(Scene *scene, Sequence *seq) +{ + Editing *ed = scene->ed; + + if(seq->strip) seq_free_strip(seq->strip); + + if(seq->anim) IMB_free_anim(seq->anim); + + if(seq->sound_handle) + sound_delete_handle(scene, seq->sound_handle); + + if (seq->type & SEQ_EFFECT) { + struct SeqEffectHandle sh = get_sequence_effect(seq); + + sh.free(seq); + } + + if (ed->act_seq==seq) + ed->act_seq= NULL; + + MEM_freeN(seq); +} + +Editing *seq_give_editing(Scene *scene, int alloc) +{ + if (scene->ed == NULL && alloc) { + Editing *ed; + + ed= scene->ed= MEM_callocN( sizeof(Editing), "addseq"); + ed->seqbasep= &ed->seqbase; + } + return scene->ed; +} + +void seq_free_editing(Scene *scene) +{ + Editing *ed = scene->ed; + MetaStack *ms; + Sequence *seq; + + if(ed==NULL) + return; + + SEQ_BEGIN(ed, seq) { + seq_free_sequence(scene, seq); + } + SEQ_END + + while((ms= ed->metastack.first)) { + BLI_remlink(&ed->metastack, ms); + MEM_freeN(ms); + } + + MEM_freeN(ed); +} + +/* ************************* itterator ************************** */ +/* *************** (replaces old WHILE_SEQ) ********************* */ +/* **************** use now SEQ_BEGIN() SEQ_END ***************** */ + +/* sequence strip iterator: + * - builds a full array, recursively into meta strips */ + +static void seq_count(ListBase *seqbase, int *tot) +{ + Sequence *seq; + + for(seq=seqbase->first; seq; seq=seq->next) { + (*tot)++; + + if(seq->seqbase.first) + seq_count(&seq->seqbase, tot); + } +} + +static void seq_build_array(ListBase *seqbase, Sequence ***array, int depth) +{ + Sequence *seq; + + for(seq=seqbase->first; seq; seq=seq->next) { + seq->depth= depth; + + if(seq->seqbase.first) + seq_build_array(&seq->seqbase, array, depth+1); + + **array= seq; + (*array)++; + } +} + +void seq_array(Editing *ed, Sequence ***seqarray, int *tot, int use_pointer) +{ + Sequence **array; + + *seqarray= NULL; + *tot= 0; + + if(ed == NULL) + return; + + if(use_pointer) + seq_count(ed->seqbasep, tot); + else + seq_count(&ed->seqbase, tot); + + if(*tot == 0) + return; + + *seqarray= array= MEM_mallocN(sizeof(Sequence *)*(*tot), "SeqArray"); + if(use_pointer) + seq_build_array(ed->seqbasep, &array, 0); + else + seq_build_array(&ed->seqbase, &array, 0); +} + +void seq_begin(Editing *ed, SeqIterator *iter, int use_pointer) +{ + memset(iter, 0, sizeof(*iter)); + seq_array(ed, &iter->array, &iter->tot, use_pointer); + + if(iter->tot) { + iter->cur= 0; + iter->seq= iter->array[iter->cur]; + iter->valid= 1; + } +} + +void seq_next(SeqIterator *iter) +{ + if(++iter->cur < iter->tot) + iter->seq= iter->array[iter->cur]; + else + iter->valid= 0; +} + +void seq_end(SeqIterator *iter) +{ + if(iter->array) + MEM_freeN(iter->array); + + iter->valid= 0; +} + +/* + ********************************************************************** + * build_seqar + ********************************************************************** + * Build a complete array of _all_ sequencies (including those + * in metastrips!) + ********************************************************************** +*/ + +static void do_seq_count(ListBase *seqbase, int *totseq) +{ + Sequence *seq; + + seq= seqbase->first; + while(seq) { + (*totseq)++; + if(seq->seqbase.first) do_seq_count(&seq->seqbase, totseq); + seq= seq->next; + } +} + +static void do_build_seqar(ListBase *seqbase, Sequence ***seqar, int depth) +{ + Sequence *seq; + + seq= seqbase->first; + while(seq) { + seq->depth= depth; + if(seq->seqbase.first) do_build_seqar(&seq->seqbase, seqar, depth+1); + **seqar= seq; + (*seqar)++; + seq= seq->next; + } +} + +void build_seqar(ListBase *seqbase, Sequence ***seqar, int *totseq) +{ + Sequence **tseqar; + + *totseq= 0; + do_seq_count(seqbase, totseq); + + if(*totseq==0) { + *seqar= 0; + return; + } + *seqar= MEM_mallocN(sizeof(void *)* *totseq, "seqar"); + tseqar= *seqar; + + do_build_seqar(seqbase, seqar, 0); + *seqar= tseqar; +} + +static void do_seq_count_cb(ListBase *seqbase, int *totseq, + int (*test_func)(Sequence * seq)) +{ + Sequence *seq; + + seq= seqbase->first; + while(seq) { + int test = test_func(seq); + if (test & BUILD_SEQAR_COUNT_CURRENT) { + (*totseq)++; + } + if(seq->seqbase.first && (test & BUILD_SEQAR_COUNT_CHILDREN)) { + do_seq_count_cb(&seq->seqbase, totseq, test_func); + } + seq= seq->next; + } +} + +static void do_build_seqar_cb(ListBase *seqbase, Sequence ***seqar, int depth, + int (*test_func)(Sequence * seq)) +{ + Sequence *seq; + + seq= seqbase->first; + while(seq) { + int test = test_func(seq); + seq->depth= depth; + + if(seq->seqbase.first && (test & BUILD_SEQAR_COUNT_CHILDREN)) { + do_build_seqar_cb(&seq->seqbase, seqar, depth+1, + test_func); + } + if (test & BUILD_SEQAR_COUNT_CURRENT) { + **seqar= seq; + (*seqar)++; + } + seq= seq->next; + } +} + +void build_seqar_cb(ListBase *seqbase, Sequence ***seqar, int *totseq, + int (*test_func)(Sequence * seq)) +{ + Sequence **tseqar; + + *totseq= 0; + do_seq_count_cb(seqbase, totseq, test_func); + + if(*totseq==0) { + *seqar= 0; + return; + } + *seqar= MEM_mallocN(sizeof(void *)* *totseq, "seqar"); + tseqar= *seqar; + + do_build_seqar_cb(seqbase, seqar, 0, test_func); + *seqar= tseqar; +} + + +void calc_sequence_disp(Sequence *seq) +{ + if(seq->startofs && seq->startstill) seq->startstill= 0; + if(seq->endofs && seq->endstill) seq->endstill= 0; + + seq->startdisp= seq->start + seq->startofs - seq->startstill; + seq->enddisp= seq->start+seq->len - seq->endofs + seq->endstill; + + seq->handsize= 10.0; /* 10 frames */ + if( seq->enddisp-seq->startdisp < 10 ) { + seq->handsize= (float)(0.5*(seq->enddisp-seq->startdisp)); + } + else if(seq->enddisp-seq->startdisp > 250) { + seq->handsize= (float)((seq->enddisp-seq->startdisp)/25); + } + + seq_update_sound(seq); +} + +void calc_sequence(Sequence *seq) +{ + Sequence *seqm; + int min, max; + + /* check all metas recursively */ + seqm= seq->seqbase.first; + while(seqm) { + if(seqm->seqbase.first) calc_sequence(seqm); + seqm= seqm->next; + } + + /* effects and meta: automatic start and end */ + + if(seq->type & SEQ_EFFECT) { + /* pointers */ + if(seq->seq2==0) seq->seq2= seq->seq1; + if(seq->seq3==0) seq->seq3= seq->seq1; + + /* effecten go from seq1 -> seq2: test */ + + /* we take the largest start and smallest end */ + + // seq->start= seq->startdisp= MAX2(seq->seq1->startdisp, seq->seq2->startdisp); + // seq->enddisp= MIN2(seq->seq1->enddisp, seq->seq2->enddisp); + + if (seq->seq1) { + seq->start= seq->startdisp= MAX3(seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp); + seq->enddisp= MIN3(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp); + seq->len= seq->enddisp - seq->startdisp; + } else { + calc_sequence_disp(seq); + } + + if(seq->strip && seq->len!=seq->strip->len) { + new_tstripdata(seq); + } + + } + else { + if(seq->type==SEQ_META) { + seqm= seq->seqbase.first; + if(seqm) { + min= 1000000; + max= -1000000; + while(seqm) { + if(seqm->startdisp < min) min= seqm->startdisp; + if(seqm->enddisp > max) max= seqm->enddisp; + seqm= seqm->next; + } + seq->start= min + seq->anim_startofs; + seq->len = max-min; + seq->len -= seq->anim_startofs; + seq->len -= seq->anim_endofs; + + if(seq->strip && seq->len!=seq->strip->len) { + new_tstripdata(seq); + } + } + } + calc_sequence_disp(seq); + } +} + +void reload_sequence_new_file(Scene *scene, Sequence * seq) +{ + char str[FILE_MAXDIR+FILE_MAXFILE]; + + if (!(seq->type == SEQ_MOVIE || seq->type == SEQ_IMAGE || + seq->type == SEQ_SOUND || + seq->type == SEQ_SCENE || seq->type == SEQ_META)) { + return; + } + + new_tstripdata(seq); + + if (seq->type != SEQ_SCENE && seq->type != SEQ_META && + seq->type != SEQ_IMAGE) { + BLI_join_dirfile(str, seq->strip->dir, seq->strip->stripdata->name); + BLI_convertstringcode(str, G.sce); + BLI_convertstringframe(str, scene->r.cfra); + + } + + if (seq->type == SEQ_IMAGE) { + /* Hack? */ + int olen = MEM_allocN_len(seq->strip->stripdata)/sizeof(struct StripElem); + seq->len = olen; + seq->len -= seq->anim_startofs; + seq->len -= seq->anim_endofs; + if (seq->len < 0) { + seq->len = 0; + } + seq->strip->len = seq->len; + } else if (seq->type == SEQ_MOVIE) { + if(seq->anim) IMB_free_anim(seq->anim); + seq->anim = openanim(str, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0)); + + if (!seq->anim) { + return; + } + + seq->len = IMB_anim_get_duration(seq->anim); + + seq->anim_preseek = IMB_anim_get_preseek(seq->anim); + + seq->len -= seq->anim_startofs; + seq->len -= seq->anim_endofs; + if (seq->len < 0) { + seq->len = 0; + } + seq->strip->len = seq->len; + } else if (seq->type == SEQ_SOUND) { + seq->len = AUD_getInfo(seq->sound->snd_sound).length * FPS; + seq->len -= seq->anim_startofs; + seq->len -= seq->anim_endofs; + if (seq->len < 0) { + seq->len = 0; + } + seq->strip->len = seq->len; + } else if (seq->type == SEQ_SCENE) { + Scene * sce = G.main->scene.first; + int nr = 1; + + while(sce) { + if(nr == seq->scenenr) { + break; + } + nr++; + sce= sce->id.next; + } + + if (sce) { + seq->scene = sce; + } else { + sce = seq->scene; + } + + strncpy(seq->name + 2, sce->id.name + 2, + sizeof(seq->name) - 2); + + seq->len= seq->scene->r.efra - seq->scene->r.sfra + 1; + seq->len -= seq->anim_startofs; + seq->len -= seq->anim_endofs; + if (seq->len < 0) { + seq->len = 0; + } + seq->strip->len = seq->len; + } + + free_proxy_seq(seq); + + calc_sequence(seq); +} + +void sort_seq(Scene *scene) +{ + /* all strips together per kind, and in order of y location ("machine") */ + ListBase seqbase, effbase; + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq, *seqt; + + + if(ed==NULL) return; + + seqbase.first= seqbase.last= 0; + effbase.first= effbase.last= 0; + + while( (seq= ed->seqbasep->first) ) { + BLI_remlink(ed->seqbasep, seq); + + if(seq->type & SEQ_EFFECT) { + seqt= effbase.first; + while(seqt) { + if(seqt->machine>=seq->machine) { + BLI_insertlinkbefore(&effbase, seqt, seq); + break; + } + seqt= seqt->next; + } + if(seqt==0) BLI_addtail(&effbase, seq); + } + else { + seqt= seqbase.first; + while(seqt) { + if(seqt->machine>=seq->machine) { + BLI_insertlinkbefore(&seqbase, seqt, seq); + break; + } + seqt= seqt->next; + } + if(seqt==0) BLI_addtail(&seqbase, seq); + } + } + + addlisttolist(&seqbase, &effbase); + *(ed->seqbasep)= seqbase; +} + + +void clear_scene_in_allseqs(Scene *sce) +{ + Scene *sce1; + Editing *ed; + Sequence *seq; + + /* when a scene is deleted: test all seqs */ + + sce1= G.main->scene.first; + while(sce1) { + if(sce1!=sce && sce1->ed) { + ed= sce1->ed; + + SEQ_BEGIN(ed, seq) { + + if(seq->scene==sce) seq->scene= 0; + + } + SEQ_END + } + + sce1= sce1->id.next; + } +} + +char *give_seqname_by_type(int type) +{ + switch(type) { + case SEQ_META: return "Meta"; + case SEQ_IMAGE: return "Image"; + case SEQ_SCENE: return "Scene"; + case SEQ_MOVIE: return "Movie"; + case SEQ_SOUND: return "Audio"; + case SEQ_CROSS: return "Cross"; + case SEQ_GAMCROSS: return "Gamma Cross"; + case SEQ_ADD: return "Add"; + case SEQ_SUB: return "Sub"; + case SEQ_MUL: return "Mul"; + case SEQ_ALPHAOVER: return "Alpha Over"; + case SEQ_ALPHAUNDER: return "Alpha Under"; + case SEQ_OVERDROP: return "Over Drop"; + case SEQ_WIPE: return "Wipe"; + case SEQ_GLOW: return "Glow"; + case SEQ_TRANSFORM: return "Transform"; + case SEQ_COLOR: return "Color"; + case SEQ_SPEED: return "Speed"; + default: + return 0; + } +} + +char *give_seqname(Sequence *seq) +{ + char * name = give_seqname_by_type(seq->type); + + if (!name) { + if(seq->type<SEQ_EFFECT) { + return seq->strip->dir; + } else if(seq->type==SEQ_PLUGIN) { + if(!(seq->flag & SEQ_EFFECT_NOT_LOADED) && + seq->plugin && seq->plugin->doit) { + return seq->plugin->pname; + } else { + return "Plugin"; + } + } else { + return "Effect"; + } + } + return name; +} + +/* ***************** DO THE SEQUENCE ***************** */ + +static void make_black_ibuf(ImBuf *ibuf) +{ + unsigned int *rect; + float *rect_float; + int tot; + + if(ibuf==0 || (ibuf->rect==0 && ibuf->rect_float==0)) return; + + tot= ibuf->x*ibuf->y; + + rect= ibuf->rect; + rect_float = ibuf->rect_float; + + if (rect) { + memset(rect, 0, tot * sizeof(char) * 4); + } + + if (rect_float) { + memset(rect_float, 0, tot * sizeof(float) * 4); + } +} + +static void multibuf(ImBuf *ibuf, float fmul) +{ + char *rt; + float *rt_float; + + int a, mul, icol; + + mul= (int)(256.0*fmul); + rt= (char *)ibuf->rect; + rt_float = ibuf->rect_float; + + if (rt) { + a= ibuf->x*ibuf->y; + while(a--) { + + icol= (mul*rt[0])>>8; + if(icol>254) rt[0]= 255; else rt[0]= icol; + icol= (mul*rt[1])>>8; + if(icol>254) rt[1]= 255; else rt[1]= icol; + icol= (mul*rt[2])>>8; + if(icol>254) rt[2]= 255; else rt[2]= icol; + icol= (mul*rt[3])>>8; + if(icol>254) rt[3]= 255; else rt[3]= icol; + + rt+= 4; + } + } + if (rt_float) { + a= ibuf->x*ibuf->y; + while(a--) { + rt_float[0] *= fmul; + rt_float[1] *= fmul; + rt_float[2] *= fmul; + rt_float[3] *= fmul; + + rt_float += 4; + } + } +} + +static void do_effect(Scene *scene, int cfra, Sequence *seq, TStripElem * se) +{ + TStripElem *se1, *se2, *se3; + float fac, facf; + int x, y; + int early_out; + struct SeqEffectHandle sh = get_sequence_effect(seq); + + if (!sh.execute) { /* effect not supported in this version... */ + make_black_ibuf(se->ibuf); + return; + } + +#if 0 // XXX old animation system + if(seq->ipo && seq->ipo->curve.first) { + do_seq_ipo(scene, seq, cfra); + fac= seq->facf0; + facf= seq->facf1; + } else +#endif // XXX old animation system + { + sh.get_default_fac(seq, cfra, &fac, &facf); + } + + if( !(scene->r.mode & R_FIELDS) ) facf = fac; + + early_out = sh.early_out(seq, fac, facf); + + if (early_out == -1) { /* no input needed */ + sh.execute(seq, cfra, fac, facf, + se->ibuf->x, se->ibuf->y, + 0, 0, 0, se->ibuf); + return; + } + + switch (early_out) { + case 0: + if (se->se1==0 || se->se2==0 || se->se3==0) { + make_black_ibuf(se->ibuf); + return; + } + + se1= se->se1; + se2= se->se2; + se3= se->se3; + + if ( (se1==0 || se2==0 || se3==0) + || (se1->ibuf==0 || se2->ibuf==0 || se3->ibuf==0)) { + make_black_ibuf(se->ibuf); + return; + } + + break; + case 1: + if (se->se1 == 0) { + make_black_ibuf(se->ibuf); + return; + } + + se1= se->se1; + + if (se1 == 0 || se1->ibuf == 0) { + make_black_ibuf(se->ibuf); + return; + } + + if (se->ibuf != se1->ibuf) { + IMB_freeImBuf(se->ibuf); + se->ibuf = se1->ibuf; + IMB_refImBuf(se->ibuf); + } + return; + case 2: + if (se->se2 == 0) { + make_black_ibuf(se->ibuf); + return; + } + + se2= se->se2; + + if (se2 == 0 || se2->ibuf == 0) { + make_black_ibuf(se->ibuf); + return; + } + if (se->ibuf != se2->ibuf) { + IMB_freeImBuf(se->ibuf); + se->ibuf = se2->ibuf; + IMB_refImBuf(se->ibuf); + } + return; + default: + make_black_ibuf(se->ibuf); + return; + } + + x= se2->ibuf->x; + y= se2->ibuf->y; + + if (!se1->ibuf->rect_float && se->ibuf->rect_float) { + IMB_float_from_rect(se1->ibuf); + } + if (!se2->ibuf->rect_float && se->ibuf->rect_float) { + IMB_float_from_rect(se2->ibuf); + } + if (!se3->ibuf->rect_float && se->ibuf->rect_float) { + IMB_float_from_rect(se3->ibuf); + } + + if (!se1->ibuf->rect && !se->ibuf->rect_float) { + IMB_rect_from_float(se1->ibuf); + } + if (!se2->ibuf->rect && !se->ibuf->rect_float) { + IMB_rect_from_float(se2->ibuf); + } + if (!se3->ibuf->rect && !se->ibuf->rect_float) { + IMB_rect_from_float(se3->ibuf); + } + + sh.execute(seq, cfra, fac, facf, x, y, se1->ibuf, se2->ibuf, se3->ibuf, + se->ibuf); +} + +static int give_stripelem_index(Sequence *seq, int cfra) +{ + int nr; + + if(seq->startdisp >cfra || seq->enddisp <= cfra) return -1; + if(seq->len == 0) return -1; + if(seq->flag&SEQ_REVERSE_FRAMES) { + /*reverse frame in this sequence */ + if(cfra <= seq->start) nr= seq->len-1; + else if(cfra >= seq->start+seq->len-1) nr= 0; + else nr= (seq->start + seq->len) - cfra; + } else { + if(cfra <= seq->start) nr= 0; + else if(cfra >= seq->start+seq->len-1) nr= seq->len-1; + else nr= cfra-seq->start; + } + if (seq->strobe < 1.0) seq->strobe = 1.0; + if (seq->strobe > 1.0) { + nr -= (int)fmod((double)nr, (double)seq->strobe); + } + + return nr; +} + +static TStripElem* alloc_tstripdata(int len, const char * name) +{ + int i; + TStripElem *se = MEM_callocN(len * sizeof(TStripElem), name); + for (i = 0; i < len; i++) { + se[i].ok = STRIPELEM_OK; + } + return se; +} + +TStripElem *give_tstripelem(Sequence *seq, int cfra) +{ + TStripElem *se; + int nr; + + se = seq->strip->tstripdata; + if (se == 0 && seq->len > 0) { + se = seq->strip->tstripdata = alloc_tstripdata(seq->len, + "tstripelems"); + } + nr = give_stripelem_index(seq, cfra); + + if (nr == -1) return 0; + if (se == 0) return 0; + + se += nr; + + /* if there are IPOs with blend modes active, one has to watch out + for startstill + endstill area: we can't use the same tstripelem + here for all ibufs, since then, blending with IPOs won't work! + + Rather common case, if you use a single image and try to fade + it in and out... or want to use your strip as a watermark in + alpha over mode... + */ + if (seq->blend_mode != SEQ_BLEND_REPLACE || + (/*seq->ipo && seq->ipo->curve.first &&*/ + (!(seq->type & SEQ_EFFECT) || !seq->seq1))) { + Strip * s = seq->strip; + if (cfra < seq->start) { + se = s->tstripdata_startstill; + if (seq->startstill > s->startstill) { + free_tstripdata(s->startstill, + s->tstripdata_startstill); + se = 0; + } + + if (se == 0) { + s->startstill = seq->startstill; + se = seq->strip->tstripdata_startstill + = alloc_tstripdata( + s->startstill, + "tstripelems_startstill"); + } + se += seq->start - cfra - 1; + + } else if (cfra > seq->start + seq->len-1) { + se = s->tstripdata_endstill; + if (seq->endstill > s->endstill) { + free_tstripdata(s->endstill, + s->tstripdata_endstill); + se = 0; + } + + if (se == 0) { + s->endstill = seq->endstill; + se = seq->strip->tstripdata_endstill + = alloc_tstripdata( + s->endstill, + "tstripelems_endstill"); + } + se += cfra - (seq->start + seq->len-1) - 1; + } + } + + + se->nr= nr; + + return se; +} + +StripElem *give_stripelem(Sequence *seq, int cfra) +{ + StripElem *se; + int nr; + + se = seq->strip->stripdata; + nr = give_stripelem_index(seq, cfra); + + if (nr == -1) return 0; + if (se == 0) return 0; + + se += nr + seq->anim_startofs; + + return se; +} + +static int evaluate_seq_frame_gen(Sequence ** seq_arr, ListBase *seqbase, int cfra) +{ + Sequence *seq; + int totseq=0; + + memset(seq_arr, 0, sizeof(Sequence*) * (MAXSEQ+1)); + + seq= seqbase->first; + while(seq) { + if(seq->startdisp <=cfra && seq->enddisp > cfra) { + seq_arr[seq->machine]= seq; + totseq++; + } + seq= seq->next; + } + + return totseq; +} + +int evaluate_seq_frame(Scene *scene, int cfra) +{ + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq_arr[MAXSEQ+1]; + + if(ed==NULL) return 0; + return evaluate_seq_frame_gen(seq_arr, ed->seqbasep, cfra); +} + +static int video_seq_is_rendered(Sequence * seq) +{ + return (seq + && !(seq->flag & SEQ_MUTE) + && seq->type != SEQ_SOUND); +} + +static int get_shown_sequences( ListBase * seqbasep, int cfra, int chanshown, Sequence ** seq_arr_out) +{ + Sequence *seq_arr[MAXSEQ+1]; + int b = chanshown; + int cnt = 0; + + if (b > MAXSEQ) { + return 0; + } + + if(evaluate_seq_frame_gen(seq_arr, seqbasep, cfra)) { + if (b > 0) { + if (seq_arr[b] == 0) { + return 0; + } + } else { + for (b = MAXSEQ; b > 0; b--) { + if (video_seq_is_rendered(seq_arr[b])) { + break; + } + } + } + } + + chanshown = b; + + for (;b > 0; b--) { + if (video_seq_is_rendered(seq_arr[b])) { + if (seq_arr[b]->blend_mode == SEQ_BLEND_REPLACE) { + break; + } + } + } + + for (;b <= chanshown; b++) { + if (video_seq_is_rendered(seq_arr[b])) { + seq_arr_out[cnt++] = seq_arr[b]; + } + } + + return cnt; +} + + +/* ********************************************************************** + proxy management + ********************************************************************** */ + +#define PROXY_MAXFILE (2*FILE_MAXDIR+FILE_MAXFILE) + +static int seq_proxy_get_fname(Scene *scene, Sequence * seq, int cfra, char * name, int render_size) +{ + int frameno; + char dir[FILE_MAXDIR]; + + if (!seq->strip->proxy) { + return FALSE; + } + + if (seq->flag & SEQ_USE_PROXY_CUSTOM_DIR) { + strcpy(dir, seq->strip->proxy->dir); + } else { + if (seq->type == SEQ_IMAGE || seq->type == SEQ_MOVIE) { + snprintf(dir, FILE_MAXDIR, "%s/BL_proxy", + seq->strip->dir); + } else { + return FALSE; + } + } + + if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) { + BLI_join_dirfile(name, dir, seq->strip->proxy->file); + BLI_convertstringcode(name, G.sce); + BLI_convertstringframe(name, cfra); + + return TRUE; + } + + /* generate a seperate proxy directory for each preview size */ + + if (seq->type == SEQ_IMAGE) { + StripElem * se = give_stripelem(seq, cfra); + snprintf(name, PROXY_MAXFILE, "%s/images/%d/%s_proxy", + dir, render_size, se->name); + frameno = 1; + } else if (seq->type == SEQ_MOVIE) { + TStripElem * tse = give_tstripelem(seq, cfra); + + frameno = tse->nr + seq->anim_startofs; + + snprintf(name, PROXY_MAXFILE, "%s/%s/%d/####", dir, + seq->strip->stripdata->name, + render_size); + } else { + TStripElem * tse = give_tstripelem(seq, cfra); + + frameno = tse->nr + seq->anim_startofs; + + snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####", dir, + render_size); + } + + BLI_convertstringcode(name, G.sce); + BLI_convertstringframe(name, frameno); + + + strcat(name, ".jpg"); + + return TRUE; +} + +static struct ImBuf * seq_proxy_fetch(Scene *scene, Sequence * seq, int cfra, int render_size) +{ + char name[PROXY_MAXFILE]; + + if (!(seq->flag & SEQ_USE_PROXY)) { + return 0; + } + + /* rendering at 100% ? No real sense in proxy-ing, right? */ + if (render_size == 100) { + return 0; + } + + if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) { + TStripElem * tse = give_tstripelem(seq, cfra); + int frameno = tse->nr + seq->anim_startofs; + if (!seq->strip->proxy->anim) { + if (!seq_proxy_get_fname(scene, seq, cfra, name, render_size)) { + return 0; + } + + seq->strip->proxy->anim = openanim(name, IB_rect); + } + if (!seq->strip->proxy->anim) { + return 0; + } + + return IMB_anim_absolute(seq->strip->proxy->anim, frameno); + } + + if (!seq_proxy_get_fname(scene, seq, cfra, name, render_size)) { + return 0; + } + + if (BLI_exists(name)) { + return IMB_loadiffname(name, IB_rect); + } else { + return 0; + } +} + +static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int cfra, + int build_proxy_run, int render_size); + +static void seq_proxy_build_frame(Scene *scene, Sequence * seq, int cfra, int render_size) +{ + char name[PROXY_MAXFILE]; + int quality; + TStripElem * se; + int ok; + int rectx, recty; + struct ImBuf * ibuf; + + if (!(seq->flag & SEQ_USE_PROXY)) { + return; + } + + /* rendering at 100% ? No real sense in proxy-ing, right? */ + if (render_size == 100) { + return; + } + + /* that's why it is called custom... */ + if (seq->flag & SEQ_USE_PROXY_CUSTOM_FILE) { + return; + } + + if (!seq_proxy_get_fname(scene, seq, cfra, name, render_size)) { + return; + } + + se = give_tstripelem(seq, cfra); + if (!se) { + return; + } + + if(se->ibuf) { + IMB_freeImBuf(se->ibuf); + se->ibuf = 0; + } + + do_build_seq_ibuf(scene, seq, se, cfra, TRUE, render_size); + + if (!se->ibuf) { + return; + } + + rectx= (render_size*scene->r.xsch)/100; + recty= (render_size*scene->r.ysch)/100; + + ibuf = se->ibuf; + + if (ibuf->x != rectx || ibuf->y != recty) { + IMB_scalefastImBuf(ibuf, (short)rectx, (short)recty); + } + + /* quality is fixed, otherwise one has to generate seperate + directories for every quality... + + depth = 32 is intentionally left in, otherwise ALPHA channels + won't work... */ + quality = seq->strip->proxy->quality; + ibuf->ftype= JPG | quality; + + BLI_make_existing_file(name); + + ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat); + if (ok == 0) { + perror(name); + } + + IMB_freeImBuf(ibuf); + se->ibuf = 0; +} + +void seq_proxy_rebuild(Scene *scene, Sequence * seq) +{ + int cfra; + float rsize = seq->strip->proxy->size; + + waitcursor(1); + + G.afbreek = 0; + + /* flag management tries to account for strobe and + other "non-linearities", that might come in the future... + better way would be to "touch" the files, so that _really_ + no one is rebuild twice. + */ + + for (cfra = seq->startdisp; cfra < seq->enddisp; cfra++) { + TStripElem * tse = give_tstripelem(seq, cfra); + + tse->flag &= ~STRIPELEM_PREVIEW_DONE; + } + + + + /* a _lot_ faster for movie files, if we read frames in + sequential order */ + if (seq->flag & SEQ_REVERSE_FRAMES) { + for (cfra = seq->enddisp-seq->endstill-1; + cfra >= seq->startdisp + seq->startstill; cfra--) { + TStripElem * tse = give_tstripelem(seq, cfra); + + if (!(tse->flag & STRIPELEM_PREVIEW_DONE)) { +//XXX set_timecursor(cfra); + seq_proxy_build_frame(scene, seq, cfra, rsize); + tse->flag |= STRIPELEM_PREVIEW_DONE; + } + if (blender_test_break()) { + break; + } + } + } else { + for (cfra = seq->startdisp + seq->startstill; + cfra < seq->enddisp - seq->endstill; cfra++) { + TStripElem * tse = give_tstripelem(seq, cfra); + + if (!(tse->flag & STRIPELEM_PREVIEW_DONE)) { +//XXX set_timecursor(cfra); + seq_proxy_build_frame(scene, seq, cfra, rsize); + tse->flag |= STRIPELEM_PREVIEW_DONE; + } + if (blender_test_break()) { + break; + } + } + } + waitcursor(0); +} + + +/* ********************************************************************** + color balance + ********************************************************************** */ + +static StripColorBalance calc_cb(StripColorBalance * cb_) +{ + StripColorBalance cb = *cb_; + int c; + + if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_LIFT) { + for (c = 0; c < 3; c++) { + cb.lift[c] = 1.0 - cb.lift[c]; + } + } else { + for (c = 0; c < 3; c++) { + cb.lift[c] = -(1.0 - cb.lift[c]); + } + } + if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAIN) { + for (c = 0; c < 3; c++) { + if (cb.gain[c] != 0.0) { + cb.gain[c] = 1.0/cb.gain[c]; + } else { + cb.gain[c] = 1000000; /* should be enough :) */ + } + } + } + + if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_GAMMA)) { + for (c = 0; c < 3; c++) { + if (cb.gamma[c] != 0.0) { + cb.gamma[c] = 1.0/cb.gamma[c]; + } else { + cb.gamma[c] = 1000000; /* should be enough :) */ + } + } + } + + return cb; +} + +static void make_cb_table_byte(float lift, float gain, float gamma, + unsigned char * table, float mul) +{ + int y; + + for (y = 0; y < 256; y++) { + float v = 1.0 * y / 255; + v *= gain; + v += lift; + v = pow(v, gamma); + v *= mul; + if ( v > 1.0) { + v = 1.0; + } else if (v < 0.0) { + v = 0.0; + } + table[y] = v * 255; + } + +} + +static void make_cb_table_float(float lift, float gain, float gamma, + float * table, float mul) +{ + int y; + + for (y = 0; y < 256; y++) { + float v = (float) y * 1.0 / 255.0; + v *= gain; + v += lift; + v = pow(v, gamma); + v *= mul; + table[y] = v; + } +} + +static void color_balance_byte_byte(Sequence * seq, TStripElem* se, float mul) +{ + unsigned char cb_tab[3][256]; + int c; + unsigned char * p = (unsigned char*) se->ibuf->rect; + unsigned char * e = p + se->ibuf->x * 4 * se->ibuf->y; + + StripColorBalance cb = calc_cb(seq->strip->color_balance); + + for (c = 0; c < 3; c++) { + make_cb_table_byte(cb.lift[c], cb.gain[c], cb.gamma[c], + cb_tab[c], mul); + } + + while (p < e) { + p[0] = cb_tab[0][p[0]]; + p[1] = cb_tab[1][p[1]]; + p[2] = cb_tab[2][p[2]]; + + p += 4; + } +} + +static void color_balance_byte_float(Sequence * seq, TStripElem* se, float mul) +{ + float cb_tab[4][256]; + int c,i; + unsigned char * p = (unsigned char*) se->ibuf->rect; + unsigned char * e = p + se->ibuf->x * 4 * se->ibuf->y; + float * o; + StripColorBalance cb; + + imb_addrectfloatImBuf(se->ibuf); + + o = se->ibuf->rect_float; + + cb = calc_cb(seq->strip->color_balance); + + for (c = 0; c < 3; c++) { + make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c], + cb_tab[c], mul); + } + + for (i = 0; i < 256; i++) { + cb_tab[3][i] = ((float)i)*(1.0f/255.0f); + } + + while (p < e) { + o[0] = cb_tab[0][p[0]]; + o[1] = cb_tab[1][p[1]]; + o[2] = cb_tab[2][p[2]]; + o[3] = cb_tab[3][p[3]]; + + p += 4; o += 4; + } +} + +static void color_balance_float_float(Sequence * seq, TStripElem* se, float mul) +{ + float * p = se->ibuf->rect_float; + float * e = se->ibuf->rect_float + se->ibuf->x * 4* se->ibuf->y; + StripColorBalance cb = calc_cb(seq->strip->color_balance); + + while (p < e) { + int c; + for (c = 0; c < 3; c++) { + p[c] = pow(p[c] * cb.gain[c] + cb.lift[c], + cb.gamma[c]) * mul; + } + p += 4; + } +} + +static void color_balance(Sequence * seq, TStripElem* se, float mul) +{ + if (se->ibuf->rect_float) { + color_balance_float_float(seq, se, mul); + } else if(seq->flag & SEQ_MAKE_FLOAT) { + color_balance_byte_float(seq, se, mul); + } else { + color_balance_byte_byte(seq, se, mul); + } +} + +/* + input preprocessing for SEQ_IMAGE, SEQ_MOVIE and SEQ_SCENE + + Do all the things you can't really do afterwards using sequence effects + (read: before rescaling to render resolution has been done) + + Order is important! + + - Deinterlace + - Crop and transform in image source coordinate space + - Flip X + Flip Y (could be done afterwards, backward compatibility) + - Promote image to float data (affects pipeline operations afterwards) + - Color balance (is most efficient in the byte -> float + (future: half -> float should also work fine!) + case, if done on load, since we can use lookup tables) + - Premultiply + +*/ + +static int input_have_to_preprocess(Scene *scene, Sequence * seq, TStripElem* se, int cfra) +{ + float mul; + + if ((seq->flag & SEQ_FILTERY) || + (seq->flag & SEQ_USE_CROP) || + (seq->flag & SEQ_USE_TRANSFORM) || + (seq->flag & SEQ_FLIPX) || + (seq->flag & SEQ_FLIPY) || + (seq->flag & SEQ_USE_COLOR_BALANCE) || + (seq->flag & SEQ_MAKE_PREMUL) || + (se->ibuf->x != seqrectx || se->ibuf->y != seqrecty)) { + return TRUE; + } + + mul = seq->mul; + + if(seq->blend_mode == SEQ_BLEND_REPLACE && + !(seq->type & SEQ_EFFECT)) { +#if 0 // XXX old animation system + if (seq->ipo && seq->ipo->curve.first) { + do_seq_ipo(scene, seq, cfra); + mul *= seq->facf0; + } +#endif // XXX old animation system + mul *= seq->blend_opacity / 100.0; + } + + if (mul != 1.0) { + return TRUE; + } + + return FALSE; +} + +static void input_preprocess(Scene *scene, Sequence *seq, TStripElem *se, int cfra) +{ + float mul; + + seq->strip->orx= se->ibuf->x; + seq->strip->ory= se->ibuf->y; + + if((seq->flag & SEQ_FILTERY) && seq->type != SEQ_MOVIE) { + IMB_filtery(se->ibuf); + } + + if(seq->flag & SEQ_USE_CROP || seq->flag & SEQ_USE_TRANSFORM) { + StripCrop c; + StripTransform t; + int sx,sy,dx,dy; + + memset(&c, 0, sizeof(StripCrop)); + memset(&t, 0, sizeof(StripTransform)); + + if(seq->flag & SEQ_USE_CROP && seq->strip->crop) { + c = *seq->strip->crop; + } + if(seq->flag & SEQ_USE_TRANSFORM && seq->strip->transform) { + t = *seq->strip->transform; + } + + sx = se->ibuf->x - c.left - c.right; + sy = se->ibuf->y - c.top - c.bottom; + dx = sx; + dy = sy; + + if (seq->flag & SEQ_USE_TRANSFORM) { + dx = scene->r.xsch; + dy = scene->r.ysch; + } + + if (c.top + c.bottom >= se->ibuf->y || + c.left + c.right >= se->ibuf->x || + t.xofs >= dx || t.yofs >= dy) { + make_black_ibuf(se->ibuf); + } else { + ImBuf * i; + + if (se->ibuf->rect_float) { + i = IMB_allocImBuf(dx, dy,32, IB_rectfloat, 0); + } else { + i = IMB_allocImBuf(dx, dy,32, IB_rect, 0); + } + + IMB_rectcpy(i, se->ibuf, + t.xofs, t.yofs, + c.left, c.bottom, + sx, sy); + + IMB_freeImBuf(se->ibuf); + + se->ibuf = i; + } + } + + if(seq->flag & SEQ_FLIPX) { + IMB_flipx(se->ibuf); + } + if(seq->flag & SEQ_FLIPY) { + IMB_flipy(se->ibuf); + } + + if(seq->mul == 0.0) { + seq->mul = 1.0; + } + + mul = seq->mul; + + if(seq->blend_mode == SEQ_BLEND_REPLACE) { +#if 0 // XXX old animation system + if (seq->ipo && seq->ipo->curve.first) { + do_seq_ipo(scene, seq, cfra); + mul *= seq->facf0; + } +#endif // XXX old animation system + mul *= seq->blend_opacity / 100.0; + } + + if(seq->flag & SEQ_USE_COLOR_BALANCE && seq->strip->color_balance) { + color_balance(seq, se, mul); + mul = 1.0; + } + + if(seq->flag & SEQ_MAKE_FLOAT) { + if (!se->ibuf->rect_float) { + IMB_float_from_rect(se->ibuf); + } + if (se->ibuf->rect) { + imb_freerectImBuf(se->ibuf); + } + } + + if(mul != 1.0) { + multibuf(se->ibuf, mul); + } + + if(seq->flag & SEQ_MAKE_PREMUL) { + if(se->ibuf->depth == 32 && se->ibuf->zbuf == 0) { + converttopremul(se->ibuf); + } + } + + + if(se->ibuf->x != seqrectx || se->ibuf->y != seqrecty ) { + if(scene->r.mode & R_OSA) { + IMB_scaleImBuf(se->ibuf, + (short)seqrectx, (short)seqrecty); + } else { + IMB_scalefastImBuf(se->ibuf, + (short)seqrectx, (short)seqrecty); + } + } +} + +/* test if image too small or discarded from cache: reload */ + +static void test_and_auto_discard_ibuf(TStripElem * se) +{ + if (se->ibuf) { + if(se->ibuf->x != seqrectx || se->ibuf->y != seqrecty + || !(se->ibuf->rect || se->ibuf->rect_float)) { + IMB_freeImBuf(se->ibuf); + + se->ibuf= 0; + se->ok= STRIPELEM_OK; + } + } + if (se->ibuf_comp) { + if(se->ibuf_comp->x != seqrectx || se->ibuf_comp->y != seqrecty + || !(se->ibuf_comp->rect || se->ibuf_comp->rect_float)) { + IMB_freeImBuf(se->ibuf_comp); + + se->ibuf_comp = 0; + } + } +} + +static void test_and_auto_discard_ibuf_stills(Strip * strip) +{ + if (strip->ibuf_startstill) { + if (!strip->ibuf_startstill->rect && + !strip->ibuf_startstill->rect_float) { + IMB_freeImBuf(strip->ibuf_startstill); + strip->ibuf_startstill = 0; + } + } + if (strip->ibuf_endstill) { + if (!strip->ibuf_endstill->rect && + !strip->ibuf_endstill->rect_float) { + IMB_freeImBuf(strip->ibuf_endstill); + strip->ibuf_endstill = 0; + } + } +} + +static void copy_from_ibuf_still(Sequence * seq, TStripElem * se) +{ + if (!se->ibuf) { + if (se->nr == 0 && seq->strip->ibuf_startstill) { + IMB_cache_limiter_touch(seq->strip->ibuf_startstill); + + se->ibuf = IMB_dupImBuf(seq->strip->ibuf_startstill); + } + if (se->nr == seq->len - 1 + && (seq->len != 1) + && seq->strip->ibuf_endstill) { + IMB_cache_limiter_touch(seq->strip->ibuf_endstill); + + se->ibuf = IMB_dupImBuf(seq->strip->ibuf_endstill); + } + } +} + +static void copy_to_ibuf_still(Sequence * seq, TStripElem * se) +{ + if (se->ibuf) { + if (se->nr == 0) { + seq->strip->ibuf_startstill = IMB_dupImBuf(se->ibuf); + + IMB_cache_limiter_insert(seq->strip->ibuf_startstill); + IMB_cache_limiter_touch(seq->strip->ibuf_startstill); + } + if (se->nr == seq->len - 1 && seq->len != 1) { + seq->strip->ibuf_endstill = IMB_dupImBuf(se->ibuf); + + IMB_cache_limiter_insert(seq->strip->ibuf_endstill); + IMB_cache_limiter_touch(seq->strip->ibuf_endstill); + } + } +} + +static void free_metastrip_imbufs(ListBase *seqbasep, int cfra, int chanshown) +{ + Sequence* seq_arr[MAXSEQ+1]; + int i; + TStripElem* se = 0; + + evaluate_seq_frame_gen(seq_arr, seqbasep, cfra); + + for (i = 0; i < MAXSEQ; i++) { + if (!video_seq_is_rendered(seq_arr[i])) { + continue; + } + se = give_tstripelem(seq_arr[i], cfra); + if (se) { + if (se->ibuf) { + IMB_freeImBuf(se->ibuf); + + se->ibuf= 0; + se->ok= STRIPELEM_OK; + } + + if (se->ibuf_comp) { + IMB_freeImBuf(se->ibuf_comp); + + se->ibuf_comp = 0; + } + } + } + +} + +static void check_limiter_refcount(const char * func, TStripElem *se) +{ + if (se && se->ibuf) { + int refcount = IMB_cache_limiter_get_refcount(se->ibuf); + if (refcount != 1) { + /* can happen on complex pipelines */ + if (refcount > 1 && (G.f & G_DEBUG) == 0) { + return; + } + + fprintf(stderr, + "sequencer: (ibuf) %s: " + "suspicious memcache " + "limiter refcount: %d\n", func, refcount); + } + } +} + +static void check_limiter_refcount_comp(const char * func, TStripElem *se) +{ + if (se && se->ibuf_comp) { + int refcount = IMB_cache_limiter_get_refcount(se->ibuf_comp); + if (refcount != 1) { + /* can happen on complex pipelines */ + if (refcount > 1 && (G.f & G_DEBUG) == 0) { + return; + } + fprintf(stderr, + "sequencer: (ibuf comp) %s: " + "suspicious memcache " + "limiter refcount: %d\n", func, refcount); + } + } +} + +static TStripElem* do_build_seq_array_recursively(Scene *scene, + ListBase *seqbasep, int cfra, int chanshown, int render_size); + +static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int cfra, + int build_proxy_run, int render_size) +{ + char name[FILE_MAXDIR+FILE_MAXFILE]; + int use_limiter = TRUE; + + test_and_auto_discard_ibuf(se); + test_and_auto_discard_ibuf_stills(seq->strip); + + if(seq->type == SEQ_META) { + TStripElem * meta_se = 0; + int use_preprocess = FALSE; + use_limiter = FALSE; + + if (!build_proxy_run && se->ibuf == 0) { + se->ibuf = seq_proxy_fetch(scene, seq, cfra, render_size); + if (se->ibuf) { + use_limiter = TRUE; + use_preprocess = TRUE; + } + } + + if(!se->ibuf && seq->seqbase.first) { + meta_se = do_build_seq_array_recursively(scene, + &seq->seqbase, seq->start + se->nr, 0, + render_size); + + check_limiter_refcount("do_build_seq_ibuf: for META", meta_se); + } + + se->ok = STRIPELEM_OK; + + if(!se->ibuf && meta_se) { + se->ibuf = meta_se->ibuf_comp; + if(se->ibuf && + (!input_have_to_preprocess(scene, seq, se, cfra) || + build_proxy_run)) { + IMB_refImBuf(se->ibuf); + if (build_proxy_run) { + IMB_cache_limiter_unref(se->ibuf); + } + } else if (se->ibuf) { + struct ImBuf * i = IMB_dupImBuf(se->ibuf); + + IMB_cache_limiter_unref(se->ibuf); + + se->ibuf = i; + + use_limiter = TRUE; + use_preprocess = TRUE; + } + } else if (se->ibuf) { + use_limiter = TRUE; + } + if (meta_se) { + free_metastrip_imbufs( + &seq->seqbase, seq->start + se->nr, 0); + } + + if (use_preprocess) { + input_preprocess(scene, seq, se, cfra); + } + } else if(seq->type & SEQ_EFFECT) { + int use_preprocess = FALSE; + /* should the effect be recalculated? */ + + if (!build_proxy_run && se->ibuf == 0) { + se->ibuf = seq_proxy_fetch(scene, seq, cfra, render_size); + if (se->ibuf) { + use_preprocess = TRUE; + } + } + + if(se->ibuf == 0) { + /* if any inputs are rectfloat, output is float too */ + if((se->se1 && se->se1->ibuf && se->se1->ibuf->rect_float) || + (se->se2 && se->se2->ibuf && se->se2->ibuf->rect_float) || + (se->se3 && se->se3->ibuf && se->se3->ibuf->rect_float)) + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0); + else + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0); + + do_effect(scene, cfra, seq, se); + if (input_have_to_preprocess(scene, seq, se, cfra) && + !build_proxy_run) { + if ((se->se1 && (se->ibuf == se->se1->ibuf)) || + (se->se2 && (se->ibuf == se->se2->ibuf))) { + struct ImBuf * i + = IMB_dupImBuf(se->ibuf); + + IMB_freeImBuf(se->ibuf); + + se->ibuf = i; + } + use_preprocess = TRUE; + } + } + if (use_preprocess) { + input_preprocess(scene, seq, se, cfra); + } + } else if(seq->type == SEQ_IMAGE) { + if(se->ok == STRIPELEM_OK && se->ibuf == 0) { + StripElem * s_elem = give_stripelem(seq, cfra); + BLI_join_dirfile(name, seq->strip->dir, s_elem->name); + BLI_convertstringcode(name, G.sce); + BLI_convertstringframe(name, scene->r.cfra); + if (!build_proxy_run) { + se->ibuf = seq_proxy_fetch(scene, seq, cfra, render_size); + } + copy_from_ibuf_still(seq, se); + + if (!se->ibuf) { + se->ibuf= IMB_loadiffname( + name, IB_rect); + /* we don't need both (speed reasons)! */ + if (se->ibuf && + se->ibuf->rect_float && se->ibuf->rect) { + imb_freerectImBuf(se->ibuf); + } + + copy_to_ibuf_still(seq, se); + } + + if(se->ibuf == 0) { + se->ok = STRIPELEM_FAILED; + } else if (!build_proxy_run) { + input_preprocess(scene, seq, se, cfra); + } + } + } else if(seq->type == SEQ_MOVIE) { + if(se->ok == STRIPELEM_OK && se->ibuf==0) { + if(!build_proxy_run) { + se->ibuf = seq_proxy_fetch(scene, seq, cfra, render_size); + } + copy_from_ibuf_still(seq, se); + + if (se->ibuf == 0) { + if(seq->anim==0) { + BLI_join_dirfile(name, seq->strip->dir, seq->strip->stripdata->name); + BLI_convertstringcode(name, G.sce); + BLI_convertstringframe(name, scene->r.cfra); + + seq->anim = openanim( + name, IB_rect | + ((seq->flag & SEQ_FILTERY) + ? IB_animdeinterlace : 0)); + } + if(seq->anim) { + IMB_anim_set_preseek(seq->anim, seq->anim_preseek); + se->ibuf = IMB_anim_absolute(seq->anim, se->nr + seq->anim_startofs); + /* we don't need both (speed reasons)! */ + if (se->ibuf + && se->ibuf->rect_float + && se->ibuf->rect) { + imb_freerectImBuf(se->ibuf); + } + + } + copy_to_ibuf_still(seq, se); + } + + if(se->ibuf == 0) { + se->ok = STRIPELEM_FAILED; + } else if (!build_proxy_run) { + input_preprocess(scene, seq, se, cfra); + } + } + } else if(seq->type == SEQ_SCENE) { // scene can be NULL after deletions +#if 0 + /* XXX move entirely to render? */ + int oldcfra = CFRA; + Sequence * oldseq = get_last_seq(); + Scene *sce= seq->scene, *oldsce= scene; + Render *re; + RenderResult rres; + int doseq, rendering= G.rendering; + char scenename[64]; + int have_seq= (sce->r.scemode & R_DOSEQ) && sce->ed && sce->ed->seqbase.first; + int sce_valid =sce && (sce->camera || have_seq); + + if (se->ibuf == NULL && sce_valid && !build_proxy_run) { + se->ibuf = seq_proxy_fetch(scene, seq, cfra, render_size); + if (se->ibuf) { + input_preprocess(scene, seq, se, cfra); + } + } + + if (se->ibuf == NULL && sce_valid) { + copy_from_ibuf_still(seq, se); + if (se->ibuf) { + input_preprocess(scene, seq, se, cfra); + } + } + + if (!sce_valid) { + se->ok = STRIPELEM_FAILED; + } else if (se->ibuf==NULL && sce_valid) { + /* no need to display a waitcursor on sequencer + scene strips */ + if (!have_seq) + waitcursor(1); + + /* Hack! This function can be called from do_render_seq(), in that case + the seq->scene can already have a Render initialized with same name, + so we have to use a default name. (compositor uses scene name to + find render). + However, when called from within the UI (image preview in sequencer) + we do want to use scene Render, that way the render result is defined + for display in render/imagewindow */ + if(rendering) { + BLI_strncpy(scenename, sce->id.name+2, 64); + strcpy(sce->id.name+2, " do_build_seq_ibuf"); + } + re= RE_NewRender(sce->id.name); + + /* prevent eternal loop */ + doseq= scene->r.scemode & R_DOSEQ; + scene->r.scemode &= ~R_DOSEQ; + + BIF_init_render_callbacks(re, 0); /* 0= no display callbacks */ + + /* XXX hrms, set_scene still needed? work on that... */ + if(sce!=oldsce) set_scene_bg(sce); + RE_BlenderFrame(re, sce, + seq->sfra+se->nr+seq->anim_startofs); + if(sce!=oldsce) set_scene_bg(oldsce); + + /* UGLY WARNING, it is set to zero in RE_BlenderFrame */ + G.rendering= rendering; + if(rendering) + BLI_strncpy(sce->id.name+2, scenename, 64); + + RE_GetResultImage(re, &rres); + + if(rres.rectf) { + se->ibuf= IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat, 0); + memcpy(se->ibuf->rect_float, rres.rectf, 4*sizeof(float)*rres.rectx*rres.recty); + if(rres.rectz) { + addzbuffloatImBuf(se->ibuf); + memcpy(se->ibuf->zbuf_float, rres.rectz, sizeof(float)*rres.rectx*rres.recty); + } + } else if (rres.rect32) { + se->ibuf= IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect, 0); + memcpy(se->ibuf->rect, rres.rect32, 4*rres.rectx*rres.recty); + } + + BIF_end_render_callbacks(); + + /* restore */ + scene->r.scemode |= doseq; + + // XXX +#if 0 + if((G.f & G_PLAYANIM)==0 /* bad, is set on do_render_seq */ + && !have_seq + && !build_proxy_run) +#endif + + CFRA = oldcfra; + set_last_seq(oldseq); + + copy_to_ibuf_still(seq, se); + + if (!build_proxy_run) { + if(se->ibuf == NULL) { + se->ok = STRIPELEM_FAILED; + } else { + input_preprocess(scene, seq, se, cfra); + } + } + + } +#endif + } + if (!build_proxy_run) { + if (se->ibuf && use_limiter) { + IMB_cache_limiter_insert(se->ibuf); + IMB_cache_limiter_ref(se->ibuf); + IMB_cache_limiter_touch(se->ibuf); + } + } +} + +static TStripElem* do_build_seq_recursively(Scene *scene, Sequence *seq, int cfra, int render_size); + +static void do_effect_seq_recursively(Scene *scene, Sequence *seq, TStripElem *se, int cfra, int render_size) +{ + float fac, facf; + struct SeqEffectHandle sh = get_sequence_effect(seq); + int early_out; + + se->se1 = 0; + se->se2 = 0; + se->se3 = 0; + +#if 0 // XXX old animation system + if(seq->ipo && seq->ipo->curve.first) { + do_seq_ipo(scene, seq, cfra); + fac= seq->facf0; + facf= seq->facf1; + } else +#endif // XXX old animation system + { + sh.get_default_fac(seq, cfra, &fac, &facf); + } + + if( scene->r.mode & R_FIELDS ); else facf= fac; + + early_out = sh.early_out(seq, fac, facf); + switch (early_out) { + case -1: + /* no input needed */ + break; + case 0: + se->se1 = do_build_seq_recursively(scene, seq->seq1, cfra, render_size); + se->se2 = do_build_seq_recursively(scene, seq->seq2, cfra, render_size); + if (seq->seq3) { + se->se3 = do_build_seq_recursively(scene, seq->seq3, cfra, render_size); + } + break; + case 1: + se->se1 = do_build_seq_recursively(scene, seq->seq1, cfra, render_size); + break; + case 2: + se->se2 = do_build_seq_recursively(scene, seq->seq2, cfra, render_size); + break; + } + + + do_build_seq_ibuf(scene, seq, se, cfra, FALSE, render_size); + + /* children are not needed anymore ... */ + + if (se->se1 && se->se1->ibuf) { + IMB_cache_limiter_unref(se->se1->ibuf); + } + if (se->se2 && se->se2->ibuf) { + IMB_cache_limiter_unref(se->se2->ibuf); + } + if (se->se3 && se->se3->ibuf) { + IMB_cache_limiter_unref(se->se3->ibuf); + } + check_limiter_refcount("do_effect_seq_recursively", se); +} + +static TStripElem* do_build_seq_recursively_impl(Scene *scene, Sequence * seq, int cfra, int render_size) +{ + TStripElem *se; + + se = give_tstripelem(seq, cfra); + + if(se) { + if (seq->type & SEQ_EFFECT) { + do_effect_seq_recursively(scene, seq, se, cfra, render_size); + } else { + do_build_seq_ibuf(scene, seq, se, cfra, FALSE, render_size); + } + } + return se; +} + +/* FIXME: + +If cfra was float throughout blender (especially in the render +pipeline) one could even _render_ with subframe precision +instead of faking using the blend code below... + +*/ + +static TStripElem* do_handle_speed_effect(Scene *scene, Sequence * seq, int cfra, int render_size) +{ + SpeedControlVars * s = (SpeedControlVars *)seq->effectdata; + int nr = cfra - seq->start; + float f_cfra; + int cfra_left; + int cfra_right; + TStripElem * se = 0; + TStripElem * se1 = 0; + TStripElem * se2 = 0; + + sequence_effect_speed_rebuild_map(seq, 0); + + f_cfra = seq->start + s->frameMap[nr]; + + cfra_left = (int) floor(f_cfra); + cfra_right = (int) ceil(f_cfra); + + se = give_tstripelem(seq, cfra); + + if (!se) { + return se; + } + + if (cfra_left == cfra_right || + (s->flags & SEQ_SPEED_BLEND) == 0) { + test_and_auto_discard_ibuf(se); + + if (se->ibuf == NULL) { + se1 = do_build_seq_recursively_impl(scene, seq->seq1, cfra_left, render_size); + + if((se1 && se1->ibuf && se1->ibuf->rect_float)) + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0); + else + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0); + + if (se1 == 0 || se1->ibuf == 0) { + make_black_ibuf(se->ibuf); + } else { + if (se->ibuf != se1->ibuf) { + if (se->ibuf) { + IMB_freeImBuf(se->ibuf); + } + + se->ibuf = se1->ibuf; + IMB_refImBuf(se->ibuf); + } + } + } + } else { + struct SeqEffectHandle sh; + + if(se->ibuf) { + if(se->ibuf->x < seqrectx || se->ibuf->y < seqrecty + || !(se->ibuf->rect || se->ibuf->rect_float)) { + IMB_freeImBuf(se->ibuf); + se->ibuf= 0; + } + } + + if (se->ibuf == NULL) { + se1 = do_build_seq_recursively_impl(scene, seq->seq1, cfra_left, render_size); + se2 = do_build_seq_recursively_impl(scene, seq->seq1, cfra_right, render_size); + + if((se1 && se1->ibuf && se1->ibuf->rect_float)) + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0); + else + se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0); + + if (!se1 || !se2) { + make_black_ibuf(se->ibuf); + } else { + sh = get_sequence_effect(seq); + + sh.execute(seq, cfra, + f_cfra - (float) cfra_left, + f_cfra - (float) cfra_left, + se->ibuf->x, se->ibuf->y, + se1->ibuf, se2->ibuf, 0, se->ibuf); + } + } + + } + + /* caller expects this to be referenced, so do it! */ + if (se->ibuf) { + IMB_cache_limiter_insert(se->ibuf); + IMB_cache_limiter_ref(se->ibuf); + IMB_cache_limiter_touch(se->ibuf); + } + + /* children are no longer needed */ + if (se1 && se1->ibuf) + IMB_cache_limiter_unref(se1->ibuf); + if (se2 && se2->ibuf) + IMB_cache_limiter_unref(se2->ibuf); + + check_limiter_refcount("do_handle_speed_effect", se); + + return se; +} + +/* + * build all ibufs recursively + * + * if successfull, the returned TStripElem contains the (referenced!) imbuf + * that means: you _must_ call + * + * IMB_cache_limiter_unref(rval); + * + * if rval != 0 + * + */ + +static TStripElem* do_build_seq_recursively(Scene *scene, Sequence * seq, int cfra, int render_size) +{ + TStripElem *se; + if (seq->type == SEQ_SPEED) { + se = do_handle_speed_effect(scene, seq, cfra, render_size); + } else { + se = do_build_seq_recursively_impl(scene, seq, cfra, render_size); + } + + check_limiter_refcount("do_build_seq_recursively", se); + + return se; +} + +static TStripElem* do_build_seq_array_recursively(Scene *scene, + ListBase *seqbasep, int cfra, int chanshown, int render_size) +{ + Sequence* seq_arr[MAXSEQ+1]; + int count; + int i; + TStripElem* se = 0; + + count = get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr); + + if (!count) { + return 0; + } + + se = give_tstripelem(seq_arr[count - 1], cfra); + + if (!se) { + return 0; + } + + test_and_auto_discard_ibuf(se); + + if (se->ibuf_comp != 0) { + IMB_cache_limiter_insert(se->ibuf_comp); + IMB_cache_limiter_ref(se->ibuf_comp); + IMB_cache_limiter_touch(se->ibuf_comp); + return se; + } + + + if(count == 1) { + se = do_build_seq_recursively(scene, seq_arr[0], cfra, render_size); + if (se->ibuf) { + se->ibuf_comp = se->ibuf; + IMB_refImBuf(se->ibuf_comp); + } + return se; + } + + + for (i = count - 1; i >= 0; i--) { + int early_out; + Sequence * seq = seq_arr[i]; + struct SeqEffectHandle sh; + + se = give_tstripelem(seq, cfra); + + test_and_auto_discard_ibuf(se); + + if (se->ibuf_comp != 0) { + break; + } + if (seq->blend_mode == SEQ_BLEND_REPLACE) { + do_build_seq_recursively(scene, seq, cfra, render_size); + if (se->ibuf) { + se->ibuf_comp = se->ibuf; + IMB_refImBuf(se->ibuf); + } else { + se->ibuf_comp = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rect, 0); + IMB_cache_limiter_insert(se->ibuf_comp); + IMB_cache_limiter_ref(se->ibuf_comp); + IMB_cache_limiter_touch(se->ibuf_comp); + } + break; + } + + sh = get_sequence_blend(seq); + + seq->facf0 = seq->facf1 = 1.0; + +#if 0 // XXX old animation system + if(seq->ipo && seq->ipo->curve.first) { + do_seq_ipo(scene, seq, cfra); + } +#endif + + if( scene->r.mode & R_FIELDS ); else seq->facf0 = seq->facf1; + + seq->facf0 *= seq->blend_opacity / 100.0; + seq->facf1 *= seq->blend_opacity / 100.0; + + early_out = sh.early_out(seq, seq->facf0, seq->facf1); + + switch (early_out) { + case -1: + case 2: + do_build_seq_recursively(scene, seq, cfra, render_size); + if (se->ibuf) { + se->ibuf_comp = se->ibuf; + IMB_refImBuf(se->ibuf_comp); + } else { + se->ibuf_comp = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rect, 0); + IMB_cache_limiter_insert(se->ibuf_comp); + IMB_cache_limiter_ref(se->ibuf_comp); + IMB_cache_limiter_touch(se->ibuf_comp); + } + break; + case 1: + if (i == 0) { + se->ibuf_comp = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rect, 0); + IMB_cache_limiter_insert(se->ibuf_comp); + IMB_cache_limiter_ref(se->ibuf_comp); + IMB_cache_limiter_touch(se->ibuf_comp); + } + break; + case 0: + do_build_seq_recursively(scene, seq, cfra, render_size); + if (!se->ibuf) { + se->ibuf = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rect, 0); + IMB_cache_limiter_insert(se->ibuf); + IMB_cache_limiter_ref(se->ibuf); + IMB_cache_limiter_touch(se->ibuf); + } + if (i == 0) { + se->ibuf_comp = se->ibuf; + IMB_refImBuf(se->ibuf_comp); + } + break; + } + + if (se->ibuf_comp) { + break; + } + } + + i++; + + for (; i < count; i++) { + Sequence * seq = seq_arr[i]; + struct SeqEffectHandle sh = get_sequence_blend(seq); + TStripElem* se1 = give_tstripelem(seq_arr[i-1], cfra); + TStripElem* se2 = give_tstripelem(seq_arr[i], cfra); + + int early_out = sh.early_out(seq, seq->facf0, seq->facf1); + switch (early_out) { + case 0: { + int x= se2->ibuf->x; + int y= se2->ibuf->y; + int swap_input = FALSE; + + if (se1->ibuf_comp->rect_float || + se2->ibuf->rect_float) { + se2->ibuf_comp = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rectfloat, 0); + } else { + se2->ibuf_comp = IMB_allocImBuf( + (short)seqrectx, (short)seqrecty, + 32, IB_rect, 0); + } + + + if (!se1->ibuf_comp->rect_float && + se2->ibuf_comp->rect_float) { + IMB_float_from_rect(se1->ibuf_comp); + } + if (!se2->ibuf->rect_float && + se2->ibuf_comp->rect_float) { + IMB_float_from_rect(se2->ibuf); + } + + if (!se1->ibuf_comp->rect && + !se2->ibuf_comp->rect_float) { + IMB_rect_from_float(se1->ibuf_comp); + } + if (!se2->ibuf->rect && + !se2->ibuf_comp->rect_float) { + IMB_rect_from_float(se2->ibuf); + } + + /* bad hack, to fix crazy input ordering of + those two effects */ + + if (seq->blend_mode == SEQ_ALPHAOVER || + seq->blend_mode == SEQ_ALPHAUNDER || + seq->blend_mode == SEQ_OVERDROP) { + swap_input = TRUE; + } + + if (swap_input) { + sh.execute(seq, cfra, + seq->facf0, seq->facf1, x, y, + se2->ibuf, se1->ibuf_comp, 0, + se2->ibuf_comp); + } else { + sh.execute(seq, cfra, + seq->facf0, seq->facf1, x, y, + se1->ibuf_comp, se2->ibuf, 0, + se2->ibuf_comp); + } + + IMB_cache_limiter_insert(se2->ibuf_comp); + IMB_cache_limiter_ref(se2->ibuf_comp); + IMB_cache_limiter_touch(se2->ibuf_comp); + + IMB_cache_limiter_unref(se1->ibuf_comp); + IMB_cache_limiter_unref(se2->ibuf); + + break; + } + case 1: { + se2->ibuf_comp = se1->ibuf; + IMB_refImBuf(se2->ibuf_comp); + + break; + } + } + se = se2; + } + + return se; +} + +/* + * returned ImBuf is refed! + * you have to unref after usage! + */ + +static ImBuf *give_ibuf_seq_impl(Scene *scene, int rectx, int recty, int cfra, int chanshown, int render_size) +{ + Editing *ed= seq_give_editing(scene, FALSE); + int count; + ListBase *seqbasep; + TStripElem *se; + + + if(ed==NULL) return NULL; + + count = BLI_countlist(&ed->metastack); + if((chanshown < 0) && (count > 0)) { + count = MAX2(count + chanshown, 0); + seqbasep= ((MetaStack*)BLI_findlink(&ed->metastack, count))->oldbasep; + } else { + seqbasep= ed->seqbasep; + } + + seqrectx= rectx; /* bad bad global! */ + seqrecty= recty; + + se = do_build_seq_array_recursively(scene, seqbasep, cfra, chanshown, render_size); + + if(!se) { + return 0; + } + + check_limiter_refcount_comp("give_ibuf_seq_impl", se); + + return se->ibuf_comp; +} + +ImBuf *give_ibuf_seq_direct(Scene *scene, int rectx, int recty, int cfra, int render_size, Sequence *seq) +{ + TStripElem* se; + + seqrectx= rectx; /* bad bad global! */ + seqrecty= recty; + + se = do_build_seq_recursively(scene, seq, cfra, render_size); + + if(!se) { + return 0; + } + + check_limiter_refcount("give_ibuf_seq_direct", se); + + if (se->ibuf) { + IMB_cache_limiter_unref(se->ibuf); + } + + return se->ibuf; +} + +ImBuf *give_ibuf_seq(Scene *scene, int rectx, int recty, int cfra, int chanshown, int render_size) +{ + ImBuf* i = give_ibuf_seq_impl(scene, rectx, recty, cfra, chanshown, render_size); + + if (i) { + IMB_cache_limiter_unref(i); + } + return i; +} + +/* check used when we need to change seq->blend_mode but not to effect or audio strips */ +int seq_can_blend(Sequence *seq) +{ + if (ELEM4(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE)) { + return 1; + } else { + return 0; + } +} + +/* *********************** threading api ******************* */ + +static ListBase running_threads; +static ListBase prefetch_wait; +static ListBase prefetch_done; + +static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t wakeup_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t wakeup_cond = PTHREAD_COND_INITIALIZER; + +static pthread_mutex_t prefetch_ready_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t prefetch_ready_cond = PTHREAD_COND_INITIALIZER; + +static pthread_mutex_t frame_done_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t frame_done_cond = PTHREAD_COND_INITIALIZER; + +static volatile int seq_thread_shutdown = FALSE; +static volatile int seq_last_given_monoton_cfra = 0; +static int monoton_cfra = 0; + +typedef struct PrefetchThread { + struct PrefetchThread *next, *prev; + + Scene *scene; + struct PrefetchQueueElem *current; + pthread_t pthread; + int running; + +} PrefetchThread; + +typedef struct PrefetchQueueElem { + struct PrefetchQueueElem *next, *prev; + + int rectx; + int recty; + int cfra; + int chanshown; + int render_size; + + int monoton_cfra; + + struct ImBuf * ibuf; +} PrefetchQueueElem; + +static void *seq_prefetch_thread(void * This_) +{ + PrefetchThread * This = This_; + + while (!seq_thread_shutdown) { + PrefetchQueueElem *e; + int s_last; + + pthread_mutex_lock(&queue_lock); + e = prefetch_wait.first; + if (e) { + BLI_remlink(&prefetch_wait, e); + } + s_last = seq_last_given_monoton_cfra; + + This->current = e; + + pthread_mutex_unlock(&queue_lock); + + if (!e) { + pthread_mutex_lock(&prefetch_ready_lock); + + This->running = FALSE; + + pthread_cond_signal(&prefetch_ready_cond); + pthread_mutex_unlock(&prefetch_ready_lock); + + pthread_mutex_lock(&wakeup_lock); + if (!seq_thread_shutdown) { + pthread_cond_wait(&wakeup_cond, &wakeup_lock); + } + pthread_mutex_unlock(&wakeup_lock); + continue; + } + + This->running = TRUE; + + if (e->cfra >= s_last) { + e->ibuf = give_ibuf_seq_impl(This->scene, + e->rectx, e->recty, e->cfra, e->chanshown, + e->render_size); + } + + pthread_mutex_lock(&queue_lock); + + BLI_addtail(&prefetch_done, e); + + for (e = prefetch_wait.first; e; e = e->next) { + if (s_last > e->monoton_cfra) { + BLI_remlink(&prefetch_wait, e); + MEM_freeN(e); + } + } + + for (e = prefetch_done.first; e; e = e->next) { + if (s_last > e->monoton_cfra) { + if (e->ibuf) { + IMB_cache_limiter_unref(e->ibuf); + } + BLI_remlink(&prefetch_done, e); + MEM_freeN(e); + } + } + + pthread_mutex_unlock(&queue_lock); + + pthread_mutex_lock(&frame_done_lock); + pthread_cond_signal(&frame_done_cond); + pthread_mutex_unlock(&frame_done_lock); + } + return 0; +} + +void seq_start_threads(Scene *scene) +{ + int i; + + running_threads.first = running_threads.last = NULL; + prefetch_wait.first = prefetch_wait.last = NULL; + prefetch_done.first = prefetch_done.last = NULL; + + seq_thread_shutdown = FALSE; + seq_last_given_monoton_cfra = monoton_cfra = 0; + + /* since global structures are modified during the processing + of one frame, only one render thread is currently possible... + + (but we code, in the hope, that we can remove this restriction + soon...) + */ + + fprintf(stderr, "SEQ-THREAD: seq_start_threads\n"); + + for (i = 0; i < 1; i++) { + PrefetchThread *t = MEM_callocN(sizeof(PrefetchThread), "prefetch_thread"); + t->scene= scene; + t->running = TRUE; + BLI_addtail(&running_threads, t); + + pthread_create(&t->pthread, NULL, seq_prefetch_thread, t); + } + + /* init malloc mutex */ + BLI_init_threads(0, 0, 0); +} + +void seq_stop_threads() +{ + PrefetchThread *tslot; + PrefetchQueueElem *e; + + fprintf(stderr, "SEQ-THREAD: seq_stop_threads()\n"); + + if (seq_thread_shutdown) { + fprintf(stderr, "SEQ-THREAD: ... already stopped\n"); + return; + } + + pthread_mutex_lock(&wakeup_lock); + + seq_thread_shutdown = TRUE; + + pthread_cond_broadcast(&wakeup_cond); + pthread_mutex_unlock(&wakeup_lock); + + for(tslot = running_threads.first; tslot; tslot= tslot->next) { + pthread_join(tslot->pthread, NULL); + } + + + for (e = prefetch_wait.first; e; e = e->next) { + BLI_remlink(&prefetch_wait, e); + MEM_freeN(e); + } + + for (e = prefetch_done.first; e; e = e->next) { + if (e->ibuf) { + IMB_cache_limiter_unref(e->ibuf); + } + BLI_remlink(&prefetch_done, e); + MEM_freeN(e); + } + + BLI_freelistN(&running_threads); + + /* deinit malloc mutex */ + BLI_end_threads(0); +} + +void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown, + int render_size) +{ + PrefetchQueueElem *e; + if (seq_thread_shutdown) { + return; + } + + e = MEM_callocN(sizeof(PrefetchQueueElem), "prefetch_queue_elem"); + e->rectx = rectx; + e->recty = recty; + e->cfra = cfra; + e->chanshown = chanshown; + e->render_size = render_size; + e->monoton_cfra = monoton_cfra++; + + pthread_mutex_lock(&queue_lock); + BLI_addtail(&prefetch_wait, e); + pthread_mutex_unlock(&queue_lock); + + pthread_mutex_lock(&wakeup_lock); + pthread_cond_signal(&wakeup_cond); + pthread_mutex_unlock(&wakeup_lock); +} + +void seq_wait_for_prefetch_ready() +{ + PrefetchThread *tslot; + + if (seq_thread_shutdown) { + return; + } + + fprintf(stderr, "SEQ-THREAD: rendering prefetch frames...\n"); + + pthread_mutex_lock(&prefetch_ready_lock); + + for(;;) { + for(tslot = running_threads.first; tslot; tslot= tslot->next) { + if (tslot->running) { + break; + } + } + if (!tslot) { + break; + } + pthread_cond_wait(&prefetch_ready_cond, &prefetch_ready_lock); + } + + pthread_mutex_unlock(&prefetch_ready_lock); + + fprintf(stderr, "SEQ-THREAD: prefetch done\n"); +} + +ImBuf *give_ibuf_seq_threaded(Scene *scene, int rectx, int recty, int cfra, int chanshown, int render_size) +{ + PrefetchQueueElem *e = NULL; + int found_something = FALSE; + + if (seq_thread_shutdown) { + return give_ibuf_seq(scene, rectx, recty, cfra, chanshown, render_size); + } + + while (!e) { + int success = FALSE; + pthread_mutex_lock(&queue_lock); + + for (e = prefetch_done.first; e; e = e->next) { + if (cfra == e->cfra && + chanshown == e->chanshown && + rectx == e->rectx && + recty == e->recty && + render_size == e->render_size) { + success = TRUE; + found_something = TRUE; + break; + } + } + + if (!e) { + for (e = prefetch_wait.first; e; e = e->next) { + if (cfra == e->cfra && + chanshown == e->chanshown && + rectx == e->rectx && + recty == e->recty && + render_size == e->render_size) { + found_something = TRUE; + break; + } + } + } + + if (!e) { + PrefetchThread *tslot; + + for(tslot = running_threads.first; + tslot; tslot= tslot->next) { + if (tslot->current && + cfra == tslot->current->cfra && + chanshown == tslot->current->chanshown && + rectx == tslot->current->rectx && + recty == tslot->current->recty && + render_size== tslot->current->render_size){ + found_something = TRUE; + break; + } + } + } + + /* e->ibuf is unrefed by render thread on next round. */ + + if (e) { + seq_last_given_monoton_cfra = e->monoton_cfra; + } + + pthread_mutex_unlock(&queue_lock); + + if (!success) { + e = NULL; + + if (!found_something) { + fprintf(stderr, + "SEQ-THREAD: Requested frame " + "not in queue ???\n"); + break; + } + pthread_mutex_lock(&frame_done_lock); + pthread_cond_wait(&frame_done_cond, &frame_done_lock); + pthread_mutex_unlock(&frame_done_lock); + } + } + + return e ? e->ibuf : 0; +} + +/* Functions to free imbuf and anim data on changes */ + +static void free_imbuf_strip_elem(TStripElem *se) +{ + if(se->ibuf) { + IMB_freeImBuf(se->ibuf); + } + if(se->ibuf_comp) { + IMB_freeImBuf(se->ibuf_comp); + } + se->ibuf_comp = 0; + se->ibuf= 0; + se->ok= STRIPELEM_OK; + se->se1= se->se2= se->se3= 0; +} + +static void free_anim_seq(Sequence *seq) +{ + if(seq->anim) { + IMB_free_anim(seq->anim); + seq->anim = 0; + } +} + +void free_imbuf_seq_except(Scene *scene, int cfra) +{ + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + TStripElem *se; + int a; + + if(ed==NULL) return; + + SEQ_BEGIN(ed, seq) { + if(seq->strip) { + TStripElem * curelem = give_tstripelem(seq, cfra); + + for(a = 0, se = seq->strip->tstripdata; + a < seq->strip->len && se; a++, se++) { + if(se != curelem) { + free_imbuf_strip_elem(se); + } + } + for(a = 0, se = seq->strip->tstripdata_startstill; + a < seq->strip->startstill && se; a++, se++) { + if(se != curelem) { + free_imbuf_strip_elem(se); + } + } + for(a = 0, se = seq->strip->tstripdata_endstill; + a < seq->strip->endstill && se; a++, se++) { + if(se != curelem) { + free_imbuf_strip_elem(se); + } + } + if(seq->strip->ibuf_startstill) { + IMB_freeImBuf(seq->strip->ibuf_startstill); + seq->strip->ibuf_startstill = 0; + } + + if(seq->strip->ibuf_endstill) { + IMB_freeImBuf(seq->strip->ibuf_endstill); + seq->strip->ibuf_endstill = 0; + } + + if(seq->type==SEQ_MOVIE) + if(seq->startdisp > cfra || seq->enddisp < cfra) + free_anim_seq(seq); + free_proxy_seq(seq); + } + } + SEQ_END +} + +void free_imbuf_seq(ListBase * seqbase, int check_mem_usage) +{ + Sequence *seq; + TStripElem *se; + int a; + + if (check_mem_usage) { + /* Let the cache limitor take care of this (schlaile) */ + /* While render let's keep all memory available for render + (ton) + At least if free memory is tight... + This can make a big difference in encoding speed + (it is around 4 times(!) faster, if we do not waste time + on freeing _all_ buffers every time on long timelines...) + (schlaile) + */ + + uintptr_t mem_in_use; + uintptr_t mmap_in_use; + uintptr_t max; + + mem_in_use= MEM_get_memory_in_use(); + mmap_in_use= MEM_get_mapped_memory_in_use(); + max = MEM_CacheLimiter_get_maximum(); + + if (max == 0 || mem_in_use + mmap_in_use <= max) { + return; + } + } + + + for(seq= seqbase->first; seq; seq= seq->next) { + if(seq->strip) { + for(a = 0, se = seq->strip->tstripdata; + a < seq->strip->len && se; a++, se++) { + free_imbuf_strip_elem(se); + } + for(a = 0, se = seq->strip->tstripdata_startstill; + a < seq->strip->startstill && se; a++, se++) { + free_imbuf_strip_elem(se); + } + for(a = 0, se = seq->strip->tstripdata_endstill; + a < seq->strip->endstill && se; a++, se++) { + free_imbuf_strip_elem(se); + } + if(seq->strip->ibuf_startstill) { + IMB_freeImBuf(seq->strip->ibuf_startstill); + seq->strip->ibuf_startstill = 0; + } + + if(seq->strip->ibuf_endstill) { + IMB_freeImBuf(seq->strip->ibuf_endstill); + seq->strip->ibuf_endstill = 0; + } + + if(seq->type==SEQ_MOVIE) + free_anim_seq(seq); + if(seq->type==SEQ_SPEED) { + sequence_effect_speed_rebuild_map(seq, 1); + } + } + if(seq->type==SEQ_META) { + free_imbuf_seq(&seq->seqbase, FALSE); + } + if(seq->type==SEQ_SCENE) { + /* FIXME: recurs downwards, + but do recurs protection somehow! */ + } + } + +} + +static int update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *changed_seq, int len_change, int ibuf_change) +{ + Sequence *subseq; + int a, free_imbuf = 0; + TStripElem *se; + + /* recurs downwards to see if this seq depends on the changed seq */ + + if(seq == NULL) + return 0; + + if(seq == changed_seq) + free_imbuf = 1; + + for(subseq=seq->seqbase.first; subseq; subseq=subseq->next) + if(update_changed_seq_recurs(scene, subseq, changed_seq, len_change, ibuf_change)) + free_imbuf = TRUE; + + if(seq->seq1) + if(update_changed_seq_recurs(scene, seq->seq1, changed_seq, len_change, ibuf_change)) + free_imbuf = TRUE; + if(seq->seq2 && (seq->seq2 != seq->seq1)) + if(update_changed_seq_recurs(scene, seq->seq2, changed_seq, len_change, ibuf_change)) + free_imbuf = TRUE; + if(seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) + if(update_changed_seq_recurs(scene, seq->seq3, changed_seq, len_change, ibuf_change)) + free_imbuf = TRUE; + + if(free_imbuf) { + if(ibuf_change) { + se= seq->strip->tstripdata; + if (se) { + for(a=0; a<seq->len; a++, se++) + free_imbuf_strip_elem(se); + } + + if(seq->type == SEQ_MOVIE) + free_anim_seq(seq); + if(seq->type == SEQ_SPEED) { + sequence_effect_speed_rebuild_map(seq, 1); + } + } + + if(len_change) + calc_sequence(seq); + } + + return free_imbuf; +} + +void update_changed_seq_and_deps(Scene *scene, Sequence *changed_seq, int len_change, int ibuf_change) +{ + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + + if (ed==NULL) return; + + for (seq=ed->seqbase.first; seq; seq=seq->next) + update_changed_seq_recurs(scene, seq, changed_seq, len_change, ibuf_change); +} + +#if 0 // XXX from 2.4x, needs updating +void free_imbuf_seq() +{ + Scene * sce = G.main->scene.first; + while(sce) { + free_imbuf_seq_editing(sce->ed); + sce= sce->id.next; + } +} +#endif + +void free_imbuf_seq_with_ipo(Scene *scene, struct Ipo *ipo) +{ + /* force update of all sequences with this ipo, on ipo changes */ + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + + if(ed==NULL) return; + + SEQ_BEGIN(ed, seq) { + if(seq->ipo == ipo) { + update_changed_seq_and_deps(scene, seq, 0, 1); + if(seq->type == SEQ_SPEED) { + sequence_effect_speed_rebuild_map(seq, 1); + } + free_proxy_seq(seq); + } + } + SEQ_END +} + +/* seq funcs's for transforming internally + notice the difference between start/end and left/right. + + left and right are the bounds at which the sequence is rendered, +start and end are from the start and fixed length of the sequence. +*/ +int seq_tx_get_start(Sequence *seq) { + return seq->start; +} +int seq_tx_get_end(Sequence *seq) +{ + return seq->start+seq->len; +} + +int seq_tx_get_final_left(Sequence *seq, int metaclip) +{ + if (metaclip && seq->tmp) { + /* return the range clipped by the parents range */ + return MAX2( seq_tx_get_final_left(seq, 0), seq_tx_get_final_left((Sequence *)seq->tmp, 1) ); + } else { + return (seq->start - seq->startstill) + seq->startofs; + } + +} +int seq_tx_get_final_right(Sequence *seq, int metaclip) +{ + if (metaclip && seq->tmp) { + /* return the range clipped by the parents range */ + return MIN2( seq_tx_get_final_right(seq, 0), seq_tx_get_final_right((Sequence *)seq->tmp, 1) ); + } else { + return ((seq->start+seq->len) + seq->endstill) - seq->endofs; + } +} + +void seq_tx_set_final_left(Sequence *seq, int val) +{ + if (val < (seq)->start) { + seq->startstill = abs(val - (seq)->start); + (seq)->startofs = 0; + } else { + seq->startofs = abs(val - (seq)->start); + seq->startstill = 0; + } +} + +void seq_tx_set_final_right(Sequence *seq, int val) +{ + if (val > (seq)->start + (seq)->len) { + seq->endstill = abs(val - (seq->start + (seq)->len)); + (seq)->endofs = 0; + } else { + seq->endofs = abs(val - ((seq)->start + (seq)->len)); + seq->endstill = 0; + } +} + +/* used so we can do a quick check for single image seq + since they work a bit differently to normal image seq's (during transform) */ +int check_single_seq(Sequence *seq) +{ + if ( seq->len==1 && (seq->type == SEQ_IMAGE || seq->type == SEQ_COLOR)) + return 1; + else + return 0; +} + +/* use to impose limits when dragging/extending - so impossible situations dont happen + * Cant use the SEQ_LEFTSEL and SEQ_LEFTSEL directly because the strip may be in a metastrip */ +void seq_tx_handle_xlimits(Sequence *seq, int leftflag, int rightflag) +{ + if(leftflag) { + if (seq_tx_get_final_left(seq, 0) >= seq_tx_get_final_right(seq, 0)) { + seq_tx_set_final_left(seq, seq_tx_get_final_right(seq, 0)-1); + } + + if (check_single_seq(seq)==0) { + if (seq_tx_get_final_left(seq, 0) >= seq_tx_get_end(seq)) { + seq_tx_set_final_left(seq, seq_tx_get_end(seq)-1); + } + + /* dosnt work now - TODO */ + /* + if (seq_tx_get_start(seq) >= seq_tx_get_final_right(seq, 0)) { + int ofs; + ofs = seq_tx_get_start(seq) - seq_tx_get_final_right(seq, 0); + seq->start -= ofs; + seq_tx_set_final_left(seq, seq_tx_get_final_left(seq, 0) + ofs ); + }*/ + + } + } + + if(rightflag) { + if (seq_tx_get_final_right(seq, 0) <= seq_tx_get_final_left(seq, 0)) { + seq_tx_set_final_right(seq, seq_tx_get_final_left(seq, 0)+1); + } + + if (check_single_seq(seq)==0) { + if (seq_tx_get_final_right(seq, 0) <= seq_tx_get_start(seq)) { + seq_tx_set_final_right(seq, seq_tx_get_start(seq)+1); + } + } + } + + /* sounds cannot be extended past their endpoints */ + if (seq->type == SEQ_SOUND) { + seq->startstill= 0; + seq->endstill= 0; + } +} + +void fix_single_seq(Sequence *seq) +{ + int left, start, offset; + if (!check_single_seq(seq)) + return; + + /* make sure the image is always at the start since there is only one, + adjusting its start should be ok */ + left = seq_tx_get_final_left(seq, 0); + start = seq->start; + if (start != left) { + offset = left - start; + seq_tx_set_final_left( seq, seq_tx_get_final_left(seq, 0) - offset ); + seq_tx_set_final_right( seq, seq_tx_get_final_right(seq, 0) - offset ); + seq->start += offset; + } +} + +int seq_tx_test(Sequence * seq) +{ + return (seq->type < SEQ_EFFECT) || (get_sequence_effect_num_inputs(seq->type) == 0); +} + +int seq_test_overlap(ListBase * seqbasep, Sequence *test) +{ + Sequence *seq; + + seq= seqbasep->first; + while(seq) { + if(seq!=test) { + if(test->machine==seq->machine) { + if( (test->enddisp <= seq->startdisp) || (test->startdisp >= seq->enddisp) ); + else return 1; + } + } + seq= seq->next; + } + return 0; +} + + +static void seq_translate(Sequence *seq, int delta) +{ + seq->start += delta; + if(seq->type==SEQ_META) { + Sequence *seq_child; + for(seq_child= seq->seqbase.first; seq_child; seq_child= seq_child->next) { + seq_translate(seq_child, delta); + } + } + + calc_sequence_disp(seq); +} + +/* return 0 if there werent enough space */ +int shuffle_seq(ListBase * seqbasep, Sequence *test) +{ + int orig_machine= test->machine; + test->machine++; + calc_sequence(test); + while( seq_test_overlap(seqbasep, test) ) { + if(test->machine >= MAXSEQ) { + break; + } + test->machine++; + calc_sequence(test); // XXX - I dont think this is needed since were only moving vertically, Campbell. + } + + + if(test->machine >= MAXSEQ) { + /* Blender 2.4x would remove the strip. + * nicer to move it to the end */ + + Sequence *seq; + int new_frame= test->enddisp; + + for(seq= seqbasep->first; seq; seq= seq->next) { + if (seq->machine == orig_machine) + new_frame = MAX2(new_frame, seq->enddisp); + } + + test->machine= orig_machine; + new_frame = new_frame + (test->start-test->startdisp); /* adjust by the startdisp */ + seq_translate(test, new_frame - test->start); + + calc_sequence(test); + return 0; + } else { + return 1; + } +} + +void seq_update_sound(struct Sequence *seq) +{ + if(seq->type == SEQ_SOUND) + { + seq->sound_handle->startframe = seq->startdisp; + seq->sound_handle->endframe = seq->enddisp; + seq->sound_handle->frameskip = seq->startofs + seq->anim_startofs; + seq->sound_handle->mute = seq->flag & SEQ_MUTE ? 1 : 0; + seq->sound_handle->changed = -1; + } +} diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 69ce9f3d5cd..27357d92aae 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -38,6 +38,7 @@ #include "DNA_modifier_types.h" #include "DNA_meshdata_types.h" #include "DNA_mesh_types.h" +#include "DNA_scene_types.h" #include "BKE_shrinkwrap.h" #include "BKE_DerivedMesh.h" @@ -47,15 +48,18 @@ #include "BKE_cdderivedmesh.h" #include "BKE_displist.h" #include "BKE_global.h" +#include "BKE_mesh.h" #include "BKE_subsurf.h" #include "BLI_arithb.h" #include "BLI_kdtree.h" #include "BLI_kdopbvh.h" +#include "BLI_editVert.h" #include "RE_raytrace.h" #include "MEM_guardedalloc.h" +#include "ED_mesh.h" /* Util macros */ #define TO_STR(a) #a @@ -91,16 +95,21 @@ typedef void ( *Shrinkwrap_ForeachVertexCallback) (DerivedMesh *target, float *c /* get derived mesh */ //TODO is anyfunction that does this? returning the derivedFinal witouth we caring if its in edit mode or not? -DerivedMesh *object_get_derived_final(Object *ob, CustomDataMask dataMask) +DerivedMesh *object_get_derived_final(struct Scene *scene, Object *ob, CustomDataMask dataMask) { - if (ob==G.obedit) + Mesh *me= ob->data; + EditMesh *em = BKE_mesh_get_editmesh(me); + + if (em) { DerivedMesh *final = NULL; - editmesh_get_derived_cage_and_final(&final, dataMask); + editmesh_get_derived_cage_and_final(scene, ob, em, &final, dataMask); + + BKE_mesh_end_editmesh(me, em); return final; } else - return mesh_get_derived_final(ob, dataMask); + return mesh_get_derived_final(scene, ob, dataMask); } /* Space transform */ @@ -122,13 +131,13 @@ void space_transform_invert(const SpaceTransform *data, float *co) VecMat4MulVecfl(co, ((SpaceTransform*)data)->target2local, co); } -void space_transform_apply_normal(const SpaceTransform *data, float *no) +static void space_transform_apply_normal(const SpaceTransform *data, float *no) { Mat4Mul3Vecfl( ((SpaceTransform*)data)->local2target, no); Normalize(no); // TODO: could we just determine de scale value from the matrix? } -void space_transform_invert_normal(const SpaceTransform *data, float *no) +static void space_transform_invert_normal(const SpaceTransform *data, float *no) { Mat4Mul3Vecfl(((SpaceTransform*)data)->target2local, no); Normalize(no); // TODO: could we just determine de scale value from the matrix? @@ -144,117 +153,13 @@ static float squared_dist(const float *a, const float *b) return INPR(tmp, tmp); } -/* Main shrinkwrap function */ -void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) -{ - - DerivedMesh *ss_mesh = NULL; - ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; - - //remove loop dependencies on derived meshs (TODO should this be done elsewhere?) - if(smd->target == ob) smd->target = NULL; - if(smd->auxTarget == ob) smd->auxTarget = NULL; - - - //Configure Shrinkwrap calc data - calc.smd = smd; - calc.ob = ob; - calc.numVerts = numVerts; - calc.vertexCos = vertexCos; - - //DeformVertex - calc.vgroup = get_named_vertexgroup_num(calc.ob, calc.smd->vgroup_name); - if(dm) - { - calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); - } - else if(calc.ob->type == OB_LATTICE) - { - calc.dvert = lattice_get_deform_verts(calc.ob); - } - - - if(smd->target) - { - calc.target = object_get_derived_final(smd->target, CD_MASK_BAREMESH); - - //TODO there might be several "bugs" on non-uniform scales matrixs - //because it will no longer be nearest surface, not sphere projection - //because space has been deformed - space_transform_setup(&calc.local2target, ob, smd->target); - - //TODO: smd->keepDist is in global units.. must change to local - calc.keepDist = smd->keepDist; - } - - - - calc.vgroup = get_named_vertexgroup_num(calc.ob, smd->vgroup_name); - - if(dm != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) - { - //Setup arrays to get vertexs positions, normals and deform weights - calc.vert = dm->getVertDataArray(dm, CD_MVERT); - calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); - - //Using vertexs positions/normals as if a subsurface was applied - if(smd->subsurfLevels) - { - SubsurfModifierData ssmd; - memset(&ssmd, 0, sizeof(ssmd)); - ssmd.subdivType = ME_CC_SUBSURF; //catmull clark - ssmd.levels = smd->subsurfLevels; //levels - - ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, FALSE, NULL, 0, 0); - - if(ss_mesh) - { - calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT); - if(calc.vert) - { - //TRICKY: this code assumes subsurface will have the transformed original vertices - //in their original order at the end of the vert array. - calc.vert = calc.vert + ss_mesh->getNumVerts(ss_mesh) - dm->getNumVerts(dm); - } - } - - //Just to make sure we are not letting any memory behind - assert(ssmd.emCache == NULL); - assert(ssmd.mCache == NULL); - } - } - - //Projecting target defined - lets work! - if(calc.target) - { - switch(smd->shrinkType) - { - case MOD_SHRINKWRAP_NEAREST_SURFACE: - BENCH(shrinkwrap_calc_nearest_surface_point(&calc)); - break; - - case MOD_SHRINKWRAP_PROJECT: - BENCH(shrinkwrap_calc_normal_projection(&calc)); - break; - - case MOD_SHRINKWRAP_NEAREST_VERTEX: - BENCH(shrinkwrap_calc_nearest_vertex(&calc)); - break; - } - } - - //free memory - if(ss_mesh) - ss_mesh->release(ss_mesh); -} - /* * Shrinkwrap to the nearest vertex * * it builds a kdtree of vertexs we can attach to and then * for each vertex performs a nearest vertex search on the tree */ -void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) +static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) { int i; @@ -272,8 +177,9 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) //Setup nearest nearest.index = -1; nearest.dist = FLT_MAX; - +#ifndef __APPLE__ #pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData,calc) schedule(static) +#endif for(i = 0; i<calc->numVerts; ++i) { float *co = calc->vertexCos[i]; @@ -389,7 +295,7 @@ int normal_projection_project_vertex(char options, const float *vert, const floa } -void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) +static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, struct Scene *scene) { int i; @@ -434,7 +340,7 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) if(calc->smd->auxTarget) { - auxMesh = object_get_derived_final(calc->smd->auxTarget, CD_MASK_BAREMESH); + auxMesh = object_get_derived_final(scene, calc->smd->auxTarget, CD_MASK_BAREMESH); space_transform_setup( &local2aux, calc->ob, calc->smd->auxTarget); } @@ -443,7 +349,9 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) && (auxMesh == NULL || bvhtree_from_mesh_faces(&auxData, auxMesh, 0.0, 4, 6))) { +#ifndef __APPLE__ #pragma omp parallel for private(i,hit) schedule(static) +#endif for(i = 0; i<calc->numVerts; ++i) { float *co = calc->vertexCos[i]; @@ -511,7 +419,7 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) * it builds a BVHTree from the target mesh and then performs a * NN matchs for each vertex */ -void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) +static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) { int i; @@ -532,7 +440,9 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) //Find the nearest vertex +#ifndef __APPLE__ #pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc,treeData) schedule(static) +#endif for(i = 0; i<calc->numVerts; ++i) { float *co = calc->vertexCos[i]; @@ -590,3 +500,107 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) free_bvhtree_from_mesh(&treeData); } +/* Main shrinkwrap function */ +void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) +{ + + DerivedMesh *ss_mesh = NULL; + ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData; + + //remove loop dependencies on derived meshs (TODO should this be done elsewhere?) + if(smd->target == ob) smd->target = NULL; + if(smd->auxTarget == ob) smd->auxTarget = NULL; + + + //Configure Shrinkwrap calc data + calc.smd = smd; + calc.ob = ob; + calc.numVerts = numVerts; + calc.vertexCos = vertexCos; + + //DeformVertex + calc.vgroup = get_named_vertexgroup_num(calc.ob, calc.smd->vgroup_name); + if(dm) + { + calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + } + else if(calc.ob->type == OB_LATTICE) + { + calc.dvert = lattice_get_deform_verts(calc.ob); + } + + + if(smd->target) + { + calc.target = object_get_derived_final(scene, smd->target, CD_MASK_BAREMESH); + + //TODO there might be several "bugs" on non-uniform scales matrixs + //because it will no longer be nearest surface, not sphere projection + //because space has been deformed + space_transform_setup(&calc.local2target, ob, smd->target); + + //TODO: smd->keepDist is in global units.. must change to local + calc.keepDist = smd->keepDist; + } + + + + calc.vgroup = get_named_vertexgroup_num(calc.ob, smd->vgroup_name); + + if(dm != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) + { + //Setup arrays to get vertexs positions, normals and deform weights + calc.vert = dm->getVertDataArray(dm, CD_MVERT); + calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); + + //Using vertexs positions/normals as if a subsurface was applied + if(smd->subsurfLevels) + { + SubsurfModifierData ssmd; + memset(&ssmd, 0, sizeof(ssmd)); + ssmd.subdivType = ME_CC_SUBSURF; //catmull clark + ssmd.levels = smd->subsurfLevels; //levels + + ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, FALSE, NULL, 0, 0); + + if(ss_mesh) + { + calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT); + if(calc.vert) + { + //TRICKY: this code assumes subsurface will have the transformed original vertices + //in their original order at the end of the vert array. + calc.vert = calc.vert + ss_mesh->getNumVerts(ss_mesh) - dm->getNumVerts(dm); + } + } + + //Just to make sure we are not letting any memory behind + assert(ssmd.emCache == NULL); + assert(ssmd.mCache == NULL); + } + } + + //Projecting target defined - lets work! + if(calc.target) + { + switch(smd->shrinkType) + { + case MOD_SHRINKWRAP_NEAREST_SURFACE: + BENCH(shrinkwrap_calc_nearest_surface_point(&calc)); + break; + + case MOD_SHRINKWRAP_PROJECT: + BENCH(shrinkwrap_calc_normal_projection(&calc, scene)); + break; + + case MOD_SHRINKWRAP_NEAREST_VERTEX: + BENCH(shrinkwrap_calc_nearest_vertex(&calc)); + break; + } + } + + //free memory + if(ss_mesh) + ss_mesh->release(ss_mesh); +} + diff --git a/source/blender/blenkernel/intern/sketch.c b/source/blender/blenkernel/intern/sketch.c new file mode 100644 index 00000000000..8deae7e8e10 --- /dev/null +++ b/source/blender/blenkernel/intern/sketch.c @@ -0,0 +1,600 @@ +/** + * + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <math.h> +#include <float.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "BKE_sketch.h" +#include "BKE_utildefines.h" + +#include "DNA_userdef_types.h" + +void freeSketch(SK_Sketch *sketch) +{ + SK_Stroke *stk, *next; + + for (stk = sketch->strokes.first; stk; stk = next) + { + next = stk->next; + + sk_freeStroke(stk); + } + + BLI_freelistN(&sketch->depth_peels); + + MEM_freeN(sketch); +} + +SK_Sketch* createSketch() +{ + SK_Sketch *sketch; + + sketch = MEM_callocN(sizeof(SK_Sketch), "SK_Sketch"); + + sketch->active_stroke = NULL; + sketch->gesture = NULL; + + sketch->strokes.first = NULL; + sketch->strokes.last = NULL; + + return sketch; +} + +void sk_initPoint(SK_Point *pt, SK_DrawData *dd, float *no) +{ + if (no) + { + VECCOPY(pt->no, no); + Normalize(pt->no); + } + else + { + pt->no[0] = 0; + pt->no[1] = 0; + pt->no[2] = 1; + } + pt->p2d[0] = dd->mval[0]; + pt->p2d[1] = dd->mval[1]; + /* more init code here */ +} + +void sk_copyPoint(SK_Point *dst, SK_Point *src) +{ + memcpy(dst, src, sizeof(SK_Point)); +} + +void sk_allocStrokeBuffer(SK_Stroke *stk) +{ + stk->points = MEM_callocN(sizeof(SK_Point) * stk->buf_size, "SK_Point buffer"); +} + +void sk_freeStroke(SK_Stroke *stk) +{ + MEM_freeN(stk->points); + MEM_freeN(stk); +} + +SK_Stroke* sk_createStroke() +{ + SK_Stroke *stk; + + stk = MEM_callocN(sizeof(SK_Stroke), "SK_Stroke"); + + stk->selected = 0; + stk->nb_points = 0; + stk->buf_size = SK_Stroke_BUFFER_INIT_SIZE; + + sk_allocStrokeBuffer(stk); + + return stk; +} + +void sk_shrinkStrokeBuffer(SK_Stroke *stk) +{ + if (stk->nb_points < stk->buf_size) + { + SK_Point *old_points = stk->points; + + stk->buf_size = stk->nb_points; + + sk_allocStrokeBuffer(stk); + + memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points); + + MEM_freeN(old_points); + } +} + +void sk_growStrokeBuffer(SK_Stroke *stk) +{ + if (stk->nb_points == stk->buf_size) + { + SK_Point *old_points = stk->points; + + stk->buf_size *= 2; + + sk_allocStrokeBuffer(stk); + + memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points); + + MEM_freeN(old_points); + } +} + +void sk_growStrokeBufferN(SK_Stroke *stk, int n) +{ + if (stk->nb_points + n > stk->buf_size) + { + SK_Point *old_points = stk->points; + + while (stk->nb_points + n > stk->buf_size) + { + stk->buf_size *= 2; + } + + sk_allocStrokeBuffer(stk); + + memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points); + + MEM_freeN(old_points); + } +} + + +void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n) +{ + memcpy(stk->points + n, pt, sizeof(SK_Point)); +} + +void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n) +{ + int size = stk->nb_points - n; + + sk_growStrokeBuffer(stk); + + memmove(stk->points + n + 1, stk->points + n, size * sizeof(SK_Point)); + + memcpy(stk->points + n, pt, sizeof(SK_Point)); + + stk->nb_points++; +} + +void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt) +{ + sk_growStrokeBuffer(stk); + + memcpy(stk->points + stk->nb_points, pt, sizeof(SK_Point)); + + stk->nb_points++; +} + +void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end) +{ + int size = end - start + 1; + + sk_growStrokeBufferN(stk, len - size); + + if (len != size) + { + int tail_size = stk->nb_points - end + 1; + + memmove(stk->points + start + len, stk->points + end + 1, tail_size * sizeof(SK_Point)); + } + + memcpy(stk->points + start, pts, len * sizeof(SK_Point)); + + stk->nb_points += len - size; +} + +void sk_trimStroke(SK_Stroke *stk, int start, int end) +{ + int size = end - start + 1; + + if (start > 0) + { + memmove(stk->points, stk->points + start, size * sizeof(SK_Point)); + } + + stk->nb_points = size; +} + +void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3]) +{ + SK_Point pt1, pt2; + SK_Point *prev, *next; + float delta_p[3]; + int i, total; + + total = end - start; + + VecSubf(delta_p, p_end, p_start); + + prev = stk->points + start; + next = stk->points + end; + + VECCOPY(pt1.p, p_start); + VECCOPY(pt1.no, prev->no); + pt1.mode = prev->mode; + pt1.type = prev->type; + + VECCOPY(pt2.p, p_end); + VECCOPY(pt2.no, next->no); + pt2.mode = next->mode; + pt2.type = next->type; + + sk_insertStrokePoint(stk, &pt1, start + 1); /* insert after start */ + sk_insertStrokePoint(stk, &pt2, end + 1); /* insert before end (since end was pushed back already) */ + + for (i = 1; i < total; i++) + { + float delta = (float)i / (float)total; + float *p = stk->points[start + 1 + i].p; + + VECCOPY(p, delta_p); + VecMulf(p, delta); + VecAddf(p, p, p_start); + } +} + +void sk_polygonizeStroke(SK_Stroke *stk, int start, int end) +{ + int offset; + int i; + + /* find first exact points outside of range */ + for (;start > 0; start--) + { + if (stk->points[start].type == PT_EXACT) + { + break; + } + } + + for (;end < stk->nb_points - 1; end++) + { + if (stk->points[end].type == PT_EXACT) + { + break; + } + } + + offset = start + 1; + + for (i = start + 1; i < end; i++) + { + if (stk->points[i].type == PT_EXACT) + { + if (offset != i) + { + memcpy(stk->points + offset, stk->points + i, sizeof(SK_Point)); + } + + offset++; + } + } + + /* some points were removes, move end of array */ + if (offset < end) + { + int size = stk->nb_points - end; + memmove(stk->points + offset, stk->points + end, size * sizeof(SK_Point)); + stk->nb_points = offset + size; + } +} + +void sk_flattenStroke(SK_Stroke *stk, int start, int end) +{ + float normal[3], distance[3]; + float limit; + int i, total; + + total = end - start + 1; + + VECCOPY(normal, stk->points[start].no); + + VecSubf(distance, stk->points[end].p, stk->points[start].p); + Projf(normal, distance, normal); + limit = Normalize(normal); + + for (i = 1; i < total - 1; i++) + { + float d = limit * i / total; + float offset[3]; + float *p = stk->points[start + i].p; + + VecSubf(distance, p, stk->points[start].p); + Projf(distance, distance, normal); + + VECCOPY(offset, normal); + VecMulf(offset, d); + + VecSubf(p, p, distance); + VecAddf(p, p, offset); + } +} + +void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk) +{ + if (sketch->active_stroke == stk) + { + sketch->active_stroke = NULL; + } + + BLI_remlink(&sketch->strokes, stk); + sk_freeStroke(stk); +} + +void sk_reverseStroke(SK_Stroke *stk) +{ + SK_Point *old_points = stk->points; + int i = 0; + + sk_allocStrokeBuffer(stk); + + for (i = 0; i < stk->nb_points; i++) + { + sk_copyPoint(stk->points + i, old_points + stk->nb_points - 1 - i); + } + + MEM_freeN(old_points); +} + + +/* Ramer-Douglas-Peucker algorithm for line simplification */ +void sk_filterStroke(SK_Stroke *stk, int start, int end) +{ + SK_Point *old_points = stk->points; + int nb_points = stk->nb_points; + char *marked = NULL; + char work; + int i; + + if (start == -1) + { + start = 0; + end = stk->nb_points - 1; + } + + sk_allocStrokeBuffer(stk); + stk->nb_points = 0; + + /* adding points before range */ + for (i = 0; i < start; i++) + { + sk_appendStrokePoint(stk, old_points + i); + } + + marked = MEM_callocN(nb_points, "marked array"); + marked[start] = 1; + marked[end] = 1; + + work = 1; + + /* while still reducing */ + while (work) + { + int ls, le; + work = 0; + + ls = start; + le = start+1; + + /* while not over interval */ + while (ls < end) + { + int max_i = 0; + short v1[2]; + float max_dist = 16; /* more than 4 pixels */ + + /* find the next marked point */ + while(marked[le] == 0) + { + le++; + } + + /* perpendicular vector to ls-le */ + v1[1] = old_points[le].p2d[0] - old_points[ls].p2d[0]; + v1[0] = old_points[ls].p2d[1] - old_points[le].p2d[1]; + + + for( i = ls + 1; i < le; i++ ) + { + float mul; + float dist; + short v2[2]; + + v2[0] = old_points[i].p2d[0] - old_points[ls].p2d[0]; + v2[1] = old_points[i].p2d[1] - old_points[ls].p2d[1]; + + if (v2[0] == 0 && v2[1] == 0) + { + continue; + } + + mul = (float)(v1[0]*v2[0] + v1[1]*v2[1]) / (float)(v2[0]*v2[0] + v2[1]*v2[1]); + + dist = mul * mul * (v2[0]*v2[0] + v2[1]*v2[1]); + + if (dist > max_dist) + { + max_dist = dist; + max_i = i; + } + } + + if (max_i != 0) + { + work = 1; + marked[max_i] = 1; + } + + ls = le; + le = ls + 1; + } + } + + + /* adding points after range */ + for (i = start; i <= end; i++) + { + if (marked[i]) + { + sk_appendStrokePoint(stk, old_points + i); + } + } + + MEM_freeN(marked); + + /* adding points after range */ + for (i = end + 1; i < nb_points; i++) + { + sk_appendStrokePoint(stk, old_points + i); + } + + MEM_freeN(old_points); + + sk_shrinkStrokeBuffer(stk); +} + + +void sk_filterLastContinuousStroke(SK_Stroke *stk) +{ + int start, end; + + end = stk->nb_points -1; + + for (start = end - 1; start > 0 && stk->points[start].type == PT_CONTINUOUS; start--) + { + /* nothing to do here*/ + } + + if (end - start > 1) + { + sk_filterStroke(stk, start, end); + } +} + +SK_Point *sk_lastStrokePoint(SK_Stroke *stk) +{ + SK_Point *pt = NULL; + + if (stk->nb_points > 0) + { + pt = stk->points + (stk->nb_points - 1); + } + + return pt; +} + +void sk_endContinuousStroke(SK_Stroke *stk) +{ + stk->points[stk->nb_points - 1].type = PT_EXACT; +} + +void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk) +{ + if (stk) + { + memcpy(&sketch->next_point, stk->points[stk->nb_points - 1].p, sizeof(SK_Point)); + } +} + +int sk_stroke_filtermval(SK_DrawData *dd) +{ + int retval = 0; + if (ABS(dd->mval[0] - dd->previous_mval[0]) + ABS(dd->mval[1] - dd->previous_mval[1]) > U.gp_manhattendist) + { + retval = 1; + } + + return retval; +} + +void sk_initDrawData(SK_DrawData *dd, short mval[2]) +{ + dd->mval[0] = mval[0]; + dd->mval[1] = mval[1]; + dd->previous_mval[0] = -1; + dd->previous_mval[1] = -1; + dd->type = PT_EXACT; +} + + +void sk_deleteSelectedStrokes(SK_Sketch *sketch) +{ + SK_Stroke *stk, *next; + + for (stk = sketch->strokes.first; stk; stk = next) + { + next = stk->next; + + if (stk->selected == 1) + { + sk_removeStroke(sketch, stk); + } + } +} + +void sk_selectAllSketch(SK_Sketch *sketch, int mode) +{ + SK_Stroke *stk = NULL; + + if (mode == -1) + { + for (stk = sketch->strokes.first; stk; stk = stk->next) + { + stk->selected = 0; + } + } + else if (mode == 0) + { + for (stk = sketch->strokes.first; stk; stk = stk->next) + { + stk->selected = 1; + } + } + else if (mode == 1) + { + int selected = 1; + + for (stk = sketch->strokes.first; stk; stk = stk->next) + { + selected &= stk->selected; + } + + selected ^= 1; + + for (stk = sketch->strokes.first; stk; stk = stk->next) + { + stk->selected = selected; + } + } +} diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c new file mode 100644 index 00000000000..9d4c75245cf --- /dev/null +++ b/source/blender/blenkernel/intern/smoke.c @@ -0,0 +1,1515 @@ +/** + * smoke.c + * + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Daniel Genrich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */ + +#include <GL/glew.h> + +#include "MEM_guardedalloc.h" + +#include <float.h> +#include <math.h> +#include "stdio.h" + +#include "BLI_linklist.h" +#include "BLI_rand.h" +#include "BLI_jitter.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_edgehash.h" +#include "BLI_kdtree.h" +#include "BLI_kdopbvh.h" + +#include "BKE_bvhutils.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#include "BKE_modifier.h" +#include "BKE_particle.h" +#include "BKE_utildefines.h" + +#include "DNA_customdata_types.h" +#include "DNA_group_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_particle_types.h" +#include "DNA_scene_types.h" +#include "DNA_smoke_types.h" + +#include "smoke_API.h" + +#include "BKE_smoke.h" + +#ifdef _WIN32 +#include <time.h> +#include <stdio.h> +#include <conio.h> +#include <windows.h> + +static LARGE_INTEGER liFrequency; +static LARGE_INTEGER liStartTime; +static LARGE_INTEGER liCurrentTime; + +static void tstart ( void ) +{ + QueryPerformanceFrequency ( &liFrequency ); + QueryPerformanceCounter ( &liStartTime ); +} +static void tend ( void ) +{ + QueryPerformanceCounter ( &liCurrentTime ); +} +static double tval() +{ + return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart )); +} +#else +#include <sys/time.h> +static struct timeval _tstart, _tend; +static struct timezone tz; +static void tstart ( void ) +{ + gettimeofday ( &_tstart, &tz ); +} +static void tend ( void ) +{ + gettimeofday ( &_tend,&tz ); +} +static double tval() +{ + double t1, t2; + t1 = ( double ) _tstart.tv_sec*1000 + ( double ) _tstart.tv_usec/ ( 1000 ); + t2 = ( double ) _tend.tv_sec*1000 + ( double ) _tend.tv_usec/ ( 1000 ); + return t2-t1; +} +#endif + +struct Object; +struct Scene; +struct DerivedMesh; +struct SmokeModifierData; + +// forward declerations +static void get_cell(struct SmokeModifierData *smd, float *pos, int *cell, int correct); +static void get_bigcell(struct SmokeModifierData *smd, float *pos, int *cell, int correct); +void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int numfaces, int numtris, int **tridivs, float cell_len); + +#define TRI_UVOFFSET (1./4.) + +int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm) +{ + if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) + { + size_t i; + float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; + float size[3]; + MVert *verts = dm->getVertArray(dm); + float scale = 0.0; + int res; + + res = smd->domain->maxres; + + // get BB of domain + for(i = 0; i < dm->getNumVerts(dm); i++) + { + float tmp[3]; + + VECCOPY(tmp, verts[i].co); + Mat4MulVecfl(ob->obmat, tmp); + + // min BB + min[0] = MIN2(min[0], tmp[0]); + min[1] = MIN2(min[1], tmp[1]); + min[2] = MIN2(min[2], tmp[2]); + + // max BB + max[0] = MAX2(max[0], tmp[0]); + max[1] = MAX2(max[1], tmp[1]); + max[2] = MAX2(max[2], tmp[2]); + } + + VECCOPY(smd->domain->p0, min); + VECCOPY(smd->domain->p1, max); + + // calc other res with max_res provided + VECSUB(size, max, min); + if(size[0] > size[1]) + { + if(size[0] > size[1]) + { + scale = res / size[0]; + smd->domain->dx = size[0] / res; + smd->domain->res[0] = res; + smd->domain->res[1] = (int)(size[1] * scale + 0.5); + smd->domain->res[2] = (int)(size[2] * scale + 0.5); + } + else + { + scale = res / size[1]; + smd->domain->dx = size[1] / res; + smd->domain->res[1] = res; + smd->domain->res[0] = (int)(size[0] * scale + 0.5); + smd->domain->res[2] = (int)(size[2] * scale + 0.5); + } + } + else + { + if(size[1] > size[2]) + { + scale = res / size[1]; + smd->domain->dx = size[1] / res; + smd->domain->res[1] = res; + smd->domain->res[0] = (int)(size[0] * scale + 0.5); + smd->domain->res[2] = (int)(size[2] * scale + 0.5); + } + else + { + scale = res / size[2]; + smd->domain->dx = size[2] / res; + smd->domain->res[2] = res; + smd->domain->res[0] = (int)(size[0] * scale + 0.5); + smd->domain->res[1] = (int)(size[1] * scale + 0.5); + } + } + + // TODO: put in failsafe if res<=0 - dg + + // printf("res[0]: %d, res[1]: %d, res[2]: %d\n", smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]); + + // dt max is 0.1 + smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->p0, 0.1); + smd->domain->wt = smoke_turbulence_init(smd->domain->res, (smd->domain->flags & MOD_SMOKE_HIGHRES) ? (smd->domain->amplify + 1) : 0, smd->domain->noise); + smd->time = scene->r.cfra; + smd->domain->firstframe = smd->time; + + smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta)); + + if(smd->domain->wt) + smoke_initWaveletBlenderRNA(smd->domain->wt, &(smd->domain->strength)); + + return 1; + } + else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) + { + // handle flow object here + // XXX TODO + + smd->time = scene->r.cfra; + + // update particle lifetime to be one frame + // smd->flow->psys->part->lifetime = scene->r.efra + 1; +/* + if(!smd->flow->bvh) + { + // smd->flow->bvh = MEM_callocN(sizeof(BVHTreeFromMesh), "smoke_bvhfromfaces"); + // bvhtree_from_mesh_faces(smd->flow->bvh, dm, 0.0, 2, 6); + + // copy obmat + // Mat4CpyMat4(smd->flow->mat, ob->obmat); + // Mat4CpyMat4(smd->flow->mat_old, ob->obmat); + } +*/ + + return 1; + } + else if((smd->type & MOD_SMOKE_TYPE_COLL)) + { + smd->time = scene->r.cfra; + + // todo: delete this when loading colls work -dg + if(!smd->coll) + smokeModifier_createType(smd); + + if(!smd->coll->points) + { + // init collision points + SmokeCollSettings *scs = smd->coll; + MVert *mvert = dm->getVertArray(dm); + MFace *mface = dm->getFaceArray(dm); + size_t i = 0, divs = 0; + int *tridivs = NULL; + float cell_len = 1.0 / 50.0; // for res = 50 + size_t newdivs = 0; + size_t max_points = 0; + size_t quads = 0, facecounter = 0; + + // copy obmat + Mat4CpyMat4(scs->mat, ob->obmat); + Mat4CpyMat4(scs->mat_old, ob->obmat); + + // count quads + for(i = 0; i < dm->getNumFaces(dm); i++) + { + if(mface[i].v4) + quads++; + } + + calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface, dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len); + + // count triangle divisions + for(i = 0; i < dm->getNumFaces(dm) + quads; i++) + { + divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1); + } + + // printf("divs: %d\n", divs); + + scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints"); + + for(i = 0; i < dm->getNumVerts(dm); i++) + { + float tmpvec[3]; + VECCOPY(tmpvec, mvert[i].co); + Mat4MulVecfl (ob->obmat, tmpvec); + VECCOPY(&scs->points[i * 3], tmpvec); + } + + for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++) + { + int again = 0; + do + { + size_t j, k; + int divs1 = tridivs[3 * facecounter + 0]; + int divs2 = tridivs[3 * facecounter + 1]; + int divs3 = tridivs[3 * facecounter + 2]; + float side1[3], side2[3], trinormorg[3], trinorm[3]; + + if(again == 1 && mface[i].v4) + { + VECSUB(side1, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co); + VECSUB(side2, mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co); + } + else + { + VECSUB(side1, mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co); + VECSUB(side2, mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co); + } + + Crossf(trinormorg, side1, side2); + Normalize(trinormorg); + VECCOPY(trinorm, trinormorg); + VecMulf(trinorm, 0.25 * cell_len); + + for(j = 0; j <= divs1; j++) + { + for(k = 0; k <= divs2; k++) + { + float p1[3], p2[3], p3[3], p[3]={0,0,0}; + const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0); + const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0); + float tmpvec[3]; + + if(uf+vf > 1.0) + { + // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2); + continue; + } + + VECCOPY(p1, mvert[ mface[i].v1 ].co); + if(again == 1 && mface[i].v4) + { + VECCOPY(p2, mvert[ mface[i].v3 ].co); + VECCOPY(p3, mvert[ mface[i].v4 ].co); + } + else + { + VECCOPY(p2, mvert[ mface[i].v2 ].co); + VECCOPY(p3, mvert[ mface[i].v3 ].co); + } + + VecMulf(p1, (1.0-uf-vf)); + VecMulf(p2, uf); + VecMulf(p3, vf); + + VECADD(p, p1, p2); + VECADD(p, p, p3); + + if(newdivs > divs) + printf("mem problem\n"); + + // mMovPoints.push_back(p + trinorm); + VECCOPY(tmpvec, p); + VECADD(tmpvec, tmpvec, trinorm); + Mat4MulVecfl (ob->obmat, tmpvec); + VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec); + newdivs++; + + if(newdivs > divs) + printf("mem problem\n"); + + // mMovPoints.push_back(p - trinorm); + VECCOPY(tmpvec, p); + VECSUB(tmpvec, tmpvec, trinorm); + Mat4MulVecfl (ob->obmat, tmpvec); + VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec); + newdivs++; + } + } + + if(again == 0 && mface[i].v4) + again++; + else + again = 0; + + facecounter++; + + } while(again!=0); + } + + scs->numpoints = dm->getNumVerts(dm) + newdivs; + + MEM_freeN(tridivs); + } + + if(!smd->coll->bvhtree) + { + smd->coll->bvhtree = NULL; // bvhtree_build_from_smoke ( ob->obmat, dm->getFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 ); + } + + } + + return 0; +} + +/*! init triangle divisions */ +void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len) +{ + // mTriangleDivs1.resize( faces.size() ); + // mTriangleDivs2.resize( faces.size() ); + // mTriangleDivs3.resize( faces.size() ); + + size_t i = 0, facecounter = 0; + float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale); + float maxpart = ABS(maxscale[0]); + float scaleFac = 0; + float fsTri = 0; + if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]); + if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]); + scaleFac = 1.0 / maxpart; + // featureSize = mLevel[mMaxRefine].nodeSize + fsTri = cell_len * 0.5 * scaleFac; + + if(*tridivs) + MEM_freeN(*tridivs); + + *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs"); + + for(i = 0, facecounter = 0; i < numfaces; i++) + { + float p0[3], p1[3], p2[3]; + float side1[3]; + float side2[3]; + float side3[3]; + int divs1=0, divs2=0, divs3=0; + + VECCOPY(p0, verts[faces[i].v1].co); + Mat4MulVecfl (ob->obmat, p0); + VECCOPY(p1, verts[faces[i].v2].co); + Mat4MulVecfl (ob->obmat, p1); + VECCOPY(p2, verts[faces[i].v3].co); + Mat4MulVecfl (ob->obmat, p2); + + VECSUB(side1, p1, p0); + VECSUB(side2, p2, p0); + VECSUB(side3, p1, p2); + + if(INPR(side1, side1) > fsTri*fsTri) + { + float tmp = Normalize(side1); + divs1 = (int)ceil(tmp/fsTri); + } + if(INPR(side2, side2) > fsTri*fsTri) + { + float tmp = Normalize(side2); + divs2 = (int)ceil(tmp/fsTri); + + /* + // debug + if(i==0) + printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2); + */ + } + + (*tridivs)[3 * facecounter + 0] = divs1; + (*tridivs)[3 * facecounter + 1] = divs2; + (*tridivs)[3 * facecounter + 2] = divs3; + + // TODO quad case + if(faces[i].v4) + { + divs1=0, divs2=0, divs3=0; + + facecounter++; + + VECCOPY(p0, verts[faces[i].v3].co); + Mat4MulVecfl (ob->obmat, p0); + VECCOPY(p1, verts[faces[i].v4].co); + Mat4MulVecfl (ob->obmat, p1); + VECCOPY(p2, verts[faces[i].v1].co); + Mat4MulVecfl (ob->obmat, p2); + + VECSUB(side1, p1, p0); + VECSUB(side2, p2, p0); + VECSUB(side3, p1, p2); + + if(INPR(side1, side1) > fsTri*fsTri) + { + float tmp = Normalize(side1); + divs1 = (int)ceil(tmp/fsTri); + } + if(INPR(side2, side2) > fsTri*fsTri) + { + float tmp = Normalize(side2); + divs2 = (int)ceil(tmp/fsTri); + } + + (*tridivs)[3 * facecounter + 0] = divs1; + (*tridivs)[3 * facecounter + 1] = divs2; + (*tridivs)[3 * facecounter + 2] = divs3; + } + facecounter++; + } +} + +void smokeModifier_freeDomain(SmokeModifierData *smd) +{ + if(smd->domain) + { + // free visualisation buffers + if(smd->domain->bind) + { + glDeleteTextures(smd->domain->max_textures, (GLuint *)smd->domain->bind); + MEM_freeN(smd->domain->bind); + } + smd->domain->max_textures = 0; // unnecessary but let's be sure + + if(smd->domain->tray) + MEM_freeN(smd->domain->tray); + if(smd->domain->tvox) + MEM_freeN(smd->domain->tvox); + if(smd->domain->traybig) + MEM_freeN(smd->domain->traybig); + if(smd->domain->tvoxbig) + MEM_freeN(smd->domain->tvoxbig); + + if(smd->domain->fluid) + smoke_free(smd->domain->fluid); + + if(smd->domain->wt) + smoke_turbulence_free(smd->domain->wt); + + MEM_freeN(smd->domain); + smd->domain = NULL; + } +} + +void smokeModifier_freeFlow(SmokeModifierData *smd) +{ + if(smd->flow) + { +/* + if(smd->flow->bvh) + { + free_bvhtree_from_mesh(smd->flow->bvh); + MEM_freeN(smd->flow->bvh); + } + smd->flow->bvh = NULL; +*/ + MEM_freeN(smd->flow); + smd->flow = NULL; + } +} + +void smokeModifier_freeCollision(SmokeModifierData *smd) +{ + if(smd->coll) + { + if(smd->coll->points) + { + MEM_freeN(smd->coll->points); + smd->coll->points = NULL; + } + + if(smd->coll->bvhtree) + { + BLI_bvhtree_free(smd->coll->bvhtree); + smd->coll->bvhtree = NULL; + } + + if(smd->coll->dm) + smd->coll->dm->release(smd->coll->dm); + smd->coll->dm = NULL; + + MEM_freeN(smd->coll); + smd->coll = NULL; + } +} + +void smokeModifier_reset(struct SmokeModifierData *smd) +{ + if(smd) + { + if(smd->domain) + { + // free visualisation buffers + if(smd->domain->bind) + { + glDeleteTextures(smd->domain->max_textures, (GLuint *)smd->domain->bind); + MEM_freeN(smd->domain->bind); + smd->domain->bind = NULL; + } + smd->domain->max_textures = 0; + if(smd->domain->viewsettings < MOD_SMOKE_VIEW_USEBIG) + smd->domain->viewsettings = 0; + else + smd->domain->viewsettings = MOD_SMOKE_VIEW_USEBIG; + + if(smd->domain->tray) + MEM_freeN(smd->domain->tray); + if(smd->domain->tvox) + MEM_freeN(smd->domain->tvox); + if(smd->domain->traybig) + MEM_freeN(smd->domain->traybig); + if(smd->domain->tvoxbig) + MEM_freeN(smd->domain->tvoxbig); + + smd->domain->tvox = NULL; + smd->domain->tray = NULL; + smd->domain->tvoxbig = NULL; + smd->domain->traybig = NULL; + + if(smd->domain->fluid) + { + smoke_free(smd->domain->fluid); + smd->domain->fluid = NULL; + } + + if(smd->domain->wt) + { + smoke_turbulence_free(smd->domain->wt); + smd->domain->wt = NULL; + } + } + else if(smd->flow) + { + /* + if(smd->flow->bvh) + { + free_bvhtree_from_mesh(smd->flow->bvh); + MEM_freeN(smd->flow->bvh); + } + smd->flow->bvh = NULL; + */ + } + else if(smd->coll) + { + if(smd->coll->points) + { + MEM_freeN(smd->coll->points); + smd->coll->points = NULL; + } + + if(smd->coll->bvhtree) + { + BLI_bvhtree_free(smd->coll->bvhtree); + smd->coll->bvhtree = NULL; + } + + if(smd->coll->dm) + smd->coll->dm->release(smd->coll->dm); + smd->coll->dm = NULL; + + } + } +} + +void smokeModifier_free (SmokeModifierData *smd) +{ + if(smd) + { + smokeModifier_freeDomain(smd); + smokeModifier_freeFlow(smd); + smokeModifier_freeCollision(smd); + } +} + +void smokeModifier_createType(struct SmokeModifierData *smd) +{ + if(smd) + { + if(smd->type & MOD_SMOKE_TYPE_DOMAIN) + { + if(smd->domain) + smokeModifier_freeDomain(smd); + + smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain"); + + smd->domain->smd = smd; + + /* set some standard values */ + smd->domain->fluid = NULL; + smd->domain->wt = NULL; + smd->domain->eff_group = NULL; + smd->domain->fluid_group = NULL; + smd->domain->coll_group = NULL; + smd->domain->maxres = 32; + smd->domain->amplify = 1; + smd->domain->omega = 1.0; + smd->domain->alpha = -0.001; + smd->domain->beta = 0.1; + smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG; + smd->domain->strength = 2.0; + smd->domain->noise = MOD_SMOKE_NOISEWAVE; + smd->domain->visibility = 1; + smd->domain->diss_speed = 5; + + // init 3dview buffer + smd->domain->tvox = NULL; + smd->domain->tray = NULL; + smd->domain->tvoxbig = NULL; + smd->domain->traybig = NULL; + smd->domain->viewsettings = 0; + smd->domain->bind = NULL; + smd->domain->max_textures = 0; + } + else if(smd->type & MOD_SMOKE_TYPE_FLOW) + { + if(smd->flow) + smokeModifier_freeFlow(smd); + + smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow"); + + smd->flow->smd = smd; + + /* set some standard values */ + smd->flow->density = 1.0; + smd->flow->temp = 1.0; + + smd->flow->psys = NULL; + + } + else if(smd->type & MOD_SMOKE_TYPE_COLL) + { + if(smd->coll) + smokeModifier_freeCollision(smd); + + smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl"); + + smd->coll->smd = smd; + smd->coll->points = NULL; + smd->coll->numpoints = 0; + smd->coll->bvhtree = NULL; + smd->coll->dm = NULL; + } + } +} + +// forward declaration +void smoke_calc_transparency(struct SmokeModifierData *smd, float *light, int big); + +void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) +{ + if(scene->r.cfra >= smd->time) + smokeModifier_init(smd, ob, scene, dm); + + if((smd->type & MOD_SMOKE_TYPE_FLOW)) + { + if(scene->r.cfra > smd->time) + { + // XXX TODO + smd->time = scene->r.cfra; + + // rigid movement support + /* + Mat4CpyMat4(smd->flow->mat_old, smd->flow->mat); + Mat4CpyMat4(smd->flow->mat, ob->obmat); + */ + } + else if(scene->r.cfra < smd->time) + { + smd->time = scene->r.cfra; + smokeModifier_reset(smd); + } + } + else if(smd->type & MOD_SMOKE_TYPE_COLL) + { + if(scene->r.cfra > smd->time) + { + // XXX TODO + smd->time = scene->r.cfra; + + if(smd->coll->dm) + smd->coll->dm->release(smd->coll->dm); + + smd->coll->dm = CDDM_copy(dm); + + // rigid movement support + Mat4CpyMat4(smd->coll->mat_old, smd->coll->mat); + Mat4CpyMat4(smd->coll->mat, ob->obmat); + } + else if(scene->r.cfra < smd->time) + { + smd->time = scene->r.cfra; + smokeModifier_reset(smd); + } + } + else if(smd->type & MOD_SMOKE_TYPE_DOMAIN) + { + SmokeDomainSettings *sds = smd->domain; + + if(scene->r.cfra > smd->time) + { + GroupObject *go = NULL; + Base *base = NULL; + + tstart(); + + if(sds->flags & MOD_SMOKE_DISSOLVE) + { + smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); + + if(sds->wt) + smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); + } + + /* reset view for new frame */ + if(sds->viewsettings < MOD_SMOKE_VIEW_USEBIG) + sds->viewsettings = 0; + else + sds->viewsettings = MOD_SMOKE_VIEW_USEBIG; + + // do flows and fluids + if(1) + { + Object *otherobj = NULL; + ModifierData *md = NULL; + + if(sds->fluid_group) // we use groups since we have 2 domains + go = sds->fluid_group->gobject.first; + else + base = scene->base.first; + + while(base || go) + { + otherobj = NULL; + + if(sds->fluid_group) + { + if(go->ob) + otherobj = go->ob; + } + else + otherobj = base->object; + + if(!otherobj) + { + if(sds->fluid_group) + go = go->next; + else + base= base->next; + + continue; + } + + md = modifiers_findByType(otherobj, eModifierType_Smoke); + + // check for active smoke modifier + if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) + { + SmokeModifierData *smd2 = (SmokeModifierData *)md; + + // check for initialized smoke object + if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) + { + // we got nice flow object + SmokeFlowSettings *sfs = smd2->flow; + + if(sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected + { + ParticleSystem *psys = sfs->psys; + ParticleSettings *part=psys->part; + ParticleData *pa = NULL; + int p = 0; + float *density = smoke_get_density(sds->fluid); + float *bigdensity = smoke_turbulence_get_density(sds->wt); + float *heat = smoke_get_heat(sds->fluid); + float *velocity_x = smoke_get_velocity_x(sds->fluid); + float *velocity_y = smoke_get_velocity_y(sds->fluid); + float *velocity_z = smoke_get_velocity_z(sds->fluid); + unsigned char *obstacle = smoke_get_obstacle(sds->fluid); + int bigres[3]; + + printf("found flow psys\n"); + + // mostly copied from particle code + for(p=0, pa=psys->particles; p<psys->totpart; p++, pa++) + { + int cell[3]; + size_t i = 0; + size_t index = 0; + int badcell = 0; + + if(pa->alive == PARS_KILLED) continue; + else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue; + else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0) continue; + else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue; + + // VECCOPY(pos, pa->state.co); + // Mat4MulVecfl (ob->imat, pos); + + // 1. get corresponding cell + get_cell(smd, pa->state.co, cell, 0); + + // check if cell is valid (in the domain boundary) + for(i = 0; i < 3; i++) + { + if((cell[i] > sds->res[i] - 1) || (cell[i] < 0)) + { + badcell = 1; + break; + } + } + + if(badcell) + continue; + + // 2. set cell values (heat, density and velocity) + index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]); + + if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) && !(obstacle[index] & 2)) // this is inflow + { + // heat[index] += sfs->temp * 0.1; + // density[index] += sfs->density * 0.1; + + heat[index] = sfs->temp; + density[index] = sfs->density; + + /* + velocity_x[index] = pa->state.vel[0]; + velocity_y[index] = pa->state.vel[1]; + velocity_z[index] = pa->state.vel[2]; + */ + obstacle[index] |= 2; + + // we need different handling for the high-res feature + if(bigdensity) + { + // init all surrounding cells according to amplification, too + int i, j, k; + + smoke_turbulence_get_res(smd->domain->wt, bigres); + + for(i = 0; i < smd->domain->amplify + 1; i++) + for(j = 0; j < smd->domain->amplify + 1; j++) + for(k = 0; k < smd->domain->amplify + 1; k++) + { + index = smoke_get_index((smd->domain->amplify + 1)* cell[0] + i, bigres[0], (smd->domain->amplify + 1)* cell[1] + j, bigres[1], (smd->domain->amplify + 1)* cell[2] + k); + bigdensity[index] = sfs->density; + } + } + } + else if(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) // outflow + { + heat[index] = 0.f; + density[index] = 0.f; + velocity_x[index] = 0.f; + velocity_y[index] = 0.f; + velocity_z[index] = 0.f; + + // we need different handling for the high-res feature + if(bigdensity) + { + // init all surrounding cells according to amplification, too + int i, j, k; + + smoke_turbulence_get_res(smd->domain->wt, bigres); + + for(i = 0; i < smd->domain->amplify + 1; i++) + for(j = 0; j < smd->domain->amplify + 1; j++) + for(k = 0; k < smd->domain->amplify + 1; k++) + { + index = smoke_get_index((smd->domain->amplify + 1)* cell[0] + i, bigres[0], (smd->domain->amplify + 1)* cell[1] + j, bigres[1], (smd->domain->amplify + 1)* cell[2] + k); + bigdensity[index] = 0.f; + } + } + } + } + } + else + { + /* + for() + { + // no psys + BVHTreeNearest nearest; + + nearest.index = -1; + nearest.dist = FLT_MAX; + + BLI_bvhtree_find_nearest(sfs->bvh->tree, pco, &nearest, sfs->bvh->nearest_callback, sfs->bvh); + }*/ + } + } + } + + if(sds->fluid_group) + go = go->next; + else + base= base->next; + } + } + + // do effectors + /* + if(sds->eff_group) + { + for(go = sds->eff_group->gobject.first; go; go = go->next) + { + if(go->ob) + { + if(ob->pd) + { + + } + } + } + } + */ + + // do collisions + if(1) + { + Object *otherobj = NULL; + ModifierData *md = NULL; + + if(sds->coll_group) // we use groups since we have 2 domains + go = sds->coll_group->gobject.first; + else + base = scene->base.first; + + while(base || go) + { + otherobj = NULL; + + if(sds->coll_group) + { + if(go->ob) + otherobj = go->ob; + } + else + otherobj = base->object; + + if(!otherobj) + { + if(sds->coll_group) + go = go->next; + else + base= base->next; + + continue; + } + + md = modifiers_findByType(otherobj, eModifierType_Smoke); + + // check for active smoke modifier + if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) + { + SmokeModifierData *smd2 = (SmokeModifierData *)md; + + if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) + { + // we got nice collision object + SmokeCollSettings *scs = smd2->coll; + size_t i, j; + unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid); + + for(i = 0; i < scs->numpoints; i++) + { + int badcell = 0; + size_t index = 0; + int cell[3]; + + // 1. get corresponding cell + get_cell(smd, &scs->points[3 * i], cell, 0); + + // check if cell is valid (in the domain boundary) + for(j = 0; j < 3; j++) + if((cell[j] > sds->res[j] - 1) || (cell[j] < 0)) + { + badcell = 1; + break; + } + + if(badcell) + continue; + + // 2. set cell values (heat, density and velocity) + index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]); + + // printf("cell[0]: %d, cell[1]: %d, cell[2]: %d\n", cell[0], cell[1], cell[2]); + // printf("res[0]: %d, res[1]: %d, res[2]: %d, index: %d\n\n", sds->res[0], sds->res[1], sds->res[2], index); + + obstacles[index] = 1; + + // for moving gobstacles + /* + const LbmFloat maxVelVal = 0.1666; + const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5; + + LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); { + const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; + USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); + if(usqr>maxusqr) { + // cutoff at maxVelVal + for(int jj=0; jj<3; jj++) { + if(objvel[jj]>0.) objvel[jj] = maxVelVal; + if(objvel[jj]<0.) objvel[jj] = -maxVelVal; + } + } } + + const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); + const LbmVec oldov=objvel; // debug + objvel = vec2L((*pNormals)[n]) *dp; + */ + } + } + } + + if(sds->coll_group) + go = go->next; + else + base= base->next; + } + } + + // set new time + smd->time = scene->r.cfra; + + // simulate the actual smoke (c++ code in intern/smoke) + smoke_step(sds->fluid, smd->time); + if(sds->wt) + smoke_turbulence_step(sds->wt, sds->fluid); + + tend(); + printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() ); + } + else if(scene->r.cfra < smd->time) + { + // we got back in time, reset smoke in this case (TODO: use cache later) + smd->time = scene->r.cfra; + smokeModifier_reset(smd); + } + } +} + +// update necessary information for 3dview +void smoke_prepare_View(SmokeModifierData *smd, float *light) +{ + float *density = NULL; + int x, y, z; + + if(!smd->domain->tray) + { + // TRay is for self shadowing + smd->domain->tray = MEM_callocN(sizeof(float)*smd->domain->res[0]*smd->domain->res[1]*smd->domain->res[2], "Smoke_tRay"); + } + if(!smd->domain->tvox) + { + // TVox is for tranaparency + smd->domain->tvox = MEM_callocN(sizeof(float)*smd->domain->res[0]*smd->domain->res[1]*smd->domain->res[2], "Smoke_tVox"); + } + + // update 3dview + density = smoke_get_density(smd->domain->fluid); + for(x = 0; x < smd->domain->res[0]; x++) + for(y = 0; y < smd->domain->res[1]; y++) + for(z = 0; z < smd->domain->res[2]; z++) + { + size_t index; + + index = smoke_get_index(x, smd->domain->res[0], y, smd->domain->res[1], z); + // Transparency computation + // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4 + // T_vox = exp(-C_ext * h) + // C_ext/sigma_t = density * C_ext + smoke_set_tvox(smd, index, exp(-density[index] * 7.0 * smd->domain->dx)); + } + smoke_calc_transparency(smd, light, 0); +} + +// update necessary information for 3dview ("high res" option) +void smoke_prepare_bigView(SmokeModifierData *smd, float *light) +{ + float *density = NULL; + size_t i = 0; + int bigres[3]; + + smoke_turbulence_get_res(smd->domain->wt, bigres); + + if(!smd->domain->traybig) + { + // TRay is for self shadowing + smd->domain->traybig = MEM_callocN(sizeof(float)*bigres[0]*bigres[1]*bigres[2], "Smoke_tRayBig"); + } + if(!smd->domain->tvoxbig) + { + // TVox is for tranaparency + smd->domain->tvoxbig = MEM_callocN(sizeof(float)*bigres[0]*bigres[1]*bigres[2], "Smoke_tVoxBig"); + } + + density = smoke_turbulence_get_density(smd->domain->wt); + for (i = 0; i < bigres[0] * bigres[1] * bigres[2]; i++) + { + // Transparency computation + // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4 + // T_vox = exp(-C_ext * h) + // C_ext/sigma_t = density * C_ext + smoke_set_bigtvox(smd, i, exp(-density[i] * 7.0 * smd->domain->dx / (smd->domain->amplify + 1)) ); + } + smoke_calc_transparency(smd, light, 1); +} + + +float smoke_get_tvox(SmokeModifierData *smd, size_t index) +{ + return smd->domain->tvox[index]; +} + +void smoke_set_tvox(SmokeModifierData *smd, size_t index, float tvox) +{ + smd->domain->tvox[index] = tvox; +} + +float smoke_get_tray(SmokeModifierData *smd, size_t index) +{ + return smd->domain->tray[index]; +} + +void smoke_set_tray(SmokeModifierData *smd, size_t index, float transparency) +{ + smd->domain->tray[index] = transparency; +} + +float smoke_get_bigtvox(SmokeModifierData *smd, size_t index) +{ + return smd->domain->tvoxbig[index]; +} + +void smoke_set_bigtvox(SmokeModifierData *smd, size_t index, float tvox) +{ + smd->domain->tvoxbig[index] = tvox; +} + +float smoke_get_bigtray(SmokeModifierData *smd, size_t index) +{ + return smd->domain->traybig[index]; +} + +void smoke_set_bigtray(SmokeModifierData *smd, size_t index, float transparency) +{ + smd->domain->traybig[index] = transparency; +} + +long long smoke_get_mem_req(int xres, int yres, int zres, int amplify) +{ + int totalCells = xres * yres * zres; + int amplifiedCells = totalCells * amplify * amplify * amplify; + + // print out memory requirements + long long int coarseSize = sizeof(float) * totalCells * 22 + + sizeof(unsigned char) * totalCells; + + long long int fineSize = sizeof(float) * amplifiedCells * 7 + // big grids + sizeof(float) * totalCells * 8 + // small grids + sizeof(float) * 128 * 128 * 128; // noise tile + + long long int totalMB = (coarseSize + fineSize) / (1024 * 1024); + + return totalMB; +} + + +static void calc_voxel_transp(SmokeModifierData *smd, int *pixel, float *tRay) +{ + // printf("Pixel(%d, %d, %d)\n", pixel[0], pixel[1], pixel[2]); + const size_t index = smoke_get_index(pixel[0], smd->domain->res[0], pixel[1], smd->domain->res[1], pixel[2]); + + // T_ray *= T_vox + *tRay *= smoke_get_tvox(smd, index); +} + +static void calc_voxel_transp_big(SmokeModifierData *smd, int *pixel, float *tRay) +{ + int bigres[3]; + size_t index; + + smoke_turbulence_get_res(smd->domain->wt, bigres); + index = smoke_get_index(pixel[0], bigres[0], pixel[1], bigres[1], pixel[2]); + + /* + if(index > bigres[0]*bigres[1]*bigres[2]) + printf("pixel[0]: %d, [1]: %d, [2]: %d\n", pixel[0], pixel[1], pixel[2]); + */ + + // T_ray *= T_vox + *tRay *= smoke_get_bigtvox(smd, index); +} + +static void bresenham_linie_3D(SmokeModifierData *smd, int x1, int y1, int z1, int x2, int y2, int z2, float *tRay, int big) +{ + int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2; + int pixel[3]; + + pixel[0] = x1; + pixel[1] = y1; + pixel[2] = z1; + + dx = x2 - x1; + dy = y2 - y1; + dz = z2 - z1; + + x_inc = (dx < 0) ? -1 : 1; + l = abs(dx); + y_inc = (dy < 0) ? -1 : 1; + m = abs(dy); + z_inc = (dz < 0) ? -1 : 1; + n = abs(dz); + dx2 = l << 1; + dy2 = m << 1; + dz2 = n << 1; + + if ((l >= m) && (l >= n)) { + err_1 = dy2 - l; + err_2 = dz2 - l; + for (i = 0; i < l; i++) { + if(!big) + calc_voxel_transp(smd, pixel, tRay); + else + calc_voxel_transp_big(smd, pixel, tRay); + if(*tRay < 0.0f) + return; + if (err_1 > 0) { + pixel[1] += y_inc; + err_1 -= dx2; + } + if (err_2 > 0) { + pixel[2] += z_inc; + err_2 -= dx2; + } + err_1 += dy2; + err_2 += dz2; + pixel[0] += x_inc; + } + } else if ((m >= l) && (m >= n)) { + err_1 = dx2 - m; + err_2 = dz2 - m; + for (i = 0; i < m; i++) { + if(!big) + calc_voxel_transp(smd, pixel, tRay); + else + calc_voxel_transp_big(smd, pixel, tRay); + if(*tRay < 0.0f) + return; + if (err_1 > 0) { + pixel[0] += x_inc; + err_1 -= dy2; + } + if (err_2 > 0) { + pixel[2] += z_inc; + err_2 -= dy2; + } + err_1 += dx2; + err_2 += dz2; + pixel[1] += y_inc; + } + } else { + err_1 = dy2 - n; + err_2 = dx2 - n; + for (i = 0; i < n; i++) { + if(!big) + calc_voxel_transp(smd, pixel, tRay); + else + calc_voxel_transp_big(smd, pixel, tRay); + if(*tRay < 0.0f) + return; + if (err_1 > 0) { + pixel[1] += y_inc; + err_1 -= dz2; + } + if (err_2 > 0) { + pixel[0] += x_inc; + err_2 -= dz2; + } + err_1 += dy2; + err_2 += dx2; + pixel[2] += z_inc; + } + } + if(!big) + calc_voxel_transp(smd, pixel, tRay); + else + calc_voxel_transp_big(smd, pixel, tRay); +} + +static void get_cell(struct SmokeModifierData *smd, float *pos, int *cell, int correct) +{ + float tmp[3]; + + VECSUB(tmp, pos, smd->domain->p0); + VecMulf(tmp, 1.0 / smd->domain->dx); + + if(correct) + { + cell[0] = MIN2(smd->domain->res[0] - 1, MAX2(0, (int)floor(tmp[0]))); + cell[1] = MIN2(smd->domain->res[1] - 1, MAX2(0, (int)floor(tmp[1]))); + cell[2] = MIN2(smd->domain->res[2] - 1, MAX2(0, (int)floor(tmp[2]))); + } + else + { + cell[0] = (int)floor(tmp[0]); + cell[1] = (int)floor(tmp[1]); + cell[2] = (int)floor(tmp[2]); + } +} +static void get_bigcell(struct SmokeModifierData *smd, float *pos, int *cell, int correct) +{ + float tmp[3]; + int res[3]; + smoke_turbulence_get_res(smd->domain->wt, res); + + VECSUB(tmp, pos, smd->domain->p0); + + VecMulf(tmp, (smd->domain->amplify + 1)/ smd->domain->dx ); + + if(correct) + { + cell[0] = MIN2(res[0] - 1, MAX2(0, (int)floor(tmp[0]))); + cell[1] = MIN2(res[1] - 1, MAX2(0, (int)floor(tmp[1]))); + cell[2] = MIN2(res[2] - 1, MAX2(0, (int)floor(tmp[2]))); + } + else + { + cell[0] = (int)floor(tmp[0]); + cell[1] = (int)floor(tmp[1]); + cell[2] = (int)floor(tmp[2]); + } +} + + +void smoke_calc_transparency(struct SmokeModifierData *smd, float *light, int big) +{ + int x, y, z; + float bv[6]; + int res[3]; + float bigfactor = 1.0; + + // x + bv[0] = smd->domain->p0[0]; + bv[1] = smd->domain->p1[0]; + // y + bv[2] = smd->domain->p0[1]; + bv[3] = smd->domain->p1[1]; + // z + bv[4] = smd->domain->p0[2]; + bv[5] = smd->domain->p1[2]; +/* + printf("bv[0]: %f, [1]: %f, [2]: %f, [3]: %f, [4]: %f, [5]: %f\n", bv[0], bv[1], bv[2], bv[3], bv[4], bv[5]); + + printf("p0[0]: %f, p0[1]: %f, p0[2]: %f\n", smd->domain->p0[0], smd->domain->p0[1], smd->domain->p0[2]); + printf("p1[0]: %f, p1[1]: %f, p1[2]: %f\n", smd->domain->p1[0], smd->domain->p1[1], smd->domain->p1[2]); + printf("dx: %f, amp: %d\n", smd->domain->dx, smd->domain->amplify); +*/ + if(!big) + { + res[0] = smd->domain->res[0]; + res[1] = smd->domain->res[1]; + res[2] = smd->domain->res[2]; + } + else + { + smoke_turbulence_get_res(smd->domain->wt, res); + bigfactor = 1.0 / (smd->domain->amplify + 1); + } + +#pragma omp parallel for schedule(static) private(y, z) shared(big, smd, light, res, bigfactor) + for(x = 0; x < res[0]; x++) + for(y = 0; y < res[1]; y++) + for(z = 0; z < res[2]; z++) + { + float voxelCenter[3]; + size_t index; + float pos[3]; + int cell[3]; + float tRay = 1.0; + + index = smoke_get_index(x, res[0], y, res[1], z); + + // voxelCenter = m_voxelarray[i].GetCenter(); + voxelCenter[0] = smd->domain->p0[0] + smd->domain->dx * bigfactor * x + smd->domain->dx * bigfactor * 0.5; + voxelCenter[1] = smd->domain->p0[1] + smd->domain->dx * bigfactor * y + smd->domain->dx * bigfactor * 0.5; + voxelCenter[2] = smd->domain->p0[2] + smd->domain->dx * bigfactor * z + smd->domain->dx * bigfactor * 0.5; + + // printf("vc[0]: %f, vc[1]: %f, vc[2]: %f\n", voxelCenter[0], voxelCenter[1], voxelCenter[2]); + // printf("light[0]: %f, light[1]: %f, light[2]: %f\n", light[0], light[1], light[2]); + + // get starting position (in voxel coords) + if(BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) + { + // we're ouside + // printf("out: pos[0]: %f, pos[1]: %f, pos[2]: %f\n", pos[0], pos[1], pos[2]); + if(!big) + get_cell(smd, pos, cell, 1); + else + get_bigcell(smd, pos, cell, 1); + } + else + { + // printf("in: pos[0]: %f, pos[1]: %f, pos[2]: %f\n", light[0], light[1], light[2]); + // we're inside + if(!big) + get_cell(smd, light, cell, 1); + else + get_bigcell(smd, light, cell, 1); + } + + // printf("cell - [0]: %d, [1]: %d, [2]: %d\n", cell[0], cell[1], cell[2]); + bresenham_linie_3D(smd, cell[0], cell[1], cell[2], x, y, z, &tRay, big); + + if(!big) + smoke_set_tray(smd, index, tRay); + else + smoke_set_bigtray(smd, index, tRay); + } +} + diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 25eb999cc4f..68f918b0c68 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -83,8 +83,8 @@ variables on the UI for now #include "BKE_pointcache.h" #include "BKE_modifier.h" #include "BKE_deform.h" -#include "BIF_editdeform.h" -#include "BIF_graphics.h" +//XXX #include "BIF_editdeform.h" +//XXX #include "BIF_graphics.h" #include "PIL_time.h" // #include "ONL_opennl.h" remove linking to ONL for now @@ -120,7 +120,8 @@ typedef struct SBScratch { float aabbmin[3],aabbmax[3]; }SBScratch; -typedef struct SB_thread_context{ +typedef struct SB_thread_context { + Scene *scene; Object *ob; float forcetime; float timenow; @@ -196,7 +197,7 @@ static float sb_time_scale(Object *ob) /* this would be frames/sec independant timing assuming 25 fps is default but does not work very well with NLA - return (25.0f/G.scene->r.frs_sec) + return (25.0f/scene->r.frs_sec) */ } /*--- frame based timing ---*/ @@ -484,12 +485,11 @@ static void ccd_mesh_free(ccd_Mesh *ccdm) } } -static void ccd_build_deflector_hache(Object *vertexowner,GHash *hash) +static void ccd_build_deflector_hash(Scene *scene, Object *vertexowner, GHash *hash) { - Base *base; + Base *base= scene->base.first; Object *ob; - base= G.scene->base.first; - base= G.scene->base.first; + if (!hash) return; while (base) { /*Only proceed for mesh object in same layer */ @@ -516,9 +516,9 @@ static void ccd_build_deflector_hache(Object *vertexowner,GHash *hash) } else { if(ob->softflag & OB_SB_COLLFINAL) /* so maybe someone wants overkill to collide with subsurfed */ - dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); + dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); else - dm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH); + dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); } if(dm){ @@ -536,12 +536,11 @@ static void ccd_build_deflector_hache(Object *vertexowner,GHash *hash) } /* while (base) */ } -static void ccd_update_deflector_hache(Object *vertexowner,GHash *hash) +static void ccd_update_deflector_hash(Scene *scene, Object *vertexowner, GHash *hash) { - Base *base; + Base *base= scene->base.first; Object *ob; - base= G.scene->base.first; - base= G.scene->base.first; + if ((!hash) || (!vertexowner)) return; while (base) { /*Only proceed for mesh object in same layer */ @@ -558,9 +557,9 @@ static void ccd_update_deflector_hache(Object *vertexowner,GHash *hash) DerivedMesh *dm= NULL; if(ob->softflag & OB_SB_COLLFINAL) { /* so maybe someone wants overkill to collide with subsurfed */ - dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH); + dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); } else { - dm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH); + dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); } if(dm){ ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash,ob); @@ -830,12 +829,12 @@ static void calculate_collision_balls(Object *ob) /* creates new softbody if didn't exist yet, makes new points and springs arrays */ -static void renew_softbody(Object *ob, int totpoint, int totspring) +static void renew_softbody(Scene *scene, Object *ob, int totpoint, int totspring) { SoftBody *sb; int i; short softflag; - if(ob->soft==NULL) ob->soft= sbNew(); + if(ob->soft==NULL) ob->soft= sbNew(scene); else free_softbody_intern(ob->soft); sb= ob->soft; softflag=ob->softflag; @@ -970,11 +969,11 @@ static void Vec3PlusStVec(float *v, float s, float *v1) /* +++ dependancy information functions*/ -static int are_there_deflectors(unsigned int layer) +static int are_there_deflectors(Scene *scene, unsigned int layer) { Base *base; - for(base = G.scene->base.first; base; base= base->next) { + for(base = scene->base.first; base; base= base->next) { if( (base->lay & layer) && base->object->pd) { if(base->object->pd->deflect) return 1; @@ -983,9 +982,9 @@ static int are_there_deflectors(unsigned int layer) return 0; } -static int query_external_colliders(Object *me) +static int query_external_colliders(Scene *scene, Object *me) { - return(are_there_deflectors(me->lay)); + return(are_there_deflectors(scene, me->lay)); } /* --- dependancy information functions*/ @@ -1528,9 +1527,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3],float edge_v2[3],floa return deflected; } - - -static void _scan_for_ext_spring_forces(Object *ob,float timenow,int ifirst,int ilast, struct ListBase *do_effector) +static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *do_effector) { SoftBody *sb = ob->soft; int a; @@ -1569,7 +1566,7 @@ static void _scan_for_ext_spring_forces(Object *ob,float timenow,int ifirst,int float pos[3]; VecMidf(pos, sb->bpoint[bs->v1].pos , sb->bpoint[bs->v2].pos); VecMidf(vel, sb->bpoint[bs->v1].vec , sb->bpoint[bs->v2].vec); - pdDoEffectors(do_effector, pos, force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); + pdDoEffectors(scene, do_effector, pos, force, speed, (float)scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); VecMulf(speed,windfactor); VecAddf(vel,vel,speed); } @@ -1601,26 +1598,27 @@ static void _scan_for_ext_spring_forces(Object *ob,float timenow,int ifirst,int } -static void scan_for_ext_spring_forces(Object *ob,float timenow) +static void scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow) { SoftBody *sb = ob->soft; ListBase *do_effector= NULL; - do_effector= pdInitEffectors(ob,NULL); + + do_effector= pdInitEffectors(scene, ob,NULL); if (sb){ - _scan_for_ext_spring_forces(ob,timenow,0,sb->totspring,do_effector); + _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, do_effector); } if(do_effector) - pdEndEffectors(do_effector); + pdEndEffectors(do_effector); } static void *exec_scan_for_ext_spring_forces(void *data) { SB_thread_context *pctx = (SB_thread_context*)data; - _scan_for_ext_spring_forces(pctx->ob,pctx->timenow,pctx->ifirst,pctx->ilast,pctx->do_effector); + _scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->do_effector); return 0; } -static void sb_sfesf_threads_run(struct Object *ob, float timenow,int totsprings,int *ptr_to_break_func()) +static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow,int totsprings,int *ptr_to_break_func()) { ListBase *do_effector = NULL; ListBase threads; @@ -1628,11 +1626,11 @@ static void sb_sfesf_threads_run(struct Object *ob, float timenow,int totsprings int i, totthread,left,dec; int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */ - do_effector= pdInitEffectors(ob,NULL); + do_effector= pdInitEffectors(scene, ob,NULL); /* figure the number of threads while preventing pretty pointless threading overhead */ - if(G.scene->r.mode & R_FIXED_THREADS) - totthread= G.scene->r.threads; + if(scene->r.mode & R_FIXED_THREADS) + totthread= scene->r.threads; else totthread= BLI_system_thread_count(); /* what if we got zillions of CPUs running but less to spread*/ @@ -1645,6 +1643,7 @@ static void sb_sfesf_threads_run(struct Object *ob, float timenow,int totsprings left = totsprings; dec = totsprings/totthread +1; for(i=0; i<totthread; i++) { + sb_threads[i].scene = scene; sb_threads[i].ob = ob; sb_threads[i].forcetime = 0.0; // not used here sb_threads[i].timenow = timenow; @@ -2122,13 +2121,14 @@ static void sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float fo /* since this is definitely the most CPU consuming task here .. try to spread it */ /* core function _softbody_calc_forces_slice_in_a_thread */ /* result is int to be able to flag user break */ -static int _softbody_calc_forces_slice_in_a_thread(Object *ob, float forcetime, float timenow,int ifirst,int ilast,int *ptr_to_break_func(),ListBase *do_effector,int do_deflector,float fieldfactor, float windfactor) +static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow,int ifirst,int ilast,int *ptr_to_break_func(),ListBase *do_effector,int do_deflector,float fieldfactor, float windfactor) { float iks; int bb,do_selfcollision,do_springcollision,do_aero; int number_of_points_here = ilast - ifirst; SoftBody *sb= ob->soft; /* is supposed to be there */ BodyPoint *bp; + /* intitialize */ if (sb) { /* check conditions for various options */ @@ -2250,7 +2250,7 @@ static int _softbody_calc_forces_slice_in_a_thread(Object *ob, float forcetime, float speed[3]= {0.0f, 0.0f, 0.0f}; float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */ - pdDoEffectors(do_effector, bp->pos, force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); + pdDoEffectors(scene, do_effector, bp->pos, force, speed, (float)scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); /* apply forcefield*/ VecMulf(force,fieldfactor* eval_sb_fric_force_scale); @@ -2325,11 +2325,11 @@ return 0; /*done fine*/ static void *exec_softbody_calc_forces(void *data) { SB_thread_context *pctx = (SB_thread_context*)data; - _softbody_calc_forces_slice_in_a_thread(pctx->ob,pctx->forcetime,pctx->timenow,pctx->ifirst,pctx->ilast,NULL,pctx->do_effector,pctx->do_deflector,pctx->fieldfactor,pctx->windfactor); + _softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->do_effector,pctx->do_deflector,pctx->fieldfactor,pctx->windfactor); return 0; } -static void sb_cf_threads_run(struct Object *ob, float forcetime, float timenow,int totpoint,int *ptr_to_break_func(),struct ListBase *do_effector,int do_deflector,float fieldfactor, float windfactor) +static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow,int totpoint,int *ptr_to_break_func(),struct ListBase *do_effector,int do_deflector,float fieldfactor, float windfactor) { ListBase threads; SB_thread_context *sb_threads; @@ -2337,8 +2337,8 @@ static void sb_cf_threads_run(struct Object *ob, float forcetime, float timenow, int lowpoints =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */ /* figure the number of threads while preventing pretty pointless threading overhead */ - if(G.scene->r.mode & R_FIXED_THREADS) - totthread= G.scene->r.threads; + if(scene->r.mode & R_FIXED_THREADS) + totthread= scene->r.threads; else totthread= BLI_system_thread_count(); /* what if we got zillions of CPUs running but less to spread*/ @@ -2386,7 +2386,7 @@ static void sb_cf_threads_run(struct Object *ob, float forcetime, float timenow, MEM_freeN(sb_threads); } -static void softbody_calc_forcesEx(Object *ob, float forcetime, float timenow, int nl_flags) +static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, float timenow, int nl_flags) { /* rule we never alter free variables :bp->vec bp->pos in here ! * this will ruin adaptive stepsize AKA heun! (BM) @@ -2401,7 +2401,7 @@ static void softbody_calc_forcesEx(Object *ob, float forcetime, float timenow, i gravity = sb->grav * sb_grav_force_scale(ob); /* check conditions for various options */ - do_deflector= query_external_colliders(ob); + do_deflector= query_external_colliders(scene, ob); do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); @@ -2410,17 +2410,17 @@ static void softbody_calc_forcesEx(Object *ob, float forcetime, float timenow, i bproot= sb->bpoint; /* need this for proper spring addressing */ if (do_springcollision || do_aero) - sb_sfesf_threads_run(ob,timenow,sb->totspring,NULL); + sb_sfesf_threads_run(scene, ob, timenow,sb->totspring,NULL); /* after spring scan because it uses Effoctors too */ - do_effector= pdInitEffectors(ob,NULL); + do_effector= pdInitEffectors(scene, ob,NULL); if (do_deflector) { float defforce[3]; do_deflector = sb_detect_aabb_collisionCached(defforce,ob->lay,ob,timenow); } - sb_cf_threads_run(ob,forcetime,timenow,sb->totpoint,NULL,do_effector,do_deflector,fieldfactor,windfactor); + sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, do_effector, do_deflector, fieldfactor, windfactor); /* finally add forces caused by face collision */ if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob,timenow); @@ -2432,11 +2432,11 @@ static void softbody_calc_forcesEx(Object *ob, float forcetime, float timenow, i -static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int nl_flags) +static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, float timenow, int nl_flags) { /* redirection to the new threaded Version */ if (!(G.rt & 0x10)){ // 16 - softbody_calc_forcesEx(ob, forcetime, timenow, nl_flags); + softbody_calc_forcesEx(scene, ob, forcetime, timenow, nl_flags); return; } else{ @@ -2475,7 +2475,7 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int gravity = sb->grav * sb_grav_force_scale(ob); /* check conditions for various options */ - do_deflector= query_external_colliders(ob); + do_deflector= query_external_colliders(scene, ob); do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); @@ -2483,9 +2483,9 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ bproot= sb->bpoint; /* need this for proper spring addressing */ - if (do_springcollision || do_aero) scan_for_ext_spring_forces(ob,timenow); + if (do_springcollision || do_aero) scan_for_ext_spring_forces(scene, ob, timenow); /* after spring scan because it uses Effoctors too */ - do_effector= pdInitEffectors(ob,NULL); + do_effector= pdInitEffectors(scene, ob,NULL); if (do_deflector) { float defforce[3]; @@ -2652,7 +2652,7 @@ static void softbody_calc_forces(Object *ob, float forcetime, float timenow, int float speed[3]= {0.0f, 0.0f, 0.0f}; float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */ - pdDoEffectors(do_effector, bp->pos, force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); + pdDoEffectors(scene, do_effector, bp->pos, force, speed, (float)scene->r.cfra, 0.0f, PE_WIND_AS_SPEED); /* apply forcefield*/ VecMulf(force,fieldfactor* eval_sb_fric_force_scale); @@ -3202,7 +3202,7 @@ static void springs_from_mesh(Object *ob) /* makes totally fresh start situation */ -static void mesh_to_softbody(Object *ob) +static void mesh_to_softbody(Scene *scene, Object *ob) { SoftBody *sb; Mesh *me= ob->data; @@ -3215,7 +3215,7 @@ static void mesh_to_softbody(Object *ob) else totedge= 0; /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ - renew_softbody(ob, me->totvert, totedge); + renew_softbody(scene, ob, me->totvert, totedge); /* we always make body points */ sb= ob->soft; @@ -3428,7 +3428,7 @@ static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff,Object * /* makes totally fresh start situation */ -static void lattice_to_softbody(Object *ob) +static void lattice_to_softbody(Scene *scene, Object *ob) { Lattice *lt= ob->data; SoftBody *sb; @@ -3447,7 +3447,7 @@ static void lattice_to_softbody(Object *ob) /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ - renew_softbody(ob, totvert, totspring); + renew_softbody(scene, ob, totvert, totspring); sb= ob->soft; /* can be created in renew_softbody() */ /* weights from bpoints, same code used as for mesh vertices */ @@ -3472,7 +3472,7 @@ static void lattice_to_softbody(Object *ob) } /* makes totally fresh start situation */ -static void curve_surf_to_softbody(Object *ob) +static void curve_surf_to_softbody(Scene *scene, Object *ob) { Curve *cu= ob->data; SoftBody *sb; @@ -3494,7 +3494,7 @@ static void curve_surf_to_softbody(Object *ob) } /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ - renew_softbody(ob, totvert, totspring); + renew_softbody(scene, ob, totvert, totspring); sb= ob->soft; /* can be created in renew_softbody() */ /* set vars now */ @@ -3604,7 +3604,7 @@ static void springs_from_particles(Object *ob) } } -static void particles_to_softbody(Object *ob) +static void particles_to_softbody(Scene *scene, Object *ob) { SoftBody *sb; BodyPoint *bp; @@ -3618,7 +3618,7 @@ static void particles_to_softbody(Object *ob) int totedge= totpoint-psys->totpart; /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ - renew_softbody(ob, totpoint, totedge); + renew_softbody(scene, ob, totpoint, totedge); /* find first BodyPoint index for each particle */ if(psys->totpart > 0) { @@ -3687,66 +3687,6 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, } } -void sbWriteCache(Object *ob, int framenr) -{ - SoftBody *sb= ob->soft; - BodyPoint *bp; - PTCacheID pid; - PTCacheFile *pf; - int a; - - if(sb->totpoint == 0) - return; - - BKE_ptcache_id_from_softbody(&pid, ob, sb); - pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_WRITE, framenr); - if(!pf) - return; - - for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) - BKE_ptcache_file_write_floats(pf, bp->pos, 3); - - for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) - BKE_ptcache_file_write_floats(pf, bp->vec, 3); - - BKE_ptcache_file_close(pf); -} - -static int softbody_read_cache(Object *ob, float framenr) -{ - SoftBody *sb= ob->soft; - BodyPoint *bp; - PTCacheID pid; - PTCacheFile *pf; - int a; - - if(sb->totpoint == 0) - return 0; - - BKE_ptcache_id_from_softbody(&pid, ob, sb); - pf= BKE_ptcache_file_open(&pid, PTCACHE_FILE_READ, framenr); - if(!pf) - return 0; - - for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) { - if(!BKE_ptcache_file_read_floats(pf, bp->pos, 3)) { - BKE_ptcache_file_close(pf); - return 0; - } - } - - for(a=0, bp=sb->bpoint; a<sb->totpoint; a++, bp++) { - if(!BKE_ptcache_file_read_floats(pf, bp->vec, 3)) { - BKE_ptcache_file_close(pf); - return 0; - } - } - - BKE_ptcache_file_close(pf); - - return 1; -} - /* +++ ************ maintaining scratch *************** */ static void sb_new_scratch(SoftBody *sb) { @@ -3764,7 +3704,7 @@ static void sb_new_scratch(SoftBody *sb) /* ************ Object level, exported functions *************** */ /* allocates and initializes general main data */ -SoftBody *sbNew(void) +SoftBody *sbNew(Scene *scene) { SoftBody *sb; @@ -3788,8 +3728,8 @@ SoftBody *sbNew(void) sb->inpush = 0.5f; sb->interval= 10; - sb->sfra= G.scene->r.sfra; - sb->efra= G.scene->r.efra; + sb->sfra= scene->r.sfra; + sb->efra= scene->r.efra; sb->colball = 0.49f; sb->balldamp = 0.50f; @@ -3806,7 +3746,7 @@ SoftBody *sbNew(void) sb->shearstiff = 1.0f; sb->solverflags |= SBSO_OLDERR; - sb->pointcache = BKE_ptcache_add(); + sb->pointcache = BKE_ptcache_add(&sb->ptcaches); return sb; } @@ -3815,7 +3755,8 @@ SoftBody *sbNew(void) void sbFree(SoftBody *sb) { free_softbody_intern(sb); - BKE_ptcache_free(sb->pointcache); + BKE_ptcache_free_list(&sb->ptcaches); + sb->pointcache = NULL; MEM_freeN(sb); } @@ -3975,16 +3916,17 @@ static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int } } -static void softbody_step(Object *ob, SoftBody *sb, float dtime) +static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) { /* the simulator */ float forcetime; double sct,sst=PIL_check_seconds_timer(); - ccd_update_deflector_hache(ob,sb->scratch->colliderhash); + + ccd_update_deflector_hash(scene, ob, sb->scratch->colliderhash); if(sb->scratch->needstobuildcollider){ - if (query_external_colliders(ob)){ - ccd_build_deflector_hache(ob,sb->scratch->colliderhash); + if (query_external_colliders(scene, ob)){ + ccd_build_deflector_hash(scene, ob, sb->scratch->colliderhash); } sb->scratch->needstobuildcollider=0; } @@ -4017,12 +3959,12 @@ static void softbody_step(Object *ob, SoftBody *sb, float dtime) sb->scratch->flag &= ~SBF_DOFUZZY; /* do predictive euler step */ - softbody_calc_forces(ob, forcetime,timedone/dtime,0); + softbody_calc_forces(scene, ob, forcetime,timedone/dtime,0); softbody_apply_forces(ob, forcetime, 1, NULL,mid_flags); /* crop new slope values to do averaged slope step */ - softbody_calc_forces(ob, forcetime,timedone/dtime,0); + softbody_calc_forces(scene, ob, forcetime,timedone/dtime,0); softbody_apply_forces(ob, forcetime, 2, &err,mid_flags); softbody_apply_goalsnap(ob); @@ -4104,7 +4046,7 @@ static void softbody_step(Object *ob, SoftBody *sb, float dtime) } /* simulates one step. framenr is in frames */ -void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts) +void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts) { ParticleSystemModifierData *psmd=0; ParticleData *pa=0; @@ -4113,6 +4055,7 @@ void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts) PTCacheID pid; float dtime, timescale; int framedelta, framenr, startframe, endframe; + int cache_result; cache= sb->pointcache; @@ -4120,14 +4063,14 @@ void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts) framedelta= framenr - cache->simframe; BKE_ptcache_id_from_softbody(&pid, ob, sb); - BKE_ptcache_id_time(&pid, framenr, &startframe, &endframe, ×cale); + BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); /* check for changes in mesh, should only happen in case the mesh * structure changes during an animation */ if(sb->bpoint && numVerts != sb->totpoint) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; - + cache->last_exact= 0; return; } @@ -4135,6 +4078,7 @@ void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts) if(framenr < startframe) { cache->flag &= ~PTCACHE_SIMULATION_VALID; cache->simframe= 0; + cache->last_exact= 0; return; } @@ -4147,22 +4091,22 @@ void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts) ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) { if(sb->particles){ - particles_to_softbody(ob); + particles_to_softbody(scene, ob); } else { switch(ob->type) { case OB_MESH: - mesh_to_softbody(ob); + mesh_to_softbody(scene, ob); break; case OB_LATTICE: - lattice_to_softbody(ob); + lattice_to_softbody(scene, ob); break; case OB_CURVE: case OB_SURF: - curve_surf_to_softbody(ob); + curve_surf_to_softbody(scene, ob); break; default: - renew_softbody(ob, numVerts, 0); + renew_softbody(scene, ob, numVerts, 0); break; } } @@ -4180,7 +4124,7 @@ void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts) dtime = timescale; softbody_update_positions(ob, sb, vertexCos, numVerts); - softbody_step(ob, sb, dtime); + softbody_step(scene, ob, sb, dtime); if(sb->particles==0) softbody_to_object(ob, vertexCos, numVerts, 0); @@ -4197,26 +4141,35 @@ void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts) } /* try to read from cache */ - if(softbody_read_cache(ob, framenr)) { - if(sb->particles==0) - softbody_to_object(ob, vertexCos, numVerts, sb->local); + cache_result = BKE_ptcache_read_cache(&pid, framenr, scene->r.frs_sec); + if(cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) { cache->flag |= PTCACHE_SIMULATION_VALID; cache->simframe= framenr; + if(sb->particles==0) + softbody_to_object(ob, vertexCos, numVerts, sb->local); + return; } + else if(cache_result==PTCACHE_READ_OLD) { + BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_FREE); + cache->flag |= PTCACHE_SIMULATION_VALID; + } else if(ob->id.lib || (cache->flag & PTCACHE_BAKED)) { /* if baked and nothing in cache, do nothing */ - if(cache->flag & PTCACHE_SIMULATION_VALID) { - cache->flag &= ~PTCACHE_SIMULATION_VALID; - cache->simframe= 0; - } - + cache->flag &= ~PTCACHE_SIMULATION_VALID; + cache->simframe= 0; + cache->last_exact= 0; return; } if(framenr == startframe) { + if(cache->flag & PTCACHE_REDO_NEEDED) { + softbody_update_positions(ob, sb, vertexCos, numVerts); + softbody_reset(ob, sb, vertexCos, numVerts); + cache->flag &= ~PTCACHE_REDO_NEEDED; + } /* first frame, no simulation to do, just set the positions */ softbody_update_positions(ob, sb, vertexCos, numVerts); @@ -4226,10 +4179,10 @@ void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts) /* don't write cache on first frame, but on second frame write * cache for frame 1 and 2 */ } - else if(framedelta == 1) { + else { /* if on second frame, write cache for first frame */ - if(framenr == startframe+1) - sbWriteCache(ob, startframe); + if(cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) + BKE_ptcache_write_cache(&pid, startframe); softbody_update_positions(ob, sb, vertexCos, numVerts); @@ -4240,19 +4193,12 @@ void sbObjectStep(Object *ob, float cfra, float (*vertexCos)[3], int numVerts) /* checking time: */ dtime = framedelta*timescale; - softbody_step(ob, sb, dtime); + softbody_step(scene, ob, sb, dtime); if(sb->particles==0) softbody_to_object(ob, vertexCos, numVerts, 0); - sbWriteCache(ob, framenr); - } - else { - /* time step backwards or too large forward - do nothing */ - if(cache->flag & PTCACHE_SIMULATION_VALID) { - cache->flag &= ~PTCACHE_SIMULATION_VALID; - cache->simframe= 0; - } + BKE_ptcache_write_cache(&pid, framenr); } } diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 2c5b49246fb..347837d1dd0 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -1,6 +1,6 @@ /** * sound.c (mar-2001 nzc) - * + * * $Id$ */ @@ -14,125 +14,468 @@ #include "DNA_scene_types.h" #include "DNA_sound_types.h" #include "DNA_packedFile_types.h" +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" + +#include "AUD_C-API.h" #include "BKE_utildefines.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_sound.h" +#include "BKE_context.h" +#include "BKE_library.h" #include "BKE_packedFile.h" #ifdef HAVE_CONFIG_H #include <config.h> #endif -ListBase _samples = {0,0}, *samples = &_samples; +void sound_init() +{ + AUD_Specs specs; + specs.channels = AUD_CHANNELS_STEREO; + specs.format = AUD_FORMAT_S16; + specs.rate = AUD_RATE_44100; + + if(!AUD_init(AUD_SDL_DEVICE, specs, AUD_DEFAULT_BUFFER_SIZE)) + if(!AUD_init(AUD_OPENAL_DEVICE, specs, AUD_DEFAULT_BUFFER_SIZE*4)) + AUD_init(AUD_NULL_DEVICE, specs, AUD_DEFAULT_BUFFER_SIZE); +} -void sound_free_sound(bSound *sound) +void sound_reinit(struct bContext *C) { - /* when sounds have been loaded, but not played, the packedfile was not copied - to sample block and not freed otherwise */ - if(sound->sample==NULL) { - if (sound->newpackedfile) { - freePackedFile(sound->newpackedfile); - sound->newpackedfile = NULL; - } + AUD_Specs specs; + int device, buffersize; + + device = U.audiodevice; + buffersize = U.mixbufsize; + specs.channels = U.audiochannels; + specs.format = U.audioformat; + specs.rate = U.audiorate; + + if(buffersize < 128) + buffersize = AUD_DEFAULT_BUFFER_SIZE; + + if(specs.rate < AUD_RATE_8000) + specs.rate = AUD_RATE_44100; + + if(specs.format <= AUD_FORMAT_INVALID) + specs.format = AUD_FORMAT_S16; + + if(specs.channels <= AUD_CHANNELS_INVALID) + specs.channels = AUD_CHANNELS_STEREO; + + if(!AUD_init(device, specs, buffersize)) + AUD_init(AUD_NULL_DEVICE, specs, buffersize); +} + +void sound_exit() +{ + AUD_exit(); +} + +struct bSound* sound_new_file(struct Main *main, char* filename) +{ + bSound* sound = NULL; + + char str[FILE_MAX]; + int len; + + strcpy(str, filename); + BLI_convertstringcode(str, G.sce); + + len = strlen(filename); + while(len > 0 && filename[len-1] != '/' && filename[len-1] != '\\') + len--; + + sound = alloc_libblock(&main->sound, ID_SO, filename+len); + strcpy(sound->name, filename); + sound->type = SOUND_TYPE_FILE; + + sound_load(sound); + + if(!sound->snd_sound) + { + free_libblock(&main->sound, sound); + sound = NULL; + } + + return sound; +} + +// XXX unused currently +#if 0 +struct bSound* sound_new_buffer(struct bContext *C, struct bSound *source) +{ + bSound* sound = NULL; + + char name[25]; + strcpy(name, "buf_"); + strcpy(name + 4, source->id.name); + + sound = alloc_libblock(&CTX_data_main(C)->sound, ID_SO, name); + + sound->child_sound = source; + sound->type = SOUND_TYPE_BUFFER; + + sound_load(sound); + + if(!sound->snd_sound) + { + free_libblock(&CTX_data_main(C)->sound, sound); + sound = NULL; + } + + return sound; +} + +struct bSound* sound_new_limiter(struct bContext *C, struct bSound *source, float start, float end) +{ + bSound* sound = NULL; + + char name[25]; + strcpy(name, "lim_"); + strcpy(name + 4, source->id.name); + + sound = alloc_libblock(&CTX_data_main(C)->sound, ID_SO, name); + + sound->child_sound = source; + sound->start = start; + sound->end = end; + sound->type = SOUND_TYPE_LIMITER; + + sound_load(sound); + + if(!sound->snd_sound) + { + free_libblock(&CTX_data_main(C)->sound, sound); + sound = NULL; + } + + return sound; +} +#endif + +void sound_delete(struct bContext *C, struct bSound* sound) +{ + if(sound) + { + sound_free(sound); + + sound_unlink(C, sound); + + free_libblock(&CTX_data_main(C)->sound, sound); } - if (sound->stream) free(sound->stream); } -void sound_free_sample(bSample *sample) +void sound_cache(struct bSound* sound, int ignore) +{ + if(sound->cache && !ignore) + AUD_unload(sound->cache); + + sound->cache = AUD_bufferSound(sound->snd_sound); +} + +void sound_load(struct bSound* sound) { - if (sample) { - if (sample->data != &sample->fakedata[0] && sample->data != NULL) { - MEM_freeN(sample->data); - sample->data = &sample->fakedata[0]; + if(sound) + { + if(sound->snd_sound) + { + AUD_unload(sound->snd_sound); + sound->snd_sound = NULL; } - - if (sample->packedfile) { - freePackedFile(sample->packedfile); //FIXME: crashes sometimes - sample->packedfile = NULL; + + switch(sound->type) + { + case SOUND_TYPE_FILE: + { + char fullpath[FILE_MAX]; + char *path; + + /* load sound */ + PackedFile* pf = sound->packedfile; + + /* dont modify soundact->sound->name, only change a copy */ + BLI_strncpy(fullpath, sound->name, sizeof(fullpath)); + + if(sound->id.lib) + path = sound->id.lib->filename; + else + path = G.sce; + + BLI_convertstringcode(fullpath, path); + + /* but we need a packed file then */ + if (pf) + sound->snd_sound = AUD_loadBuffer((unsigned char*) pf->data, pf->size); + /* or else load it from disk */ + else + sound->snd_sound = AUD_load(fullpath); + break; } - - if (sample->alindex != SAMPLE_INVALID) { -// AUD_free_sample(sample->snd_sample); - sample->alindex = SAMPLE_INVALID; + case SOUND_TYPE_BUFFER: + if(sound->child_sound && sound->child_sound->snd_sound) + sound->snd_sound = AUD_bufferSound(sound->child_sound->snd_sound); + break; + case SOUND_TYPE_LIMITER: + if(sound->child_sound && sound->child_sound->snd_sound) + sound->snd_sound = AUD_limitSound(sound->child_sound, sound->start, sound->end); + break; } - sample->type = SAMPLE_INVALID; + if(sound->cache) + { + + } } } -/* this is called after file reading or undos */ -void sound_free_all_samples(void) +void sound_free(struct bSound* sound) { - bSample *sample; - bSound *sound; - - /* ensure no sample pointers exist, and check packedfile */ - for(sound= G.main->sound.first; sound; sound= sound->id.next) { - if(sound->sample && sound->sample->packedfile==sound->newpackedfile) - sound->newpackedfile= NULL; - sound->sample= NULL; + if (sound->packedfile) + { + freePackedFile(sound->packedfile); + sound->packedfile = NULL; } - - /* now free samples */ - for(sample= samples->first; sample; sample= sample->id.next) - sound_free_sample(sample); - BLI_freelistN(samples); - -} - -void sound_set_packedfile(bSample *sample, PackedFile *pf) -{ - bSound *sound; - - if (sample) { - sample->packedfile = pf; - sound = G.main->sound.first; - while (sound) { - if (sound->sample == sample) { - sound->newpackedfile = pf; - if (pf == NULL) { - strcpy(sound->name, sample->name); + + if(sound->snd_sound) + { + AUD_unload(sound->snd_sound); + sound->snd_sound = NULL; + } +} + +void sound_unlink(struct bContext *C, struct bSound* sound) +{ + bSound *snd; + Scene *scene; + SoundHandle *handle; + + for(snd = CTX_data_main(C)->sound.first; snd; snd = snd->id.next) + { + if(snd->child_sound == sound) + { + snd->child_sound = NULL; + if(snd->snd_sound) + { + AUD_unload(sound->snd_sound); + snd->snd_sound = NULL; + } + + sound_unlink(C, snd); + } + } + + for(scene = CTX_data_main(C)->scene.first; scene; scene = scene->id.next) + { + for(handle = scene->sound_handles.first; handle; handle = handle->next) + { + if(handle->source == sound) + { + handle->source = NULL; + if(handle->handle) + AUD_stop(handle->handle); + } + } + } +} + +struct SoundHandle* sound_new_handle(struct Scene *scene, struct bSound* sound, int startframe, int endframe, int frameskip) +{ + ListBase* handles = &scene->sound_handles; + + SoundHandle* handle = MEM_callocN(sizeof(SoundHandle), "sound_handle"); + handle->source = sound; + handle->startframe = startframe; + handle->endframe = endframe; + handle->frameskip = frameskip; + handle->state = AUD_STATUS_INVALID; + handle->volume = 1.0f; + + BLI_addtail(handles, handle); + + return handle; +} + +void sound_delete_handle(struct Scene *scene, struct SoundHandle *handle) +{ + if(handle == NULL) + return; + + if(handle->handle) + AUD_stop(handle->handle); + + BLI_freelinkN(&scene->sound_handles, handle); +} + +void sound_stop_all(struct bContext *C) +{ + SoundHandle *handle; + + for(handle = CTX_data_scene(C)->sound_handles.first; handle; handle = handle->next) + { + if(handle->state == AUD_STATUS_PLAYING) + { + AUD_pause(handle->handle); + handle->state = AUD_STATUS_PAUSED; + } + } +} + +#define SOUND_PLAYBACK_LAMBDA 1.0 + +void sound_update_playing(struct bContext *C) +{ + SoundHandle *handle; + Scene* scene = CTX_data_scene(C); + int cfra = CFRA; + float fps = FPS; + int action; + + AUD_lock(); + + for(handle = scene->sound_handles.first; handle; handle = handle->next) + { + if(cfra < handle->startframe || cfra >= handle->endframe || handle->mute) + { + if(handle->state == AUD_STATUS_PLAYING) + { + AUD_pause(handle->handle); + handle->state = AUD_STATUS_PAUSED; + } + } + else + { + action = 0; + + if(handle->changed != handle->source->changed) + { + handle->changed = handle->source->changed; + action = 3; + if(handle->state != AUD_STATUS_INVALID) + { + AUD_stop(handle->handle); + handle->state = AUD_STATUS_INVALID; + } + } + else + { + if(handle->state != AUD_STATUS_PLAYING) + action = 3; + else + { + handle->state = AUD_getStatus(handle->handle); + if(handle->state != AUD_STATUS_PLAYING) + action = 3; + else + { + float diff = AUD_getPosition(handle->handle) - (cfra - handle->startframe) / fps; +// AUD_XXX float diff = AUD_getPosition(handle->handle) * fps - cfra + handle->startframe + if(diff < 0.0) + diff = -diff; + if(diff > SOUND_PLAYBACK_LAMBDA) +// AUD_XXX if(diff > 5.0f) + { + action = 2; + } + } + } + } + + if(action & 1) + { + if(handle->state == AUD_STATUS_INVALID) + { + if(handle->source && handle->source->snd_sound) + { + AUD_Sound* limiter = AUD_limitSound(handle->source->cache ? handle->source->cache : handle->source->snd_sound, handle->frameskip / fps, (handle->frameskip + handle->endframe - handle->startframe)/fps); + handle->handle = AUD_play(limiter, 1); + AUD_unload(limiter); + if(handle->handle) + handle->state = AUD_STATUS_PLAYING; + if(cfra == handle->startframe) + action &= ~2; + } } + else + if(AUD_resume(handle->handle)) + handle->state = AUD_STATUS_PLAYING; + else + handle->state = AUD_STATUS_INVALID; } - sound = sound->id.next; + + if(action & 2) + AUD_seek(handle->handle, (cfra - handle->startframe) / fps); } } + + AUD_unlock(); } -PackedFile* sound_find_packedfile(bSound *sound) -{ - bSound *search; - PackedFile *pf = NULL; - char soundname[FILE_MAXDIR + FILE_MAXFILE], searchname[FILE_MAXDIR + FILE_MAXFILE]; - - // convert sound->name to abolute filename - strcpy(soundname, sound->name); - BLI_convertstringcode(soundname, G.sce); - - search = G.main->sound.first; - while (search) { - if (search->sample && search->sample->packedfile) { - strcpy(searchname, search->sample->name); - BLI_convertstringcode(searchname, G.sce); - - if (BLI_streq(searchname, soundname)) { - pf = search->sample->packedfile; - break; +void sound_scrub(struct bContext *C) +{ + SoundHandle *handle; + Scene* scene = CTX_data_scene(C); + int cfra = CFRA; + float fps = FPS; + + if(scene->audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer) + { + AUD_lock(); + + for(handle = scene->sound_handles.first; handle; handle = handle->next) + { + if(cfra >= handle->startframe && cfra < handle->endframe && !handle->mute) + { + if(handle->source && handle->source->snd_sound) + { + int frameskip = handle->frameskip + cfra - handle->startframe; + AUD_Sound* limiter = AUD_limitSound(handle->source->cache ? handle->source->cache : handle->source->snd_sound, frameskip / fps, (frameskip + 1)/fps); + AUD_play(limiter, 0); + AUD_unload(limiter); + } } - } - - if (search->newpackedfile) { - strcpy(searchname, search->name); - BLI_convertstringcode(searchname, G.sce); - if (BLI_streq(searchname, soundname)) { - pf = search->newpackedfile; - break; + } + + AUD_unlock(); + } +} + +AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end) +{ + AUD_Device* mixdown = AUD_openReadDevice(specs); + SoundHandle *handle; + float fps = FPS; + AUD_Sound *limiter, *delayer; + int frameskip, s, e; + + end++; + + for(handle = scene->sound_handles.first; handle; handle = handle->next) + { + if(start < handle->endframe && end > handle->startframe && !handle->mute && handle->source && handle->source->snd_sound) + { + frameskip = handle->frameskip; + s = handle->startframe - start; + e = handle->frameskip + AUD_MIN(handle->endframe, end) - handle->startframe; + + if(s < 0) + { + frameskip -= s; + s = 0; } + + limiter = AUD_limitSound(handle->source->snd_sound, frameskip / fps, e / fps); + delayer = AUD_delaySound(limiter, s / fps); + + AUD_playDevice(mixdown, delayer); + + AUD_unload(delayer); + AUD_unload(limiter); } - search = search->id.next; } - - return (pf); + + return mixdown; } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index f79009e673d..6e95fe7ebc7 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -41,7 +41,6 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "BKE_bad_level_calls.h" #include "BKE_cdderivedmesh.h" #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" @@ -49,6 +48,7 @@ #include "BKE_utildefines.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_multires.h" #include "BKE_scene.h" #include "BKE_subsurf.h" @@ -60,6 +60,7 @@ #include "BLI_edgehash.h" #include "BIF_gl.h" +#include "BIF_glutil.h" #include "GPU_draw.h" #include "GPU_extensions.h" @@ -472,7 +473,7 @@ static void calc_ss_weights(int gridFaces, static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, int drawInteriorEdges, int useSubsurfUv, - DerivedMesh *dm) + DerivedMesh *dm, MultiresSubsurf *ms) { DerivedMesh *result; int edgeSize = ccgSubSurf_getEdgeSize(ss); @@ -525,14 +526,21 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, } ccgFaceIterator_free(fi); - if(dm) { - result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss), - ccgSubSurf_getNumFinalEdges(ss), - ccgSubSurf_getNumFinalFaces(ss)); - } else { - result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss), - ccgSubSurf_getNumFinalEdges(ss), - ccgSubSurf_getNumFinalFaces(ss)); + if(ms) { + result = MultiresDM_new(ms, dm, ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + ccgSubSurf_getNumFinalFaces(ss)); + } + else { + if(dm) { + result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + ccgSubSurf_getNumFinalFaces(ss)); + } else { + result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + ccgSubSurf_getNumFinalFaces(ss)); + } } // load verts @@ -558,11 +566,12 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, ++mvert; ++origIndex; i++; - + for(S = 0; S < numVerts; S++) { int prevS = (S - 1 + numVerts) % numVerts; int nextS = (S + 1) % numVerts; int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3; + for(x = 1; x < gridFaces; x++) { float w[4]; w[prevS] = weight[x][0][0]; @@ -572,6 +581,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i); VecCopyf(mvert->co, ccgSubSurf_getFaceGridEdgeData(ss, f, S, x)); + *origIndex = ORIGINDEX_NONE; ++mvert; ++origIndex; @@ -583,6 +593,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, int prevS = (S - 1 + numVerts) % numVerts; int nextS = (S + 1) % numVerts; int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3; + for(y = 1; y < gridFaces; y++) { for(x = 1; x < gridFaces; x++) { float w[4]; @@ -881,8 +892,8 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, static int hasGivenError = 0; if(!hasGivenError) { - error("Unrecoverable error in SubSurf calculation," - " mesh is inconsistent."); + //XXX error("Unrecoverable error in SubSurf calculation," + // " mesh is inconsistent."); hasGivenError = 1; } @@ -2566,9 +2577,10 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, /***/ -struct DerivedMesh *subsurf_make_derived_from_derived( +struct DerivedMesh *subsurf_make_derived_from_derived_with_multires( struct DerivedMesh *dm, struct SubsurfModifierData *smd, + struct MultiresSubsurf *ms, int useRenderParams, float (*vertCos)[3], int isFinalCalc, int editMode) { @@ -2591,7 +2603,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( CCGSubSurf *ss; int levels; - levels= get_render_subsurf_level(&G.scene->r, smd->renderLevels); + levels= smd->renderLevels; // XXX get_render_subsurf_level(&scene->r, smd->renderLevels); if(levels == 0) return dm; @@ -2600,7 +2612,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); result = ss_to_cdderivedmesh(ss, 0, drawInteriorEdges, - useSubsurfUv, dm); + useSubsurfUv, dm, ms); ccgSubSurf_free(ss); @@ -2631,7 +2643,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( return ss_to_cdderivedmesh(ss, 0, drawInteriorEdges, - useSubsurfUv, dm); + useSubsurfUv, dm, ms); /*return (DerivedMesh *)getCCGDerivedMesh(smd->mCache, drawInteriorEdges, @@ -2651,7 +2663,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived( useSubsurfUv, dm);*/ result = ss_to_cdderivedmesh(ss, 0, drawInteriorEdges, - useSubsurfUv, dm); + useSubsurfUv, dm, ms); ccgSubSurf_free(ss); @@ -2660,6 +2672,15 @@ struct DerivedMesh *subsurf_make_derived_from_derived( } } +struct DerivedMesh *subsurf_make_derived_from_derived( + struct DerivedMesh *dm, + struct SubsurfModifierData *smd, + int useRenderParams, float (*vertCos)[3], + int isFinalCalc, int editMode) +{ + return subsurf_make_derived_from_derived_with_multires(dm, smd, NULL, useRenderParams, vertCos, isFinalCalc, editMode); +} + void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]) { /* Finds the subsurf limit positions for the verts in a mesh diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index d33721541f8..8e3d59bbc58 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -40,7 +40,6 @@ #include "DNA_scene_types.h" #include "DNA_text_types.h" -#include "BKE_bad_level_calls.h" #include "BKE_utildefines.h" #include "BKE_text.h" #include "BKE_library.h" @@ -66,9 +65,6 @@ A text should relate to a file as follows - (Text *)->flags has the following bits TXT_ISDIRTY - should always be set if the file in mem. differs from the file on disk, or if there is no file on disk. - TXT_ISTMP - should always be set if the (Text *)->name file has not - been written before, and attempts to save should result - in "Save over?" TXT_ISMEM - should always be set if the Text has not been mapped to a file, in which case (Text *)->name may be NULL or garbage. TXT_ISEXT - should always be set if the Text is not to be written into @@ -131,7 +127,6 @@ static void txt_delete_line(Text *text, TextLine *line); /***/ -static char *txt_cut_buffer= NULL; static unsigned char undoing; /* allow to switch off undoing externally */ @@ -180,7 +175,7 @@ Text *add_empty_text(char *name) ta->undo_buf= MEM_mallocN(ta->undo_len, "undo buf"); ta->nlines=1; - ta->flags= TXT_ISDIRTY | TXT_ISTMP | TXT_ISMEM; + ta->flags= TXT_ISDIRTY | TXT_ISMEM; ta->lines.first= ta->lines.last= NULL; ta->markers.first= ta->markers.last= NULL; @@ -258,8 +253,6 @@ int reopen_text(Text *text) text->undo_len= TXT_INIT_UNDO; text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); - text->flags= TXT_ISTMP; - fseek(fp, 0L, SEEK_END); len= ftell(fp); fseek(fp, 0L, SEEK_SET); @@ -323,7 +316,7 @@ int reopen_text(Text *text) return 1; } -Text *add_text(char *file) +Text *add_text(char *file, const char *relpath) { FILE *fp; int i, llen, len, res; @@ -335,8 +328,8 @@ Text *add_text(char *file) struct stat st; BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE); - if (G.scene) /* can be NULL (bg mode) */ - BLI_convertstringcode(str, G.sce); + if (relpath) /* can be NULL (bg mode) */ + BLI_convertstringcode(str, relpath); BLI_split_dirfile_basic(str, NULL, sfile); fp= fopen(str, "r"); @@ -348,9 +341,6 @@ Text *add_text(char *file) ta->lines.first= ta->lines.last= NULL; ta->markers.first= ta->markers.last= NULL; ta->curl= ta->sell= NULL; - -/* ta->flags= TXT_ISTMP | TXT_ISEXT; */ - ta->flags= TXT_ISTMP; fseek(fp, 0L, SEEK_END); len= ftell(fp); @@ -431,7 +421,7 @@ Text *copy_text(Text *ta) tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name"); strcpy(tan->name, ta->name); - tan->flags = ta->flags | TXT_ISDIRTY | TXT_ISTMP; + tan->flags = ta->flags | TXT_ISDIRTY; tan->lines.first= tan->lines.last= NULL; tan->markers.first= tan->markers.last= NULL; @@ -1057,11 +1047,6 @@ void txt_sel_line (Text *text) /* Cut and paste functions */ /***************************/ -void txt_print_cutbuffer (void) -{ - printf ("Cut buffer\n--\n%s\n--\n", txt_cut_buffer); -} - char *txt_to_buf (Text *text) { int length; @@ -1166,15 +1151,6 @@ int txt_find_string(Text *text, char *findstr, int wrap) return 0; } -void txt_cut_sel (Text *text) -{ - if (!G.background) /* Python uses txt_cut_sel, which it should not, working around for now */ - txt_copy_clipboard(text); - - txt_delete_sel(text); - txt_make_dirty(text); -} - char *txt_sel_to_buf (Text *text) { char *buf; @@ -1252,85 +1228,6 @@ char *txt_sel_to_buf (Text *text) return buf; } -void txt_copy_sel (Text *text) -{ - int length=0; - TextLine *tmp, *linef, *linel; - int charf, charl; - - if (!text) return; - if (!text->curl) return; - if (!text->sell) return; - - if (!txt_has_sel(text)) return; - - if (txt_cut_buffer) MEM_freeN(txt_cut_buffer); - txt_cut_buffer= NULL; - - if (text->curl==text->sell) { - linef= linel= text->curl; - - if (text->curc < text->selc) { - charf= text->curc; - charl= text->selc; - } else{ - charf= text->selc; - charl= text->curc; - } - } else if (txt_get_span(text->curl, text->sell)<0) { - linef= text->sell; - linel= text->curl; - - charf= text->selc; - charl= text->curc; - } else { - linef= text->curl; - linel= text->sell; - - charf= text->curc; - charl= text->selc; - } - - if (linef == linel) { - length= charl-charf; - - txt_cut_buffer= MEM_mallocN(length+1, "cut buffera"); - - BLI_strncpy(txt_cut_buffer, linef->line + charf, length+1); - } else { - length+= linef->len - charf; - length+= charl; - length++; /* For the '\n' */ - - tmp= linef->next; - while (tmp && tmp!= linel) { - length+= tmp->len+1; - tmp= tmp->next; - } - - txt_cut_buffer= MEM_mallocN(length+1, "cut bufferb"); - - strncpy(txt_cut_buffer, linef->line+ charf, linef->len-charf); - length= linef->len-charf; - - txt_cut_buffer[length++]='\n'; - - tmp= linef->next; - while (tmp && tmp!=linel) { - strncpy(txt_cut_buffer+length, tmp->line, tmp->len); - length+= tmp->len; - - txt_cut_buffer[length++]='\n'; - - tmp= tmp->next; - } - strncpy(txt_cut_buffer+length, linel->line, charl); - length+= charl; - - txt_cut_buffer[length]=0; - } -} - void txt_insert_buf(Text *text, char *in_buffer) { int i=0, l=0, j, u, len; @@ -1381,38 +1278,32 @@ void txt_insert_buf(Text *text, char *in_buffer) undoing= u; } -void txt_free_cut_buffer(void) -{ - if (txt_cut_buffer) MEM_freeN(txt_cut_buffer); -} - -void txt_paste(Text *text) -{ - txt_insert_buf(text, txt_cut_buffer); -} - /******************/ /* Undo functions */ /******************/ -#define MAX_UNDO_TEST(x) \ - while (text->undo_pos+x >= text->undo_len) { \ - if(text->undo_len*2 > TXT_MAX_UNDO) { \ - error("Undo limit reached, buffer cleared\n"); \ - MEM_freeN(text->undo_buf); \ - text->undo_len= TXT_INIT_UNDO; \ - text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); \ - text->undo_pos=-1; \ - return; \ - } else { \ - void *tmp= text->undo_buf; \ - text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf"); \ - memcpy(text->undo_buf, tmp, text->undo_len); \ - text->undo_len*=2; \ - MEM_freeN(tmp); \ - } \ +static int max_undo_test(Text *text, int x) +{ + while (text->undo_pos+x >= text->undo_len) { + if(text->undo_len*2 > TXT_MAX_UNDO) { + /* XXX error("Undo limit reached, buffer cleared\n"); */ + MEM_freeN(text->undo_buf); + text->undo_len= TXT_INIT_UNDO; + text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); + text->undo_pos=-1; + return 0; + } else { + void *tmp= text->undo_buf; + text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf"); + memcpy(text->undo_buf, tmp, text->undo_len); + text->undo_len*=2; + MEM_freeN(tmp); + } } + return 1; +} + static void dump_buffer(Text *text) { int i= 0; @@ -1558,7 +1449,8 @@ void txt_print_undo(Text *text) static void txt_undo_add_op(Text *text, int op) { - MAX_UNDO_TEST(2); + if(!max_undo_test(text, 2)) + return; text->undo_pos++; text->undo_buf[text->undo_pos]= op; @@ -1571,7 +1463,8 @@ static void txt_undo_add_block(Text *text, int op, char *buf) length= strlen(buf); - MAX_UNDO_TEST(length+11); + if(!max_undo_test(text, length+11)) + return; text->undo_pos++; text->undo_buf[text->undo_pos]= op; @@ -1605,7 +1498,8 @@ static void txt_undo_add_block(Text *text, int op, char *buf) void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc) { - MAX_UNDO_TEST(15); + if(!max_undo_test(text, 15)) + return; if (froml==tol && fromc==toc) return; @@ -1648,7 +1542,8 @@ void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fr static void txt_undo_add_charop(Text *text, int op, char c) { - MAX_UNDO_TEST(4); + if(!max_undo_test(text, 4)) + return; text->undo_pos++; text->undo_buf[text->undo_pos]= op; @@ -1869,7 +1764,7 @@ void txt_do_undo(Text *text) text->undo_pos--; break; default: - error("Undo buffer error - resetting"); + //XXX error("Undo buffer error - resetting"); text->undo_pos= -1; break; @@ -2082,7 +1977,7 @@ void txt_do_redo(Text *text) } break; default: - error("Undo buffer error - resetting"); + //XXX error("Undo buffer error - resetting"); text->undo_pos= -1; break; @@ -2395,6 +2290,12 @@ int txt_add_char (Text *text, char add) return 1; } +void txt_delete_selected(Text *text) +{ + txt_delete_sel(text); + txt_make_dirty(text); +} + int txt_replace_char (Text *text, char add) { char del; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 52b88de06e0..eeffbfe5ef6 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -61,7 +61,6 @@ #include "BKE_plugin_types.h" -#include "BKE_bad_level_calls.h" #include "BKE_utildefines.h" #include "BKE_global.h" @@ -73,9 +72,9 @@ #include "BKE_texture.h" #include "BKE_key.h" #include "BKE_icons.h" -#include "BKE_ipo.h" #include "BKE_brush.h" #include "BKE_node.h" +#include "BKE_animsys.h" /* ------------------------------------------------------------------------- */ @@ -177,8 +176,8 @@ PluginTex *add_plugin_tex(char *str) open_plugin_tex(pit); if(pit->doit==0) { - if(pit->handle==0) error("no plugin: %s", str); - else error("in plugin: %s", str); + if(pit->handle==0); //XXX error("no plugin: %s", str); + else ; //XXX error("in plugin: %s", str); MEM_freeN(pit); return NULL; } @@ -436,12 +435,15 @@ void default_tex(Tex *tex) VarStruct *varstr; int a; + tex->type= TEX_CLOUDS; tex->stype= 0; tex->flag= TEX_CHECKER_ODD; - tex->imaflag= TEX_INTERPOL+TEX_MIPMAP+TEX_USEALPHA; + tex->imaflag= TEX_INTERPOL|TEX_MIPMAP|TEX_USEALPHA; tex->extend= TEX_REPEAT; tex->cropxmin= tex->cropymin= 0.0; tex->cropxmax= tex->cropymax= 1.0; + tex->texfilter = TXF_EWA; + tex->afmax = 8; tex->xrepeat= tex->yrepeat= 1; tex->fie_ima= 2; tex->sfra= 1; @@ -532,7 +534,7 @@ void default_mtex(MTex *mtex) mtex->size[1]= 1.0; mtex->size[2]= 1.0; mtex->tex= 0; - mtex->texflag= 0; + mtex->texflag= MTEX_NEW_BUMP; mtex->colormodel= 0; mtex->r= 1.0; mtex->g= 0.0; @@ -541,7 +543,7 @@ void default_mtex(MTex *mtex) mtex->def_var= 1.0; mtex->blendtype= MTEX_BLEND; mtex->colfac= 1.0; - mtex->norfac= 0.5; + mtex->norfac= 1.0; mtex->varfac= 1.0; mtex->dispfac=0.2; mtex->normapspace= MTEX_NSPACE_TANGENT; @@ -571,7 +573,9 @@ Tex *copy_texture(Tex *tex) if(texn->type==TEX_IMAGE) id_us_plus((ID *)texn->ima); else texn->ima= 0; +#if 0 // XXX old animation system id_us_plus((ID *)texn->ipo); +#endif // XXX old animation system if(texn->plugin) { texn->plugin= MEM_dupallocN(texn->plugin); @@ -733,7 +737,9 @@ void make_local_texture(Tex *tex) void autotexname(Tex *tex) { -/* extern char texstr[20][12]; *//* buttons.c, already in bad lev calls*/ + char texstr[20][12]= {"None" , "Clouds" , "Wood", "Marble", "Magic" , "Blend", + "Stucci", "Noise" , "Image", "Plugin", "EnvMap" , "Musgrave", + "Voronoi", "DistNoise", "", "", "", "", "", ""}; Image *ima; char di[FILE_MAXDIR], fi[FILE_MAXFILE]; @@ -781,7 +787,7 @@ Tex *give_current_texture(Object *ob, int act) if(act>ob->totcol) act= ob->totcol; else if(act==0) act= 1; - if( BTST(ob->colbits, act-1) ) { /* in object */ + if(ob->matbits[act-1]) { /* in object */ ma= ob->mat[act-1]; } else { /* in data */ @@ -813,14 +819,14 @@ Tex *give_current_texture(Object *ob, int act) return tex; } -Tex *give_current_world_texture(void) +Tex *give_current_world_texture(Scene *scene) { MTex *mtex = 0; Tex *tex = 0; - if(!(G.scene->world)) return 0; + if(!(scene->world)) return 0; - mtex= G.scene->world->mtex[(int)(G.scene->world->texact)]; + mtex= scene->world->mtex[(int)(scene->world->texact)]; if(mtex) tex= mtex->tex; return tex; @@ -887,13 +893,17 @@ int BKE_texture_dependsOnTime(const struct Tex *texture) if(texture->plugin) { // assume all plugins depend on time return 1; - } else if( texture->ima && + } + else if( texture->ima && ELEM(texture->ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) { return 1; - } else if(texture->ipo) { + } +#if 0 // XXX old animation system + else if(texture->ipo) { // assume any ipo means the texture is animated return 1; } +#endif // XXX old animation system return 0; } diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c new file mode 100644 index 00000000000..140f155abc3 --- /dev/null +++ b/source/blender/blenkernel/intern/unit.c @@ -0,0 +1,494 @@ +/** + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <math.h> + +#if defined(WIN32) && (!(defined snprintf)) +#define snprintf _snprintf +#endif + +#define TEMP_STR_SIZE 256 + +/* define a single unit */ +typedef struct bUnitDef { + char *name; + char *name_plural; /* abused a bit for the display name */ + char *name_short; /* this is used for display*/ + char *name_alt; /* can be NULL */ + + double scalar; + double bias; /* not used yet, needed for converting temperature */ + int flag; +} bUnitDef; + +#define B_UNIT_DEF_NONE 0 +#define B_UNIT_DEF_SUPPRESS 1 /* Use for units that are not used enough to be translated into for common use */ + +/* define a single unit */ +typedef struct bUnitCollection { + struct bUnitDef *units; + int base_unit; /* use for 0.0, or none given */ + int flag; /* options for this system */ + int length; /* to quickly find the last item */ +} bUnitCollection; + +/* Dummy */ +static struct bUnitDef buDummyDef[] = { + {"", NULL, "", NULL, 1.0, 0.0}, + {NULL, NULL, NULL, NULL, 0.0, 0.0} +}; +static struct bUnitCollection buDummyCollecton = {buDummyDef, 0, 0, sizeof(buDummyDef)}; + + +/* Lengths */ +static struct bUnitDef buMetricLenDef[] = { + {"kilometer", "Kilometers", "km", NULL, 1000.0, 0.0, B_UNIT_DEF_NONE}, + {"hectometer", "100 Meters", "hm", NULL, 100.0, 0.0, B_UNIT_DEF_SUPPRESS}, + {"dekameter", "10 Meters", "dkm",NULL, 10.0, 0.0, B_UNIT_DEF_SUPPRESS}, + {"meter", "Meters", "m", NULL, 1.0, 0.0, B_UNIT_DEF_NONE}, /* base unit */ + {"decimetre", "10 Centimeters", "dm", NULL, 0.1, 0.0, B_UNIT_DEF_SUPPRESS}, + {"centimeter", "Centimeters", "cm", NULL, 0.01, 0.0, B_UNIT_DEF_NONE}, + {"millimeter", "Millimeters", "mm", NULL, 0.001, 0.0, B_UNIT_DEF_NONE}, + {"micrometer", "Micrometers", "um", "µm", 0.000001, 0.0, B_UNIT_DEF_NONE}, // micron too? + + /* These get displayed because of float precision problems in the transform header, + * could work around, but for now probably people wont use these */ + /* + {"nanometer", "Nanometers", "nm", NULL, 0.000000001, 0.0, B_UNIT_DEF_NONE}, + {"picometer", "Picometers", "pm", NULL, 0.000000000001, 0.0,B_UNIT_DEF_NONE}, + */ + {NULL, NULL, NULL, NULL, 0.0, 0.0} +}; +static struct bUnitCollection buMetricLenCollecton = {buMetricLenDef, 3, 0, sizeof(buMetricLenDef)/sizeof(bUnitDef)}; + +static struct bUnitDef buImperialLenDef[] = { + {"mile", "Miles", "mi", "m", 1609.344, 0.0, B_UNIT_DEF_NONE}, + {"furlong", "Furlongs", "fur", NULL,201.168, 0.0, B_UNIT_DEF_SUPPRESS}, + {"chain", "Chains", "ch", NULL, 0.9144*22.0, 0.0, B_UNIT_DEF_SUPPRESS}, + {"yard", "Yards", "yd", NULL, 0.9144, 0.0, B_UNIT_DEF_NONE}, + {"foot", "Feet", "'", "ft", 0.3048, 0.0, B_UNIT_DEF_NONE}, + {"inch", "Inches", "\"", "in", 0.0254, 0.0, B_UNIT_DEF_NONE}, /* base unit */ + {"thou", "Thous", "mil", NULL,0.0000254, 0.0, B_UNIT_DEF_NONE}, + {NULL, NULL, NULL, NULL, 0.0, 0.0} +}; +static struct bUnitCollection buImperialLenCollecton = {buImperialLenDef, 4, 0, sizeof(buImperialLenDef)/sizeof(bUnitDef)}; + + +/* Time */ +static struct bUnitDef buNaturalTimeDef[] = { + /* weeks? - probably not needed for blender */ + {"day", "Days", "d", NULL, 90000.0, 0.0, B_UNIT_DEF_NONE}, + {"hour", "Hours", "hr", "h", 3600.0, 0.0, B_UNIT_DEF_NONE}, + {"minute", "Minutes", "min", "m", 60.0, 0.0, B_UNIT_DEF_NONE}, + {"second", "Seconds", "sec", "s", 1.0, 0.0, B_UNIT_DEF_NONE}, /* base unit */ + {"millisecond", "Milliseconds", "ms", NULL, 0.001, 0.0 , B_UNIT_DEF_NONE}, + {"microsecond", "Microseconds", "us", NULL, 0.000001, 0.0, B_UNIT_DEF_NONE}, + {NULL, NULL, NULL, NULL, 0.0, 0.0} +}; +static struct bUnitCollection buNaturalTimeCollecton = {buNaturalTimeDef, 3, 0, sizeof(buNaturalTimeDef)/sizeof(bUnitDef)}; + +#define UNIT_SYSTEM_MAX 3 +static struct bUnitCollection *bUnitSystems[][8] = { + {0,0,0,0,0,0,0,0}, + {0,&buMetricLenCollecton, 0,0,0,0, &buNaturalTimeCollecton,0}, /* metric */ + {0,&buImperialLenCollecton, 0,0,0,0, &buNaturalTimeCollecton,0}, /* imperial */ + {0,0,0,0,0,0,0,0} +}; + +/* internal, has some option not exposed */ +static bUnitCollection *unit_get_system(int system, int type) +{ + return bUnitSystems[system][type]; /* select system to use, metric/imperial/other? */ +} + +static bUnitDef *unit_default(bUnitCollection *usys) +{ + return &usys->units[usys->base_unit]; +} + +static bUnitDef *unit_best_fit(double value, bUnitCollection *usys, bUnitDef *unit_start, int suppress) +{ + bUnitDef *unit; + double value_abs= value>0.0?value:-value; + + for(unit= unit_start ? unit_start:usys->units; unit->name; unit++) { + + if(suppress && (unit->flag & B_UNIT_DEF_SUPPRESS)) + continue; + + if (value_abs >= unit->scalar*0.9999) /* scale down scalar so 1cm doesnt convert to 10mm because of float error */ + return unit; + } + + return unit_default(usys); +} + + + +/* convert into 2 units and 2 values for "2ft, 3inch" syntax */ +static void unit_dual_convert(double value, bUnitCollection *usys, + bUnitDef **unit_a, bUnitDef **unit_b, double *value_a, double *value_b) +{ + bUnitDef *unit= unit_best_fit(value, usys, NULL, 1); + + *value_a= floor(value/unit->scalar) * unit->scalar; + *value_b= value - (*value_a); + + *unit_a= unit; + *unit_b= unit_best_fit(*value_b, usys, *unit_a, 1); +} + +static int unit_as_string(char *str, int len_max, double value, int prec, bUnitCollection *usys, + /* non exposed options */ + bUnitDef *unit, char pad) +{ + double value_conv; + int len, i; + + if(unit) { + /* use unit without finding the best one */ + } + else if(value == 0.0) { + /* use the default units since there is no way to convert */ + unit= unit_default(usys); + } + else { + unit= unit_best_fit(value, usys, NULL, 1); + } + + value_conv= value/unit->scalar; + + /* Convert to a string */ + { + char conv_str[6] = {'%', '.', '0'+prec, 'l', 'f', '\0'}; /* "%.2lf" when prec is 2, must be under 10 */ + len= snprintf(str, len_max, conv_str, (float)value_conv); + + if(len >= len_max) + len= len_max; + } + + /* Add unit prefix and strip zeros */ + + /* replace trailing zero's with spaces + * so the number is less complicated but allignment in a button wont + * jump about while dragging */ + i= len-1; + + while(i>0 && str[i]=='0') { /* 4.300 -> 4.3 */ + str[i--]= pad; + } + + if(i>0 && str[i]=='.') { /* 10. -> 10 */ + str[i--]= pad; + } + + /* Now add the suffix */ + if(i<len_max) { + int j=0; + i++; + while(unit->name_short[j] && (i < len_max)) { + str[i++]= unit->name_short[j++]; + } + + if(pad) { + /* this loop only runs if so many zeros were removed that + * the unit name only used padded chars, + * In that case add padding for the name. */ + + while(i<=len+j && (i < len_max)) { + str[i++]= pad; + } + } + } + + /* terminate no matter whats done with padding above */ + if(i >= len_max) + i= len_max-1; + + str[i] = '\0'; + return i; +} + + +/* Used for drawing number buttons, try keep fast */ +void bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, int split, int pad) +{ + bUnitCollection *usys = unit_get_system(system, type); + + if(usys==NULL || usys->units[0].name==NULL) + usys= &buDummyCollecton; + + if(split) { + int i; + bUnitDef *unit_a, *unit_b; + double value_a, value_b; + + unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b); + + /* check the 2 is a smaller unit */ + if(unit_b > unit_a) { + i= unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0'); + + /* is there enough space for at least 1 char of the next unit? */ + if(i+3 < len_max) { + str[i++]= ','; + str[i++]= ' '; + + /* use low precision since this is a smaller unit */ + unit_as_string(str+i, len_max-i, value_b, prec?1:0, usys, unit_b, '\0'); + } + return; + } + } + + unit_as_string(str, len_max, value, prec, usys, NULL, pad?' ':'\0'); +} + + +static char *unit_find_str(char *str, char *substr) +{ + char *str_found; + + if(substr && substr[0] != '\0') { + str_found= strstr(str, substr); + if(str_found) { + /* previous char cannot be a letter */ + if (str_found == str || isalpha(*(str_found-1))==0) { + /* next char cannot be alphanum */ + int len_name = strlen(substr); + + if (!isalpha(*(str_found+len_name))) { + return str_found; + } + } + } + + } + return NULL; + +} + +static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pref, bUnitDef *unit, char *replace_str) +{ + char *str_found; + + if((len_max>0) && (str_found= unit_find_str(str, replace_str))) { /* XXX - investigate, does not respect len_max properly */ + int len, len_num, len_name, len_move, found_ofs; + + found_ofs = (int)(str_found-str); + + len= strlen(str); + + len_name = strlen(replace_str); + len_move= (len - (found_ofs+len_name)) + 1; /* 1+ to copy the string terminator */ + len_num= snprintf(str_tmp, TEMP_STR_SIZE, "*%lg", unit->scalar/scale_pref); + + if(len_num > len_max) + len_num= len_max; + + if(found_ofs+len_num+len_move > len_max) { + /* can't move the whole string, move just as much as will fit */ + len_move -= (found_ofs+len_num+len_move) - len_max; + } + + if(len_move>0) { + /* resize the last part of the string */ + memmove(str_found+len_num, str_found+len_name, len_move); /* may grow or shrink the string */ + } + + if(found_ofs+len_num > len_max) { + /* not even the number will fit into the string, only copy part of it */ + len_num -= (found_ofs+len_num) - len_max; + } + + if(len_num > 0) { + /* its possible none of the number could be copied in */ + memcpy(str_found, str_tmp, len_num); /* without the string terminator */ + } + + /* since the null terminator wont be moved if the stringlen_max + * was not long enough to fit everything in it */ + str[len_max-1]= '\0'; + return found_ofs + len_num; + } + return 0; +} + +static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref, bUnitDef *unit) +{ + int ofs= 0; + ofs += unit_scale_str(str+ofs, len_max-ofs, str_tmp, scale_pref, unit, unit->name_short); + ofs += unit_scale_str(str+ofs, len_max-ofs, str_tmp, scale_pref, unit, unit->name_plural); + ofs += unit_scale_str(str+ofs, len_max-ofs, str_tmp, scale_pref, unit, unit->name_alt); + ofs += unit_scale_str(str+ofs, len_max-ofs, str_tmp, scale_pref, unit, unit->name); + return ofs; +} + +static int unit_find(char *str, bUnitDef *unit) +{ + if (unit_find_str(str, unit->name_short)) return 1; + if (unit_find_str(str, unit->name_plural)) return 1; + if (unit_find_str(str, unit->name_alt)) return 1; + if (unit_find_str(str, unit->name)) return 1; + + return 0; +} + +/* make a copy of the string that replaces the units with numbers + * this is used before parsing + * This is only used when evaluating user input and can afford to be a bit slower + * + * This is to be used before python evaluation so.. + * 10.1km -> 10.1*1000.0 + * ...will be resolved by python. + * + * str_prev is optional, when valid it is used to get a base unit when none is set. + * + * return true of a change was made. + */ +int bUnit_ReplaceString(char *str, int len_max, char *str_prev, double scale_pref, int system, int type) +{ + bUnitCollection *usys = unit_get_system(system, type); + + bUnitDef *unit; + char str_tmp[TEMP_STR_SIZE]; + int change= 0; + + if(usys==NULL || usys->units[0].name==NULL) { + return 0; + } + + for(unit= usys->units; unit->name; unit++) { + + if(unit->flag & B_UNIT_DEF_SUPPRESS) + continue; + + /* incase there are multiple instances */ + while(unit_replace(str, len_max, str_tmp, scale_pref, unit)) + change= 1; + } + unit= NULL; + + { + /* try other unit systems now, so we can evaluate imperial when metric is set for eg. */ + bUnitCollection *usys_iter; + int system_iter; + + for(system_iter= 1; system_iter<UNIT_SYSTEM_MAX; system_iter++) { + if (system_iter != system) { + usys_iter= unit_get_system(system_iter, type); + for(unit= usys_iter->units; unit->name; unit++) { + + if((unit->flag & B_UNIT_DEF_SUPPRESS) == 0) { + int ofs = 0; + /* incase there are multiple instances */ + while((ofs=unit_replace(str+ofs, len_max-ofs, str_tmp, scale_pref, unit))) + change= 1; + } + } + } + } + } + unit= NULL; + + if(change==0) { + /* no units given so infer a unit from the previous string or default */ + if(str_prev) { + /* see which units the original value had */ + for(unit= usys->units; unit->name; unit++) { + + if(unit->flag & B_UNIT_DEF_SUPPRESS) + continue; + + if (unit_find(str_prev, unit)) + break; + } + } + + if(unit==NULL) + unit= unit_default(usys); + + /* add the unit prefic and re-run */ + snprintf(str_tmp, sizeof(str_tmp), "%s %s", str, unit->name); + strncpy(str, str_tmp, len_max); + + return bUnit_ReplaceString(str, len_max, NULL, scale_pref, system, type); + } + + // printf("replace %s\n", str); + return change; +} + + +double bUnit_ClosestScalar(double value, int system, int type) +{ + bUnitCollection *usys = unit_get_system(system, type); + bUnitDef *unit; + + if(usys==NULL) + return -1; + + unit= unit_best_fit(value, usys, NULL, 1); + if(unit==NULL) + return -1; + + return unit->scalar; +} + +double bUnit_BaseScalar(int system, int type) +{ + bUnitCollection *usys = unit_get_system(system, type); + return unit_default(usys)->scalar; +} + +/* external access */ +void bUnit_GetSystem(void **usys_pt, int *len, int system, int type) +{ + bUnitCollection *usys = unit_get_system(system, type); + *usys_pt= usys; + + if(usys==NULL) { + *len= 0; + return; + } + + *len= usys->length; +} + +char *bUnit_GetName(void *usys_pt, int index) +{ + return ((bUnitCollection *)usys_pt)->units[index].name; +} +char *bUnit_GetNamePlural(void *usys_pt, int index) +{ + return ((bUnitCollection *)usys_pt)->units[index].name_plural; +} + +double bUnit_GetScaler(void *usys_pt, int index) +{ + return ((bUnitCollection *)usys_pt)->units[index].scalar; +} diff --git a/source/blender/blenkernel/intern/verse_bitmap_node.c b/source/blender/blenkernel/intern/verse_bitmap_node.c deleted file mode 100644 index 24295cd3ad0..00000000000 --- a/source/blender/blenkernel/intern/verse_bitmap_node.c +++ /dev/null @@ -1,448 +0,0 @@ -/** - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Contributor(s): Jiri Hnidek. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifdef WITH_VERSE - -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_listBase.h" - -#include "BLI_dynamiclist.h" -#include "BLI_blenlib.h" - -#include "BIF_verse.h" - -#include "BKE_verse.h" - -#include "verse.h" - -/* function prototypes of static functions */ -static void cb_b_dimension_set(void *user_data, VNodeID node_id, uint16 width, uint16 height, uint16 depth); -static void cb_b_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type); -static void cb_b_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id); -static void cb_b_tile_set(void *user_data, VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile); - -static void change_layer_dimension( - VBitmapLayer *vblayer, - unsigned int old_width, - unsigned int old_height, - unsigned int t_old_width, - unsigned int t_old_height); -static void *alloc_verse_bitmap_layer_data(struct VBitmapLayer *vblayer); - -/* - * resize/crop verse bitmap layer - */ -static void change_layer_dimension( - VBitmapLayer *vblayer, - unsigned int old_width, - unsigned int old_height, - unsigned int t_old_width, - unsigned int t_old_height) -{ - struct VNode *vnode = vblayer->vnode; - unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width; - unsigned int width = ((VBitmapData*)(vnode->data))->width; - unsigned int height = ((VBitmapData*)(vnode->data))->height; - unsigned int x, y, i, j; - - i = j = 0; - - /* "copy" old data to new data */ - if(vblayer->type==VN_B_LAYER_UINT8) { - unsigned char *data = (unsigned char*)vblayer->data; - /* allocate new verse bitmap layer data */ - unsigned char *new_data = (unsigned char*)alloc_verse_bitmap_layer_data(vblayer); - for(y=0; y<old_height && y<height; y++, i=y*t_width, j=y*t_old_width) { - for(x=0; x<old_width && y<width; x++, i++, j++) { - new_data[i] = data[j]; - } - } - MEM_freeN(vblayer->data); - vblayer->data = new_data; - } -} - -/* - * free data stored in verse bitmap layer - */ -void free_bitmap_layer_data(VBitmapLayer *vblayer) -{ - struct VerseSession *session = vblayer->vnode->session; - - /* free name of bitmap layer */ - MEM_freeN(vblayer->name); - - /* unsubscribe from verse bitmap layer */ - if(session->flag & VERSE_CONNECTED) - verse_send_b_layer_unsubscribe(vblayer->vnode->id, vblayer->id); - - /* free image data of bitmap layer */ - if(vblayer->data) MEM_freeN(vblayer->data); -} - -/* - * allocate data of verse bitmap layer - */ -static void *alloc_verse_bitmap_layer_data(VBitmapLayer *vblayer) -{ - struct VNode *vnode = vblayer->vnode; - unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width; - unsigned int t_height = ((VBitmapData*)(vnode->data))->t_height; - unsigned int size; - void *data; - - size = t_width*t_height; - - /* allocation of own data stored in verse bitmap layer */ - switch (vblayer->type) { - case VN_B_LAYER_UINT1: - data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint1"); - break; - case VN_B_LAYER_UINT8: - data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint8"); - break; - case VN_B_LAYER_UINT16: - data = (void*)MEM_mallocN(sizeof(unsigned int)*size, "VBLayer data uint16"); - break; - case VN_B_LAYER_REAL32: - data = (void*)MEM_mallocN(sizeof(float)*size, "VBLayer data float16"); - break; - case VN_B_LAYER_REAL64: - data = (void*)MEM_mallocN(sizeof(double)*size, "VBLayer data float32"); - break; - default: - data = NULL; - break; - } - - return data; -} - -/* - * create verse bitmap layer - */ -VBitmapLayer *create_bitmap_layer( - VNode *vnode, - VLayerID layer_id, - const char *name, - VNBLayerType type) -{ - struct VBitmapLayer *vblayer; - unsigned int width = ((VBitmapData*)(vnode->data))->width; - unsigned int height = ((VBitmapData*)(vnode->data))->height; - - /* allocate memory for own verse bitmap layer */ - vblayer = (VBitmapLayer*)MEM_mallocN(sizeof(VBitmapLayer), "Verse Bitmap Layer"); - - /* verse bitmap layer will include pointer at parent verse node and own id */ - vblayer->vnode = vnode; - vblayer->id = layer_id; - - /* name of verse layer */ - vblayer->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "Verse Bitmap Layer name"); - vblayer->name[0] = '\0'; - strcpy(vblayer->name, name); - - /* type of data stored in verse bitmap layer */ - vblayer->type = type; - - /* we can allocate memory for layer data, when we know dimmension of layers; when - * we don't know it, then we will allocate this data when we will receive dimmension */ - if(width==0 || height==0) - vblayer->data = NULL; - else - vblayer->data = alloc_verse_bitmap_layer_data(vblayer); - - vblayer->flag = 0; - - return vblayer; -} - -/* - * free data of bitmap node - */ -void free_bitmap_node_data(VNode *vnode) -{ - if(vnode->data) { - struct VBitmapLayer *vblayer = (VBitmapLayer*)((VBitmapData*)(vnode->data))->layers.lb.first; - - /* free all VerseLayer data */ - while(vblayer) { - free_bitmap_layer_data(vblayer); - vblayer = vblayer->next; - } - - /* free all VerseLayers */ - BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers)); - } -} - -/* - * create data of bitmap node - */ -VBitmapData *create_bitmap_data() -{ - struct VBitmapData *vbitmap; - - vbitmap = (VBitmapData*)MEM_mallocN(sizeof(VBitmapData), "Verse Bitmap Data"); - - BLI_dlist_init(&(vbitmap->layers)); - vbitmap->queue.first = vbitmap->queue.last = NULL; - - vbitmap->width = 0; - vbitmap->height = 0; - vbitmap->depth = 0; - - vbitmap->image = NULL; - - vbitmap->post_bitmap_dimension_set = post_bitmap_dimension_set; - vbitmap->post_bitmap_layer_create = post_bitmap_layer_create; - vbitmap->post_bitmap_layer_destroy = post_bitmap_layer_destroy; - vbitmap->post_bitmap_tile_set = post_bitmap_tile_set; - - return vbitmap; -} - -/* - * callback function, dimension of image was changed, it is neccessary to - * crop all layers - */ -static void cb_b_dimension_set( - void *user_data, - VNodeID node_id, - uint16 width, - uint16 height, - uint16 depth) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VBitmapLayer *vblayer; - unsigned int old_width, old_height, t_old_width, t_old_height; - - if(!session) return; - - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - if(!vnode) return; - -#ifdef VERSE_DEBUG_PRINT - printf("\t cb_b_dimension_set()\n"); -#endif - - /* backup old width and height */ - old_width = ((VBitmapData*)(vnode->data))->width; - old_height = ((VBitmapData*)(vnode->data))->height; - t_old_width = ((VBitmapData*)(vnode->data))->t_width; - t_old_height = ((VBitmapData*)(vnode->data))->t_height; - - /* set up new dimension of layers */ - ((VBitmapData*)(vnode->data))->width = width; - ((VBitmapData*)(vnode->data))->height = height; - ((VBitmapData*)(vnode->data))->depth = depth; - - /* we cache t_width because tiles aren't one pixel width */ - if((width % VN_B_TILE_SIZE)!=0) - ((VBitmapData*)(vnode->data))->t_width = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE; - else - ((VBitmapData*)(vnode->data))->t_width = width; - - /* we cache t_height because tiles aren't one pixel height */ - if((height % VN_B_TILE_SIZE)!=0) - ((VBitmapData*)(vnode->data))->t_height = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE; - else - ((VBitmapData*)(vnode->data))->t_height = height; - - /* crop resize all layers */ - vblayer = ((VBitmapData*)vnode->data)->layers.lb.first; - - while(vblayer) { - /* when this callback function received after cb_b_layer_create, - * then we have to allocate memory for verse bitmap layer data */ - if(!vblayer->data) vblayer->data = alloc_verse_bitmap_layer_data(vblayer); - /* crop/resize all verse bitmap layers */ - else change_layer_dimension(vblayer, old_width, old_height, t_old_width, t_old_height); - - vblayer = vblayer->next; - } - - /* post callback function */ - ((VBitmapData*)(vnode->data))->post_bitmap_dimension_set(vnode); -} - -/* - * callback function, new layer channel of image was created - */ -static void cb_b_layer_create( - void *user_data, - VNodeID node_id, - VLayerID layer_id, - const char *name, - VNBLayerType type) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VBitmapLayer *vblayer; - - if(!session) return; - - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - if(!vnode) return; - -#ifdef VERSE_DEBUG_PRINT - printf("\t cb_b_layer_create()\n"); -#endif - - /* when no layer exists, then new layer will be created */ - vblayer = create_bitmap_layer(vnode, layer_id, name, type); - - /* add verse bitmap layer to list of layers */ - BLI_dlist_add_item_index(&((VBitmapData*)vnode->data)->layers, vblayer, layer_id); - - /* post callback function */ - ((VBitmapData*)(vnode->data))->post_bitmap_layer_create(vblayer); - -} - -/* - * callback function, existing layer of image was destroyed - */ -static void cb_b_layer_destroy( - void *user_data, - VNodeID node_id, - VLayerID layer_id) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VBitmapLayer *vblayer; - - if(!session) return; - - /* find node of this layer*/ - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - if(!vnode) return; - - vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id); - if(!vblayer) return; - -#ifdef VERSE_DEBUG_PRINT - printf("\t cb_b_layer_destroy()\n"); -#endif - - /* remove verse bitmap layer from list of layers */ - BLI_dlist_rem_item(&(((VBitmapData*)vnode->data)->layers), layer_id); - - /* post callback function */ - ((VBitmapData*)(vnode->data))->post_bitmap_layer_destroy(vblayer); - - /* free data of verse bitmap layer */ - free_bitmap_layer_data(vblayer); - - /* free verse bitmap layer */ - MEM_freeN(vblayer); -} - -/* - * callback function, small part (8x8 pixels) was changed - */ -static void cb_b_tile_set( - void *user_data, - VNodeID node_id, - VLayerID layer_id, - uint16 tile_x, - uint16 tile_y, - uint16 z, - VNBLayerType type, - const VNBTile *tile) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VBitmapLayer *vblayer; - unsigned int x, y, xs, ys, width, height, t_height, t_width, i, j; - - if(!session) return; - - /* try to find verse node in dynamic list nodes */ - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - if(!vnode) return; - - /* try to find verse bitmap layer in list of layers */ - vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id); - if(!vblayer) return; - - /* we have to have allocated memory for bitmap layer */ - if(!vblayer->data) return; - - width = ((VBitmapData*)vnode->data)->width; - height = ((VBitmapData*)vnode->data)->height; - - /* width of verse image including all tiles */ - t_height = ((VBitmapData*)vnode->data)->t_height; - /* height of verse image including all tiles */ - t_width = ((VBitmapData*)vnode->data)->t_width; - -#ifdef VERSE_DEBUG_PRINT - printf("\t cb_b_tile_set()\n"); -#endif - - xs = tile_x*VN_B_TILE_SIZE; - ys = tile_y*VN_B_TILE_SIZE; - - /* initial position in one dimension vblayer->data (y_start*width + x_start) */ - i = ys*t_width + xs; - /* intial position in one dimension tile array */ - j = 0; - - if(type==VN_B_LAYER_UINT8) { - unsigned char *data = (unsigned char*)vblayer->data; - for(y=ys; y<ys+VN_B_TILE_SIZE && y<height; y++, i=y*t_width+xs) - for(x=xs; x<xs+VN_B_TILE_SIZE && x<width; x++, i++, j++) - data[i] = (unsigned char)tile->vuint8[j]; - } - - /* post callback function */ - ((VBitmapData*)(vnode->data))->post_bitmap_tile_set(vblayer, xs, ys); -} - -/* - * set up all callbacks functions for image nodes - */ -void set_bitmap_callbacks(void) -{ - /* dimension (size) of bitmap was set up or changes (image will be croped) */ - verse_callback_set(verse_send_b_dimensions_set, cb_b_dimension_set, NULL); - - /* new layer (chanell) of image was added or created */ - verse_callback_set(verse_send_b_layer_create, cb_b_layer_create, NULL); - - /* existing layer was destroyed */ - verse_callback_set(verse_send_b_layer_destroy, cb_b_layer_destroy, NULL); - - /* some tile (small part 8x8 pixels of image was changed) */ - verse_callback_set(verse_send_b_tile_set, cb_b_tile_set, NULL); -} - -#endif - diff --git a/source/blender/blenkernel/intern/verse_geometry_node.c b/source/blender/blenkernel/intern/verse_geometry_node.c deleted file mode 100644 index 010e42d5cb7..00000000000 --- a/source/blender/blenkernel/intern/verse_geometry_node.c +++ /dev/null @@ -1,2098 +0,0 @@ -/** - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Contributor(s): Jiri Hnidek. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifdef WITH_VERSE - -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_listBase.h" - -#include "BLI_dynamiclist.h" -#include "BLI_blenlib.h" -#include "BLI_arithb.h" - -#include "BKE_verse.h" -#include "BKE_utildefines.h" - -#include "BIF_verse.h" - -#include "verse.h" - -/* function prototypes of static functions */ - -/* test functions for callback functions */ -static char test_polygon_set_corner_uint32(uint32 v0, uint32 v1, uint32 v2, uint32 v3); - -/* callback functions */ -static void cb_g_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real); -static void cb_g_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id); -static void cb_g_vertex_set_xyz_real32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z); -static void cb_g_polygon_set_corner_uint32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); -static void cb_g_vertex_delete_real32(void *user_data, VNodeID node_id, uint32 vertex_id); -static void cb_g_polygon_delete(void *user_data, VNodeID node_id, uint32 polygon_id); -static void cb_g_crease_set_edge(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease); -static void cb_g_crease_set_vertex(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease); - -/* other static functions */ - -static void free_unneeded_verseverts_of_verseface(struct VNode *vnode, struct VerseFace *vface); -static void free_verse_vertex(struct VLayer *vlayer, struct VerseVert *vvert); -static void free_verse_face(struct VLayer *vlayer, struct VerseFace *vface); -static void free_verse_layer_data(struct VNode *vnode, struct VLayer *vlayer); - -static void send_verse_face(struct VerseFace *vface); - -static VerseVert* find_verse_vert_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 vertex_id, real32 x, real32 y, real32 z); -static VerseFace* find_verse_face_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3); - -static unsigned short test_incoming_verseface(struct VGeomData *geom, struct VerseFace *vface); -static void find_unsent_faces(struct VNode *vnode, struct VerseVert *vvert); -static void find_vlayer_orphans(struct VNode *vnode, struct VerseVert *vvert); -static void move_face_orphan_to_dlist(struct VNode *vnode, struct VLayer *vlayer, struct VerseFace *vface); -static void increase_verse_verts_references(struct VerseFace *vface); -static void recalculate_verseface_normals(struct VNode *vnode); - -/* verse edge functions */ -static VerseEdge* find_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1); -static void insert_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge); -static void remove_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge); -static void remove_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1); -static void add_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1); -static void update_edgehash_of_deleted_verseface(struct VNode *vnode, struct VerseFace *vface); -static void update_edgehash_of_changed_verseface(struct VNode *vnode, struct VerseFace *vface, uint32 v0, uint32 v1, uint32 v2, uint32 v3); -static void update_edgehash_of_new_verseface(struct VNode *vnode, uint32 v0, uint32 v1, uint32 v2, uint32 v3); - -/* - * recalcute normals of all VerseFaces - */ -static void recalculate_verseface_normals(VNode *vnode) -{ - struct VLayer *vert_layer, *face_layer; - struct VerseFace *vface; - struct VerseVert *vvert; - - if(vnode->type != V_NT_GEOMETRY) return; - - vert_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); - face_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); - - vvert = vert_layer->dl.lb.first; - while(vvert) { - vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0; - vvert = vvert->next; - } - - vface = face_layer->dl.lb.first; - while(vface) { - /* calculate face normals */ - if(vface->vvert3) { - CalcNormFloat4(vface->vvert0->co, vface->vvert1->co, - vface->vvert2->co, vface->vvert3->co, vface->no); - VecAddf(vface->vvert3->no, vface->vvert3->no, vface->no); - } - else - CalcNormFloat(vface->vvert0->co, vface->vvert1->co, - vface->vvert2->co, vface->no); - - /* calculate vertex normals ... it is averadge of all face normals using the vertex */ - VecAddf(vface->vvert0->no, vface->vvert0->no, vface->no); - VecAddf(vface->vvert1->no, vface->vvert1->no, vface->no); - VecAddf(vface->vvert2->no, vface->vvert2->no, vface->no); - - vface = vface->next; - } - - /* we have to normalize all vertex normals */ - vvert = vert_layer->dl.lb.first; - while(vvert) { - Normalize(vvert->no); - vvert = vvert->next; - } -} - -/* - * add created item to the queue and send it if possible - */ -void add_item_to_send_queue(ListBase *lb, void *item, short type) -{ - struct VNode *vnode; - struct VLayer *vlayer; - struct VerseVert *vvert; - struct VerseFace *vface; - - /* this prevent from adding duplicated faces */ - if(type==VERSE_FACE) { - struct Link *link = (Link*)lb->first; - while(link) { - if(link==item) { - if(((VerseFace*)item)->flag & FACE_SENT) { -/* printf("\tverse face %d marked as OBSOLETE\n", ((VerseFace*)item)->id);*/ - ((VerseFace*)item)->flag |= FACE_OBSOLETE; - } - return; - } - link = link->next; - } - } - - /* add item to sending queue (two way dynamic list) */ - BLI_addtail(lb, item); - - /* send item, when it is possible */ - switch (type) { - case VERSE_NODE: /* only first node in queue can be sent */ - if(lb->first==lb->last) - send_verse_node((VNode*)item); - break; - case VERSE_LINK: /* both object between have to exist */ - if(((VLink*)item)->flag & LINK_SEND_READY) - send_verse_link((VLink*)item); - break; - case VERSE_LAYER: - if(((VLayer*)item)->vnode->flag & NODE_RECEIVED) - send_verse_layer((VLayer*)item); - break; - case VERSE_VERT: - if(((VerseVert*)item)->vlayer->flag & LAYER_RECEIVED) - send_verse_vertex((VerseVert*)item); - break; - case VERSE_FACE: /* all vertexes of face have to be received */ - if(((VerseFace*)item)->flag & FACE_SEND_READY) - send_verse_face((VerseFace*)item); - break; - case VERSE_TAG: - send_verse_tag((VTag*)item); - break; - case VERSE_TAG_GROUP: - send_verse_taggroup((VTagGroup*)item); - break; - case VERSE_VERT_UINT32: /* parent item has to exist */ - vnode = (((uint32_item*)item)->vlayer)->vnode; - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 ); - vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id ); - if(vvert != NULL) - send_verse_vert_uint32((uint32_item*)item, type); - break; - case VERSE_VERT_REAL32: /* parent item has to exist */ - vnode = (((real32_item*)item)->vlayer)->vnode; - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 ); - vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id ); - if( vvert != NULL) - send_verse_vert_real32((real32_item*)item, type); - break; - case VERSE_VERT_VEC_REAL32: /* parent item has to exist */ - vnode = (((vec_real32_item*)item)->vlayer)->vnode; - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 ); - vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((vec_real32_item*)item)->id ); - if(vvert != NULL) - send_verse_vert_vec_real32((vec_real32_item*)item, type); - break; - case VERSE_FACE_UINT8: /* parent item has to exist */ - vnode = (((uint8_item*)item)->vlayer)->vnode; - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 ); - vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint8_item*)item)->id ); - if(vface != NULL) - send_verse_face_uint8((uint8_item*)item, type); - break; - case VERSE_FACE_UINT32: /* parent item has to exist */ - vnode = (((uint32_item*)item)->vlayer)->vnode; - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 ); - vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id ); - if(vface != NULL) - send_verse_face_uint32((uint32_item*)item, type); - break; - case VERSE_FACE_REAL32: /* parent item has to exist */ - vnode = (((real32_item*)item)->vlayer)->vnode; - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 ); - vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id ); - if(vface != NULL) - send_verse_face_real32((real32_item*)item, type); - break; - case VERSE_FACE_QUAT_UINT32: /* parent item has to exist */ - vnode = (((quat_uint32_item*)item)->vlayer)->vnode; - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 ); - vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_uint32_item*)item)->id ); - if(vface != NULL) - send_verse_face_corner_quat_uint32((quat_uint32_item*)item, type); - break; - case VERSE_FACE_QUAT_REAL32: /* parent item has to exist */ - vnode = (((quat_real32_item*)item)->vlayer)->vnode; - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 ); - vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_real32_item*)item)->id ); - if(vface != NULL) - send_verse_face_corner_quat_real32((quat_real32_item*)item, type); - break; - } -} - -/* - * return VerseLayer with certain content (vertexes, polygons, in the - * future: weight, red color, etc.) - */ -VLayer* find_verse_layer_type(VGeomData *geom, short content) -{ - struct VLayer *vlayer = NULL; - - switch(content) { - case VERTEX_LAYER: - /* VERTEX_LAYER equals 0 and vertex layer is - * always in 1st layer */ - vlayer = geom->layers.da.items[VERTEX_LAYER]; - break; - case POLYGON_LAYER: - /* POLYGON_LAYER equals 1 and vertex layer is - * always in 2nd layer */ - vlayer = geom->layers.da.items[POLYGON_LAYER]; - break; - } - - return vlayer; -} - -/* - * increase references of VerseVerts of new VerseFace - */ -static void increase_verse_verts_references(VerseFace *vface) -{ - if(vface->vvert0) vface->vvert0->counter++; - if(vface->vvert1) vface->vvert1->counter++; - if(vface->vvert2) vface->vvert2->counter++; - if(vface->vvert3) vface->vvert3->counter++; -} - -/* - * move VerseFace from list of orphans to dlist of VerseFaces (if VerseFace was only changed - * then this VerseFace is only removed from list of orphans) - */ -static void move_face_orphan_to_dlist(VNode *vnode, VLayer *vlayer, VerseFace *vface) -{ - /* remove vface from list of orphans */ - BLI_remlink(&(vlayer->orphans), vface); - /* increase references of all vertexes beying part of this face*/ - increase_verse_verts_references(vface); - - if(vface->flag & FACE_RECEIVED) { - /* set up vface flag */ - vface->flag &= ~FACE_RECEIVED; - /* move vface to dynamic list of faces */ - BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id); - /* recalculate all vertex and faces normals */ - recalculate_verseface_normals(vnode); - /* post create action (change local data) */ - ((VGeomData*)vnode->data)->post_polygon_create(vface); - } - else if(vface->flag & FACE_CHANGED) { - /* set up vface flag */ - vface->flag &= ~FACE_CHANGED; - /* move vface to dynamic list of faces */ - BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id); - /* recalculate all vertex and faces normals */ - recalculate_verseface_normals(vnode); - /* post create action (change local data) */ - ((VGeomData*)vnode->data)->post_polygon_set_corner(vface); - } -} - -/* - * find all VerseFaces waiting in queue, which needs id of new VerseVert - */ -static void find_unsent_faces(VNode *vnode, VerseVert *vvert) -{ - VLayer *vlayer; - VerseFace *vface, *next_vface; - - vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); - - if(vlayer) { - vface = vlayer->queue.first; - while(vface) { - next_vface = vface->next; - if(vface->vvert0==vvert) { - vface->v0 = vvert->id; - vface->counter--; - } - else if(vface->vvert1==vvert) { - vface->v1 = vvert->id; - vface->counter--; - } - else if(vface->vvert2==vvert) { - vface->v2 = vvert->id; - vface->counter--; - } - else if(vface->vvert3==vvert){ - vface->v3 = vvert->id; - vface->counter--; - } - - if(vface->counter<1 && !(vface->flag & FACE_SENT)) - send_verse_face(vface); - - vface = next_vface; - } - } -} - -/* - * find all VerseFace orphans, which needs incoming VerseVert - */ -static void find_vlayer_orphans(VNode *vnode, VerseVert *vvert) -{ - VLayer *vlayer; - VerseFace *vface, *next_vface; - unsigned int vertex_id = vvert->id; - - vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); - - if(vlayer) { - vface = vlayer->orphans.first; - while(vface){ - next_vface = vface->next; - if(vface->v0 == vertex_id) { - vface->vvert0 = vvert; - vface->counter--; - } - else if(vface->v1 == vertex_id) { - vface->vvert1 = vvert; - vface->counter--; - } - else if(vface->v2 == vertex_id) { - vface->vvert2 = vvert; - vface->counter--; - } - else if(vface->v3 == vertex_id) { - vface->vvert3 = vvert; - vface->counter--; - } - if(vface->counter<1) { - /* moving VerseFace orphan to dlist */ - move_face_orphan_to_dlist(vnode, vlayer, vface); - } - vface = next_vface; - } - } -} - -/* - * return number of VerseVerts missing to incoming VerseFace, set up pointers - * at VerseVerts - */ -static unsigned short test_incoming_verseface(VGeomData *geom, VerseFace *vface) -{ - struct VLayer *vert_layer; - struct VerseVert *vvert; - int counter=0; - - vert_layer = find_verse_layer_type(geom, VERTEX_LAYER); - - if(vface->v0 != -1){ - vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v0); - if(vvert==NULL) counter++; - else vface->vvert0 = vvert; - } - if(vface->v1 != -1){ - vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v1); - if(vvert==NULL) counter++; - else vface->vvert1 = vvert; - } - if(vface->v2 != -1){ - vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v2); - if(vvert==NULL) counter++; - else vface->vvert2 = vvert; - } - if(vface->v3 != -1){ - vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v3); - if(vvert==NULL) counter++; - else vface->vvert3 = vvert; - } - - return counter; -} - -/* - * try to find changed VerseFace in sending queue - */ -static VerseFace* find_changed_verse_face_in_queue(VLayer *vlayer, uint32 polygon_id) -{ - struct VerseFace *vface = vlayer->queue.first; - - while(vface){ - if(vface->id == polygon_id && vface->flag & FACE_CHANGED) { - return vface; - } - vface = vface->next; - } - return NULL; -} - -/* - * try to find VerseFace in queue - */ -static VerseFace* find_verse_face_in_queue( - VLayer *vlayer, - VNodeID node_id, - uint32 polygon_id, - uint32 v0, - uint32 v1, - uint32 v2, - uint32 v3) -{ - struct VerseFace *vface = vlayer->queue.first; - - while(vface){ - if((vface->v0==v0) && (vface->v1==v1) && (vface->v2==v2) && (vface->v3==v3)){ - vface->id = polygon_id; - vface->vlayer = vlayer; - return vface; - } - vface = vface->next; - } - return NULL; -} - -/* - * try to find VerseVert in queue - */ -static VerseVert* find_verse_vert_in_queue( - VLayer *vlayer, - VNodeID node_id, - uint32 vertex_id, - real32 x, - real32 y, - real32 z) -{ - struct VerseVert *vvert = vlayer->queue.first; - - while(vvert){ - if((vvert->vlayer->vnode->id == node_id) && (vvert->co[0] == x) && (vvert->co[1] == y) && (vvert->co[2] == z)) - { - vvert->id = vertex_id; - vvert->vlayer = vlayer; - - return vvert; - } - vvert = vvert->next; - } - - return NULL; -} - - -/* - * send quat of float values to verse server (4x32 bits) - */ -void send_verse_face_corner_quat_real32(quat_real32_item *item, short type) -{ - verse_send_g_polygon_set_corner_real32( - item->vlayer->vnode->id, - item->vlayer->id, - item->id, - item->value[0], - item->value[1], - item->value[2], - item->value[3]); -} - -/* - * send quat of unsigned int values to verse server (4x32 bits) - */ -void send_verse_face_corner_quat_uint32(quat_uint32_item *item, short type) -{ - verse_send_g_polygon_set_corner_uint32( - item->vlayer->vnode->id, - item->vlayer->id, - item->id, - item->value[0], - item->value[1], - item->value[2], - item->value[3]); -} - -/* - * send float value (32 bits) to verse server - */ -void send_verse_face_real32(real32_item *item, short type) -{ - verse_send_g_polygon_set_face_real32( - item->vlayer->vnode->id, - item->vlayer->id, - item->id, - item->value); -} - -/* - * send unsigned integer (32 bits) to verse server - */ -void send_verse_face_uint32(uint32_item *item, short type) -{ - verse_send_g_polygon_set_face_uint32( - item->vlayer->vnode->id, - item->vlayer->id, - item->id, - item->value); -} - -/* - * send unsigned char (8 bits) to verse server - */ -void send_verse_face_uint8(uint8_item *item, short type) -{ - verse_send_g_polygon_set_face_uint8( - item->vlayer->vnode->id, - item->vlayer->id, - item->id, - item->value); -} - -/* - * send vector of float values to verse server (3x32 bits) - */ -void send_verse_vert_vec_real32(vec_real32_item *item, short type) -{ - verse_send_g_vertex_set_xyz_real32( - item->vlayer->vnode->id, - item->vlayer->id, - item->id, - item->value[0], - item->value[1], - item->value[2]); -} - -/* - * send float value (32 bits) to verse server - */ -void send_verse_vert_real32(real32_item *item, short type) -{ - verse_send_g_vertex_set_real32( - item->vlayer->vnode->id, - item->vlayer->id, - item->id, - item->value); -} - -/* - * send unsigned integer (32 bits) to verse server - */ -void send_verse_vert_uint32(uint32_item *item, short type) -{ - verse_send_g_vertex_set_uint32( - item->vlayer->vnode->id, - item->vlayer->id, - item->id, - item->value); -} - -/* - * send delete command to verse server - */ -void send_verse_vertex_delete(VerseVert *vvert) -{ - verse_session_set(vvert->vlayer->vnode->session->vsession); - - vvert->flag |= VERT_OBSOLETE; - - verse_send_g_vertex_delete_real32(vvert->vlayer->vnode->id, vvert->id); -} - -/* - * send VerseLayer to verse server - */ -void send_verse_layer(VLayer *vlayer) -{ - verse_session_set(vlayer->vnode->session->vsession); - - verse_send_g_layer_create( - vlayer->vnode->id, - vlayer->id, - vlayer->name, - vlayer->type, - vlayer->def_int, - vlayer->def_real); -} - -/* - * send VerseVert to verse server - */ -void send_verse_vertex(VerseVert *vvert) -{ - /* new vertex position will not be sent, when vertex was deleted */ - if(vvert->flag & VERT_OBSOLETE) return; - - verse_session_set(vvert->vlayer->vnode->session->vsession); - - verse_send_g_vertex_set_xyz_real32( - vvert->vlayer->vnode->id, - vvert->vlayer->id, - vvert->id, - vvert->co[0], - vvert->co[2], - -vvert->co[1]); -} - -/* - * send delete command to verse server - */ -void send_verse_face_delete(VerseFace *vface) -{ - verse_session_set(vface->vlayer->vnode->session->vsession); - - vface->flag |= FACE_DELETED; - - verse_send_g_polygon_delete(vface->vlayer->vnode->id, vface->id); -} - -/* - * send VerseFace to verse server - */ -static void send_verse_face(VerseFace *vface) -{ - verse_session_set(vface->vlayer->vnode->session->vsession); - - vface->flag |= FACE_SENT; - - if(vface->v3 != -1) { - verse_send_g_polygon_set_corner_uint32( - vface->vlayer->vnode->id, - vface->vlayer->id, - vface->id, - vface->v0, - vface->v3, /* verse use clock-wise winding */ - vface->v2, - vface->v1); /* verse use clock-wise winding */ - } - else { - verse_send_g_polygon_set_corner_uint32( - vface->vlayer->vnode->id, - vface->vlayer->id, - vface->id, - vface->v0, - vface->v2, /* verse use clock-wise winding */ - vface->v1, /* verse use clock-wise winding */ - vface->v3); - } -} - -/* - * free VerseVert - */ -static void free_verse_vertex(VLayer *vlayer, VerseVert *vvert) -{ - /* free VerseVert */ - BLI_freelinkN(&(vlayer->orphans), vvert); -} - -/* - * free VerseFace (and blender face) - */ -static void free_verse_face(VLayer *vlayer, VerseFace *vface) -{ - /* free VerseFace */ - BLI_dlist_free_item(&(vlayer->dl), (unsigned int)vface->id); -} - -/* - * free VerseLayer data - */ -static void free_verse_layer_data(VNode *vnode, VLayer *vlayer) -{ - struct VerseFace *vface; - struct VerseVert *vvert; - - /* set up EditVert->vvert and EditFace->vface pointers to NULL */ - switch(vlayer->content) { - case VERTEX_LAYER: - vvert = (VerseVert*)vlayer->dl.lb.first; - while(vvert) { - ((VGeomData*)vnode->data)->post_vertex_free_constraint(vvert); - vvert = vvert->next; - } - break; - case POLYGON_LAYER: - vface = (VerseFace*)vlayer->dl.lb.first; - while(vface) { - ((VGeomData*)vnode->data)->post_polygon_free_constraint(vface); - vface = vface->next; - } - break; - default: - break; - } - /* free Verse Layer name */ - MEM_freeN(vlayer->name); - /* destroy VerseLayer data (vertexes, polygons, etc.) */ - BLI_dlist_destroy(&(vlayer->dl)); - /* free unsent data */ - BLI_freelistN(&(vlayer->queue)); - /* free orphans */ - BLI_freelistN(&(vlayer->orphans)); -} - -/* - * free all unneeded VerseVerts waiting for deleting - */ -static void free_unneeded_verseverts_of_verseface(VNode *vnode, VerseFace *vface) -{ - struct VLayer *vert_vlayer; - - /* find layer containing vertexes */ - vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); - - /* free all "deleted" VerseVert waiting for deleting this VerseFace */ - - if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) { - ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0); - free_verse_vertex(vert_vlayer, vface->vvert0); - vface->vvert0 = NULL; - } - if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) { - ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1); - free_verse_vertex(vert_vlayer, vface->vvert1); - vface->vvert1 = NULL; - } - if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) { - ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2); - free_verse_vertex(vert_vlayer, vface->vvert2); - vface->vvert2 = NULL; - } - if((vface->vvert3) && (vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) { - ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3); - free_verse_vertex(vert_vlayer, vface->vvert3); - vface->vvert3 = NULL; - } -} - -/* - * This function create VerseVert and returns pointer on this vertex - */ -VerseVert* create_verse_vertex( - VLayer *vlayer, - uint32 vertex_id, - real32 x, - real32 y, - real32 z) -{ - struct VerseVert *vvert; - - vvert = (VerseVert*)MEM_mallocN(sizeof(VerseVert), "VerseVert"); - - /* set up pointer on parent node */ - vvert->vlayer = vlayer; - vvert->id = vertex_id; - /* position */ - vvert->co[0] = x; - vvert->co[1] = y; - vvert->co[2] = z; - /* normal */ - vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0; - /* blender internals */ - vvert->flag = 0; - vvert->counter = 0; - vvert->vertex = NULL; - - /* increase layer counter of vertexes */ - vlayer->counter++; - - return vvert; -} - -/* - * this function creates fake VerseEdge and returns pointer at this edge - */ -VerseEdge *create_verse_edge(uint32 v0, uint32 v1) -{ - struct VerseEdge *vedge; - - vedge = (VerseEdge*)MEM_mallocN(sizeof(VerseEdge), "VerseEdge"); - - vedge->v0 = v0; - vedge->v1 = v1; - vedge->counter = 0; - - return vedge; -} - -/* - * this function will create new VerseFace and will return pointer on such Face - */ -VerseFace* create_verse_face( - VLayer *vlayer, - uint32 polygon_id, - uint32 v0, - uint32 v1, - uint32 v2, - uint32 v3) -{ - struct VerseFace *vface; - - vface = (VerseFace*)MEM_mallocN(sizeof(VerseFace), "VerseFace"); - - /* verse data */ - vface->vlayer = vlayer; - vface->id = polygon_id; - - vface->vvert0 = NULL; - vface->vvert1 = NULL; - vface->vvert2 = NULL; - vface->vvert3 = NULL; - - vface->v0 = v0; - vface->v1 = v1; - vface->v2 = v2; - vface->v3 = v3; - - /* blender data */ - vface->face = NULL; - vface->flag = 0; - vface->counter = 4; - - /* increase layer counter of faces */ - vlayer->counter++; - - return vface; -} - -/* - * create and return VerseLayer - */ -VLayer *create_verse_layer( - VNode *vnode, - VLayerID layer_id, - const char *name, - VNGLayerType type, - uint32 def_integer, - real64 def_real) -{ - struct VLayer *vlayer; - - /* add layer to the DynamicList */ - vlayer = (VLayer*)MEM_mallocN(sizeof(VLayer), "VerseLayer"); - - /* store all relevant info to the vlayer and set up vlayer */ - vlayer->vnode = vnode; - vlayer->id = layer_id; - vlayer->name = (char*)MEM_mallocN(sizeof(char)*(sizeof(name)+1),"Verse Layer name"); - strcpy(vlayer->name, name); - vlayer->type = type; - vlayer->def_int = def_integer; - vlayer->def_real = def_real; - - if((type == VN_G_LAYER_VERTEX_XYZ) && (layer_id == 0)) - vlayer->content = VERTEX_LAYER; - else if((type == VN_G_LAYER_POLYGON_CORNER_UINT32) && (layer_id == 1)) - vlayer->content = POLYGON_LAYER; - else - vlayer->content = -1; - - /* initialize DynamicList in the vlayer (vertexes, polygons, etc.)*/ - BLI_dlist_init(&(vlayer->dl)); - /* initialization of queue of layer */ - vlayer->queue.first = vlayer->queue.last = NULL; - /* initialization of list of orphans */ - vlayer->orphans.first = vlayer->orphans.last = NULL; - /* initialize number of sent items (vertexes, faces, etc) */ - vlayer->counter = 0; - /* initialize flag */ - vlayer->flag = 0; - - /* set up methods */ - vlayer->post_layer_create = post_layer_create; - vlayer->post_layer_destroy = post_layer_destroy; - - return vlayer; -} - -/* - * create geometry data - */ -VGeomData *create_geometry_data(void) -{ - struct VGeomData *geom; - - geom = (VGeomData*)MEM_mallocN(sizeof(VGeomData), "VerseGeometryData"); - BLI_dlist_init(&(geom->layers)); - geom->vlink = NULL; - geom->queue.first = geom->queue.last = NULL; - geom->mesh = NULL; - geom->editmesh = NULL; - - /* initialize list of fake verse edges and initialize verse edge hash */ - geom->edges.first = geom->edges.last = NULL; - geom->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab"); - - /* set up methods */ - geom->post_vertex_create = post_vertex_create; - geom->post_vertex_set_xyz = post_vertex_set_xyz; - geom->post_vertex_delete = post_vertex_delete; - geom->post_vertex_free_constraint = post_vertex_free_constraint; - geom->post_polygon_create = post_polygon_create; - geom->post_polygon_set_corner = post_polygon_set_corner; - geom->post_polygon_delete = post_polygon_delete; - geom->post_polygon_free_constraint = post_polygon_free_constraint; - geom->post_geometry_free_constraint = post_geometry_free_constraint; - geom->post_polygon_set_uint8 = post_polygon_set_uint8; - - return geom; -} - -/* Create item containing 4 floats */ -static quat_real32_item *create_quat_real32_item( - VLayer *vlayer, - uint32 item_id, - real32 v0, - real32 v1, - real32 v2, - real32 v3) -{ - struct quat_real32_item *item; - - item = (quat_real32_item*)MEM_mallocN(sizeof(quat_real32_item), "quat_real32_item"); - - item->vlayer = vlayer; - item->id = item_id; - item->value[0] = v0; - item->value[1] = v1; - item->value[2] = v2; - item->value[3] = v3; - - return item; -} - -/* Create item containing 1 float */ -static real32_item *create_real32_item(VLayer *vlayer, uint32 item_id, real32 value) -{ - struct real32_item *item; - - item = (real32_item*)MEM_mallocN(sizeof(real32_item), "real32_item"); - - item->vlayer = vlayer; - item->id = item_id; - item->value = value; - - return item; -} - -/* Create item containing 1 integer */ -static uint32_item *create_uint32_item(VLayer *vlayer, uint32 item_id, uint32 value) -{ - struct uint32_item *item; - - item = (uint32_item*)MEM_mallocN(sizeof(uint32_item), "uint32_item"); - - item->vlayer = vlayer; - item->id = item_id; - item->value = value; - - return item; -} - -/* Create item containing 1 byte */ -static uint8_item *create_uint8_item(VLayer *vlayer, uint32 item_id, uint8 value) -{ - struct uint8_item *item; - - item = (uint8_item*)MEM_mallocN(sizeof(uint8_item), "uint8_item"); - - item->vlayer = vlayer; - item->id = item_id; - item->value = value; - - return item; -} - -/* - * callback function: vertex crease was set - */ -static void cb_g_crease_set_vertex( - void *user_data, - VNodeID node_id, - const char *layer, - uint32 def_crease) -{ -} - -/* - * we have to test corretness of incoming data from verse server - * no two vertexes can have the same index - */ -static char test_polygon_set_corner_uint32( - uint32 v0, - uint32 v1, - uint32 v2, - uint32 v3) -{ - if((v0==v1) || (v0==v2) || (v0==v3) || (v1==v2) || (v1==v3) || (v2==v3)) - return 0; - else - return 1; -} - -/* - * try to find verse layer in sending queue of verse geometry node - */ -static VLayer *find_vlayer_in_sending_queue(VNode *vnode, VLayerID layer_id) -{ - struct VLayer *vlayer; - - /* try to find verse layyer in sending queue */ - vlayer = ((VGeomData*)vnode->data)->queue.first; - while(vlayer) { - if(vlayer->id==layer_id) return vlayer; - vlayer = vlayer->next; - } - - return NULL; -} - -/* - * this function will find edge in hash table, hash function isn't too optimal (it needs - * lot of memory for every verse node), but it works without any bug - */ -static VerseEdge* find_verse_edge(VNode *vnode, uint32 v0, uint32 v1) -{ - struct HashVerseEdge *hve; - - if(((VGeomData*)vnode->data)->hash==NULL) - ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab"); - - hve = ((VGeomData*)vnode->data)->hash + VEDHASH(v0, v1);; - while(hve) { - /* edge v0---v1 is the same edge as v1---v0 */ - if(hve->vedge && ((hve->vedge->v0==v0 && hve->vedge->v1==v1) || (hve->vedge->v0==v1 && hve->vedge->v1==v0))) return hve->vedge; - hve = hve->next; - } - - return NULL; -} - -/* - * insert hash of verse edge to hash table - */ -static void insert_verse_edgehash(VNode *vnode, VerseEdge *vedge) -{ - struct HashVerseEdge *first, *hve; - - if(((VGeomData*)vnode->data)->hash==NULL) - ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab"); - - first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1); - - if(first->vedge==NULL) { - first->vedge = vedge; - } - else { - hve = &(vedge->hash); - hve->vedge = vedge; - hve->next = first->next; - first->next = hve; - } -} - -/* - * remove hash of verse edge from hash table - */ -static void remove_verse_edgehash(VNode *vnode, VerseEdge *vedge) -{ - struct HashVerseEdge *first, *hve, *prev; - - hve = first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1); - - while(hve) { - if(hve->vedge == vedge) { - if(hve==first) { - if(first->next) { - hve = first->next; - first->vedge = hve->vedge; - first->next = hve->next; - } - else { - hve->vedge = NULL; - } - } - else { - prev->next = hve->next; - } - return; - } - prev = hve; - hve = hve->next; - } -} - -/* - * this function will try to remove existing fake verse edge, when this verse - * edge is still used by some faces, then counter will be only decremented - */ -static void remove_verse_edge(VNode *vnode, uint32 v0, uint32 v1) -{ - struct VerseEdge *vedge; - - vedge = find_verse_edge(vnode, v0, v1); - if(vedge) { - vedge->counter--; - if(vedge->counter==0) { - remove_verse_edgehash(vnode, vedge); - BLI_freelinkN(&(((VGeomData*)vnode->data)->edges), vedge); - } - } - else { - printf("error: remove_verse_edge %d, %d\n", v0, v1); - } -} - -/* - * this function will try to add new fake verse edge, when no such edge exist, - * when such edge exist, then only counter of edge will be incremented - */ -static void add_verse_edge(VNode *vnode, uint32 v0, uint32 v1) -{ - struct VerseEdge *vedge; - - vedge = find_verse_edge(vnode, v0, v1); - if(!vedge) { - if(v0!=v1) { - vedge = create_verse_edge(v0, v1); - BLI_addtail(&(((VGeomData*)vnode->data)->edges), vedge); - insert_verse_edgehash(vnode, vedge); - } - else { - printf("error:add_verse_edge: %d, %d\n", v0, v1); - return; - } - } - vedge->counter++; -} - -/* - * verse face was deleted ... update edge hash - */ -static void update_edgehash_of_deleted_verseface(VNode *vnode, VerseFace *vface) -{ - uint32 v0, v1, v2, v3; /* verse vertex indexes of deleted verse face */ - - v0 = vface->vvert0->id; - v1 = vface->vvert1->id; - v2 = vface->vvert2->id; - v3 = vface->vvert3 ? vface->vvert3->id : -1; - - remove_verse_edge(vnode, v0, v1); - remove_verse_edge(vnode, v1, v2); - if(v3!=-1) { - remove_verse_edge(vnode, v2, v3); - remove_verse_edge(vnode, v3, v0); - } - else { - remove_verse_edge(vnode, v2, v0); - } -} - -/* - * existing verse face was changed ... update edge hash - */ -static void update_edgehash_of_changed_verseface( - VNode *vnode, - VerseFace *vface, - uint32 v0, - uint32 v1, - uint32 v2, - uint32 v3) -{ - uint32 ov0, ov1, ov2, ov3; /* old indexes at verse vertexes*/ - - ov0 = vface->vvert0->id; - ov1 = vface->vvert1->id; - ov2 = vface->vvert2->id; - ov3 = vface->vvert3 ? vface->vvert3->id : -1; - - /* 1st edge */ - if(v0!=ov0 || v1!=ov1) { - remove_verse_edge(vnode, ov0, ov1); - add_verse_edge(vnode, v0, v1); - } - - /* 2nd edge */ - if(v1!=ov1 || v2!=ov2) { - remove_verse_edge(vnode, ov1, ov2); - add_verse_edge(vnode, v1, v2); - } - - /* 3rd edge */ - if(v2!=ov2 || v3!=ov3 || v0!=ov0) { - if(ov3!=-1) { - remove_verse_edge(vnode, ov2, ov3); - if(v3!=-1) { - add_verse_edge(vnode, v2, v3); /* new 3rd edge (quat->quat) */ - } - else { - remove_verse_edge(vnode, ov3, ov0); /* old edge v3,v0 of quat have to be removed */ - add_verse_edge(vnode, v2, v0); /* new 3rd edge (quat->triangle) */ - } - } - else { - remove_verse_edge(vnode, ov2, ov0); - if(v3!=-1) { - add_verse_edge(vnode, v2, v3); /* new 3rd edge (triangle->quat) */ - } - else { - add_verse_edge(vnode, v2, v0); /* new 3rd edge (triangle->triangle) */ - } - } - } - - /* 4th edge */ - if(v3!=-1 && (v3!=ov3 || v0!=ov0)) { - remove_verse_edge(vnode, ov3, ov0); - add_verse_edge(vnode, v3, v0); - } -} - -/* - * new verse face was created ... update list of edges and edge has - */ -static void update_edgehash_of_new_verseface( - VNode *vnode, - uint32 v0, - uint32 v1, - uint32 v2, - uint32 v3) -{ - /* when edge already exists, then only its counter is incremented, - * look at commentary of add_verse_edge() function */ - add_verse_edge(vnode, v0, v1); - add_verse_edge(vnode, v1, v2); - if(v3!=-1) { - add_verse_edge(vnode, v2, v3); - add_verse_edge(vnode, v3, v0); - } - else { - add_verse_edge(vnode, v2, v0); - } -} - -/* - * callback function: edge crease was set - */ -static void cb_g_crease_set_edge( - void *user_data, - VNodeID node_id, - const char *layer, - uint32 def_crease) -{ -} - -/* - * callback function: float value for polygon was set up - */ -static void cb_g_polygon_set_face_real32( - void *user_def, - VNodeID node_id, - VLayerID layer_id, - uint32 polygon_id, - real32 value) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VLayer *vlayer; - struct real32_item *item; - - if(!session) return; - - /* find needed node (we can be sure, that it is geometry node) */ - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - /* find layer containing uint_8 data */ - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); - - /* try to find item*/ - item = BLI_dlist_find_link(&(vlayer->dl), polygon_id); - - if(item) { - item->value = value; - } - else { - item = create_real32_item(vlayer, polygon_id, value); - BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); - } -} - -/* - * callback function: int values for polygon was set up - */ -static void cb_g_polygon_set_face_uint32( - void *user_def, - VNodeID node_id, - VLayerID layer_id, - uint32 polygon_id, - uint32 value) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VLayer *vlayer; - struct uint32_item *item; - - if(!session) return; - - /* find needed node (we can be sure, that it is geometry node) */ - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - /* find layer containing uint_8 data */ - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); - - /* try to find item*/ - item = BLI_dlist_find_link(&(vlayer->dl), polygon_id); - - if(item) { - item->value = value; - } - else { - item = create_uint32_item(vlayer, polygon_id, value); - BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); - } -} - -/* - * callback function: uint8 value for polygon was set up - */ -static void cb_g_polygon_set_face_uint8( - void *user_def, - VNodeID node_id, - VLayerID layer_id, - uint32 polygon_id, - uint8 value) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VLayer *vlayer; - struct uint8_item *item; - - if(!session) return; - - /* find needed node (we can be sure, that it is geometry node) */ - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - /* find layer containing uint_8 data */ - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); - - /* try to find item*/ - item = BLI_dlist_find_link(&(vlayer->dl), polygon_id); - - if(item) { - item->value = value; - } - else { - item = create_uint8_item(vlayer, polygon_id, value); - BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); - } -} - -/* - * callback function: float value for polygon corner was set up - */ -static void cb_g_polygon_set_corner_real32( - void *user_def, - VNodeID node_id, - VLayerID layer_id, - uint32 polygon_id, - real32 v0, - real32 v1, - real32 v2, - real32 v3) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VLayer *vlayer; - struct quat_real32_item *item; - - if(!session) return; - - /* find needed node (we can be sure, that it is geometry node) */ - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - /* find layer containing uint_8 data */ - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); - - /* try to find item*/ - item = BLI_dlist_find_link(&(vlayer->dl), polygon_id); - - if(item) { - item->value[0] = v0; - item->value[1] = v1; - item->value[2] = v2; - item->value[3] = v3; - } - else { - item = create_quat_real32_item(vlayer, polygon_id, v0, v1, v2, v3); - BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); - } -} - -/* - * callback function: polygon is deleted - */ -static void cb_g_polygon_delete( - void *user_data, - VNodeID node_id, - uint32 polygon_id) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - VNode *vnode; - VLayer *vlayer; - VerseFace *vface; - - if(!session) return; - - /* find needed node (we can be sure, that it is geometry node) */ - vnode = BLI_dlist_find_link(&(session->nodes), node_id); - - /* find layer containing faces */ - vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); - - /* find wanted VerseFace */ - vface = BLI_dlist_find_link(&(vlayer->dl), polygon_id); - - if(!vface) return; - - /* update edge hash */ - update_edgehash_of_deleted_verseface(vnode, vface); - - ((VGeomData*)vnode->data)->post_polygon_delete(vface); - - /* decrease references at coresponding VerseVertexes */ - vface->vvert0->counter--; - vface->vvert1->counter--; - vface->vvert2->counter--; - if(vface->vvert3) vface->vvert3->counter--; - - /* delete unneeded VerseVertexes */ - free_unneeded_verseverts_of_verseface(vnode, vface); - - free_verse_face(vlayer, vface); -} - -/* - * callback function: new polygon (face) created or existing polygon was changed - */ -static void cb_g_polygon_set_corner_uint32( - void *user_data, - VNodeID node_id, - VLayerID layer_id, - uint32 polygon_id, - uint32 v0, - uint32 v1, - uint32 v2, - uint32 v3) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VLayer *vlayer; - struct VerseFace *vface=NULL; - - if(!session) return; - - /* try to find VerseNode */ - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - if(!vnode) return; - - /* try to find VerseLayer */ - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); - if(!vlayer) return; - - /* we have to test coretness of incoming data */ - if(!test_polygon_set_corner_uint32(v0, v1, v2, v3)) return; - - /* Blender uses different order of vertexes */ - if(v3!=-1) { /* quat swap */ - unsigned int v; v = v1; v1 = v3; v3 = v; - } - else { /* triangle swap */ - unsigned int v; v = v1; v1 = v2; v2 = v; - } - - /* try to find VerseFace */ - vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)polygon_id); - - /* try to find modified VerseFace */ - if(!vface) { - vface = find_changed_verse_face_in_queue(vlayer, polygon_id); - if(vface) { - BLI_remlink(&(vlayer->queue), (void*)vface); - BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id); - } - } - - if(!vface) { - /* try to find VerseFace in list of VerseVaces created by me and set up polygon and - * layer ids */ - vface = find_verse_face_in_queue(vlayer, node_id, polygon_id, v0, v1, v2, v3); - - /* update edge hash */ - update_edgehash_of_new_verseface(vnode, v0, v1, v2, v3); - - if(vface){ - /* I creeated this face ... remove VerseFace from queue */ - BLI_remlink(&(vlayer->queue), (void*)vface); - } - else { - /* some other client created this face*/ - vface = create_verse_face(vlayer, polygon_id, v0, v1, v2, v3); - } - - vface->flag &= ~FACE_SENT; - - /* return number of missing verse vertexes */ - vface->counter = test_incoming_verseface((VGeomData*)vnode->data, vface); - - if(vface->counter < 1) { - /* when VerseFace received all needed VerseFaces, then it is moved - * to list of VerseFaces */ - BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id); - increase_verse_verts_references(vface); - recalculate_verseface_normals(vnode); - ((VGeomData*)vnode->data)->post_polygon_create(vface); - } - else { - /* when all needed VerseVertexes weren't received, then VerseFace is moved to - * the list of orphans waiting on needed vertexes */ - vface->flag |= FACE_RECEIVED; - BLI_addtail(&(vlayer->orphans), (void*)vface); - } - } - else { - VLayer *vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); - /* VerseVertexes of existing VerseFace were changed (VerseFace will use some different - * VerseVertexes or it will use them in different order) */ - - /* update fake verse edges */ - update_edgehash_of_changed_verseface(vnode, vface, v0, v1, v2, v3); - - /* initialize count of unreceived vertexes needed for this face */ - vface->counter = 4; - - /* 1st corner */ - if(vface->vvert0->id != v0) { - /* decrease references of obsolete vertexes*/ - vface->vvert0->counter--; - /* delete this vertex, when it isn't used by any face and it was marked as deleted */ - if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) { - ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0); - free_verse_vertex(vert_vlayer, vface->vvert0); - } - /* try to set up new pointer at verse vertex */ - vface->v0 = v0; - vface->vvert0 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v0); - if(vface->vvert0) { - /* increase references at new vertex */ - vface->vvert0->counter++; - /* decrease count of needed vertex to receive */ - vface->counter--; - } - - } - else - /* this corner wasn't changed */ - vface->counter--; - - /* 2nd corner */ - if(vface->vvert1->id != v1) { - vface->vvert1->counter--; - if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) { - ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1); - free_verse_vertex(vert_vlayer, vface->vvert1); - } - vface->v1 = v1; - vface->vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v1); - if(vface->vvert1) { - vface->vvert1->counter++; - vface->counter--; - } - } - else - vface->counter--; - - /* 3rd corner */ - if(vface->vvert2->id != v2) { - vface->vvert2->counter--; - if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) { - ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2); - free_verse_vertex(vert_vlayer, vface->vvert2); - } - vface->v2 = v2; - vface->vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v2); - if(vface->vvert2) { - vface->vvert2->counter++; - vface->counter--; - } - } - else - vface->counter--; - - /* 4th corner */ - if(vface->vvert3) { - if(vface->vvert3->id != v3) { - vface->vvert3->counter--; - if((vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) { - ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3); - free_verse_vertex(vert_vlayer, vface->vvert3); - } - vface->v3 = v3; - if(v3 != -1) { - vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3); - if(vface->vvert3) { - vface->vvert3->counter++; - vface->counter--; - } - } - else { - /* this is some special case, this face hase now only 3 corners - * quat -> triangle */ - vface->vvert3 = NULL; - vface->counter--; - } - } - } - else if(v3 != -1) - /* this is some special case, 4th corner of this polygon was created - * triangle -> quat */ - vface->v3 = v3; - vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3); - if(vface->vvert3) { - vface->vvert3->counter++; - vface->counter--; - } - else { - vface->v3 = -1; - vface->counter--; - } - - vface->flag &= ~FACE_SENT; - vface->flag |= FACE_CHANGED; - - if(vface->counter<1) { - vface->flag &= ~FACE_CHANGED; - recalculate_verseface_normals(vnode); - ((VGeomData*)vnode->data)->post_polygon_set_corner(vface); - } - else { - /* when all needed VerseVertexes weren't received, then VerseFace is added to - * the list of orphans waiting on needed vertexes */ - BLI_dlist_rem_item(&(vlayer->dl), vface->id); - BLI_addtail(&(vlayer->orphans), (void*)vface); - } - } -} - -/* - * callback function: float value was set up for VerseVert with vertex_id - */ -static void cb_g_vertex_set_real32( - void *user_def, - VNodeID node_id, - VLayerID layer_id, - uint32 vertex_id, - real32 value) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VLayer *vlayer; - struct real32_item *item; - - if(!session) return; - - /* find needed node (we can be sure, that it is geometry node) */ - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - /* find layer containing uint_8 data */ - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); - - /* try to find item*/ - item = BLI_dlist_find_link(&(vlayer->dl), vertex_id); - - if(item) { - item->value = value; - } - else { - item = create_real32_item(vlayer, vertex_id, value); - BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); - } -} - -/* - * callback function: int value was set up for VerseVert with vertex_id - */ -static void cb_g_vertex_set_uint32( - void *user_def, - VNodeID node_id, - VLayerID layer_id, - uint32 vertex_id, - uint32 value) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VLayer *vlayer; - struct uint32_item *item; - - if(!session) return; - - /* find needed node (we can be sure, that it is geometry node) */ - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - /* find layer containing uint_8 data */ - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); - - /* try to find item*/ - item = BLI_dlist_find_link(&(vlayer->dl), vertex_id); - - if(item) { - item->value = value; - } - else { - item = create_uint32_item(vlayer, vertex_id, value); - BLI_dlist_add_item_index(&(vlayer->dl), item, item->id); - } -} - -/* - * callback function: polygon was deleted - */ -static void cb_g_vertex_delete_real32( - void *user_data, - VNodeID node_id, - uint32 vertex_id) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - VNode *vnode=NULL; - VLayer *vert_vlayer=NULL; - VerseVert *vvert=NULL; - - if(!session) return; - - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); - - vvert = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vertex_id); - - if(!vvert) return; - - if(vvert->counter < 1) { - ((VGeomData*)vnode->data)->post_vertex_delete(vvert); - BLI_dlist_free_item(&(vert_vlayer->dl), (unsigned int)vertex_id); - } - else { - /* some VerseFace(s) still need VerseVert, remove verse vert from - * list verse vertexes and put it to list of orphans */ - vvert->flag |= VERT_DELETED; - BLI_dlist_rem_item(&(vert_vlayer->dl), (unsigned int)vertex_id); - BLI_addtail(&(vert_vlayer->orphans), vvert); - } -} - -/* - * callback function: position of one vertex was changed or new vertex was created - */ -static void cb_g_vertex_set_xyz_real32( - void *user_data, - VNodeID node_id, - VLayerID layer_id, - uint32 vertex_id, - real32 x, - real32 y, - real32 z) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode = NULL; - struct VLayer *vlayer = NULL; - struct VerseVert *vvert = NULL; - real32 tmp; - - if(!session) return; - - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - if(!vnode)return; - - vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id); - if(!vlayer) return; - - /* switch axis orientation */ - tmp = y; - y = -z; - z = tmp; - - if(vlayer->id == 0) { - /* try to pick up verse vert from DynamicList */ - vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)vertex_id); - - if(vvert) { - if(vvert->flag & VERT_OBSOLETE) return; - - if (vvert->flag & VERT_LOCKED) { - /* this application changed position of this vertex */ - if((vvert->co[0]==x) && (vvert->co[1]==y) && (vvert->co[2]==z)) { - /* unlock vertex position */ - vvert->flag &= ~VERT_LOCKED; - /* call post_vertex_set_xyz only, when position of vertex is - * obsolete ... the new vertex position will be sent to - * verse server */ - if (vvert->flag & VERT_POS_OBSOLETE) { - ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert); - } - } - } - else { - /* somebody else changed position of this vertex*/ - if((vvert->co[0]!=x) || (vvert->co[1]!=y) || (vvert->co[2]!=z)) { - vvert->co[0] = x; - vvert->co[1] = y; - vvert->co[2] = z; - recalculate_verseface_normals(vnode); - ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert); - } - } - } - else { - /* create new verse vert */ - - /* test if we are authors of this vertex :-) */ - vvert = find_verse_vert_in_queue(vlayer, node_id, vertex_id, x, y, z); - - if(vvert) { - /* remove vert from queue */ - BLI_remlink(&(vlayer->queue), (void*)vvert); - /* add vvert to the dynamic list */ - BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id); - /* set VerseVert flags */ - vvert->flag |= VERT_RECEIVED; - if(!(vvert->flag & VERT_POS_OBSOLETE)) - vvert->flag &= ~VERT_LOCKED; - /* find VerseFaces orphans */ - find_vlayer_orphans(vnode, vvert); - /* find unsent VerseFaces */ - find_unsent_faces(vnode, vvert); - } - else { - /* create new VerseVert */ - vvert = create_verse_vertex(vlayer, vertex_id, x, y, z); - /* add VerseVert to list of VerseVerts */ - BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id); - /* set VerseVert flags */ - vvert->flag |= VERT_RECEIVED; - /* find VerseFaces orphans */ - find_vlayer_orphans(vnode, vvert); - } - - ((VGeomData*)vnode->data)->post_vertex_create(vvert); - } - } -} - -/* - * callback function for destroyng of verse layer - */ -static void cb_g_layer_destroy( - void *user_data, - VNodeID node_id, - VLayerID layer_id) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VLayer *vlayer; - - if(!session) return; - - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), node_id); - if(!vnode) return; - - vlayer = (VLayer*) BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), layer_id); - - if(vlayer){ - /* free VerseLayer data */ - free_verse_layer_data(vnode, vlayer); - /* remove VerseLayer from list of verse layers */ - BLI_dlist_rem_item(&(((VGeomData*)vnode->data)->layers), layer_id); - /* do client dependent actions */ - vlayer->post_layer_destroy(vlayer); - /* free vlayer itself */ - MEM_freeN(vlayer); - } - -} - -/* - * callback function: new layer was created - */ -static void cb_g_layer_create( - void *user_data, - VNodeID node_id, - VLayerID layer_id, - const char *name, - VNGLayerType type, - uint32 def_integer, - real64 def_real) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode=NULL; - struct VLayer *vlayer=NULL; - - if(!session) return; - - /* find node of this layer*/ - vnode = BLI_dlist_find_link(&(session->nodes), node_id); - if(!vnode) return; - - /* when we created this layer, then subscribe to this layer */ - if(vnode->owner_id == VN_OWNER_MINE || session->flag & VERSE_AUTOSUBSCRIBE) - verse_send_g_layer_subscribe(node_id, layer_id, 0); - - /* try to find */ - if(vnode->owner_id == VN_OWNER_MINE) - vlayer = find_vlayer_in_sending_queue(vnode, layer_id); - - if(vlayer) { - /* remove vlayer form sending queue add verse layer to list of verse layers */ - BLI_remlink(&((VGeomData*)vnode->data)->queue, vlayer); - BLI_dlist_add_item_index(&((VGeomData*)vnode->data)->layers, (void*)vlayer, (unsigned int)vlayer->id); - /* send all not sent vertexes to verse server - * other items waiting in sending queue will be automaticaly sent to verse server, - * when verse vertexes will be received from verse server */ - if((vlayer->type == VN_G_LAYER_VERTEX_XYZ) && (layer_id==0)) { - struct VerseVert *vvert = (VerseVert*)vlayer->queue.first; - while(vvert) { - send_verse_vertex(vvert); - vvert = vvert->next; - } - } - } - else { - /* create new VerseLayer */ - vlayer = create_verse_layer(vnode, layer_id, name, type, def_integer, def_real); - /* add layer to the list of VerseLayers */ - BLI_dlist_add_item_index(&(((VGeomData*)vnode->data)->layers), (void*)vlayer, (unsigned int)layer_id); - } - - vlayer->flag |= LAYER_RECEIVED; - - /* post callback function */ - vlayer->post_layer_create(vlayer); -} - -/* - * this function will send destroy commands for all VerseVertexes and - * VerseFaces to verse server, but it will not send destroy commands - * for VerseLayers or geometry node, it can be used in other functions - * (undo, destroy geom node, some edit mesh commands, ... ), parameter of - * this function has to be geometry verse node - */ -void destroy_geometry(VNode *vnode) -{ - struct VLayer *vert_vlayer, *face_vlayer; - struct VerseFace *vface; - struct VerseVert *vvert; - - if(vnode->type != V_NT_GEOMETRY) return; - - face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER); - vface = face_vlayer->dl.lb.first; - - while(vface) { - send_verse_face_delete(vface); - vface = vface->next; - } - - vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER); - vvert = vert_vlayer->dl.lb.first; - - while(vvert) { - send_verse_vertex_delete(vvert); - vvert = vvert->next; - } - - /* own destruction of local verse date will be executed, when client will - * receive apropriate callback commands from verse server */ -} - -/* - * free VGeomData - */ -void free_geom_data(VNode *vnode) -{ - struct VerseSession *session = vnode->session; - struct VLayer *vlayer; - - if(vnode->data){ - vlayer = (VLayer*)((VGeomData*)vnode->data)->layers.lb.first; - while(vlayer){ - /* unsubscribe from layer */ - if(session->flag & VERSE_CONNECTED) - verse_send_g_layer_unsubscribe(vnode->id, vlayer->id); - /* free VerseLayer data */ - free_verse_layer_data(vnode, vlayer); - /* next layer */ - vlayer = vlayer->next; - } - /* free constraint between vnode and mesh */ - ((VGeomData*)vnode->data)->post_geometry_free_constraint(vnode); - /* free all VerseLayers */ - BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers)); - /* free fake verse edges */ - BLI_freelistN(&((VGeomData*)vnode->data)->edges); - /* free edge hash */ - MEM_freeN(((VGeomData*)vnode->data)->hash); - } -} - -void set_geometry_callbacks(void) -{ - /* new layer created */ - verse_callback_set(verse_send_g_layer_create, cb_g_layer_create, NULL); - /* layer was destroyed */ - verse_callback_set(verse_send_g_layer_destroy, cb_g_layer_destroy, NULL); - - /* position of vertex was changed */ - verse_callback_set(verse_send_g_vertex_set_xyz_real32, cb_g_vertex_set_xyz_real32, NULL); - /* vertex was deleted */ - verse_callback_set(verse_send_g_vertex_delete_real32, cb_g_vertex_delete_real32, NULL); - - /* callback functions for values being associated with vertexes */ - verse_callback_set(verse_send_g_vertex_set_uint32, cb_g_vertex_set_uint32, NULL); - verse_callback_set(verse_send_g_vertex_set_real32, cb_g_vertex_set_real32, NULL); - - /* new polygon was created / vertex(es) of polygon was set */ - verse_callback_set(verse_send_g_polygon_set_corner_uint32, cb_g_polygon_set_corner_uint32, NULL); - /* polygon was deleted */ - verse_callback_set(verse_send_g_polygon_delete, cb_g_polygon_delete, NULL); - - /* callback functions for values being associated with polygon corners */ - verse_callback_set(verse_send_g_polygon_set_corner_real32, cb_g_polygon_set_corner_real32, NULL); - /* callback functions for values being associated with faces */ - verse_callback_set(verse_send_g_polygon_set_face_uint8, cb_g_polygon_set_face_uint8, NULL); - verse_callback_set(verse_send_g_polygon_set_face_uint32, cb_g_polygon_set_face_uint32, NULL); - verse_callback_set(verse_send_g_polygon_set_face_real32, cb_g_polygon_set_face_real32, NULL); - - /* crease of vertex was set */ - verse_callback_set(verse_send_g_crease_set_vertex, cb_g_crease_set_vertex, NULL); - /* crease of edge was set */ - verse_callback_set(verse_send_g_crease_set_edge, cb_g_crease_set_edge, NULL); -} - -#endif diff --git a/source/blender/blenkernel/intern/verse_method.c b/source/blender/blenkernel/intern/verse_method.c deleted file mode 100644 index 30886782019..00000000000 --- a/source/blender/blenkernel/intern/verse_method.c +++ /dev/null @@ -1,520 +0,0 @@ -/** - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Contributor(s): Nathan Letwory. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifdef WITH_VERSE - -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_listBase.h" -#include "DNA_userdef_types.h" -#include "DNA_text_types.h" - -#include "BLI_dynamiclist.h" -#include "BLI_blenlib.h" -#include "BLI_arithb.h" - -#include "BIF_verse.h" - -#include "BKE_bad_level_calls.h" -#include "BKE_library.h" -#include "BKE_text.h" -#include "BKE_verse.h" -#include "BKE_global.h" -#include "BKE_main.h" - -#include "verse.h" - -/* helper struct for creating method descriptions */ -typedef struct VMethodInfo { - const char *name; - uint8 param_count; - const VNOParamType param_type[4]; - const char *param_name[4]; - uint16 id; -} VMethodInfo; - -#ifdef VERSECHAT -/* array with methods for verse chat */ -static VMethodInfo vmethod_info[] = { - { "join", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}}, - { "leave", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}}, - { "hear", 3, { VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING }, { "channel", "from", "msg"}} -}; -#endif - -/* lookup a method group based on its name */ -struct VMethodGroup *lookup_vmethodgroup_name(ListBase *lb, const char *name) { - struct VMethodGroup *vmg; - - for(vmg= lb->first; vmg; vmg= vmg->next) - if(strcmp(vmg->name,name)==0) break; - - return vmg; -} - -/* lookup a method group based on its group_id */ -struct VMethodGroup *lookup_vmethodgroup(ListBase *lb, uint16 group_id) { - struct VMethodGroup *vmg; - - for(vmg= lb->first; vmg; vmg= vmg->next) - if(vmg->group_id==group_id) break; - - return vmg; -} - -/* lookup a method based on its name */ -struct VMethod *lookup_vmethod_name(ListBase *lb, const char *name) { - struct VMethod *vm; - for(vm= lb->first; vm; vm= vm->next) - if(strcmp(vm->name,name)==0) break; - - return vm; -} - -/* lookup a method based on its method_id */ -struct VMethod *lookup_vmethod(ListBase *lb, uint8 method_id) { - struct VMethod *vm; - for(vm= lb->first; vm; vm= vm->next) - if(vm->id==method_id) break; - - return vm; -} - -#ifdef VERSECHAT -/* - * send say command - */ -void send_say(const char *chan, const char *utter) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VMethodGroup *vmg; - struct VMethod *vm; - VNOPackedParams *utterpack; - VNOParam args[2]; - - vnode= (VNode *)(session->nodes.lb.first); - - for( ; vnode; vnode= vnode->next) { - if(strcmp(vnode->name, "tawksrv")==0) { - vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk"); - if(!vmg) break; - vm= lookup_vmethod_name(&(vmg->methods), "say"); - if(!vm) break; - args[0].vstring= (char *)chan; - args[1].vstring= (char *)utter; - if((utterpack= verse_method_call_pack(vm->param_count, vm->param_type, args))!=NULL) { - verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, utterpack); - } - break; - } - - } -} - -/* - * send logout command - */ -void send_logout(VNode *vnode) -{ - struct VMethodGroup *vmg; - struct VMethod *vm; - VNOPackedParams *pack; - - vnode->chat_flag = CHAT_LOGGED; - vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk"); - if(!vmg) return; - vm= lookup_vmethod_name(&(vmg->methods), "logout"); - if(!vm) return; - - if((pack= verse_method_call_pack(vm->param_count, vm->param_type, NULL))!=NULL) { - verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, pack); - } - vnode->chat_flag = CHAT_NOTLOGGED; -} - -/* - * send join command - */ -void send_join(VNode *vnode, const char *chan) -{ - struct VMethodGroup *vmg; - struct VMethod *vm; - VNOPackedParams *join; - VNOParam channel[1]; - - vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk"); - if(!vmg) return; - vm= lookup_vmethod_name(&(vmg->methods), "join"); - if(!vm) return; - - channel[0].vstring= (char *)chan; - if((join= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) { - verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, join); - } -} - -/* - * send leave command - */ -void send_leave(VNode *vnode, const char *chan) -{ - struct VMethodGroup *vmg; - struct VMethod *vm; - VNOPackedParams *leave; - VNOParam channel[1]; - - vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk"); - if(!vmg) return; - vm= lookup_vmethod_name(&(vmg->methods), "leave"); - if(!vm) return; - - channel[0].vstring= (char *)chan; - if((leave= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) { - verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, leave); - } -} - -/* - * send login command - */ -void send_login(VNode *vnode) -{ - struct VMethodGroup *vmg; - struct VMethod *vm; - VNOPackedParams *login; - VNOParam param[1]; - - vnode->chat_flag = CHAT_LOGGED; - vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk"); - if(!vmg) return; - vm= lookup_vmethod_name(&(vmg->methods), "login"); - if(!vm) return; - - param[0].vstring= U.verseuser; - - if((login= verse_method_call_pack(vm->param_count, vm->param_type, param))!=NULL) { - verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, login); - } - vnode->chat_flag = CHAT_LOGGED; - - vnode= lookup_vnode(vnode->session, vnode->session->avatar); - vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk-client"); - if(!vmg) - verse_send_o_method_group_create(vnode->session->avatar, ~0, "tawk-client"); -} -#endif - -/* - * Free a VMethod - */ -void free_verse_method(VMethod *vm) { - if(!vm) return; - - MEM_freeN(vm->param_type); -} - -/* - * Free methods for VMethodGroup - */ -void free_verse_methodgroup(VMethodGroup *vmg) -{ - struct VMethod *vm, *tmpvm; - - if(!vmg) return; - - vm= vmg->methods.first; - while(vm) { - tmpvm=vm->next; - free_verse_method(vm); - vm= tmpvm; - } - BLI_freelistN(&(vmg->methods)); -} - -/* callback for method group creation */ -static void cb_o_method_group_create( - void *user_data, - VNodeID node_id, - uint16 group_id, - const char *name) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VMethodGroup *vmg; - - if(!session) return; - - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - vmg = lookup_vmethodgroup(&(vnode->methodgroups), group_id); - - /* create method group holder in node node_id */ - if(!vmg) { - vmg= MEM_mallocN(sizeof(VMethodGroup), "VMethodGroup"); - vmg->group_id = group_id; - vmg->methods.first = vmg->methods.last = NULL; - BLI_addtail(&(vnode->methodgroups), vmg); - printf("new method group with name %s (group_id %d) for node %u created\n", name, group_id, node_id); - } - - /* this ensures name of an existing group gets updated, in case it is changed */ - BLI_strncpy(vmg->name, (char *)name, 16); - - /* subscribe to method group */ - verse_send_o_method_group_subscribe(node_id, group_id); - -#ifdef VERSECHAT - /* if this is our own method group, register our methods */ - if(node_id==session->avatar) { - verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[0].name, - vmethod_info[0].param_count, - (VNOParamType *)vmethod_info[0].param_type, - (const char **)vmethod_info[0].param_name); - b_verse_update(); - verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[1].name, - vmethod_info[1].param_count, - (VNOParamType *)vmethod_info[1].param_type, - (const char **)vmethod_info[1].param_name); - b_verse_update(); - verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[2].name, - vmethod_info[2].param_count, - (VNOParamType *)vmethod_info[2].param_type, - (const char **)vmethod_info[2].param_name); - b_verse_update(); - } -#endif -} - -/* callback for method group destruction */ -static void cb_o_method_group_destroy( - void *user_data, - VNodeID node_id, - uint16 group_id, - const char *name) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VMethodGroup *vmg; - struct VMethod *vm; - - printf("method group %d destroyed\n", group_id); - - if(!session) return; - - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - for(vmg= vnode->methodgroups.first; vmg; vmg= vmg->next) - if(vmg->group_id==group_id) break; - - if(!vmg) return; /* method group doesn't exist? */ - - vmg->group_id = 0; - vmg->name[0] = '\0'; - vm= vmg->methods.first; - while(vm) { - /* free vm */ - - } - - /* TODO: unsubscribe from method group */ - BLI_remlink(&(vnode->methodgroups),vmg); - MEM_freeN(vmg); -} - -/* callback for method creation */ -static void cb_o_method_create( - void *user_data, - VNodeID node_id, - uint16 group_id, - uint16 method_id, - const char *name, - uint8 param_count, - const VNOParamType *param_type, - const char *param_name[]) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VMethodGroup *vmg; - struct VMethod *vm; - unsigned int size; - unsigned int i; - char *put; - - if(!session) return; - - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - vmg= lookup_vmethodgroup((&vnode->methodgroups), group_id); - - if(!vmg) return; - - vm= lookup_vmethod((&vmg->methods), method_id); - - if(!vm) { - vm= MEM_mallocN(sizeof(VMethod), "VMethod"); - vm->id= method_id; - vm->param_count= param_count; - size= param_count* (sizeof(*vm->param_type) + sizeof(*vm->param_name)); - for(i= 0; i <param_count; i++) { - size+=strlen(param_name[i])+1; - } - vm->param_type= MEM_mallocN(size, "param_type and param_name"); - memcpy(vm->param_type, param_type, sizeof(VNOParamType)*param_count); - vm->param_name= (char **)(vm->param_type + param_count); - put= (char *)(vm->param_name + param_count); - for(i= 0; i < param_count; i++) { - vm->param_name[i]= put; - strcpy(put, param_name[i]); - put += strlen(param_name[i]) + 1; - } - - BLI_addtail(&(vmg->methods), vm); -#ifdef VERSECHAT - if(strcmp(vmethod_info[0].name, name)==0) { - vmethod_info[0].id = method_id; - } -#endif - printf("method %s in group %d of node %u created\n", name, group_id, node_id); - } - - BLI_strncpy(vm->name, (char *)name, 500); -} - -/* callback for method destruction */ -static void cb_o_method_destroy( - void *user_data, - VNodeID node_id, - uint16 group_id, - uint16 method_id, - const char *name, - uint8 param_count, - const VNOParamType *param_type, - const char *param_name[]) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VMethodGroup *vmg; - struct VMethod *vm; - - if(!session) return; - - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - for(vmg= vnode->methodgroups.first; vmg; vmg= vmg->next) - if(vmg->group_id==group_id) break; - - if(!vmg) return; /* method group doesn't exist? */ - - for(vm= vmg->methods.first; vm; vm= vm->next) - if(vm->id==method_id) break; - - if(!vm) return; - - BLI_remlink(&(vmg->methods), vm); - MEM_freeN(vm->param_type); - MEM_freeN(vm); -} - -/* callback for method calls */ -static void cb_o_method_call(void *user_data, VNodeID node_id, uint8 group_id, uint8 method_id, VNodeID sender, VNOPackedParams *params) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VMethodGroup *vmg; - struct VMethod *vm; - Text *text; - int method_idx= -1; - - VNOParam arg[3]; - - if(!session) return; - - if(session->avatar!=node_id) return; - - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - vmg= lookup_vmethodgroup(&(vnode->methodgroups), group_id); - if(!vmg) return; - - vm= lookup_vmethod(&(vmg->methods), method_id); - if(!vm) return; -#ifdef VERSECHAT - if(strcmp(vm->name, "join")==0) method_idx=0; - if(strcmp(vm->name, "leave")==0) method_idx=1; - if(strcmp(vm->name, "hear")==0) method_idx=2; - if(method_idx>-1) - verse_method_call_unpack(params, vmethod_info[method_idx].param_count, vmethod_info[method_idx].param_type, arg); - - switch(method_idx) { - case 0: - printf("Joining channel %s\n",arg[0].vstring); - text=add_empty_text(); - text->flags |= TXT_ISCHAT; - rename_id(&(text->id), arg[0].vstring); - break; - case 1: - printf("Leaving channel %s\n",arg[0].vstring); - break; - case 2: - { - ListBase lb = G.main->text; - ID *id= (ID *)lb.first; - char showstr[1024]; - showstr[0]='\0'; - text = NULL; - sprintf(showstr, "%s: %s\n", arg[1].vstring, arg[2].vstring); - for(; id; id= id->next) { - if(strcmp(id->name+2, arg[0].vstring)==0 && strcmp(arg[0].vstring, "#server")!=0) { - text = (Text *)id; - break; - } - } - if(text) { - txt_insert_buf(text, showstr); - txt_move_eof(text, 0); - allqueue(REDRAWCHAT, 0); - } else { - printf("%s> %s: %s\n",arg[0].vstring, arg[1].vstring, arg[2].vstring); - } - } - break; - } -#endif -} - -void set_method_callbacks(void) -{ - /* create and destroy method groups */ - verse_callback_set(verse_send_o_method_group_create, cb_o_method_group_create, NULL); - verse_callback_set(verse_send_o_method_group_destroy, cb_o_method_group_destroy, NULL); - - /* create and destroy methods */ - verse_callback_set(verse_send_o_method_create, cb_o_method_create, NULL); - verse_callback_set(verse_send_o_method_destroy, cb_o_method_destroy, NULL); - - /* call methods */ - verse_callback_set(verse_send_o_method_call, cb_o_method_call, NULL); -} - -#endif diff --git a/source/blender/blenkernel/intern/verse_node.c b/source/blender/blenkernel/intern/verse_node.c deleted file mode 100644 index 1fe86f24d6e..00000000000 --- a/source/blender/blenkernel/intern/verse_node.c +++ /dev/null @@ -1,747 +0,0 @@ -/** - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Contributor(s): Jiri Hnidek. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifdef WITH_VERSE - -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_listBase.h" -#include "DNA_userdef_types.h" - -#include "BLI_dynamiclist.h" -#include "BLI_blenlib.h" - -#include "BIF_verse.h" - -#include "BKE_verse.h" - -#include "verse.h" - -/* function prototypes of static functions */ - /* for tags */ -static void free_verse_tag_data(struct VTag *vtag); -static struct VTag *find_tag_in_queue(struct VTagGroup *vtaggroup, const char *name); -static struct VTag *create_verse_tag(struct VTagGroup *vtaggroup, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag); - /* for verse tag groups */ -static void free_verse_taggroup_data(struct VTagGroup *taggroup); -static struct VTagGroup *find_taggroup_in_queue(struct VNode *vnode, const char *name); -static struct VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name); - /* for verse nodes */ -static void move_verse_node_to_dlist(struct VerseSession *session, VNodeID vnode_id); - /* function prototypes of node callback functions */ -static void cb_tag_destroy(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id); -static void cb_tag_create(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag); -static void cb_tag_group_destroy(void *user_data, VNodeID node_id, uint16 group_id); -static void cb_tag_group_create(void *user_data, VNodeID node_id, uint16 group_id, const char *name); -static void cb_node_name_set(void *user_data, VNodeID node_id, const char *name); -static void cb_node_destroy(void *user_data, VNodeID node_id); -static void cb_node_create(void *user_data, VNodeID node_id, uint8 type, VNodeID owner_id); - -/* - * send new tag to verse server - */ -void send_verse_tag(VTag *vtag) -{ - verse_send_tag_create(vtag->vtaggroup->vnode->id, - vtag->vtaggroup->id, - vtag->id, - vtag->name, - vtag->type, - vtag->tag); -} - -/* - * free tag data - */ -static void free_verse_tag_data(VTag *vtag) -{ - /* free name of verse tag */ - MEM_freeN(vtag->name); - /* free value of tag */ - MEM_freeN(vtag->tag); -} - -/* - * try to find tag in sending queue ... if tag will be found, then - * this function will removed tag from queue and will return pointer - * at this tag - */ -static VTag *find_tag_in_queue(VTagGroup *vtaggroup, const char *name) -{ - struct VTag *vtag; - - vtag = vtaggroup->queue.first; - - while(vtag) { - if(strcmp(vtag->name, name)==0) { - BLI_remlink(&(vtaggroup->queue), vtag); - break; - } - vtag = vtag->next; - } - - return vtag; -} - -/* - * create new verse tag - */ -static VTag *create_verse_tag( - VTagGroup *vtaggroup, - uint16 tag_id, - const char *name, - VNTagType type, - const VNTag *tag) -{ - struct VTag *vtag; - - vtag = (VTag*)MEM_mallocN(sizeof(VTag), "VTag"); - - vtag->vtaggroup = vtaggroup; - vtag->id = tag_id; - vtag->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTag name"); - strcpy(vtag->name, name); - vtag->type = type; - - vtag->tag = (VNTag*)MEM_mallocN(sizeof(VNTag), "VNTag"); - *vtag->tag = *tag; - - vtag->value = NULL; - - return vtag; -} - -/* - * send taggroup to verse server - */ -void send_verse_taggroup(VTagGroup *vtaggroup) -{ - verse_send_tag_group_create( - vtaggroup->vnode->id, - vtaggroup->id, - vtaggroup->name); -} - -/* - * free taggroup data - */ -static void free_verse_taggroup_data(VTagGroup *taggroup) -{ - struct VerseSession *session = taggroup->vnode->session; - struct VTag *vtag; - - vtag = taggroup->tags.lb.first; - - while(vtag) { - free_verse_tag_data(vtag); - vtag = vtag->next; - } - - /* unsubscribe from taggroup */ - if(session->flag & VERSE_CONNECTED) - verse_send_tag_group_unsubscribe(taggroup->vnode->id, taggroup->id); - - BLI_dlist_destroy(&(taggroup->tags)); - MEM_freeN(taggroup->name); -} - -/* - * move taggroup from queue to dynamic list with access array, - * set up taggroup id and return pointer at this taggroup - */ -static VTagGroup *find_taggroup_in_queue(VNode *vnode, const char *name) -{ - struct VTagGroup *vtaggroup; - - vtaggroup = vnode->queue.first; - - while(vtaggroup) { - if(strcmp(vtaggroup->name, name)==0) { - BLI_remlink(&(vnode->queue), vtaggroup); - break; - } - vtaggroup = vtaggroup->next; - } - - return vtaggroup; -} - -/* - * create new verse group of tags - */ -static VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name) -{ - struct VTagGroup *taggroup; - - taggroup = (VTagGroup*)MEM_mallocN(sizeof(VTagGroup), "VTagGroup"); - - taggroup->vnode = vnode; - taggroup->id = group_id; - taggroup->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTagGroup name"); - strcpy(taggroup->name, name); - - BLI_dlist_init(&(taggroup->tags)); - taggroup->queue.first = taggroup->queue.last = NULL; - - taggroup->post_tag_change = post_tag_change; - taggroup->post_taggroup_create = post_taggroup_create; - - return taggroup; -} - -/* - * move first VerseNode waiting in sending queue to dynamic list of VerseNodes - * (it usually happens, when "our" VerseNode was received from verse server) - */ -static void move_verse_node_to_dlist(VerseSession *session, VNodeID vnode_id) -{ - VNode *vnode; - - vnode = session->queue.first; - - if(vnode) { - BLI_remlink(&(session->queue), vnode); - BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, vnode_id); - } -} - -/* - * send VerseNode to verse server - */ -void send_verse_node(VNode *vnode) -{ - verse_send_node_create( - vnode->id, - vnode->type, - vnode->session->avatar); -} - -/* - * free Verse Node data - */ -void free_verse_node_data(VNode *vnode) -{ - struct VerseSession *session = vnode->session; - struct VTagGroup *vtaggroup; - - /* free node data (object, geometry, etc.) */ - switch(vnode->type){ - case V_NT_OBJECT: - free_object_data(vnode); - break; - case V_NT_GEOMETRY: - free_geom_data(vnode); - break; - case V_NT_BITMAP: - free_bitmap_node_data(vnode); - break; - default: - break; - } - - /* free all tag groups in dynamic list with access array */ - vtaggroup = vnode->taggroups.lb.first; - while(vtaggroup) { - free_verse_taggroup_data(vtaggroup); - vtaggroup = vtaggroup->next; - } - BLI_dlist_destroy(&(vnode->taggroups)); - - /* free all tag groups still waiting in queue */ - vtaggroup = vnode->queue.first; - while(vtaggroup) { - free_verse_taggroup_data(vtaggroup); - vtaggroup = vtaggroup->next; - } - BLI_freelistN(&(vnode->queue)); - - /* unsubscribe from node */ - if(session->flag & VERSE_CONNECTED) - verse_send_node_unsubscribe(vnode->id); - - /* free node name */ - MEM_freeN(vnode->name); - vnode->name = NULL; - - /* free node data */ - MEM_freeN(vnode->data); - vnode->data = NULL; - -} - -/* - * free VerseNode - */ -void free_verse_node(VNode *vnode) -{ - free_verse_node_data(vnode); - - BLI_dlist_free_item(&(vnode->session->nodes), vnode->id); -} - -/* - * Find a Verse Node from session - */ -VNode* lookup_vnode(VerseSession *session, VNodeID node_id) -{ - struct VNode *vnode; - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - return vnode; -} - -/* - * create new Verse Node - */ -VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id) -{ - struct VNode *vnode; - - vnode = (VNode*)MEM_mallocN(sizeof(VNode), "VerseNode"); - - vnode->session = session; - vnode->id = node_id; - vnode->owner_id = owner_id; - vnode->name = NULL; - vnode->type = type; - - BLI_dlist_init(&(vnode->taggroups)); - vnode->queue.first = vnode->queue.last = NULL; - vnode->methodgroups.first = vnode->methodgroups.last = NULL; - - vnode->data = NULL; - - vnode->counter = 0; - - vnode->flag = 0; -#ifdef VERSECHAT - vnode->chat_flag = CHAT_NOTLOGGED; -#endif - - vnode->post_node_create = post_node_create; - vnode->post_node_destroy = post_node_destroy; - vnode->post_node_name_set = post_node_name_set; - - return vnode; -} - -/* - * callback function: tag was destroyed - */ -static void cb_tag_destroy( - void *user_data, - VNodeID node_id, - uint16 group_id, - uint16 tag_id) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VTagGroup *vtaggroup; - struct VTag *vtag; - - if(!session) return; - - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - if(!vnode) return; - - /* try to find tag group in list of tag groups */ - vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); - - if(!vtaggroup) return; - - /* try to find verse tag in dynamic list of tags in tag group */ - vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id); - - if(vtag) { - free_verse_tag_data(vtag); - BLI_dlist_free_item(&(vtaggroup->tags), vtag->id); - } -} - -/* - * callback function: new tag was created - */ -static void cb_tag_create( - void *user_data, - VNodeID node_id, - uint16 group_id, - uint16 tag_id, - const char *name, - VNTagType type, - const VNTag *tag) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VTagGroup *vtaggroup; - struct VTag *vtag; - - if(!session) return; - - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - if(!vnode) return; - - /* try to find tag group in list of tag groups */ - vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); - - if(!vtaggroup) return; - - /* try to find verse tag in dynamic list of tags in tag group */ - vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id); - - if(!vtag) { - /* we will try to find vtag in sending queue */ - vtag = find_tag_in_queue(vtaggroup, name); - - /* when we didn't create this tag, then we will have to create one */ - if(!vtag) vtag = create_verse_tag(vtaggroup, tag_id, name, type, tag); - else vtag->id = tag_id; - - /* add tag to the list of tags in tag group */ - BLI_dlist_add_item_index(&(vtaggroup->tags), vtag, tag_id); - - /* post change/create method */ - vtaggroup->post_tag_change(vtag); - } - else { - /* this tag exists, then we will propably change value of this tag */ - if((vtag->type != type) || (strcmp(vtag->name, name)!=0)) { - /* changes of type or name are not allowed and such - * stupid changes will be returned back */ - send_verse_tag(vtag); - } - else { - /* post change/create method */ - vtaggroup->post_tag_change(vtag); - } - } -} - -/* - * callback function: tag group was destroyed - */ -static void cb_tag_group_destroy( - void *user_data, - VNodeID node_id, - uint16 group_id) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VTagGroup *vtaggroup; - - if(!session) return; - - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - if(!vnode) return; - - vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); - - if(vtaggroup) { - free_verse_taggroup_data(vtaggroup); - BLI_dlist_free_item(&(vnode->taggroups), vtaggroup->id); - } -} - -/* - * callback function: new tag group was created - */ -static void cb_tag_group_create( - void *user_data, - VNodeID node_id, - uint16 group_id, - const char *name) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VTagGroup *vtaggroup; - - if(!session) return; - - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - if(!vnode) return; - - /* name of taggroup has to begin with string "blender:" */ - if(strncmp("blender:", name, 8)) return; - - /* try to find tag group in list of tag groups */ - vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id); - - if(!vtaggroup) { - /* subscribe to tag group (when new tag will be created, then blender will - * receive command about it) */ - verse_send_tag_group_subscribe(vnode->id, group_id); - verse_callback_update(0); - - /* try to find taggroup in waiting queue */ - vtaggroup = find_taggroup_in_queue(vnode, name); - - /* if no taggroup exist, then new has to be created */ - if(!vtaggroup) vtaggroup = create_verse_taggroup(vnode, group_id, name); - else vtaggroup->id = group_id; - - /* add tag group to dynamic list with access array */ - BLI_dlist_add_item_index(&(vnode->taggroups), (void*)vtaggroup, (unsigned int)group_id); - - /* post create method */ - vtaggroup->post_taggroup_create(vtaggroup); - } - else { - /* this taggroup exist and somebody try to change its name */ - if(strcmp(vtaggroup->name, name)!=0) { - /* blender doesn't allow such stupid and dangerous things */ - send_verse_taggroup(vtaggroup); - } - } -} - -/* - * callback function: change name of node - */ -static void cb_node_name_set( - void *user_data, - VNodeID node_id, - const char *name) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - - if(!session) return; - - vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - if(vnode && name) { - if(!vnode->name) { - vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name"); - } - else if(strlen(name) > strlen(vnode->name)) { - MEM_freeN(vnode->name); - vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name"); - } - strcpy(vnode->name, name); - - vnode->post_node_name_set(vnode); - } -} - -/* - * callback function for deleting node - */ -static void cb_node_destroy( - void *user_data, - VNodeID node_id) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - - if(!session) return; - - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - if(vnode) { - /* remove VerseNode from dynamic list */ - BLI_dlist_rem_item(&(session->nodes), (unsigned int)node_id); - /* do post destroy operations */ - vnode->post_node_destroy(vnode); - /* free verse data */ - free_verse_node_data(vnode); - /* free VerseNode */ - MEM_freeN(vnode); - }; -} - - -/* - * callback function for new created node - */ -static void cb_node_create( - void *user_data, - VNodeID node_id, - uint8 type, - VNodeID owner_id) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode = NULL; - - if(!session) return; - - /* subscribe to node */ - if((type==V_NT_OBJECT) || (type==V_NT_GEOMETRY) || (type==V_NT_BITMAP)) - verse_send_node_subscribe(node_id); - else - return; - - switch(type){ - case V_NT_OBJECT : - if(owner_id==VN_OWNER_MINE) { - struct VLink *vlink; - /* collect VerseNode from VerseNode queue */ - move_verse_node_to_dlist(session, node_id); - /* send next VerseNode waiting in queue */ - if(session->queue.first) send_verse_node(session->queue.first); - /* get received VerseNode from list of VerseNodes */ - vnode = BLI_dlist_find_link(&(session->nodes), node_id); - /* set up ID */ - vnode->id = node_id; - /* set up flags */ - vnode->flag |= NODE_RECEIVED; - /* find unsent link pointing at this VerseNode */ - vlink = find_unsent_child_vlink(session, vnode); - /* send VerseLink */ - if(vlink) send_verse_link(vlink); - /* send name of object node */ - verse_send_node_name_set(node_id, vnode->name); - /* subscribe to changes of object node transformations */ - verse_send_o_transform_subscribe(node_id, 0); - /* send object transformation matrix */ - send_verse_object_position(vnode); - send_verse_object_rotation(vnode); - send_verse_object_scale(vnode); - } - else { - /* create new VerseNode */ - vnode = create_verse_node(session, node_id, type, owner_id); - /* add VerseNode to list of nodes */ - BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id); - /* set up flags */ - vnode->flag |= NODE_RECEIVED; - /* create object data */ - vnode->data = create_object_data(); - /* set up avatar's name */ - if(node_id == session->avatar) { - verse_send_node_name_set(node_id, U.verseuser); - } - else if(session->flag & VERSE_AUTOSUBSCRIBE) { - /* subscribe to changes of object node transformations */ - verse_send_o_transform_subscribe(node_id, 0); - } - } - break; - case V_NT_GEOMETRY : - if(owner_id==VN_OWNER_MINE){ - struct VLink *vlink; - struct VLayer *vlayer; - /* collect VerseNode from VerseNode queue */ - move_verse_node_to_dlist(session, node_id); - /* send next VerseNode waiting in queue */ - if(session->queue.first) send_verse_node(session->queue.first); - /* get received VerseNode from list of VerseNodes */ - vnode = BLI_dlist_find_link(&(session->nodes), node_id); - /* set up ID */ - vnode->id = node_id; - /* set up flags */ - vnode->flag |= NODE_RECEIVED; - /* find unsent link pointing at this VerseNode */ - vlink = find_unsent_parent_vlink(session, vnode); - /* send VerseLink */ - if(vlink) send_verse_link(vlink); - /* send name of geometry node */ - verse_send_node_name_set(node_id, vnode->name); - /* send all not sent layer to verse server */ - vlayer = (VLayer*)((VGeomData*)vnode->data)->queue.first; - if(vlayer) { - while(vlayer) { - send_verse_layer(vlayer); - vlayer = vlayer->next; - } - } - else { - /* send two verse layers to verse server */ -/* verse_send_g_layer_create(node_id, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0); - verse_send_g_layer_create(node_id, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0);*/ - } - } - else { - /* create new VerseNode*/ - vnode = create_verse_node(session, node_id, type, owner_id); - /* add VerseNode to dlist of nodes */ - BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id); - /* set up flags */ - vnode->flag |= NODE_RECEIVED; - /* create geometry data */ - vnode->data = (void*)create_geometry_data(); - } - break; - case V_NT_BITMAP : - if(owner_id==VN_OWNER_MINE) { - /* collect VerseNode from VerseNode queue */ - move_verse_node_to_dlist(session, node_id); - /* send next VerseNode waiting in queue */ - if(session->queue.first) send_verse_node(session->queue.first); - /* get received VerseNode from list of VerseNodes */ - vnode = BLI_dlist_find_link(&(session->nodes), node_id); - /* set up ID */ - vnode->id = node_id; - /* set up flags */ - vnode->flag |= NODE_RECEIVED; - /* send name of object node */ - verse_send_node_name_set(node_id, vnode->name); - /* send dimension of image to verse server */ - verse_send_b_dimensions_set(node_id, - ((VBitmapData*)vnode->data)->width, - ((VBitmapData*)vnode->data)->height, - ((VBitmapData*)vnode->data)->depth); - } - else { - /* create new VerseNode*/ - vnode = create_verse_node(session, node_id, type, owner_id); - /* add VerseNode to dlist of nodes */ - BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id); - /* set up flags */ - vnode->flag |= NODE_RECEIVED; - /* create bitmap data */ - vnode->data = (void*)create_bitmap_data(); - } - break; - default: - vnode = NULL; - break; - } - - if(vnode) vnode->post_node_create(vnode); -} - -/* - * set up all callbacks for verse nodes - */ -void set_node_callbacks(void) -{ - /* new node created */ - verse_callback_set(verse_send_node_create, cb_node_create, NULL); - /* node was deleted */ - verse_callback_set(verse_send_node_destroy, cb_node_destroy, NULL); - /* name of node was set */ - verse_callback_set(verse_send_node_name_set, cb_node_name_set, NULL); - - /* new tag group was created */ - verse_callback_set(verse_send_tag_group_create, cb_tag_group_create, NULL); - /* tag group was destroy */ - verse_callback_set(verse_send_tag_group_destroy, cb_tag_group_destroy, NULL); - - /* new tag was created */ - verse_callback_set(verse_send_tag_create, cb_tag_create, NULL); - /* tag was destroy */ - verse_callback_set(verse_send_tag_destroy, cb_tag_destroy, NULL); -} - -#endif diff --git a/source/blender/blenkernel/intern/verse_object_node.c b/source/blender/blenkernel/intern/verse_object_node.c deleted file mode 100644 index 89f9f0edcbd..00000000000 --- a/source/blender/blenkernel/intern/verse_object_node.c +++ /dev/null @@ -1,617 +0,0 @@ -/** - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Contributor(s): Jiri Hnidek. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifdef WITH_VERSE - -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_listBase.h" -#include "DNA_userdef_types.h" - -#include "BLI_dynamiclist.h" -#include "BLI_blenlib.h" -#include "BLI_arithb.h" - -#include "BIF_verse.h" - -#include "BKE_verse.h" -#include "BKE_utildefines.h" - -#include "verse.h" - -/* function prototypes of static functions */ - -/* callback functions */ -static void cb_o_transform_pos_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag); -static void cb_o_transform_rot_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *temp, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag); -static void cb_o_transform_scale_real32(void *user_data, VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z); -static void cb_o_link_set(void *user_data, VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id); -static void cb_o_link_destroy(void *user_data, VNodeID node_id,uint16 link_id); - -/* other functions */ -static void set_target_node_link_pointer(struct VNode *vnode, struct VLink *vlink); -static void free_verse_link_data(struct VLink *vlink); - -/* - * find noy sent VerseLink in queue - */ -VLink *find_unsent_child_vlink(VerseSession *session, VNode *vnode) -{ - struct VLink *vlink; - - if(vnode->type!=V_NT_OBJECT) return NULL; - - vlink = ((VObjectData*)vnode->data)->queue.first; - while(vlink) { - if(vlink->target->id != -1) { - printf("\t vlink found, vnode target id %d\n", vlink->target->id); - return vlink; - } - vlink = vlink->next; - } - return NULL; -} - -/* - * find unsent VerseLink "pointing at this VerseNode" - */ -VLink *find_unsent_parent_vlink(VerseSession *session, VNode *vnode) -{ - struct VNode *tmp; - struct VLink *vlink; - - tmp = session->nodes.lb.first; - - while(tmp) { - if(tmp->type==V_NT_OBJECT) { - vlink = ((VObjectData*)tmp->data)->queue.first; - while(vlink) { - if(vlink->target == vnode) - return vlink; - vlink = vlink->next; - } - } - tmp = tmp->next; - } - return NULL; -} - -/* - * send object position to verse server - */ -void send_verse_object_position(VNode *vnode) -{ - float tmp; - - ((VObjectData*)vnode->data)->flag &= ~POS_SEND_READY; - - /* we have to do rotation around x axis (+pi/2) to be - compatible with other verse applications */ - tmp = -((VObjectData*)vnode->data)->pos[1]; - ((VObjectData*)vnode->data)->pos[1] = ((VObjectData*)vnode->data)->pos[2]; - ((VObjectData*)vnode->data)->pos[2] = tmp; - - verse_send_o_transform_pos_real32( - vnode->id, /* node id */ - 0, /* time_s ... no interpolation */ - 0, /* time_f ... no interpolation */ - ((VObjectData*)vnode->data)->pos, - NULL, /* speed ... no interpolation */ - NULL, /* accelerate ... no interpolation */ - NULL, /* drag normal ... no interpolation */ - 0.0); /* drag ... no interpolation */ -} - -/* - * send object rotation to verse server - */ -void send_verse_object_rotation(VNode *vnode) -{ - VNQuat32 quat; - float q[4] = {cos(-M_PI/4), -sin(-M_PI/4), 0, 0}, v[4], tmp[4]; - - /* inverse transformation to transformation in function cb_o_transform_rot_real32 */ - QuatMul(v, ((VObjectData*)vnode->data)->quat, q); - q[1]= sin(-M_PI/4); - QuatMul(tmp, q, v); - - quat.x = tmp[1]; - quat.y = tmp[2]; - quat.z = tmp[3]; - quat.w = tmp[0]; - - ((VObjectData*)vnode->data)->flag &= ~ROT_SEND_READY; - - verse_send_o_transform_rot_real32( - vnode->id, /* node id */ - 0, /* time_s ... no interpolation */ - 0, /* time_f ... no interpolation */ - &quat, - NULL, /* speed ... no interpolation */ - NULL, /* accelerate ... no interpolation */ - NULL, /* drag normal ... no interpolation */ - 0.0); /* drag ... no interpolation */ -} - -/* - * send object rotation to verse server - */ -void send_verse_object_scale(VNode *vnode) -{ - float tmp; - - ((VObjectData*)vnode->data)->flag &= ~SCALE_SEND_READY; - - /* we have to do rotation around x axis (+pi/2) to be - compatible with other verse applications */ - tmp = ((VObjectData*)vnode->data)->scale[1]; - ((VObjectData*)vnode->data)->scale[1] = ((VObjectData*)vnode->data)->scale[2]; - ((VObjectData*)vnode->data)->scale[2] = tmp; - - verse_send_o_transform_scale_real32( - vnode->id, - ((VObjectData*)vnode->data)->scale[0], - ((VObjectData*)vnode->data)->scale[1], - ((VObjectData*)vnode->data)->scale[2]); -} - -/* - * send VerseLink to verse server - */ -void send_verse_link(VLink *vlink) -{ - verse_session_set(vlink->session->vsession); - - verse_send_o_link_set( - vlink->source->id, - vlink->id, - vlink->target->id, - vlink->label, - vlink->target_id); -} - -/* - * set up pointer at VerseLink of target node (geometry node, material node, etc.) - */ -static void set_target_node_link_pointer(VNode *vnode, VLink *vlink) -{ - switch (vnode->type) { - case V_NT_GEOMETRY: - ((VGeomData*)vnode->data)->vlink = vlink; - break; - default: - break; - } -} - -/* - * free VerseLink and it's label - */ -static void free_verse_link_data(VLink *vlink) -{ - MEM_freeN(vlink->label); -} - -/* - * create new VerseLink - */ -VLink *create_verse_link( - VerseSession *session, - VNode *source, - VNode *target, - uint16 link_id, - uint32 target_id, - const char *label) -{ - struct VLink *vlink; - - vlink = (VLink*)MEM_mallocN(sizeof(VLink), "VerseLink"); - vlink->session = session; - vlink->source = source; - vlink->target = target; - vlink->id = link_id; - vlink->target_id = target_id; - - set_target_node_link_pointer(target, vlink); - - vlink->label = (char*)MEM_mallocN(sizeof(char)*(strlen(label)+1), "VerseLink label"); - vlink->label[0] = '\0'; - strcat(vlink->label, label); - - vlink->flag = 0; - - vlink->post_link_set = post_link_set; - vlink->post_link_destroy = post_link_destroy; - - return vlink; -} - -/* - * free ObjectData (links, links in queue and lables of links) - */ -void free_object_data(VNode *vnode) -{ - struct VerseSession *session = vnode->session; - struct VObjectData *obj = (VObjectData*)vnode->data; - struct VLink *vlink; - struct VMethodGroup *vmg; - - if(!obj) return; - - /* free all labels of links in dlist */ - vlink = obj->links.lb.first; - while(vlink){ - free_verse_link_data(vlink); - vlink = vlink->next; - } - - /* free all labels of links waiting in queue */ - vlink = obj->queue.first; - while(vlink){ - free_verse_link_data(vlink); - vlink = vlink->next; - } - /* free dynamic list and sendig queue of links */ - BLI_dlist_destroy(&(obj->links)); - BLI_freelistN(&(obj->queue)); - - /* free method groups and their methods */ - for(vmg = vnode->methodgroups.first; vmg; vmg= vmg->next) { - free_verse_methodgroup(vmg); - } - BLI_freelistN(&(vnode->methodgroups)); - - /* free constraint between VerseNode and Object */ - obj->post_object_free_constraint(vnode); - - /* unsubscribe from receiving changes of transformation matrix */ - if(session->flag & VERSE_CONNECTED) - verse_send_o_transform_unsubscribe(vnode->id, 0); -} - -/* - * create new object data - */ -VObjectData *create_object_data(void) -{ - VObjectData *obj; - - obj = (VObjectData*)MEM_mallocN(sizeof(VObjectData), "VerseObjectData"); - obj->object = NULL; - BLI_dlist_init(&(obj->links)); - obj->queue.first = obj->queue.last = NULL; - obj->flag = 0; - - /* transformation matrix */ - obj->pos[0] = obj->pos[1] = obj->pos[2] = 0.0; - obj->quat[0] = obj->quat[1] = obj->quat[2] = 0.0; obj->quat[3] = 1; - obj->scale[0] = obj->scale[1] = obj->scale[2] = 1.0; - - /* transformation flags */ - obj->flag |= POS_SEND_READY; - obj->flag |= ROT_SEND_READY; - obj->flag |= SCALE_SEND_READY; - - /* set up pointers at post callback functions */ -/* obj->post_transform = post_transform;*/ - obj->post_transform_pos = post_transform_pos; - obj->post_transform_rot = post_transform_rot; - obj->post_transform_scale = post_transform_scale; - obj->post_object_free_constraint = post_object_free_constraint; - - return obj; -} - -/* - * callback function: - */ -static void cb_o_transform_pos_real32( - void *user_data, - VNodeID node_id, - uint32 time_s, - uint32 time_f, - const real32 *pos, - const real32 *speed, - const real32 *accelerate, - const real32 *drag_normal, - real32 drag) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - float vec[3], dt, tmp; - - if(!session) return; - - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - ((VObjectData*)vnode->data)->flag |= POS_SEND_READY; - - /* verse server sends automaticaly some stupid default values ... - * we have to ignore these values, when we created this object node */ - if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & POS_RECEIVE_READY) ) { - ((VObjectData*)vnode->data)->flag |= POS_RECEIVE_READY; - return; - } - - dt = time_s + time_f/(0xffff); - - if(pos) { - vec[0] = pos[0]; - vec[1] = pos[1]; - vec[2] = pos[2]; - } - else { - vec[0] = 0.0f; - vec[1] = 0.0f; - vec[2] = 0.0f; - } - - if(speed) { - vec[0] += speed[0]*dt; - vec[1] += speed[1]*dt; - vec[2] += speed[2]*dt; - } - - if(accelerate) { - vec[0] += accelerate[0]*dt*dt/2; - vec[1] += accelerate[1]*dt*dt/2; - vec[2] += accelerate[2]*dt*dt/2; - } - - /* we have to do rotation around x axis (+pi/2) to be - compatible with other verse applications */ - tmp = vec[1]; - vec[1] = -vec[2]; - vec[2] = tmp; - - if( (((VObjectData*)vnode->data)->pos[0] != vec[0]) || - (((VObjectData*)vnode->data)->pos[1] != vec[1]) || - (((VObjectData*)vnode->data)->pos[2] != vec[2])) - { - ((VObjectData*)vnode->data)->pos[0] = vec[0]; - ((VObjectData*)vnode->data)->pos[1] = vec[1]; - ((VObjectData*)vnode->data)->pos[2] = vec[2]; - - ((VObjectData*)vnode->data)->post_transform_pos(vnode); - } -} - -/* - * callback function: - */ -static void cb_o_transform_rot_real32( - void *user_data, - VNodeID node_id, - uint32 time_s, - uint32 time_f, - const VNQuat32 *quat, - const VNQuat32 *speed, - const VNQuat32 *accelerate, - const VNQuat32 *drag_normal, - real32 drag) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - float temp[4]={0, 0, 0, 0}, v[4], dt; /* temporary quaternions */ - float q[4]={cos(M_PI/4), -sin(M_PI/4), 0, 0}; /* conjugate quaternion (represents rotation - around x-axis +90 degrees) */ - - if(!session) return; - - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY; - - /* verse server sends automaticaly some stupid default values ... - * we have to ignore these values, when we created this object node */ - if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & ROT_RECEIVE_READY) ) { - ((VObjectData*)vnode->data)->flag |= ROT_RECEIVE_READY; - return; - } - - dt = time_s + time_f/(0xffff); - - if(quat) { - temp[1] = quat->x; - temp[2] = quat->y; - temp[3] = quat->z; - temp[0] = quat->w; - } - - if(speed) { - temp[1] += speed->x*dt; - temp[2] += speed->y*dt; - temp[3] += speed->z*dt; - temp[0] += speed->w*dt; - } - - if(accelerate) { - temp[1] += accelerate->x*dt*dt/2; - temp[2] += accelerate->y*dt*dt/2; - temp[3] += accelerate->z*dt*dt/2; - temp[0] += accelerate->w*dt*dt/2; - } - - /* following matematical operation transform rotation: - * - * v' = quaternion * v * conjugate_quaternion - * - *, where v is original representation of rotation */ - - QuatMul(v, temp, q); - q[1]= sin(M_PI/4); /* normal quaternion */ - QuatMul(temp, q, v); - - if( (((VObjectData*)vnode->data)->quat[0] != temp[0]) || - (((VObjectData*)vnode->data)->quat[1] != temp[1]) || - (((VObjectData*)vnode->data)->quat[2] != temp[2]) || - (((VObjectData*)vnode->data)->quat[3] != temp[3])) - { - QUATCOPY(((VObjectData*)vnode->data)->quat, temp); - - ((VObjectData*)vnode->data)->post_transform_rot(vnode); - } -} - -/* - * callback function: - */ -static void cb_o_transform_scale_real32( - void *user_data, - VNodeID node_id, - real32 scale_x, - real32 scale_y, - real32 scale_z) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - real32 tmp; - - if(!session) return; - - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY; - - /* verse server sends automaticaly some stupid default values ... - * we have to ignore these values, when we created this object node */ - if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & SCALE_RECEIVE_READY) ) { - ((VObjectData*)vnode->data)->flag |= SCALE_RECEIVE_READY; - return; - } - - /* flip axis (verse spec) */ - tmp = scale_y; - scale_y = scale_z; - scale_z = tmp; - - /* z and y axis are flipped here too */ - if( (((VObjectData*)vnode->data)->scale[0] != scale_x) || - (((VObjectData*)vnode->data)->scale[1] != scale_y) || - (((VObjectData*)vnode->data)->scale[2] != scale_z)) - { - ((VObjectData*)vnode->data)->scale[0] = scale_x; - ((VObjectData*)vnode->data)->scale[1] = scale_y; - ((VObjectData*)vnode->data)->scale[2] = scale_z; - - ((VObjectData*)vnode->data)->post_transform_scale(vnode); - } -} - -/* - * callback function: link between object node and some other node was created - */ -static void cb_o_link_set( - void *user_data, - VNodeID node_id, - uint16 link_id, - VNodeID link, - const char *label, - uint32 target_id) -{ - struct VLink *vlink; - struct VNode *source; - struct VNode *target; - - struct VerseSession *session = (VerseSession*)current_verse_session(); - - if(!session) return; - - source = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - target = BLI_dlist_find_link(&(session->nodes), (unsigned int)link); - - if(!(source && target)) return; - - vlink = ((VObjectData*)source->data)->queue.first; - - if(vlink && (vlink->source==source) && (vlink->target==target)) { - /* remove VerseLink from sending queue */ - BLI_remlink(&(((VObjectData*)source->data)->queue), vlink); - /* add VerseLink to dynamic list of VerseLinks */ - BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id); - /* send next link from sending queue */ - if(((VObjectData*)source->data)->queue.first) - send_verse_link(((VObjectData*)source->data)->queue.first); - /* set up VerseLink variables */ - vlink->flag = 0; - vlink->id = link_id; - vlink->target_id = target_id; - } - else { - /* create new VerseLink */ - vlink = create_verse_link(session, source, target, link_id, target_id, label); - /* add VerseLink to dynamic list of VerseLinks */ - BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id); - } - - target->counter++; - - vlink->post_link_set(vlink); -} - -/* - * callback function: destroy link between two VerseNodes - */ -static void cb_o_link_destroy( - void *user_data, - VNodeID node_id, - uint16 link_id) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VNode *vnode; - struct VLink *vlink; - - if(!session) return; - - vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id); - - vlink = BLI_dlist_find_link(&(((VObjectData*)vnode->data)->links), link_id); - - if(vlink) { - vlink->target->counter--; - free_verse_link_data(vlink); - BLI_dlist_free_item(&(((VObjectData*)vnode->data)->links), link_id); - } - - vlink->post_link_destroy(vlink); -} - -void set_object_callbacks(void) -{ - /* position of object was changed */ - verse_callback_set(verse_send_o_transform_pos_real32, cb_o_transform_pos_real32, NULL); - /* rotation of object was changed */ - verse_callback_set(verse_send_o_transform_rot_real32, cb_o_transform_rot_real32, NULL); - /* size of object was changed */ - verse_callback_set(verse_send_o_transform_scale_real32, cb_o_transform_scale_real32, NULL); - /* new link between nodes was created */ - verse_callback_set(verse_send_o_link_set, cb_o_link_set, NULL); - /* link between nodes was destroyed */ - verse_callback_set(verse_send_o_link_destroy, cb_o_link_destroy, NULL); -} - -#endif diff --git a/source/blender/blenkernel/intern/verse_session.c b/source/blender/blenkernel/intern/verse_session.c deleted file mode 100644 index 28a9ef85536..00000000000 --- a/source/blender/blenkernel/intern/verse_session.c +++ /dev/null @@ -1,477 +0,0 @@ -/** - * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Contributor(s): Jiri Hnidek. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifdef WITH_VERSE - -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_mesh_types.h" /* temp */ -#include "DNA_listBase.h" -#include "DNA_screen_types.h" -#include "DNA_userdef_types.h" - -#include "BLI_dynamiclist.h" -#include "BLI_blenlib.h" - -#include "BIF_screen.h" -#include "BIF_verse.h" - -#include "BKE_global.h" -#include "BKE_verse.h" - -struct ListBase session_list={NULL, NULL}; -struct ListBase server_list={NULL, NULL}; - -static int cb_ping_registered = 0; - -/* list of static function prototypes */ -static void cb_connect_terminate(const char *address, const char *bye); -static void cb_connect_accept(void *user_data, uint32 avatar, void *address, void *connection, const uint8 *host_id); -static void set_all_callbacks(void); -static void free_verse_session_data(struct VerseSession *session); -static void add_verse_server(VMSServer *server); -static void check_connection_state(struct VerseServer *server); - -static void check_connection_state(struct VerseServer *server) -{ - struct VerseSession *session; - session = session_list.first; - while(session) { - if(strcmp(server->ip,session->address)==0) { - server->flag = session->flag; - return; - } - session = session->next; - } -} -/* - * add verse server to server_list. Prevents duplicate - * entries - */ -static void add_verse_server(VMSServer *server) -{ - struct VerseServer *iter, *niter; - VerseServer *newserver; - const char *name = verse_ms_field_value(server, "DE"); - iter = server_list.first; - - while(iter) { - niter = iter->next; - if(strcmp(iter->ip, server->ip)==0) { - return; - } - iter = niter; - } - - newserver = (VerseServer *)MEM_mallocN(sizeof(VerseServer), "VerseServer"); - newserver->ip = (char *)MEM_mallocN(sizeof(char)*(strlen(server->ip)+1), "VerseServer ip"); - strcpy(newserver->ip, server->ip); - - if(name) { - newserver->name = (char *)MEM_mallocN(sizeof(char)*(strlen(name)+strlen(newserver->ip)+4), "VerseServer name"); - strcpy(newserver->name, name); - strcat(newserver->name, " ("); - strcat(newserver->name, newserver->ip); - strcat(newserver->name, ")"); - } - - newserver->flag = 0; - check_connection_state(newserver); - - printf("Adding new verse server: %s at %s\n", newserver->name, newserver->ip); - - BLI_addtail(&server_list, newserver); - post_server_add(); -} - -/* - * callback function for ping - */ -static void cb_ping(void *user, const char *address, const char *message) -{ - VMSServer **servers = verse_ms_list_parse(message); - if(servers != NULL) - { - int i; - - for(i = 0; servers[i] != NULL; i++) - add_verse_server(servers[i]); - - free(servers); - } -} - -/* - * callback function for connection terminated - */ -static void cb_connect_terminate(const char *address, const char *bye) -{ - VerseSession *session = (VerseSession*)current_verse_session(); - - if(!session) return; - - /* remove session from list of session */ - BLI_remlink(&session_list, session); - /* do post connect operations */ - session->post_connect_terminated(session); - /* free session data */ - free_verse_session_data(session); - /* free session */ - MEM_freeN(session); -} - -/* - * callback function for accepted connection to verse server - */ -static void cb_connect_accept( - void *user_data, - uint32 avatar, - void *address, - void *connection, - const uint8 *host_id) -{ - struct VerseSession *session = (VerseSession*)current_verse_session(); - struct VerseServer *server = server_list.first; - uint32 i, mask=0; - - if(!session) return; - - session->flag |= VERSE_CONNECTED; - session->flag &= ~VERSE_CONNECTING; - - while(server) { - if(strcmp(session->address, server->ip)==0) { - server->flag |= VERSE_CONNECTED; - server->flag &= ~VERSE_CONNECTING; - server->session = session; - break; - } - server = server->next; - } - - printf("\tBlender is connected to verse server: %s\n", (char*)address); - printf("\tVerseSession->counter: %d\n", session->counter); - - session->avatar = avatar; - - session->post_connect_accept(session); - - for(i = 0; i < V_NT_NUM_TYPES; i++) - mask = mask | (1 << i); - verse_send_node_index_subscribe(mask); - verse_send_node_subscribe(session->avatar); /* subscribe to avatar node, as well */ - - /* create our own method group and method */ - /*verse_send_o_method_group_create(session->avatar, ~0, "tawk-client");*/ -} - -/* - * set up all callbacks for sessions - */ -void set_verse_session_callbacks(void) -{ - /* connection */ - verse_callback_set(verse_send_connect_accept, cb_connect_accept, NULL); - /* connection was terminated */ - verse_callback_set(verse_send_connect_terminate, cb_connect_terminate, NULL); - -} - -/* - * set all callbacks used in Blender - */ -static void set_all_callbacks(void) -{ - /* set up all callbacks for sessions */ - set_verse_session_callbacks(); - - /* set up callbacks for nodes */ - set_node_callbacks(); - - /* set up all callbacks for object nodes */ - set_object_callbacks(); - - /* set up all callbacks for geometry nodes */ - set_geometry_callbacks(); - - /* set up all callbacks for bitmap nodes */ - set_bitmap_callbacks(); - - /* set up all callbacks for method groups and methods */ - set_method_callbacks(); -} - -/* - * this function sends and receive all packets for all sessions - */ -void b_verse_update(void) -{ - VerseSession *session, *next_session; - - session = session_list.first; - while(session){ - next_session = session->next; - verse_session_set(session->vsession); - if((session->flag & VERSE_CONNECTED) || (session->flag & VERSE_CONNECTING)) { - verse_callback_update(10); - session->post_connect_update(session); - } - session = next_session; - } - if(cb_ping_registered>0) { - verse_callback_update(10); - } -} - -/* - * returns VerseSession coresponding to vsession pointer - */ -VerseSession *versesession_from_vsession(VSession *vsession) -{ - struct VerseSession *session; - - session = session_list.first; - - while(session) { - if(session->vsession==vsession) return session; - session = session->next; - } - - return session; -} - -/* - * returns pointer at current VerseSession - */ -VerseSession *current_verse_session(void) -{ - struct VerseSession *session; - VSession vsession = verse_session_get(); - - session = session_list.first; - - while(session){ - if(session->vsession == vsession) - return session; - session = session->next; - } - - printf("error: non-existing SESSION occured!\n"); - return NULL; -} - -/* - * free VerseSession - */ -static void free_verse_session_data(VerseSession *session) -{ - struct VNode *vnode; - - /* free data of all nodes */ - vnode = session->nodes.lb.first; - while(vnode){ - free_verse_node_data(vnode); - vnode = vnode->next; - } - - /* free data of nodes waiting in queue */ - vnode = session->queue.first; - while(vnode){ - free_verse_node_data(vnode); - vnode = vnode->next; - } - - /* free all VerseNodes */ - BLI_dlist_destroy(&(session->nodes)); - /* free all VerseNodes waiting in queque */ - BLI_freelistN(&(session->queue)); - - /* free name of verse host for this session */ - MEM_freeN(session->address); -} - -/* - * free VerseSession - */ -void free_verse_session(VerseSession *session) -{ - /* remove session from session list*/ - BLI_remlink(&session_list, session); - /* do post terminated operations */ - session->post_connect_terminated(session); - /* free session data (nodes, layers) */ - free_verse_session_data(session); - /* free session */ - MEM_freeN(session); -} - -/* - * create new verse session and return coresponding data structure - */ -VerseSession *create_verse_session( - const char *name, - const char *pass, - const char *address, - uint8 *expected_key) -{ - struct VerseSession *session; - VSession *vsession; - - vsession = verse_send_connect(name, pass, address, expected_key); - - if(!vsession) return NULL; - - session = (VerseSession*)MEM_mallocN(sizeof(VerseSession), "VerseSession"); - - session->flag = VERSE_CONNECTING; - - session->vsession = vsession; - session->avatar = -1; - - session->address = (char*)MEM_mallocN(sizeof(char)*(strlen(address)+1),"session adress name"); - strcpy(session->address, address); - - session->connection = NULL; - session->host_id = NULL; - session->counter = 0; - - /* initialize dynamic list of nodes and node queue */ - BLI_dlist_init(&(session->nodes)); - session->queue.first = session->queue.last = NULL; - - /* set up all client dependent functions */ - session->post_connect_accept = post_connect_accept; - session->post_connect_terminated = post_connect_terminated; - session->post_connect_update = post_connect_update; - - post_server_add(); - - return session; -} - -/* - * end verse session and free all session data - */ -void end_verse_session(VerseSession *session) -{ - /* send terminate command to verse server */ - verse_send_connect_terminate(session->address, "blender: bye bye"); - /* update callbacks */ - verse_callback_update(1000); - /* send destroy session command to verse server */ - verse_session_destroy(session->vsession); - /* set up flag of verse session */ - session->flag &= ~VERSE_CONNECTED; - /* do post connect operations */ - session->post_connect_terminated(session); - /* free structure of verse session */ - free_verse_session(session); -} - -void free_all_servers(void) -{ - VerseServer *server, *nextserver; - - server = server_list.first; - - while(server) { - nextserver = server->next; - BLI_remlink(&server_list, server); - MEM_freeN(server->name); - MEM_freeN(server->ip); - MEM_freeN(server); - server = nextserver; - } - - BLI_freelistN(&server_list); -} - -/* - * end connection to all verse hosts (servers) ... free all VerseSessions - * free all VerseServers - */ -void end_all_verse_sessions(void) -{ - VerseSession *session,*nextsession; - - session = session_list.first; - - while(session) { - nextsession= session->next; - end_verse_session(session); - /* end next session */ - session = nextsession; - } - - BLI_freelistN(&session_list); - - free_all_servers(); -} - -/* - * do a get from ms - */ -void b_verse_ms_get(void) -{ - if(cb_ping_registered==0) { - /* handle ping messages (for master server) */ - verse_callback_set(verse_send_ping, cb_ping, NULL); - add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1); - cb_ping_registered++; - } - free_all_servers(); - - verse_ms_get_send(U.versemaster, VERSE_MS_FIELD_DESCRIPTION, NULL); - verse_callback_update(10); -} - -/* - * connect to verse host, set up all callbacks, create session - */ -void b_verse_connect(char *address) -{ - VerseSession *session = NULL; - - /* if no session was created before, then set up all callbacks */ - if((session_list.first==NULL) && (session_list.last==NULL)) - set_all_callbacks(); - - /* create new session */ - if(address) - session = create_verse_session("Blender", "pass", address, NULL); - - if(session) { - /* add new session to the list of sessions */ - BLI_addtail(&session_list, session); - - /* add verse handler if this is first session */ - if(session_list.first == session_list.last) - add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1); - - } -} - -#endif diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index d47f4efeb4e..f795c147f54 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -36,7 +36,6 @@ #include "DNA_world_types.h" #include "DNA_texture_types.h" -#include "DNA_scriptlink_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_camera_types.h" @@ -45,10 +44,10 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" -#include "BKE_bad_level_calls.h" #include "BKE_utildefines.h" #include "BKE_library.h" +#include "BKE_animsys.h" #include "BKE_world.h" #include "BKE_global.h" #include "BKE_main.h" @@ -66,10 +65,7 @@ void free_world(World *wrld) { MTex *mtex; int a; - -#ifndef DISABLE_PYTHON - BPY_free_scriptlink(&wrld->scriptlink); -#endif + for(a=0; a<MAX_MTEX; a++) { mtex= wrld->mtex[a]; if(mtex && mtex->tex) mtex->tex->id.us--; @@ -77,7 +73,8 @@ void free_world(World *wrld) } BKE_previewimg_free(&wrld->preview); - wrld->ipo= 0; + BKE_free_animdata((ID *)wrld); + BKE_icon_delete((struct ID*)wrld); wrld->id.icon_id = 0; } @@ -93,7 +90,6 @@ World *add_world(char *name) wrld->skytype= WO_SKYBLEND; wrld->stardist= 15.0f; wrld->starsize= 2.0f; - wrld->gravity= 9.8f; wrld->exp= 0.0f; wrld->exposure=wrld->range= 1.0f; @@ -105,14 +101,7 @@ World *add_world(char *name) wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY; wrld->ao_approx_error= 0.25f; - wrld->physicsEngine= WOPHY_BULLET;//WOPHY_SUMO; Bullet by default - wrld->mode = WO_DBVT_CULLING; // DBVT culling by default - wrld->occlusionRes = 128; wrld->preview = NULL; - wrld->ticrate = 60; - wrld->maxlogicstep = 5; - wrld->physubstep = 1; - wrld->maxphystep = 5; return wrld; } @@ -133,10 +122,10 @@ World *copy_world(World *wrld) } if (wrld->preview) wrldn->preview = BKE_previewimg_copy(wrld->preview); -#ifndef DISABLE_PYTHON - BPY_copy_scriptlink(&wrld->scriptlink); -#endif + +#if 0 // XXX old animation system id_us_plus((ID *)wrldn->ipo); +#endif // XXX old animation system return wrldn; } diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index 44004eeee80..7c58a4f9499 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -40,6 +40,7 @@ #include "BLI_blenlib.h" #include "BKE_global.h" +#include "BKE_utildefines.h" #include "BKE_writeavi.h" #include "AVI_avi.h" @@ -50,10 +51,6 @@ #include "quicktime_export.h" #endif -#if defined(_WIN32) && !defined(FREE_WINDOWS) -#include "BIF_writeavicodec.h" -#endif - #ifdef WITH_FFMPEG #include "BKE_writeffmpeg.h" #endif @@ -68,7 +65,7 @@ bMovieHandle *BKE_get_movie_handle(int imtype) mh.start_movie= start_avi; mh.append_movie= append_avi; mh.end_movie= end_avi; - mh.get_next_frame = 0; + mh.get_next_frame = NULL; /* do the platform specific handles */ #ifdef __sgi @@ -78,9 +75,9 @@ bMovieHandle *BKE_get_movie_handle(int imtype) #endif #if defined(_WIN32) && !defined(FREE_WINDOWS) if (imtype == R_AVICODEC) { - mh.start_movie= start_avi_codec; - mh.append_movie= append_avi_codec; - mh.end_movie= end_avi_codec; + //XXX mh.start_movie= start_avi_codec; + //XXX mh.append_movie= append_avi_codec; + //XXX mh.end_movie= end_avi_codec; } #endif #ifdef WITH_QUICKTIME @@ -91,7 +88,7 @@ bMovieHandle *BKE_get_movie_handle(int imtype) } #endif #ifdef WITH_FFMPEG - if (imtype == R_FFMPEG) { + if (ELEM4(imtype, R_FFMPEG, R_H264, R_XVID, R_THEORA)) { mh.start_movie = start_ffmpeg; mh.append_movie = append_ffmpeg; mh.end_movie = end_ffmpeg; @@ -130,7 +127,7 @@ void makeavistring (RenderData *rd, char *string) } } -void start_avi(RenderData *rd, int rectx, int recty) +void start_avi(struct Scene *scene, RenderData *rd, int rectx, int recty) { int x, y; char name[256]; @@ -175,7 +172,7 @@ void start_avi(RenderData *rd, int rectx, int recty) printf("Created avi: %s\n", name); } -void append_avi(int frame, int *pixels, int rectx, int recty) +void append_avi(RenderData *rd, int frame, int *pixels, int rectx, int recty) { unsigned int *rt1, *rt2, *rectot; int x, y; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 6576d25dd76..e7164dc4794 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -57,24 +57,24 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" -#include "BKE_bad_level_calls.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" -#include "BSE_seqaudio.h" - #include "DNA_scene_types.h" -#include "blendef.h" + +#include "AUD_C-API.h" +#include "BKE_sound.h" +#include "BKE_main.h" #ifdef HAVE_CONFIG_H #include <config.h> #endif extern void do_init_ffmpeg(); -void makeffmpegstring(char* string); +static void makeffmpegstring(RenderData* rd, char* string); static int ffmpeg_type = 0; static int ffmpeg_codec = CODEC_ID_MPEG4; @@ -100,7 +100,7 @@ static int audio_input_frame_size = 0; static uint8_t* audio_output_buffer = 0; static int audio_outbuf_size = 0; -static RenderData *ffmpeg_renderdata = 0; +static AUD_Device* audio_mixdown_device = 0; #define FFMPEG_AUTOSPLIT_SIZE 2000000000 @@ -133,9 +133,8 @@ static int write_audio_frame(void) c = get_codec_from_stream(audio_stream); - audiostream_fill(audio_input_buffer, - audio_input_frame_size - * sizeof(short) * c->channels); + if(audio_mixdown_device) + AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_frame_size); av_init_packet(&pkt); @@ -154,7 +153,7 @@ static int write_audio_frame(void) pkt.stream_index = audio_stream->index; pkt.flags |= PKT_FLAG_KEY; if (av_interleaved_write_frame(outfile, &pkt) != 0) { - error("Error writing audio packet"); + //XXX error("Error writing audio packet"); return -1; } return 0; @@ -240,16 +239,16 @@ static const char** get_file_extensions(int format) } /* Write a frame to the output file */ -static void write_video_frame(AVFrame* frame) +static void write_video_frame(RenderData *rd, AVFrame* frame) { int outsize = 0; int ret; AVCodecContext* c = get_codec_from_stream(video_stream); #ifdef FFMPEG_CODEC_TIME_BASE - frame->pts = G.scene->r.cfra - G.scene->r.sfra; + frame->pts = rd->cfra - rd->sfra; #endif - if (G.scene->r.mode & R_FIELDS) { - frame->top_field_first = ((G.scene->r.mode & R_ODDFIELD) != 0); + if (rd->mode & R_FIELDS) { + frame->top_field_first = ((rd->mode & R_ODDFIELD) != 0); } outsize = avcodec_encode_video(c, video_buffer, video_buffersize, @@ -279,7 +278,7 @@ static void write_video_frame(AVFrame* frame) } else ret = 0; if (ret != 0) { G.afbreek = 1; - error("Error writing frame"); + //XXX error("Error writing frame"); } } @@ -297,7 +296,7 @@ static AVFrame* generate_video_frame(uint8_t* pixels) rgb_frame = alloc_picture(PIX_FMT_BGR32, width, height); if (!rgb_frame) { G.afbreek=1; - error("Couldn't allocate temporary frame"); + //XXX error("Couldn't allocate temporary frame"); return NULL; } } else { @@ -309,7 +308,7 @@ static AVFrame* generate_video_frame(uint8_t* pixels) /* Do RGBA-conversion and flipping in one step depending on CPU-Endianess */ - if (G.order == L_ENDIAN) { + if (ENDIAN_ORDER == L_ENDIAN) { int y; for (y = 0; y < height; y++) { uint8_t* target = rgb_frame->data[0] @@ -400,18 +399,18 @@ static void set_ffmpeg_property_option(AVCodecContext* c, IDProperty * prop) } } -static void set_ffmpeg_properties(AVCodecContext* c, const char * prop_name) +static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char * prop_name) { IDProperty * prop; void * iter; IDProperty * curr; - if (!G.scene->r.ffcodecdata.properties) { + if (!rd->ffcodecdata.properties) { return; } prop = IDP_GetPropertyFromGroup( - G.scene->r.ffcodecdata.properties, (char*) prop_name); + rd->ffcodecdata.properties, (char*) prop_name); if (!prop) { return; } @@ -425,7 +424,7 @@ static void set_ffmpeg_properties(AVCodecContext* c, const char * prop_name) /* prepare a video stream for the output file */ -static AVStream* alloc_video_stream(int codec_id, AVFormatContext* of, +static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContext* of, int rectx, int recty) { AVStream* st; @@ -448,39 +447,39 @@ static AVStream* alloc_video_stream(int codec_id, AVFormatContext* of, #ifdef FFMPEG_CODEC_TIME_BASE /* FIXME: Really bad hack (tm) for NTSC support */ - if (ffmpeg_type == FFMPEG_DV && G.scene->r.frs_sec != 25) { + if (ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) { c->time_base.den = 2997; c->time_base.num = 100; - } else if ((double) ((int) G.scene->r.frs_sec_base) == - G.scene->r.frs_sec_base) { - c->time_base.den = G.scene->r.frs_sec; - c->time_base.num = (int) G.scene->r.frs_sec_base; + } else if ((double) ((int) rd->frs_sec_base) == + rd->frs_sec_base) { + c->time_base.den = rd->frs_sec; + c->time_base.num = (int) rd->frs_sec_base; } else { - c->time_base.den = G.scene->r.frs_sec * 100000; - c->time_base.num = ((double) G.scene->r.frs_sec_base) * 100000; + c->time_base.den = rd->frs_sec * 100000; + c->time_base.num = ((double) rd->frs_sec_base) * 100000; } #else /* FIXME: Really bad hack (tm) for NTSC support */ - if (ffmpeg_type == FFMPEG_DV && G.scene->r.frs_sec != 25) { + if (ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) { c->frame_rate = 2997; c->frame_rate_base = 100; - } else if ((double) ((int) G.scene->r.frs_sec_base) == - G.scene->r.frs_sec_base) { - c->frame_rate = G.scene->r.frs_sec; - c->frame_rate_base = G.scene->r.frs_sec_base; + } else if ((double) ((int) rd->frs_sec_base) == + rd->frs_sec_base) { + c->frame_rate = rd->frs_sec; + c->frame_rate_base = rd->frs_sec_base; } else { - c->frame_rate = G.scene->r.frs_sec * 100000; - c->frame_rate_base = ((double) G.scene->r.frs_sec_base)*100000; + c->frame_rate = rd->frs_sec * 100000; + c->frame_rate_base = ((double) rd->frs_sec_base)*100000; } #endif c->gop_size = ffmpeg_gop_size; c->bit_rate = ffmpeg_video_bitrate*1000; - c->rc_max_rate = G.scene->r.ffcodecdata.rc_max_rate*1000; - c->rc_min_rate = G.scene->r.ffcodecdata.rc_min_rate*1000; - c->rc_buffer_size = G.scene->r.ffcodecdata.rc_buffer_size * 1024; + c->rc_max_rate = rd->ffcodecdata.rc_max_rate*1000; + c->rc_min_rate = rd->ffcodecdata.rc_min_rate*1000; + c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024; c->rc_initial_buffer_occupancy - = G.scene->r.ffcodecdata.rc_buffer_size*3/4; + = rd->ffcodecdata.rc_buffer_size*3/4; c->rc_buffer_aggressivity = 1.0; c->me_method = ME_EPZS; @@ -511,7 +510,7 @@ static AVStream* alloc_video_stream(int codec_id, AVFormatContext* of, } /* Determine whether we are encoding interlaced material or not */ - if (G.scene->r.mode & R_FIELDS) { + if (rd->mode & R_FIELDS) { fprintf(stderr, "Encoding interlaced video\n"); c->flags |= CODEC_FLAG_INTERLACED_DCT; c->flags |= CODEC_FLAG_INTERLACED_ME; @@ -520,12 +519,13 @@ static AVStream* alloc_video_stream(int codec_id, AVFormatContext* of, /* xasp & yasp got float lately... */ st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q( - ((double) G.scene->r.xasp / (double) G.scene->r.yasp), 255); + ((double) rd->xasp / (double) rd->yasp), 255); - set_ffmpeg_properties(c, "video"); + set_ffmpeg_properties(rd, c, "video"); if (avcodec_open(c, codec) < 0) { - error("Couldn't initialize codec"); + // + //XXX error("Couldn't initialize codec"); return NULL; } @@ -546,7 +546,7 @@ static AVStream* alloc_video_stream(int codec_id, AVFormatContext* of, /* Prepare an audio stream for the output file */ -static AVStream* alloc_audio_stream(int codec_id, AVFormatContext* of) +static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext* of) { AVStream* st; AVCodecContext* c; @@ -559,19 +559,19 @@ static AVStream* alloc_audio_stream(int codec_id, AVFormatContext* of) c->codec_id = codec_id; c->codec_type = CODEC_TYPE_AUDIO; - c->sample_rate = G.scene->audio.mixrate; + c->sample_rate = rd->audio.mixrate; c->bit_rate = ffmpeg_audio_bitrate*1000; c->channels = 2; codec = avcodec_find_encoder(c->codec_id); if (!codec) { - error("Couldn't find a valid audio codec"); + //XXX error("Couldn't find a valid audio codec"); return NULL; } - set_ffmpeg_properties(c, "audio"); + set_ffmpeg_properties(rd, c, "audio"); if (avcodec_open(c, codec) < 0) { - error("Couldn't initialize audio codec"); + //XXX error("Couldn't initialize audio codec"); return NULL; } @@ -635,7 +635,7 @@ void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) do_init_ffmpeg(); /* Determine the correct filename */ - makeffmpegstring(name); + makeffmpegstring(rd, name); fprintf(stderr, "Starting output to %s(ffmpeg)...\n" " Using type=%d, codec=%d, audio_codec=%d,\n" " video_bitrate=%d, audio_bitrate=%d,\n" @@ -649,27 +649,27 @@ void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) exts = get_file_extensions(ffmpeg_type); if (!exts) { G.afbreek = 1; /* Abort render */ - error("No valid formats found"); + //XXX error("No valid formats found"); return; } fmt = guess_format(NULL, exts[0], NULL); if (!fmt) { G.afbreek = 1; /* Abort render */ - error("No valid formats found"); + //XXX error("No valid formats found"); return; } of = av_alloc_format_context(); if (!of) { G.afbreek = 1; - error("Error opening output file"); + //XXX error("Error opening output file"); return; } of->oformat = fmt; - of->packet_size= G.scene->r.ffcodecdata.mux_packet_size; + of->packet_size= rd->ffcodecdata.mux_packet_size; if (ffmpeg_multiplex_audio) { - of->mux_rate = G.scene->r.ffcodecdata.mux_rate; + of->mux_rate = rd->ffcodecdata.mux_rate; } else { of->mux_rate = 0; } @@ -712,20 +712,20 @@ void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) if (fmt->video_codec == CODEC_ID_DVVIDEO) { if (rectx != 720) { G.afbreek = 1; - error("Render width has to be 720 pixels for DV!"); + //XXX error("Render width has to be 720 pixels for DV!"); return; } - if (G.scene->r.frs_sec != 25 && recty != 480) { + if (rd->frs_sec != 25 && recty != 480) { G.afbreek = 1; - error("Render height has to be 480 pixels " - "for DV-NTSC!"); + //XXX error("Render height has to be 480 pixels " + // "for DV-NTSC!"); return; } - if (G.scene->r.frs_sec == 25 && recty != 576) { + if (rd->frs_sec == 25 && recty != 576) { G.afbreek = 1; - error("Render height has to be 576 pixels " - "for DV-PAL!"); + //XXX error("Render height has to be 576 pixels " + // "for DV-PAL!"); return; } } @@ -734,40 +734,40 @@ void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) if (ffmpeg_type == FFMPEG_DV) { fmt->audio_codec = CODEC_ID_PCM_S16LE; - if (ffmpeg_multiplex_audio - && G.scene->audio.mixrate != 48000) { + if (ffmpeg_multiplex_audio && rd->audio.mixrate != 48000) { G.afbreek = 1; - error("FFMPEG only supports 48khz / stereo " - "audio for DV!"); + //XXX error("FFMPEG only supports 48khz / stereo " + // "audio for DV!"); return; } } - video_stream = alloc_video_stream(fmt->video_codec, of, rectx, recty); + video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty); if (!video_stream) { G.afbreek = 1; - error("Error initializing video stream"); + //XXX error("Error initializing video stream"); return; } if (ffmpeg_multiplex_audio) { - audio_stream = alloc_audio_stream(fmt->audio_codec, of); + audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of); if (!audio_stream) { G.afbreek = 1; - error("Error initializing audio stream"); + //XXX error("Error initializing audio stream"); return; } - audiostream_play(SFRA, 0, 1); + //XXX audiostream_play(SFRA, 0, 1); } if (av_set_parameters(of, NULL) < 0) { G.afbreek = 1; - error("Error setting output parameters"); + //XXX error("Error setting output parameters"); return; } if (!(fmt->flags & AVFMT_NOFILE)) { if (url_fopen(&of->pb, name, URL_WRONLY) < 0) { G.afbreek = 1; - error("Could not open file for writing"); + // + //XXX error("Could not open file for writing"); return; } } @@ -782,25 +782,32 @@ void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty) ********************************************************************** */ /* Get the output filename-- similar to the other output formats */ -void makeffmpegstring(char* string) { - +static void makeffmpegstring(RenderData* rd, char* string) { + + // XXX quick define, solve! +#define FILE_MAXDIR 256 +#define FILE_MAXFILE 126 + char txt[FILE_MAXDIR+FILE_MAXFILE]; + // XXX +#undef FILE_MAXDIR +#undef FILE_MAXFILE char autosplit[20]; - const char ** exts = get_file_extensions(G.scene->r.ffcodecdata.type); + const char ** exts = get_file_extensions(rd->ffcodecdata.type); const char ** fe = exts; if (!string || !exts) return; - strcpy(string, G.scene->r.pic); + strcpy(string, rd->pic); BLI_convertstringcode(string, G.sce); - BLI_convertstringframe(string, G.scene->r.cfra); + BLI_convertstringframe(string, rd->cfra); BLI_make_existing_file(string); autosplit[0] = 0; - if ((G.scene->r.ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) { + if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) { sprintf(autosplit, "_%03d", ffmpeg_autosplit_count); } @@ -814,8 +821,8 @@ void makeffmpegstring(char* string) { if (!*fe) { strcat(string, autosplit); - sprintf(txt, "%04d_%04d%s", (G.scene->r.sfra), - (G.scene->r.efra), *exts); + sprintf(txt, "%04d_%04d%s", (rd->sfra), + (rd->efra), *exts); strcat(string, txt); } else { *(string + strlen(string) - strlen(*fe)) = 0; @@ -825,13 +832,21 @@ void makeffmpegstring(char* string) { } -void start_ffmpeg(RenderData *rd, int rectx, int recty) +void start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty) { ffmpeg_autosplit_count = 0; - ffmpeg_renderdata = rd; - start_ffmpeg_impl(rd, rectx, recty); + + if(ffmpeg_multiplex_audio && audio_stream) + { + AVCodecContext* c = get_codec_from_stream(audio_stream); + AUD_Specs specs; + specs.channels = c->channels; + specs.format = AUD_FORMAT_S16; + specs.rate = rd->audio.mixrate; + audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->efra); + } } void end_ffmpeg(void); @@ -856,21 +871,20 @@ static void write_audio_frames() } } -void append_ffmpeg(int frame, int *pixels, int rectx, int recty) +void append_ffmpeg(RenderData *rd, int frame, int *pixels, int rectx, int recty) { fprintf(stderr, "Writing frame %i, " "render width=%d, render height=%d\n", frame, rectx, recty); write_audio_frames(); - write_video_frame(generate_video_frame((unsigned char*) pixels)); + write_video_frame(rd, generate_video_frame((unsigned char*) pixels)); if (ffmpeg_autosplit) { if (url_ftell(OUTFILE_PB) > FFMPEG_AUTOSPLIT_SIZE) { end_ffmpeg(); ffmpeg_autosplit_count++; - start_ffmpeg_impl(ffmpeg_renderdata, - rectx, recty); + start_ffmpeg_impl(rd, rectx, recty); } } } @@ -885,6 +899,12 @@ void end_ffmpeg(void) if (audio_stream && video_stream) { write_audio_frames(); } + + if(audio_mixdown_device) + { + AUD_closeReadDevice(audio_mixdown_device); + audio_mixdown_device = 0; + } if (outfile) { av_write_trailer(outfile); @@ -938,5 +958,322 @@ void end_ffmpeg(void) img_convert_ctx = 0; } } + +/* properties */ + +void ffmpeg_property_del(RenderData *rd, void *type, void *prop_) +{ + struct IDProperty *prop = (struct IDProperty *) prop_; + IDProperty * group; + + if (!rd->ffcodecdata.properties) { + return; + } + + group = IDP_GetPropertyFromGroup( + rd->ffcodecdata.properties, (char*) type); + if (group && prop) { + IDP_RemFromGroup(group, prop); + IDP_FreeProperty(prop); + MEM_freeN(prop); + } +} + +IDProperty *ffmpeg_property_add(RenderData *rd, char * type, int opt_index, int parent_index) +{ + AVCodecContext c; + const AVOption * o; + const AVOption * parent; + IDProperty * group; + IDProperty * prop; + IDPropertyTemplate val; + int idp_type; + char name[256]; + + avcodec_get_context_defaults(&c); + + o = c.av_class->option + opt_index; + parent = c.av_class->option + parent_index; + + if (!rd->ffcodecdata.properties) { + IDPropertyTemplate val; + + rd->ffcodecdata.properties + = IDP_New(IDP_GROUP, val, "ffmpeg"); + } + + group = IDP_GetPropertyFromGroup( + rd->ffcodecdata.properties, (char*) type); + + if (!group) { + IDPropertyTemplate val; + + group = IDP_New(IDP_GROUP, val, (char*) type); + IDP_AddToGroup(rd->ffcodecdata.properties, group); + } + + if (parent_index) { + sprintf(name, "%s:%s", parent->name, o->name); + } else { + strcpy(name, o->name); + } + + fprintf(stderr, "ffmpeg_property_add: %s %d %d %s\n", + type, parent_index, opt_index, name); + + prop = IDP_GetPropertyFromGroup(group, name); + if (prop) { + return prop; + } + + switch (o->type) { + case FF_OPT_TYPE_INT: + case FF_OPT_TYPE_INT64: + val.i = o->default_val; + idp_type = IDP_INT; + break; + case FF_OPT_TYPE_DOUBLE: + case FF_OPT_TYPE_FLOAT: + val.f = o->default_val; + idp_type = IDP_FLOAT; + break; + case FF_OPT_TYPE_STRING: + val.str = " "; + idp_type = IDP_STRING; + break; + case FF_OPT_TYPE_CONST: + val.i = 1; + idp_type = IDP_INT; + break; + default: + return NULL; + } + prop = IDP_New(idp_type, val, name); + IDP_AddToGroup(group, prop); + return prop; +} + +/* not all versions of ffmpeg include that, so here we go ... */ + +static const AVOption *my_av_find_opt(void *v, const char *name, + const char *unit, int mask, int flags){ + AVClass *c= *(AVClass**)v; + const AVOption *o= c->option; + + for(;o && o->name; o++){ + if(!strcmp(o->name, name) && + (!unit || (o->unit && !strcmp(o->unit, unit))) && + (o->flags & mask) == flags ) + return o; + } + return NULL; +} + +int ffmpeg_property_add_string(RenderData *rd, const char * type, const char * str) +{ + AVCodecContext c; + const AVOption * o = 0; + const AVOption * p = 0; + char name_[128]; + char * name; + char * param; + IDProperty * prop; + + avcodec_get_context_defaults(&c); + + strncpy(name_, str, 128); + + name = name_; + while (*name == ' ') name++; + + param = strchr(name, ':'); + + if (!param) { + param = strchr(name, ' '); + } + if (param) { + *param++ = 0; + while (*param == ' ') param++; + } + + o = my_av_find_opt(&c, name, NULL, 0, 0); + if (!o) { + return 0; + } + if (param && o->type == FF_OPT_TYPE_CONST) { + return 0; + } + if (param && o->type != FF_OPT_TYPE_CONST && o->unit) { + p = my_av_find_opt(&c, param, o->unit, 0, 0); + prop = ffmpeg_property_add(rd, + (char*) type, p - c.av_class->option, + o - c.av_class->option); + } else { + prop = ffmpeg_property_add(rd, + (char*) type, o - c.av_class->option, 0); + } + + + if (!prop) { + return 0; + } + + if (param && !p) { + switch (prop->type) { + case IDP_INT: + IDP_Int(prop) = atoi(param); + break; + case IDP_FLOAT: + IDP_Float(prop) = atof(param); + break; + case IDP_STRING: + strncpy(IDP_String(prop), param, prop->len); + break; + } + } + return 1; +} + +void ffmpeg_set_preset(RenderData *rd, int preset) +{ + int isntsc = (rd->frs_sec != 25); + + switch (preset) { + case FFMPEG_PRESET_VCD: + rd->ffcodecdata.type = FFMPEG_MPEG1; + rd->ffcodecdata.video_bitrate = 1150; + rd->xsch = 352; + rd->ysch = isntsc ? 240 : 288; + rd->ffcodecdata.gop_size = isntsc ? 18 : 15; + rd->ffcodecdata.rc_max_rate = 1150; + rd->ffcodecdata.rc_min_rate = 1150; + rd->ffcodecdata.rc_buffer_size = 40*8; + rd->ffcodecdata.mux_packet_size = 2324; + rd->ffcodecdata.mux_rate = 2352 * 75 * 8; + break; + + case FFMPEG_PRESET_SVCD: + rd->ffcodecdata.type = FFMPEG_MPEG2; + rd->ffcodecdata.video_bitrate = 2040; + rd->xsch = 480; + rd->ysch = isntsc ? 480 : 576; + rd->ffcodecdata.gop_size = isntsc ? 18 : 15; + rd->ffcodecdata.rc_max_rate = 2516; + rd->ffcodecdata.rc_min_rate = 0; + rd->ffcodecdata.rc_buffer_size = 224*8; + rd->ffcodecdata.mux_packet_size = 2324; + rd->ffcodecdata.mux_rate = 0; + break; + + case FFMPEG_PRESET_DVD: + rd->ffcodecdata.type = FFMPEG_MPEG2; + rd->ffcodecdata.video_bitrate = 6000; + rd->xsch = 720; + rd->ysch = isntsc ? 480 : 576; + rd->ffcodecdata.gop_size = isntsc ? 18 : 15; + rd->ffcodecdata.rc_max_rate = 9000; + rd->ffcodecdata.rc_min_rate = 0; + rd->ffcodecdata.rc_buffer_size = 224*8; + rd->ffcodecdata.mux_packet_size = 2048; + rd->ffcodecdata.mux_rate = 10080000; + break; + + case FFMPEG_PRESET_DV: + rd->ffcodecdata.type = FFMPEG_DV; + rd->xsch = 720; + rd->ysch = isntsc ? 480 : 576; + break; + + case FFMPEG_PRESET_H264: + rd->ffcodecdata.type = FFMPEG_AVI; + rd->ffcodecdata.codec = CODEC_ID_H264; + rd->ffcodecdata.video_bitrate = 6000; + rd->ffcodecdata.gop_size = isntsc ? 18 : 15; + rd->ffcodecdata.rc_max_rate = 9000; + rd->ffcodecdata.rc_min_rate = 0; + rd->ffcodecdata.rc_buffer_size = 224*8; + rd->ffcodecdata.mux_packet_size = 2048; + rd->ffcodecdata.mux_rate = 10080000; + + ffmpeg_property_add_string(rd, "video", "coder:vlc"); + ffmpeg_property_add_string(rd, "video", "flags:loop"); + ffmpeg_property_add_string(rd, "video", "cmp:chroma"); + ffmpeg_property_add_string(rd, "video", "partitions:parti4x4"); + ffmpeg_property_add_string(rd, "video", "partitions:partp8x8"); + ffmpeg_property_add_string(rd, "video", "partitions:partb8x8"); + ffmpeg_property_add_string(rd, "video", "me:hex"); + ffmpeg_property_add_string(rd, "video", "subq:5"); + ffmpeg_property_add_string(rd, "video", "me_range:16"); + ffmpeg_property_add_string(rd, "video", "keyint_min:25"); + ffmpeg_property_add_string(rd, "video", "sc_threshold:40"); + ffmpeg_property_add_string(rd, "video", "i_qfactor:0.71"); + ffmpeg_property_add_string(rd, "video", "b_strategy:1"); + + break; + + case FFMPEG_PRESET_THEORA: + case FFMPEG_PRESET_XVID: + if(preset == FFMPEG_PRESET_XVID) { + rd->ffcodecdata.type = FFMPEG_AVI; + rd->ffcodecdata.codec = CODEC_ID_XVID; + } + else if(preset == FFMPEG_PRESET_THEORA) { + rd->ffcodecdata.type = FFMPEG_OGG; // XXX broken + rd->ffcodecdata.codec = CODEC_ID_THEORA; + } + + rd->ffcodecdata.video_bitrate = 6000; + rd->ffcodecdata.gop_size = isntsc ? 18 : 15; + rd->ffcodecdata.rc_max_rate = 9000; + rd->ffcodecdata.rc_min_rate = 0; + rd->ffcodecdata.rc_buffer_size = 224*8; + rd->ffcodecdata.mux_packet_size = 2048; + rd->ffcodecdata.mux_rate = 10080000; + break; + + } +} + +void ffmpeg_verify_image_type(RenderData *rd) +{ + int audio= 0; + + if(rd->imtype == R_FFMPEG) { + if(rd->ffcodecdata.type <= 0 || + rd->ffcodecdata.codec <= 0 || + rd->ffcodecdata.audio_codec <= 0 || + rd->ffcodecdata.video_bitrate <= 1) { + + rd->ffcodecdata.codec = CODEC_ID_MPEG2VIDEO; + ffmpeg_set_preset(rd, FFMPEG_PRESET_DVD); + } + + audio= 1; + } + else if(rd->imtype == R_H264) { + if(rd->ffcodecdata.codec != CODEC_ID_H264) { + ffmpeg_set_preset(rd, FFMPEG_PRESET_H264); + audio= 1; + } + } + else if(rd->imtype == R_XVID) { + if(rd->ffcodecdata.codec != CODEC_ID_XVID) { + ffmpeg_set_preset(rd, FFMPEG_PRESET_XVID); + audio= 1; + } + } + else if(rd->imtype == R_THEORA) { + if(rd->ffcodecdata.codec != CODEC_ID_THEORA) { + ffmpeg_set_preset(rd, FFMPEG_PRESET_THEORA); + audio= 1; + } + } + + if(audio && rd->ffcodecdata.audio_codec <= 0) { + rd->ffcodecdata.audio_codec = CODEC_ID_MP2; + rd->ffcodecdata.audio_bitrate = 128; + } +} + #endif diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c index 40e1dc1bb03..0780cd0dc48 100644 --- a/source/blender/blenkernel/intern/writeframeserver.c +++ b/source/blender/blenkernel/intern/writeframeserver.c @@ -47,14 +47,12 @@ #include "BLI_blenlib.h" #include "DNA_userdef_types.h" -#include "BKE_bad_level_calls.h" #include "BKE_global.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "DNA_scene_types.h" -#include "blendef.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -103,21 +101,21 @@ static int closesocket(int fd) } #endif -void start_frameserver(RenderData *rd, int rectx, int recty) +void start_frameserver(struct Scene *scene, RenderData *rd, int rectx, int recty) { struct sockaddr_in addr; int arg = 1; if (!startup_socket_system()) { G.afbreek = 1; - error("Can't startup socket system"); + //XXX error("Can't startup socket system"); return; } if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { shutdown_socket_system(); G.afbreek = 1; /* Abort render */ - error("Can't open socket"); + //XXX error("Can't open socket"); return; } @@ -131,14 +129,14 @@ void start_frameserver(RenderData *rd, int rectx, int recty) if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { shutdown_socket_system(); G.afbreek = 1; /* Abort render */ - error("Can't bind to socket"); + //XXX error("Can't bind to socket"); return; } if (listen(sock, SOMAXCONN) < 0) { shutdown_socket_system(); G.afbreek = 1; /* Abort render */ - error("Can't establish listen backlog"); + //XXX error("Can't establish listen backlog"); return; } connsock = -1; @@ -190,7 +188,7 @@ static int safe_puts(char * s) return safe_write(s, strlen(s)); } -static int handle_request(char * req) +static int handle_request(RenderData *rd, char * req) { char * p; char * path; @@ -232,11 +230,11 @@ static int handle_request(char * req) "height %d\n" "rate %d\n" "ratescale %d\n", - G.scene->r.sfra, - G.scene->r.efra, + rd->sfra, + rd->efra, render_width, render_height, - G.scene->r.frs_sec, + rd->frs_sec, 1 ); @@ -251,7 +249,7 @@ static int handle_request(char * req) return -1; } -int frameserver_loop(void) +int frameserver_loop(RenderData *rd) { fd_set readfds; struct timeval tv; @@ -314,7 +312,7 @@ int frameserver_loop(void) buf[len] = 0; - return handle_request(buf); + return handle_request(rd, buf); } static void serve_ppm(int *pixels, int rectx, int recty) @@ -357,7 +355,7 @@ static void serve_ppm(int *pixels, int rectx, int recty) connsock = -1; } -void append_frameserver(int frame, int *pixels, int rectx, int recty) +void append_frameserver(RenderData *rd, int frame, int *pixels, int rectx, int recty) { fprintf(stderr, "Serving frame: %d\n", frame); if (write_ppm) { diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h new file mode 100644 index 00000000000..325798f325f --- /dev/null +++ b/source/blender/blenkernel/nla_private.h @@ -0,0 +1,85 @@ +/** + * $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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joshua Leung (full recode) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef NLA_PRIVATE +#define NLA_PRIVATE + +/* --------------- NLA Evaluation DataTypes ----------------------- */ + +/* used for list of strips to accumulate at current time */ +typedef struct NlaEvalStrip { + struct NlaEvalStrip *next, *prev; + + NlaTrack *track; /* track that this strip belongs to */ + NlaStrip *strip; /* strip that's being used */ + + short track_index; /* the index of the track within the list */ + short strip_mode; /* which end of the strip are we looking at */ + + float strip_time; /* time at which which strip is being evaluated */ +} NlaEvalStrip; + +/* NlaEvalStrip->strip_mode */ +enum { + /* standard evaluation */ + NES_TIME_BEFORE = -1, + NES_TIME_WITHIN, + NES_TIME_AFTER, + + /* transition-strip evaluations */ + NES_TIME_TRANSITION_START, + NES_TIME_TRANSITION_END, +} eNlaEvalStrip_StripMode; + + +/* temp channel for accumulating data from NLA (avoids needing to clear all values first) */ +// TODO: maybe this will be used as the 'cache' stuff needed for editable values too? +typedef struct NlaEvalChannel { + struct NlaEvalChannel *next, *prev; + + PointerRNA ptr; /* pointer to struct containing property to use */ + PropertyRNA *prop; /* RNA-property type to use (should be in the struct given) */ + int index; /* array index (where applicable) */ + + float value; /* value of this channel */ +} NlaEvalChannel; + +/* --------------- NLA Functions (not to be used as a proper API) ----------------------- */ + +/* convert from strip time <-> global time */ +float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode); + +/* --------------- NLA Evaluation (very-private stuff) ----------------------- */ +/* these functions are only defined here to avoid problems with the order in which they get defined... */ + +NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime); +void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes); +void nladata_flush_channels(ListBase *channels); + +#endif // NLA_PRIVATE |