diff options
Diffstat (limited to 'source/blender')
200 files changed, 39183 insertions, 16960 deletions
diff --git a/source/blender/SConscript b/source/blender/SConscript index a064850c170..cce0354643b 100644 --- a/source/blender/SConscript +++ b/source/blender/SConscript @@ -3,6 +3,7 @@ Import ('env') import sys SConscript(['avi/SConscript', + 'bmesh/SConscript', 'blenkernel/SConscript', 'blenlib/SConscript', 'blenloader/SConscript', diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 06103596be1..bb50056b7f2 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -43,6 +43,8 @@ */ #include "DNA_customdata_types.h" +#include "DNA_meshdata_types.h" + #include "BKE_customdata.h" #include "BKE_bvhutils.h" @@ -53,43 +55,87 @@ struct MTFace; struct Object; struct Scene; struct Mesh; -struct EditMesh; +struct BMEditMesh; struct ModifierData; struct MCol; struct ColorBand; struct GPUVertexAttribs; +struct BMEditMesh; /* number of sub-elements each mesh element has (for interpolation) */ #define SUB_ELEMS_VERT 0 #define SUB_ELEMS_EDGE 2 -#define SUB_ELEMS_FACE 4 +#define SUB_ELEMS_FACE 50 + +/* +note: all mface interfaces now officially operate on tesselated data. +*/ + +/*DM Iterators. For now, first implement face iterators. + These are read-only, at least for now.*/ + +typedef struct DMLoopIter { + void (*step)(void *self); + int done; + + int index, vindex, eindex; + MVert v; /*copy of the associated vert's data*/ + + /*note: if layer is -1, then the active layer is retrieved. + loop refers to per-face-vertex data.*/ + void *(*getLoopCDData)(void *self, int type, int layer); + void *(*getVertCDData)(void *self, int type, int layer); +} DMLoopIter; + +typedef struct DMFaceIter { + void (*step)(void *self); + void (*free)(void *self); + int done; + + int index; + int len; + int mat_nr; + int flags; + + /*note: you may only use one + loop iterator at a time.*/ + DMLoopIter *(*getLoopsIter)(void *self); + + /*if layer is -1, returns active layer*/ + void *(*getCDData)(void *self, int type, int layer); +} DMFaceIter; typedef struct DerivedMesh DerivedMesh; struct DerivedMesh { /* Private DerivedMesh data, only for internal DerivedMesh use */ - CustomData vertData, edgeData, faceData; - int numVertData, numEdgeData, numFaceData; + CustomData vertData, edgeData, faceData, loopData, polyData; + int numVertData, numEdgeData, numFaceData, numLoopData, numPolyData; int needsFree; /* checked on ->release, is set to 0 for cached results */ int deformedOnly; /* set by modifier stack if only deformed from original */ BVHCache bvhCache; /* Misc. Queries */ + + /*face iterator. initializes iter.*/ + DMFaceIter *(*newFaceIter)(DerivedMesh *dm); + + /*recalculates mesh tesselation*/ + void (*recalcTesselation)(DerivedMesh *dm); /* Also called in Editmode */ int (*getNumVerts)(DerivedMesh *dm); - /* Also called in Editmode */ - int (*getNumFaces)(DerivedMesh *dm); - int (*getNumEdges)(DerivedMesh *dm); + int (*getNumTessFaces)(DerivedMesh *dm); + int (*getNumFaces) (DerivedMesh *dm); - /* copy a single vert/edge/face from the derived mesh into + /* copy a single vert/edge/tesselated 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) */ void (*getVert)(DerivedMesh *dm, int index, struct MVert *vert_r); void (*getEdge)(DerivedMesh *dm, int index, struct MEdge *edge_r); - void (*getFace)(DerivedMesh *dm, int index, struct MFace *face_r); + void (*getTessFace)(DerivedMesh *dm, int index, struct MFace *face_r); /* return a pointer to the entire array of verts/edges/face from the * derived mesh. if such an array does not exist yet, it will be created, @@ -98,21 +144,21 @@ struct DerivedMesh { */ struct MVert *(*getVertArray)(DerivedMesh *dm); struct MEdge *(*getEdgeArray)(DerivedMesh *dm); - struct MFace *(*getFaceArray)(DerivedMesh *dm); + struct MFace *(*getTessFaceArray)(DerivedMesh *dm); /* copy all verts/edges/faces from the derived mesh into * *{vert/edge/face}_r (must point to a buffer large enough) */ void (*copyVertArray)(DerivedMesh *dm, struct MVert *vert_r); void (*copyEdgeArray)(DerivedMesh *dm, struct MEdge *edge_r); - void (*copyFaceArray)(DerivedMesh *dm, struct MFace *face_r); + void (*copyTessFaceArray)(DerivedMesh *dm, struct MFace *face_r); /* return a copy of all verts/edges/faces from the derived mesh * it is the caller's responsibility to free the returned pointer */ struct MVert *(*dupVertArray)(DerivedMesh *dm); struct MEdge *(*dupEdgeArray)(DerivedMesh *dm); - struct MFace *(*dupFaceArray)(DerivedMesh *dm); + struct MFace *(*dupTessFaceArray)(DerivedMesh *dm); /* return a pointer to a single element of vert/edge/face custom data * from the derived mesh (this gives a pointer to the actual data, not @@ -120,7 +166,7 @@ struct DerivedMesh { */ void *(*getVertData)(DerivedMesh *dm, int index, int type); void *(*getEdgeData)(DerivedMesh *dm, int index, int type); - void *(*getFaceData)(DerivedMesh *dm, int index, int type); + void *(*getTessFaceData)(DerivedMesh *dm, int index, int type); /* return a pointer to the entire array of vert/edge/face custom data * from the derived mesh (this gives a pointer to the actual data, not @@ -128,7 +174,20 @@ struct DerivedMesh { */ void *(*getVertDataArray)(DerivedMesh *dm, int type); void *(*getEdgeDataArray)(DerivedMesh *dm, int type); - void *(*getFaceDataArray)(DerivedMesh *dm, int type); + void *(*getTessFaceDataArray)(DerivedMesh *dm, int type); + + /*retrieves the base CustomData structures for + verts/edges/tessfaces/loops/facdes*/ + CustomData *(*getVertDataLayout)(DerivedMesh *dm); + CustomData *(*getEdgeDataLayout)(DerivedMesh *dm); + CustomData *(*getTessFaceDataLayout)(DerivedMesh *dm); + CustomData *(*getLoopDataLayout)(DerivedMesh *dm); + CustomData *(*getFaceDataLayout)(DerivedMesh *dm); + + /*copies all customdata for an element source into dst at index dest*/ + void (*copyFromVertCData)(DerivedMesh *dm, int source, CustomData *dst, int dest); + void (*copyFromEdgeCData)(DerivedMesh *dm, int source, CustomData *dst, int dest); + void (*copyFromFaceCData)(DerivedMesh *dm, int source, CustomData *dst, int dest); /* Iterate over each mapped vertex in the derived mesh, calling the * given function with the original vert and the mapped vert's new @@ -299,13 +358,15 @@ void DM_init_funcs(DerivedMesh *dm); * of vertices, edges and faces (doesn't allocate memory for them, just * sets up the custom data layers) */ -void DM_init(DerivedMesh *dm, int numVerts, int numEdges, int numFaces); +void DM_init(DerivedMesh *dm, int numVerts, int numEdges, int numFaces, + int numLoops, int numPolys); /* utility function to initialise a DerivedMesh for the desired number * of vertices, edges and faces, with a layer setup copied from source */ void DM_from_template(DerivedMesh *dm, DerivedMesh *source, - int numVerts, int numEdges, int numFaces); + int numVerts, int numEdges, int numFaces, + int numLoops, int numPolys); /* utility function to release a DerivedMesh's layers * returns 1 if DerivedMesh has to be released by the backend, 0 otherwise @@ -368,6 +429,10 @@ void DM_copy_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest, int source_index, int dest_index, int count); void DM_copy_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest, int source_index, int dest_index, int count); +void DM_copy_tessface_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int source_index, int dest_index, int count); +void DM_copy_loop_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int source_index, int dest_index, int count); void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest, int source_index, int dest_index, int count); @@ -377,8 +442,13 @@ void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest, */ void DM_free_vert_data(struct DerivedMesh *dm, int index, int count); void DM_free_edge_data(struct DerivedMesh *dm, int index, int count); +void DM_free_tessface_data(struct DerivedMesh *dm, int index, int count); +void DM_free_loop_data(struct DerivedMesh *dm, int index, int count); void DM_free_face_data(struct DerivedMesh *dm, int index, int count); +/*sets up mpolys for a DM based on face iterators in source*/ +void DM_DupPolys(DerivedMesh *source, DerivedMesh *target); + /* interpolates vertex data from the vertices indexed by src_indices in the * source mesh using the given weights and stores the result in the vertex * indexed by dest_index in the dest mesh @@ -408,12 +478,20 @@ void DM_interp_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest, * vert_weights[i] multiplied by weights[i]. */ typedef float FaceVertWeight[SUB_ELEMS_FACE][SUB_ELEMS_FACE]; -void DM_interp_face_data(struct DerivedMesh *source, struct DerivedMesh *dest, +void DM_interp_tessface_data(struct DerivedMesh *source, struct DerivedMesh *dest, int *src_indices, float *weights, FaceVertWeight *vert_weights, int count, int dest_index); -void DM_swap_face_data(struct DerivedMesh *dm, int index, int *corner_indices); +void DM_swap_tessface_data(struct DerivedMesh *dm, int index, int *corner_indices); + +void DM_interp_loop_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int *src_indices, + float *weights, int count, int dest_index); + +void DM_interp_face_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int *src_indices, + float *weights, int count, int dest_index); /* Temporary? A function to give a colorband to derivedmesh for vertexcolor ranges */ void vDM_ColorBand_store(struct ColorBand *coba); @@ -434,6 +512,9 @@ DerivedMesh *mesh_create_derived_for_modifier(struct Scene *scene, struct Object DerivedMesh *mesh_create_derived_render(struct Scene *scene, struct Object *ob, CustomDataMask dataMask); +DerivedMesh *getEditDerivedBMesh(struct BMEditMesh *em, struct Object *ob, + float (*vertexCos)[3]); + DerivedMesh *mesh_create_derived_index_render(struct Scene *scene, struct Object *ob, CustomDataMask dataMask, int index); /* same as above but wont use render settings */ @@ -449,17 +530,17 @@ DerivedMesh *mesh_create_derived_no_deform_render(struct Scene *scene, struct Ob DerivedMesh *mesh_create_derived_no_virtual(struct Scene *scene, struct Object *ob, float (*vertCos)[3], CustomDataMask dataMask); -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, +DerivedMesh *editbmesh_get_derived_base(struct Object *, struct BMEditMesh *em); +DerivedMesh *editbmesh_get_derived_cage(struct Scene *scene, struct Object *, + struct BMEditMesh *em, CustomDataMask dataMask); +DerivedMesh *editbmesh_get_derived_cage_and_final(struct Scene *scene, struct Object *, + struct BMEditMesh *em, DerivedMesh **final_r, CustomDataMask dataMask); -void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct EditMesh *em, CustomDataMask dataMask); +void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct BMEditMesh *em, CustomDataMask dataMask); /* returns an array of deform matrices for crazyspace correction, and the number of modifiers left */ -int editmesh_get_first_deform_matrices(struct Object *, struct EditMesh *em, float (**deformmats)[3][3], +int editbmesh_get_first_deform_matrices(struct Object *, struct BMEditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3]); void weight_to_rgb(float input, float *fr, float *fg, float *fb); diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h index a570b4fe598..36db9553c59 100644 --- a/source/blender/blenkernel/BKE_cdderivedmesh.h +++ b/source/blender/blenkernel/BKE_cdderivedmesh.h @@ -38,12 +38,14 @@ #include "BKE_DerivedMesh.h" struct DerivedMesh; +struct BMEditMesh; struct EditMesh; struct Mesh; struct Object; /* creates a new CDDerivedMesh */ -struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces); +struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces, + int numLoops, int numPolys); /* creates a CDDerivedMesh from the given Mesh, this will reference the original data in Mesh, but it is safe to apply vertex coordinates or @@ -54,6 +56,9 @@ struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh, struct Object *ob); /* creates a CDDerivedMesh from the given EditMesh */ struct DerivedMesh *CDDM_from_editmesh(struct EditMesh *em, struct Mesh *me); +/* creates a CDDerivedMesh from the given BMEditMesh */ +DerivedMesh *CDDM_from_BMEditMesh(struct BMEditMesh *em, struct Mesh *me); + /* Copies the given DerivedMesh with verts, faces & edges stored as * custom element data. */ @@ -64,7 +69,13 @@ struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm); * elements are initialised to all zeros */ struct DerivedMesh *CDDM_from_template(struct DerivedMesh *source, - int numVerts, int numEdges, int numFaces); + int numVerts, int numEdges, int numFaces, + int numLoops, int numPolys); + +/*converts mfaces to mpolys. note things may break if there are not valid + *medges surrounding each mface. + */ +void CDDM_tessfaces_to_faces(struct DerivedMesh *dm); /* applies vertex coordinates or normals to a CDDerivedMesh. if the MVert * layer is a referenced layer, it will be duplicate to not overwrite the @@ -95,7 +106,9 @@ void CDDM_lower_num_faces(struct DerivedMesh *dm, int numFaces); */ struct MVert *CDDM_get_vert(struct DerivedMesh *dm, int index); struct MEdge *CDDM_get_edge(struct DerivedMesh *dm, int index); -struct MFace *CDDM_get_face(struct DerivedMesh *dm, int index); +struct MFace *CDDM_get_tessface(struct DerivedMesh *dm, int index); +struct MLoop *CDDM_get_loop(struct DerivedMesh *dm, int index); +struct MPoly *CDDM_get_face(struct DerivedMesh *dm, int index); /* vertex/edge/face array access functions - return the array holding the * desired data @@ -104,6 +117,9 @@ struct MFace *CDDM_get_face(struct DerivedMesh *dm, int index); */ struct MVert *CDDM_get_verts(struct DerivedMesh *dm); struct MEdge *CDDM_get_edges(struct DerivedMesh *dm); -struct MFace *CDDM_get_faces(struct DerivedMesh *dm); +struct MFace *CDDM_get_tessfaces(struct DerivedMesh *dm); +struct MLoop *CDDM_get_loops(struct DerivedMesh *dm); +struct MPoly *CDDM_get_faces(struct DerivedMesh *dm); + #endif diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 95ee918a888..d442a57b525 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -69,6 +69,12 @@ void CustomData_copy(const struct CustomData *source, struct CustomData *dest, void CustomData_merge(const struct CustomData *source, struct CustomData *dest, CustomDataMask mask, int alloctype, int totelem); +/*bmesh version of CustomData_merge; merges the layouts of source and dest, + then goes through the mesh and makes sure all the customdata blocks are + consistent with the new layout.*/ +void CustomData_bmesh_merge(struct CustomData *source, struct CustomData *dest, + int mask, int alloctype, struct BMesh *bm, int type); + /* frees data associated with a CustomData object (doesn't free the object * itself, though) */ @@ -179,6 +185,7 @@ void CustomData_swap(struct CustomData *data, int index, int *corner_indices); * returns NULL if there is no layer of type */ void *CustomData_get(const struct CustomData *data, int index, int type); +void *CustomData_get_n(const struct CustomData *data, int type, int index, int n); void *CustomData_em_get(const struct CustomData *data, void *block, int type); void *CustomData_em_get_n(const struct CustomData *data, void *block, int type, int n); void *CustomData_bmesh_get(const struct CustomData *data, void *block, int type); @@ -275,7 +282,8 @@ void CustomData_set_layer_unique_name(struct CustomData *data, int index); int CustomData_verify_versions(struct CustomData *data, int index); /*BMesh specific customdata stuff*/ -void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata); +void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, + struct CustomData *ldata, int totloop, int totpoly); void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata, int total); void CustomData_bmesh_init_pool(struct CustomData *data, int allocsize); #endif diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 24e7b3957a7..5a672ddc5b2 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -43,6 +43,7 @@ struct MFace; struct MEdge; struct MVert; struct MCol; +struct BMesh; struct Object; struct MTFace; struct VecNor; @@ -54,6 +55,7 @@ extern "C" { struct EditMesh *BKE_mesh_get_editmesh(struct Mesh *me); void BKE_mesh_end_editmesh(struct Mesh *me, struct EditMesh *em); +struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me); void unlink_mesh(struct Mesh *me); void free_mesh(struct Mesh *me); @@ -135,8 +137,6 @@ int mesh_layers_menu_charlen(struct CustomData *data, int type); /* use this to void mesh_layers_menu_concat(struct CustomData *data, int type, char *str); int mesh_layers_menu(struct CustomData *data, int type); - - #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 144ed3bc624..b4efb742b27 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -43,6 +43,7 @@ struct ListBase; struct LinkNode; struct bArmature; struct ModifierData; +struct BMEditMesh; typedef enum { /* Should not be used, only for None modifier type */ @@ -134,13 +135,13 @@ typedef struct ModifierTypeInfo { */ void (*deformVertsEM)( struct ModifierData *md, struct Object *ob, - struct EditMesh *editData, struct DerivedMesh *derivedData, + struct BMEditMesh *editData, struct DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts); /* Set deform matrix per vertex for crazyspace correction */ void (*deformMatricesEM)( struct ModifierData *md, struct Object *ob, - struct EditMesh *editData, struct DerivedMesh *derivedData, + struct BMEditMesh *editData, struct DerivedMesh *derivedData, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts); /********************* Non-deform modifier functions *********************/ @@ -178,7 +179,7 @@ typedef struct ModifierTypeInfo { */ struct DerivedMesh *(*applyModifierEM)( struct ModifierData *md, struct Object *ob, - struct EditMesh *editData, + struct BMEditMesh *editData, struct DerivedMesh *derivedData); diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index 6558212519f..063f0ee96aa 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -40,7 +40,8 @@ typedef struct MultiresSubsurf { /* MultiresDM */ struct Mesh *MultiresDM_get_mesh(struct DerivedMesh *dm); -struct DerivedMesh *MultiresDM_new(struct MultiresSubsurf *, struct DerivedMesh*, int, int, int); +struct DerivedMesh *MultiresDM_new(struct MultiresSubsurf *, struct DerivedMesh*, + int, int, int, int, int); void *MultiresDM_get_vertnorm(struct DerivedMesh *); void *MultiresDM_get_orco(struct DerivedMesh *); struct MVert *MultiresDM_get_subco(struct DerivedMesh *); diff --git a/source/blender/blenkernel/BKE_tessmesh.h b/source/blender/blenkernel/BKE_tessmesh.h new file mode 100644 index 00000000000..c3ccf4b1e6a --- /dev/null +++ b/source/blender/blenkernel/BKE_tessmesh.h @@ -0,0 +1,66 @@ +#include "bmesh.h" + +struct BMesh; +struct BMLoop; +struct DerivedMesh; +struct BMFace; + +/* +ok: the EDBM module is for editmode bmesh stuff. in contrast, the + BMEdit module is for code shared with blenkernel that concerns + the BMEditMesh structure. +*/ + +typedef struct BMEditSelection +{ + struct BMEditSelection *next, *prev; + short type; + void *data; +} BMEditSelection; + +/*this structure replaces EditMesh. + + through this, you get access to both the edit bmesh, + it's tesselation, and various stuff that doesn't belong in the BMesh + struct itself. + + the entire derivedmesh and modifier system works with this structure, + and not BMesh. Mesh->editbmesh will store a pointer to this structure.*/ +typedef struct BMEditMesh { + struct BMesh *bm; + + /*this is for undoing failed operations*/ + struct BMEditMesh *emcopy; + + /*we store tesselations as triplets of three loops, + which each define a triangle.*/ + struct BMLoop *(*looptris)[3]; + int tottri; + + /*derivedmesh stuff*/ + struct DerivedMesh *derivedFinal, *derivedCage; + int lastDataMask; + + /*retopo data pointer*/ + struct RetopoPaintData *retopo_paint_data; + + /*index tables, to map indices to elements via + EDBM_init_index_arrays and associated functions. don't + touch this or read it directly.*/ + struct BMVert **vert_index; + struct BMEdge **edge_index; + struct BMFace **face_index; + + /*selection order list*/ + ListBase selected; + + /*selection mode*/ + int selectmode; + + int mat_nr; +} BMEditMesh; + +void BMEdit_RecalcTesselation(BMEditMesh *tm); +BMEditMesh *BMEdit_Create(BMesh *bm); +BMEditMesh *BMEdit_Copy(BMEditMesh *tm); +void BMEdit_Free(BMEditMesh *em); diff --git a/source/blender/blenkernel/BKE_utildefines.h b/source/blender/blenkernel/BKE_utildefines.h index f6c305b202d..3c01f86dc02 100644 --- a/source/blender/blenkernel/BKE_utildefines.h +++ b/source/blender/blenkernel/BKE_utildefines.h @@ -113,6 +113,8 @@ #define VECADD(v1,v2,v3) {*(v1)= *(v2) + *(v3); *(v1+1)= *(v2+1) + *(v3+1); *(v1+2)= *(v2+2) + *(v3+2);} #define VECSUB(v1,v2,v3) {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1); *(v1+2)= *(v2+2) - *(v3+2);} #define VECSUB2D(v1,v2,v3) {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1);} +#define VECMUL(v1, fac) {v1[0] *= fac; v1[1] *= fac; v1[2] *= fac;} + #define VECADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac);} #define QUATADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac); *(v1+3)= *(v2+3) + *(v3+3)*(fac);} @@ -199,5 +201,50 @@ #define SET_INT_IN_POINTER(i) ((void*)(intptr_t)(i)) #define GET_INT_FROM_POINTER(i) ((int)(intptr_t)(i)) +/*little pointer array macro library. example of usage: + +int *arr = NULL; +V_DECLARE(arr); +int i; + +for (i=0; i<10; i++) { + V_GROW(arr); + arr[i] = something; +} +V_FREE(arr); + +arrays are buffered, using double-buffering (so on each reallocation, +the array size is doubled). supposedly this should give good Big Oh +behaviour, though it may not be the best in practice. +*/ + +#define V_DECLARE(vec) int _##vec##_count=0; void *_##vec##_tmp + +/*in the future, I plan on having V_DECLARE allocate stack memory it'll + use at first, and switch over to heap when it needs more. that'll mess + up cases where you'd want to use this API to build a dynamic list for + non-local use, so all such cases should use this macro.*/ +#define V_DYNDECLARE(vec) V_DECLARE(vec) + +/*this returns the entire size of the array, including any buffering.*/ +#define V_SIZE(vec) ((signed int)((vec)==NULL ? 0 : MEM_allocN_len(vec) / sizeof(*vec))) + +/*this returns the logical size of the array, not including buffering.*/ +#define V_COUNT(vec) _##vec##_count + +/*grow the array by one. zeroes the new elements.*/ +#define V_GROW(vec) \ + V_SIZE(vec) > _##vec##_count ? _##vec##_count++ : \ + ((_##vec##_tmp = MEM_callocN(sizeof(*vec)*(_##vec##_count*2+2), #vec " " __FILE__ " ")),\ + (vec && memcpy(_##vec##_tmp, vec, sizeof(*vec) * _##vec##_count)),\ + (vec && (MEM_freeN(vec),1)),\ + (vec = _##vec##_tmp),\ + _##vec##_count++) + +#define V_FREE(vec) if (vec) MEM_freeN(vec); +/*resets the logical size of an array to zero, but doesn't + free the memory.*/ +#define V_RESET(vec) _##vec##_count=0 + #endif diff --git a/source/blender/blenkernel/BKE_verse.h b/source/blender/blenkernel/BKE_verse.h new file mode 100644 index 00000000000..ee22081b03f --- /dev/null +++ b/source/blender/blenkernel/BKE_verse.h @@ -0,0 +1,586 @@ +/** + * $Id: BKE_verse.h 12931 2007-12-17 18:20:48Z theeth $ + * + * ***** BEGIN GPL/BL DUAL 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL 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/SConscript b/source/blender/blenkernel/SConscript index dbc990d0613..ae522b029cb 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -10,6 +10,7 @@ incs += ' #/intern/iksolver/extern ../blenloader' incs += ' #/extern/bullet2/src' incs += ' #/intern/opennl/extern #/intern/bsp/extern' incs += ' ../gpu #/extern/glew/include' +incs += ' ../bmesh' incs += ' ' + env['BF_OPENGL_INC'] incs += ' ' + env['BF_ZLIB_INC'] diff --git a/source/blender/blenkernel/intern/BME_conversions.c b/source/blender/blenkernel/intern/BME_conversions.c index 177bb4a136b..0f372790a9d 100644 --- a/source/blender/blenkernel/intern/BME_conversions.c +++ b/source/blender/blenkernel/intern/BME_conversions.c @@ -268,7 +268,7 @@ BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em) { CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); /*copy face corner data*/ - CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata); + CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata, 0, 0); /*initialize memory pools*/ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]); CustomData_bmesh_init_pool(&bm->edata, allocsize[1]); @@ -463,7 +463,7 @@ BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm) CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); /*copy face corner data*/ - CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata); + CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata, 0, 0); /*initialize memory pools*/ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]); CustomData_bmesh_init_pool(&bm->edata, allocsize[1]); @@ -475,10 +475,10 @@ BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm) totvert = dm->getNumVerts(dm); totedge = dm->getNumEdges(dm); - totface = dm->getNumFaces(dm); + totface = dm->getNumTessFaces(dm); mvert = dm->getVertArray(dm); medge = dm->getEdgeArray(dm); - mface = dm->getFaceArray(dm); + mface = dm->getTessFaceArray(dm); vert_array = MEM_mallocN(sizeof(*vert_array)*totvert,"BME_derivedmesh_to_bmesh BME_Vert* array"); @@ -574,7 +574,8 @@ DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm) } /*convert back to mesh*/ - result = CDDM_from_template(dm,totvert,totedge,totface); + /*BMESH_TODO this should add in mloops and mpolys as well*/ + result = CDDM_from_template(dm,totvert,totedge,totface, 0, 0); CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert); CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge); CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface); @@ -613,7 +614,7 @@ DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm) } } if(totface){ - mface = CDDM_get_faces(result); + mface = CDDM_get_tessfaces(result); /*make faces*/ for(i=0,f=bm->polys.first;f;f=f->next){ mf = &mface[i]; diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index cee032f364e..c2fc626b8e1 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -2035,7 +2035,7 @@ int ccgSubSurf_getNumVerts(CCGSubSurf *ss) { int ccgSubSurf_getNumEdges(CCGSubSurf *ss) { return ss->eMap->numEntries; } -int ccgSubSurf_getNumFaces(CCGSubSurf *ss) { +int ccgSubSurf_getNumTessFaces(CCGSubSurf *ss) { return ss->fMap->numEntries; } diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h index fbd0aecc0a5..c7716314899 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.h +++ b/source/blender/blenkernel/intern/CCGSubSurf.h @@ -73,7 +73,7 @@ CCGError ccgSubSurf_setCalcVertexNormals (CCGSubSurf *ss, int useVertNormals, i int ccgSubSurf_getNumVerts (CCGSubSurf *ss); int ccgSubSurf_getNumEdges (CCGSubSurf *ss); -int ccgSubSurf_getNumFaces (CCGSubSurf *ss); +int ccgSubSurf_getNumTessFaces (CCGSubSurf *ss); int ccgSubSurf_getSubdivisionLevels (CCGSubSurf *ss); int ccgSubSurf_getEdgeSize (CCGSubSurf *ss); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 090f256ab9f..a1068080927 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -76,6 +76,7 @@ #include "BKE_texture.h" #include "BKE_utildefines.h" #include "BKE_particle.h" +#include "BKE_tessmesh.h" #include "BKE_bvhutils.h" #include "BLO_sys_types.h" // for intptr_t support @@ -124,9 +125,9 @@ static MFace *dm_getFaceArray(DerivedMesh *dm) if (!mface) { mface = CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, - dm->getNumFaces(dm)); + dm->getNumTessFaces(dm)); CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY); - dm->copyFaceArray(dm, mface); + dm->copyTessFaceArray(dm, mface); } return mface; @@ -154,40 +155,73 @@ static MEdge *dm_dupEdgeArray(DerivedMesh *dm) static MFace *dm_dupFaceArray(DerivedMesh *dm) { - MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumFaces(dm), + MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumTessFaces(dm), "dm_dupFaceArray tmp"); - if(tmp) dm->copyFaceArray(dm, tmp); + if(tmp) dm->copyTessFaceArray(dm, tmp); return tmp; } +CustomData *dm_getVertCData(DerivedMesh *dm) +{ + return &dm->vertData; +} + +CustomData *dm_getEdgeCData(DerivedMesh *dm) +{ + return &dm->edgeData; +} + +CustomData *dm_getFaceCData(DerivedMesh *dm) +{ + return &dm->faceData; +} + +CustomData *dm_getLoopCData(DerivedMesh *dm) +{ + return &dm->loopData; +} + +CustomData *dm_getPolyCData(DerivedMesh *dm) +{ + return &dm->polyData; +} + void DM_init_funcs(DerivedMesh *dm) { /* default function implementations */ dm->getVertArray = dm_getVertArray; dm->getEdgeArray = dm_getEdgeArray; - dm->getFaceArray = dm_getFaceArray; + dm->getTessFaceArray = dm_getFaceArray; dm->dupVertArray = dm_dupVertArray; dm->dupEdgeArray = dm_dupEdgeArray; - dm->dupFaceArray = dm_dupFaceArray; + dm->dupTessFaceArray = dm_dupFaceArray; + + dm->getVertDataLayout = dm_getVertCData; + dm->getEdgeDataLayout = dm_getEdgeCData; + dm->getTessFaceDataLayout = dm_getFaceCData; + dm->getLoopDataLayout = dm_getLoopCData; + dm->getFaceDataLayout = dm_getPolyCData; dm->getVertData = DM_get_vert_data; dm->getEdgeData = DM_get_edge_data; - dm->getFaceData = DM_get_face_data; + dm->getTessFaceData = DM_get_face_data; dm->getVertDataArray = DM_get_vert_data_layer; dm->getEdgeDataArray = DM_get_edge_data_layer; - dm->getFaceDataArray = DM_get_face_data_layer; + dm->getTessFaceDataArray = DM_get_face_data_layer; bvhcache_init(&dm->bvhCache); } -void DM_init(DerivedMesh *dm, - int numVerts, int numEdges, int numFaces) +void DM_init(DerivedMesh *dm, int numVerts, int numEdges, int numFaces, + int numLoops, int numPoly) { dm->numVertData = numVerts; dm->numEdgeData = numEdges; dm->numFaceData = numFaces; + dm->numLoopData = numLoops; + dm->numPolyData = numPoly; DM_init_funcs(dm); @@ -195,7 +229,8 @@ void DM_init(DerivedMesh *dm, } void DM_from_template(DerivedMesh *dm, DerivedMesh *source, - int numVerts, int numEdges, int numFaces) + int numVerts, int numEdges, int numFaces, + int numLoops, int numPolys) { CustomData_copy(&source->vertData, &dm->vertData, CD_MASK_DERIVEDMESH, CD_CALLOC, numVerts); @@ -203,10 +238,16 @@ void DM_from_template(DerivedMesh *dm, DerivedMesh *source, CD_CALLOC, numEdges); CustomData_copy(&source->faceData, &dm->faceData, CD_MASK_DERIVEDMESH, CD_CALLOC, numFaces); + CustomData_copy(&source->loopData, &dm->loopData, CD_MASK_DERIVEDMESH, + CD_CALLOC, numLoops); + CustomData_copy(&source->polyData, &dm->polyData, CD_MASK_DERIVEDMESH, + CD_CALLOC, numPolys); dm->numVertData = numVerts; dm->numEdgeData = numEdges; dm->numFaceData = numFaces; + dm->numLoopData = numLoops; + dm->numPolyData = numPolys; DM_init_funcs(dm); @@ -221,6 +262,8 @@ int DM_release(DerivedMesh *dm) CustomData_free(&dm->vertData, dm->numVertData); CustomData_free(&dm->edgeData, dm->numEdgeData); CustomData_free(&dm->faceData, dm->numFaceData); + CustomData_free(&dm->loopData, dm->numLoopData); + CustomData_free(&dm->polyData, dm->numPolyData); return 1; } @@ -228,28 +271,105 @@ int DM_release(DerivedMesh *dm) CustomData_free_temporary(&dm->vertData, dm->numVertData); CustomData_free_temporary(&dm->edgeData, dm->numEdgeData); CustomData_free_temporary(&dm->faceData, dm->numFaceData); + CustomData_free_temporary(&dm->loopData, dm->numLoopData); + CustomData_free_temporary(&dm->polyData, dm->numPolyData); return 0; } } +void dm_add_polys_from_iter(CustomData *ldata, CustomData *pdata, DerivedMesh *dm, int totloop) +{ + DMFaceIter *iter = dm->newFaceIter(dm); + DMLoopIter *liter; + MPoly *mpoly; + MLoop *mloop; + int i; + + mloop = MEM_callocN(sizeof(MLoop)*totloop, "MLoop from dm_add_polys_from_iter"); + mpoly = MEM_callocN(sizeof(MPoly)*dm->getNumFaces(dm), "MPoly from dm_add_polys_from_iter"); + + CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop); + CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, dm->getNumFaces(dm)); + + i = 0; + for (; !iter->done; iter->step(iter), mpoly++) { + mpoly->flag = iter->flags; + mpoly->loopstart = i; + mpoly->totloop = iter->len; + mpoly->mat_nr = iter->mat_nr; + + liter = iter->getLoopsIter(iter); + for (; !liter->done; liter->step(liter), mloop++, i++) { + mloop->v = liter->vindex; + mloop->e = liter->eindex; + } + } + iter->free(iter); +} + +void DM_DupPolys(DerivedMesh *source, DerivedMesh *target) +{ + DMFaceIter *iter = source->newFaceIter(source); + DMLoopIter *liter; + MPoly *mpoly; + MLoop *mloop; + int i; + + mloop = MEM_callocN(sizeof(MLoop)*source->numLoopData, "MLoop from dm_add_polys_from_iter"); + mpoly = MEM_callocN(sizeof(MPoly)*source->getNumFaces(source), "MPoly from dm_add_polys_from_iter"); + + CustomData_add_layer(&target->loopData, CD_MLOOP, CD_ASSIGN, mloop, source->numLoopData); + CustomData_add_layer(&target->polyData, CD_MPOLY, CD_ASSIGN, mpoly, source->getNumFaces(source)); + + target->numLoopData = source->numLoopData; + target->numPolyData = source->numPolyData; + + i = 0; + for (; !iter->done; iter->step(iter), mpoly++) { + mpoly->flag = iter->flags; + mpoly->loopstart = i; + mpoly->totloop = iter->len; + mpoly->mat_nr = iter->mat_nr; + + liter = iter->getLoopsIter(iter); + for (; !liter->done; liter->step(liter), mloop++, i++) { + mloop->v = liter->vindex; + mloop->e = liter->eindex; + } + } + iter->free(iter); +} + void DM_to_mesh(DerivedMesh *dm, Mesh *me) { /* dm might depend on me, so we need to do everything with a local copy */ Mesh tmp = *me; - int totvert, totedge, totface; + DMFaceIter *iter; + int totvert, totedge, totface, totloop, totpoly; memset(&tmp.vdata, 0, sizeof(tmp.vdata)); memset(&tmp.edata, 0, sizeof(tmp.edata)); memset(&tmp.fdata, 0, sizeof(tmp.fdata)); + memset(&tmp.ldata, 0, sizeof(tmp.ldata)); + memset(&tmp.pdata, 0, sizeof(tmp.pdata)); totvert = tmp.totvert = dm->getNumVerts(dm); totedge = tmp.totedge = dm->getNumEdges(dm); - totface = tmp.totface = dm->getNumFaces(dm); + totface = tmp.totface = dm->getNumTessFaces(dm); + totpoly = tmp.totpoly = dm->getNumFaces(dm); + + totloop = 0; + for (iter=dm->newFaceIter(dm); !iter->done; iter->step(iter)) { + totloop += iter->len; + } + iter->free(iter); CustomData_copy(&dm->vertData, &tmp.vdata, CD_MASK_MESH, CD_DUPLICATE, totvert); CustomData_copy(&dm->edgeData, &tmp.edata, CD_MASK_MESH, CD_DUPLICATE, totedge); CustomData_copy(&dm->faceData, &tmp.fdata, CD_MASK_MESH, CD_DUPLICATE, totface); + CustomData_copy(&dm->loopData, &tmp.ldata, CD_MASK_MESH, CD_DUPLICATE, totloop); + CustomData_copy(&dm->polyData, &tmp.pdata, CD_MASK_MESH, CD_DUPLICATE, totpoly); /* not all DerivedMeshes store their verts/edges/faces in CustomData, so we set them here in case they are missing */ @@ -258,13 +378,18 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me) if(!CustomData_has_layer(&tmp.edata, CD_MEDGE)) CustomData_add_layer(&tmp.edata, CD_MEDGE, CD_ASSIGN, dm->dupEdgeArray(dm), totedge); if(!CustomData_has_layer(&tmp.fdata, CD_MFACE)) - CustomData_add_layer(&tmp.fdata, CD_MFACE, CD_ASSIGN, dm->dupFaceArray(dm), totface); + CustomData_add_layer(&tmp.fdata, CD_MFACE, CD_ASSIGN, dm->dupTessFaceArray(dm), totface); + + if(!CustomData_has_layer(&tmp.fdata, CD_MPOLY)) + dm_add_polys_from_iter(&tmp.ldata, &tmp.pdata, dm, totloop); mesh_update_customdata_pointers(&tmp); CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); + CustomData_free(&me->ldata, me->totloop); + CustomData_free(&me->pdata, me->totpoly); /* if the number of verts has changed, remove invalid data */ if(tmp.totvert != me->totvert) { @@ -356,13 +481,27 @@ void DM_copy_edge_data(DerivedMesh *source, DerivedMesh *dest, source_index, dest_index, count); } -void DM_copy_face_data(DerivedMesh *source, DerivedMesh *dest, +void DM_copy_tessface_data(DerivedMesh *source, DerivedMesh *dest, int source_index, int dest_index, int count) { CustomData_copy_data(&source->faceData, &dest->faceData, source_index, dest_index, count); } +void DM_copy_loop_data(DerivedMesh *source, DerivedMesh *dest, + int source_index, int dest_index, int count) +{ + CustomData_copy_data(&source->loopData, &dest->loopData, + source_index, dest_index, count); +} + +void DM_copy_face_data(DerivedMesh *source, DerivedMesh *dest, + int source_index, int dest_index, int count) +{ + CustomData_copy_data(&source->polyData, &dest->polyData, + source_index, dest_index, count); +} + void DM_free_vert_data(struct DerivedMesh *dm, int index, int count) { CustomData_free_elem(&dm->vertData, index, count); @@ -373,11 +512,21 @@ void DM_free_edge_data(struct DerivedMesh *dm, int index, int count) CustomData_free_elem(&dm->edgeData, index, count); } -void DM_free_face_data(struct DerivedMesh *dm, int index, int count) +void DM_free_tessface_data(struct DerivedMesh *dm, int index, int count) { CustomData_free_elem(&dm->faceData, index, count); } +void DM_free_loop_data(struct DerivedMesh *dm, int index, int count) +{ + CustomData_free_elem(&dm->loopData, index, count); +} + +void DM_free_face_data(struct DerivedMesh *dm, int index, int count) +{ + CustomData_free_elem(&dm->polyData, index, count); +} + void DM_interp_vert_data(DerivedMesh *source, DerivedMesh *dest, int *src_indices, float *weights, int count, int dest_index) @@ -395,7 +544,7 @@ void DM_interp_edge_data(DerivedMesh *source, DerivedMesh *dest, weights, (float*)vert_weights, count, dest_index); } -void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest, +void DM_interp_tessface_data(DerivedMesh *source, DerivedMesh *dest, int *src_indices, float *weights, FaceVertWeight *vert_weights, int count, int dest_index) @@ -404,11 +553,28 @@ void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest, weights, (float*)vert_weights, count, dest_index); } -void DM_swap_face_data(DerivedMesh *dm, int index, int *corner_indices) + +void DM_swap_tessface_data(DerivedMesh *dm, int index, int *corner_indices) { CustomData_swap(&dm->faceData, index, corner_indices); } +void DM_interp_loop_data(DerivedMesh *source, DerivedMesh *dest, + int *src_indices, + float *weights, int count, int dest_index) +{ + CustomData_interp(&source->loopData, &dest->loopData, src_indices, + weights, NULL, count, dest_index); +} + +void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest, + int *src_indices, + float *weights, int count, int dest_index) +{ + CustomData_interp(&source->polyData, &dest->polyData, src_indices, + weights, NULL, count, dest_index); +} + /// static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3]) @@ -437,9 +603,9 @@ typedef struct { float (*faceNos)[3]; } EditMeshDerivedMesh; -static void emDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) +static void emDM_foreachMappedVert(void *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; EditVert *eve; int i; @@ -451,9 +617,9 @@ static void emDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, } } } -static void emDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) +static void emDM_foreachMappedEdge(void *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; EditEdge *eed; int i; @@ -469,9 +635,9 @@ static void emDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, func(userData, i, eed->v1->co, eed->v2->co); } } -static void emDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) +static void emDM_drawMappedEdges(void *dm, int (*setDrawOptions)(void *userData, int index), void *userData) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; EditEdge *eed; int i; @@ -500,13 +666,13 @@ static void emDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *us glEnd(); } } -static void emDM_drawEdges(DerivedMesh *dm, int drawLooseEdges) +static void emDM_drawEdges(void *dm, int drawLooseEdges) { emDM_drawMappedEdges(dm, NULL, NULL); } -static void emDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) +static void emDM_drawMappedEdgesInterp(void *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; EditEdge *eed; int i; @@ -540,9 +706,9 @@ static void emDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(vo } } -static void emDM_drawUVEdges(DerivedMesh *dm) +static void emDM_drawUVEdges(void *dm) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; EditFace *efa; MTFace *tf; @@ -591,9 +757,9 @@ static void emDM__calcFaceCent(EditFace *efa, float cent[3], float (*vertexCos)[ VecMulf(cent, 0.33333333333f); } } -static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) +static void emDM_foreachMappedFaceCenter(void *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; EditVert *eve; EditFace *efa; float cent[3]; @@ -609,9 +775,9 @@ static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use func(userData, i, cent, emdm->vertexCos?emdm->faceNos[i]:efa->n); } } -static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) +static void emDM_drawMappedFaces(void *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; EditFace *efa; int i, draw; @@ -696,12 +862,12 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us } } -static void emDM_drawFacesTex_common(DerivedMesh *dm, +static void emDM_drawFacesTex_common(void *dm, int (*drawParams)(MTFace *tface, MCol *mcol, int matnr), int (*drawParamsMapped)(void *userData, int index), void *userData) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; EditMesh *em= emdm->em; float (*vertexCos)[3]= emdm->vertexCos; float (*vertexNos)[3]= emdm->vertexNos; @@ -864,21 +1030,21 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm, } } -static void emDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr)) +static void emDM_drawFacesTex(void *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr)) { emDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL); } -static void emDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) +static void emDM_drawMappedFacesTex(void *dm, int (*setDrawOptions)(void *userData, int index), void *userData) { emDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData); } -static void emDM_drawMappedFacesGLSL(DerivedMesh *dm, +static void emDM_drawMappedFacesGLSL(void *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; EditMesh *em= emdm->em; float (*vertexCos)[3]= emdm->vertexCos; float (*vertexNos)[3]= emdm->vertexNos; @@ -1024,15 +1190,15 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm, } } -static void emDM_drawFacesGLSL(DerivedMesh *dm, +static void emDM_drawFacesGLSL(void *dm, int (*setMaterial)(int, void *attribs)) { - dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL); + ((DerivedMesh*)dm)->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL); } -static void emDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) +static void emDM_getMinMax(void *dm, float min_r[3], float max_r[3]) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; EditVert *eve; int i; @@ -1048,28 +1214,28 @@ static void emDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0; } } -static int emDM_getNumVerts(DerivedMesh *dm) +static int emDM_getNumVerts(void *dm) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; return BLI_countlist(&emdm->em->verts); } -static int emDM_getNumEdges(DerivedMesh *dm) +static int emDM_getNumEdges(void *dm) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; return BLI_countlist(&emdm->em->edges); } -static int emDM_getNumFaces(DerivedMesh *dm) +static int emDM_getNumTessFaces(void *dm) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; return BLI_countlist(&emdm->em->faces); } -static void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) +static void emDM_getVert(void *dm, int index, MVert *vert_r) { EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first; int i; @@ -1087,7 +1253,7 @@ static void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) vert_r->bweight = (unsigned char) (ev->bweight*255.0f); } -static void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) +static void emDM_getEdge(void *dm, int index, MEdge *edge_r) { EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; EditEdge *ee = em->edges.first; @@ -1122,7 +1288,7 @@ static void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) } } -static void emDM_getFace(DerivedMesh *dm, int index, MFace *face_r) +static void emDM_getFace(void *dm, int index, MFace *face_r) { EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; EditFace *ef = em->faces.first; @@ -1164,7 +1330,7 @@ static void emDM_getFace(DerivedMesh *dm, int index, MFace *face_r) test_index_face(face_r, NULL, 0, ef->v4?4:3); } -static void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r) +static void emDM_copyVertArray(void *dm, MVert *vert_r) { EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first; @@ -1182,7 +1348,7 @@ static void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r) } } -static void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r) +static void emDM_copyEdgeArray(void *dm, MEdge *edge_r) { EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; EditEdge *ee = em->edges.first; @@ -1210,7 +1376,7 @@ static void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r) } } -static void emDM_copyFaceArray(DerivedMesh *dm, MFace *face_r) +static void emDM_copyFaceArray(void *dm, MFace *face_r) { EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; EditFace *ef = em->faces.first; @@ -1235,9 +1401,9 @@ static void emDM_copyFaceArray(DerivedMesh *dm, MFace *face_r) } } -static void *emDM_getFaceDataArray(DerivedMesh *dm, int type) +static void *emDM_getFaceDataArray(void *dm, int type) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; EditMesh *em= emdm->em; EditFace *efa; char *data, *emdata; @@ -1258,8 +1424,8 @@ static void *emDM_getFaceDataArray(DerivedMesh *dm, int type) size = CustomData_sizeof(type); DM_add_face_layer(dm, type, CD_CALLOC, NULL); - index = CustomData_get_layer_index(&dm->faceData, type); - dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY; + index = CustomData_get_layer_index(&emdm->dm.faceData, type); + emdm->dm.faceData.layers[index].flag |= CD_FLAG_TEMPORARY; data = datalayer = DM_get_face_data_layer(dm, type); for(efa=em->faces.first; efa; efa=efa->next, data+=size) { @@ -1272,9 +1438,9 @@ static void *emDM_getFaceDataArray(DerivedMesh *dm, int type) return datalayer; } -static void emDM_release(DerivedMesh *dm) +static void emDM_release(void *dm) { - EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + EditMeshDerivedMesh *emdm= dm; if (DM_release(dm)) { if (emdm->vertexCos) { @@ -1293,21 +1459,22 @@ static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, Object *ob, EditMeshDerivedMesh *emdm = MEM_callocN(sizeof(*emdm), "emdm"); DM_init(&emdm->dm, BLI_countlist(&em->verts), - BLI_countlist(&em->edges), BLI_countlist(&em->faces)); + BLI_countlist(&em->edges), BLI_countlist(&em->faces), + 0, 0); emdm->dm.getMinMax = emDM_getMinMax; emdm->dm.getNumVerts = emDM_getNumVerts; emdm->dm.getNumEdges = emDM_getNumEdges; - emdm->dm.getNumFaces = emDM_getNumFaces; + emdm->dm.getNumTessFaces = emDM_getNumTessFaces; emdm->dm.getVert = emDM_getVert; emdm->dm.getEdge = emDM_getEdge; - emdm->dm.getFace = emDM_getFace; + emdm->dm.getTessFace = emDM_getFace; emdm->dm.copyVertArray = emDM_copyVertArray; emdm->dm.copyEdgeArray = emDM_copyEdgeArray; - emdm->dm.copyFaceArray = emDM_copyFaceArray; - emdm->dm.getFaceDataArray = emDM_getFaceDataArray; + emdm->dm.copyTessFaceArray = emDM_copyFaceArray; + emdm->dm.getTessFaceDataArray = emDM_getFaceDataArray; emdm->dm.foreachMappedVert = emDM_foreachMappedVert; emdm->dm.foreachMappedEdge = emDM_foreachMappedEdge; @@ -1417,37 +1584,36 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, Modifier return dm; } -static float *get_editmesh_orco_verts(EditMesh *em) +static float *get_editbmesh_orco_verts(BMEditMesh *em) { - EditVert *eve; + BMIter iter; + BMVert *eve; float *orco; int a, totvert; /* these may not really be the orco's, but it's only for preview. * could be solver better once, but isn't simple */ - totvert= 0; - for(eve=em->verts.first; eve; eve=eve->next) - totvert++; + totvert= em->bm->totvert; orco = MEM_mallocN(sizeof(float)*3*totvert, "EditMesh Orco"); - for(a=0, eve=em->verts.first; eve; eve=eve->next, a+=3) + eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for (a=0; eve; eve=BMIter_Step(&iter), a+=3) VECCOPY(orco+a, eve->co); return orco; } /* orco custom data layer */ - -static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, EditMesh *em) +static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, BMEditMesh *em) { DerivedMesh *dm; float (*orco)[3]; if(em) { - dm= CDDM_from_editmesh(em, me); - orco= (float(*)[3])get_editmesh_orco_verts(em); + dm= CDDM_from_BMEditMesh(em, me); + orco= (float(*)[3])get_editbmesh_orco_verts(em); } else { dm= CDDM_from_mesh(me, ob); @@ -1461,7 +1627,7 @@ static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, EditMesh *em) return dm; } -static void add_orco_dm(Object *ob, EditMesh *em, DerivedMesh *dm, DerivedMesh *orcodm) +static void add_orco_dm(Object *ob, BMEditMesh *em, DerivedMesh *dm, DerivedMesh *orcodm) { float (*orco)[3], (*layerorco)[3]; int totvert; @@ -1477,7 +1643,7 @@ static void add_orco_dm(Object *ob, EditMesh *em, DerivedMesh *dm, DerivedMesh * dm->getVertCos(dm, orco); } else { - if(em) orco= (float(*)[3])get_editmesh_orco_verts(em); + if(em) orco= (float(*)[3])get_editbmesh_orco_verts(em); else orco= (float(*)[3])get_mesh_orco_verts(ob); } @@ -1839,21 +2005,24 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos BLI_linklist_free(datamasks, NULL); } -static float (*editmesh_getVertexCos(EditMesh *em, int *numVerts_r))[3] +static float (*editbmesh_getVertexCos(BMEditMesh *em, int *numVerts_r))[3] { - int i, numVerts = *numVerts_r = BLI_countlist(&em->verts); + int i, numVerts = *numVerts_r = em->bm->totvert; float (*cos)[3]; - EditVert *eve; + BMIter iter; + BMVert *eve; cos = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos"); - for (i=0,eve=em->verts.first; i<numVerts; i++,eve=eve->next) { + + eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter), i++) { VECCOPY(cos[i], eve->co); } return cos; } -static int editmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm) +static int editbmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; @@ -1867,7 +2036,7 @@ static int editmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm) return 1; } -static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, DerivedMesh **cage_r, +static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, DerivedMesh **cage_r, DerivedMesh **final_r, CustomDataMask dataMask) { @@ -1882,7 +2051,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri modifiers_clearErrors(ob); if(cage_r && cageIndex == -1) { - *cage_r = getEditMeshDerivedMesh(em, ob, NULL); + *cage_r = getEditDerivedBMesh(em, ob, NULL); } dm = NULL; @@ -1899,7 +2068,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri md->scene= scene; - if(!editmesh_modifier_is_enabled(md, dm)) + if(!editbmesh_modifier_is_enabled(md, dm)) continue; /* add an orco layer if needed by this modifier */ @@ -1927,7 +2096,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv"); dm->getVertCos(dm, deformedVerts); } else { - deformedVerts = editmesh_getVertexCos(em, &numVerts); + deformedVerts = editbmesh_getVertexCos(em, &numVerts); } } @@ -1951,7 +2120,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri } } else { - dm = CDDM_from_editmesh(em, ob->data); + dm = CDDM_from_BMEditMesh(em, ob->data); if(deformedVerts) { CDDM_apply_vert_coords(dm, deformedVerts); @@ -2006,7 +2175,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri *cage_r = dm; } else { *cage_r = - getEditMeshDerivedMesh(em, ob, + getEditDerivedBMesh(em, ob, deformedVerts ? MEM_dupallocN(deformedVerts) : NULL); } } @@ -2030,7 +2199,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri } else if (!deformedVerts && cage_r && *cage_r) { *final_r = *cage_r; } else { - *final_r = getEditMeshDerivedMesh(em, ob, deformedVerts); + *final_r = getEditDerivedBMesh(em, ob, deformedVerts); deformedVerts = NULL; } @@ -2100,7 +2269,7 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask) } -static void editmesh_build_data(Scene *scene, Object *obedit, EditMesh *em, CustomDataMask dataMask) +static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask) { float min[3], max[3]; @@ -2119,7 +2288,7 @@ static void editmesh_build_data(Scene *scene, Object *obedit, EditMesh *em, Cust em->derivedCage = NULL; } - editmesh_calc_modifiers(scene, obedit, em, &em->derivedCage, &em->derivedFinal, dataMask); + editbmesh_calc_modifiers(scene, obedit, em, &em->derivedCage, &em->derivedFinal, dataMask); em->lastDataMask = dataMask; INIT_MINMAX(min, max); @@ -2134,10 +2303,10 @@ static void editmesh_build_data(Scene *scene, Object *obedit, EditMesh *em, Cust em->derivedCage->needsFree = 0; } -void makeDerivedMesh(Scene *scene, Object *ob, EditMesh *em, CustomDataMask dataMask) +void makeDerivedMesh(Scene *scene, Object *ob, BMEditMesh *em, CustomDataMask dataMask) { if (em) { - editmesh_build_data(scene, ob, em, dataMask); + editbmesh_build_data(scene, ob, em, dataMask); } else { mesh_build_data(scene, ob, dataMask); } @@ -2227,7 +2396,7 @@ DerivedMesh *mesh_create_derived_no_deform_render(Scene *scene, Object *ob, /***/ -DerivedMesh *editmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, EditMesh *em, DerivedMesh **final_r, +DerivedMesh *editbmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, BMEditMesh *em, DerivedMesh **final_r, CustomDataMask dataMask) { /* if there's no derived mesh or the last data mask used doesn't include @@ -2235,27 +2404,27 @@ DerivedMesh *editmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, E */ if(!em->derivedCage || (em->lastDataMask & dataMask) != dataMask) - editmesh_build_data(scene, obedit, em, dataMask); + editbmesh_build_data(scene, obedit, em, dataMask); *final_r = em->derivedFinal; return em->derivedCage; } -DerivedMesh *editmesh_get_derived_cage(Scene *scene, Object *obedit, EditMesh *em, CustomDataMask dataMask) +DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh *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(!em->derivedCage || (em->lastDataMask & dataMask) != dataMask) - editmesh_build_data(scene, obedit, em, dataMask); + editbmesh_build_data(scene, obedit, em, dataMask); return em->derivedCage; } -DerivedMesh *editmesh_get_derived_base(Object *obedit, EditMesh *em) +DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em) { - return getEditMeshDerivedMesh(em, obedit, NULL); + return getEditDerivedBMesh(em, obedit, NULL); } @@ -2317,7 +2486,7 @@ float *mesh_get_mapped_verts_nors(Scene *scene, Object *ob) /* ********* crazyspace *************** */ -int editmesh_get_first_deform_matrices(Object *ob, EditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3]) +int editbmesh_get_first_deform_matrices(Object *ob, BMEditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3]) { ModifierData *md; DerivedMesh *dm; @@ -2336,13 +2505,13 @@ int editmesh_get_first_deform_matrices(Object *ob, EditMesh *em, float (**deform for(i = 0; md && i <= cageIndex; i++, md = md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if(!editmesh_modifier_is_enabled(md, dm)) + if(!editbmesh_modifier_is_enabled(md, dm)) continue; if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatricesEM) { if(!defmats) { - dm= getEditMeshDerivedMesh(em, ob, NULL); - deformedVerts= editmesh_getVertexCos(em, &numVerts); + dm= getEditDerivedBMesh(em, ob, NULL); + deformedVerts= editbmesh_getVertexCos(em, &numVerts); defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats"); for(a=0; a<numVerts; a++) @@ -2357,7 +2526,7 @@ int editmesh_get_first_deform_matrices(Object *ob, EditMesh *em, float (**deform } for(; md && i <= cageIndex; md = md->next, i++) - if(editmesh_modifier_is_enabled(md, dm) && modifier_isDeformer(md)) + if(editbmesh_modifier_is_enabled(md, dm) && modifier_isDeformer(md)) numleft++; if(dm) @@ -2389,11 +2558,11 @@ void DM_add_tangent_layer(DerivedMesh *dm) /* check we have all the needed layers */ totvert= dm->getNumVerts(dm); - totface= dm->getNumFaces(dm); + totface= dm->getNumTessFaces(dm); mvert= dm->getVertArray(dm); - mface= dm->getFaceArray(dm); - mtface= dm->getFaceDataArray(dm, CD_MTFACE); + mface= dm->getTessFaceArray(dm); + mtface= dm->getTessFaceDataArray(dm, CD_MTFACE); if(!mtface) { orco= dm->getVertDataArray(dm, CD_ORCO); diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 6c1b8eb9000..7d9d261f306 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -68,6 +68,7 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #ifdef HAVE_CONFIG_H #include <config.h> @@ -450,7 +451,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl Scene *sce = NULL; Group *group = NULL; GroupObject * go = NULL; - EditMesh *em; + BMEditMesh *em; float vec[3], no[3], pmat[4][4]; int lay, totvert, a, oblay; @@ -459,11 +460,10 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl /* simple preventing of too deep nested groups */ if(level>MAX_DUPLI_RECUR) return; - em = BKE_mesh_get_editmesh(me); + em = me->edit_btmesh; if(em) { - dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); - BKE_mesh_end_editmesh(me, em); + dm= editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); } else dm= mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH); @@ -566,34 +566,31 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa Scene *sce = NULL; Group *group = NULL; GroupObject *go = NULL; - EditMesh *em; + BMEditMesh *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); - - em = BKE_mesh_get_editmesh(me); + em = me->edit_btmesh; + if(em) { int totvert; + dm= editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); - dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH); - - totface= dm->getNumFaces(dm); + totface= dm->getNumTessFaces(dm); mface= MEM_mallocN(sizeof(MFace)*totface, "mface temp"); - dm->copyFaceArray(dm, mface); + dm->copyTessFaceArray(dm, mface); 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(scene, par, CD_MASK_BAREMESH); - totface= dm->getNumFaces(dm); - mface= dm->getFaceArray(dm); + totface= dm->getNumTessFaces(dm); + mface= dm->getTessFaceArray(dm); mvert= dm->getVertArray(dm); } diff --git a/source/blender/blenkernel/intern/booleanops.c b/source/blender/blenkernel/intern/booleanops.c index eb3aefe7ee6..b6d1f7612b0 100644 --- a/source/blender/blenkernel/intern/booleanops.c +++ b/source/blender/blenkernel/intern/booleanops.c @@ -178,14 +178,14 @@ 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)); + return(iterator->pos >= iterator->dm->getNumTessFaces(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 *mfaces = face_it->dm->getTessFaceArray(face_it->dm); MFace *mface = &mfaces[face_it->pos]; /* reverse face vertices if necessary */ @@ -259,7 +259,7 @@ static void FaceIt_Construct( output->Fill = FaceIt_Fill; output->Done = FaceIt_Done; output->Reset = FaceIt_Reset; - output->num_elements = it->dm->getNumFaces(it->dm); + output->num_elements = it->dm->getNumTessFaces(it->dm); output->it = it; } @@ -309,8 +309,8 @@ static void InterpCSGFace( MFace *mface, *orig_mface; int j; - mface = CDDM_get_face(dm, index); - orig_mface = orig_dm->getFaceArray(orig_dm) + orig_index; + mface = CDDM_get_tessface(dm, index); + orig_mface = orig_dm->getTessFaceArray(orig_dm) + orig_index; // get the vertex coordinates from the original mesh orig_co[0] = (orig_dm->getVertArray(orig_dm) + orig_mface->v1)->co; @@ -358,7 +358,7 @@ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh( int i; // create a new DerivedMesh - result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements); + result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements, 0, 0); CustomData_merge(&dm1->faceData, &result->faceData, CD_MASK_DERIVEDMESH, CD_DEFAULT, face_it->num_elements); CustomData_merge(&dm2->faceData, &result->faceData, CD_MASK_DERIVEDMESH, @@ -398,16 +398,16 @@ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh( 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_ob = (csgface.orig_face < dm1->getNumTessFaces(dm1))? ob1: ob2; + orig_dm = (csgface.orig_face < dm1->getNumTessFaces(dm1))? dm1: dm2; orig_me = (orig_ob == ob1)? me1: me2; - orig_index = (orig_ob == ob1)? csgface.orig_face: csgface.orig_face - dm1->getNumFaces(dm1); + orig_index = (orig_ob == ob1)? csgface.orig_face: csgface.orig_face - dm1->getNumTessFaces(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 = CDDM_get_tessface(result, i); mface->v1 = csgface.vertex_index[0]; mface->v2 = csgface.vertex_index[1]; mface->v3 = csgface.vertex_index[2]; @@ -440,6 +440,8 @@ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh( CDDM_calc_edges(result); CDDM_calc_normals(result); + CDDM_tessfaces_to_faces(result); + return result; } @@ -473,7 +475,7 @@ DerivedMesh *NewBooleanDerivedMesh_intern( DerivedMesh *result = NULL; if (dm == NULL || dm_select == NULL) return 0; - if (!dm->getNumFaces(dm) || !dm_select->getNumFaces(dm_select)) return 0; + if (!dm->getNumTessFaces(dm) || !dm_select->getNumTessFaces(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), @@ -505,7 +507,7 @@ DerivedMesh *NewBooleanDerivedMesh_intern( } BuildMeshDescriptors(dm_select, ob_select, 0, &fd_1, &vd_1); - BuildMeshDescriptors(dm, ob, dm_select->getNumFaces(dm_select) , &fd_2, &vd_2); + BuildMeshDescriptors(dm, ob, dm_select->getNumTessFaces(dm_select) , &fd_2, &vd_2); bool_op = CSG_NewBooleanFunction(); @@ -559,7 +561,7 @@ int NewBooleanMesh(Scene *scene, Base *base, Base *base_select, int int_op_type) /* 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)) + if (!dm->getNumTessFaces(dm) || !dm_select->getNumTessFaces(dm_select)) { MEM_freeN(mat); return -1; diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index d9e005811d0..08bcd9c2820 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -532,7 +532,7 @@ BVHTree* bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *mesh, float data->mesh = mesh; data->vert = mesh->getVertDataArray(mesh, CD_MVERT); - data->face = mesh->getFaceDataArray(mesh, CD_MFACE); + data->face = mesh->getTessFaceDataArray(mesh, CD_MFACE); data->sphere_radius = epsilon; } @@ -549,9 +549,9 @@ BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float if(tree == NULL) { int i; - int numFaces= mesh->getNumFaces(mesh); + int numFaces= mesh->getNumTessFaces(mesh); MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT); - MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE); + MFace *face = mesh->getTessFaceDataArray(mesh, CD_MFACE); if(vert != NULL && face != NULL) { @@ -597,7 +597,7 @@ BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float data->mesh = mesh; data->vert = mesh->getVertDataArray(mesh, CD_MVERT); - data->face = mesh->getFaceDataArray(mesh, CD_MFACE); + data->face = mesh->getTessFaceDataArray(mesh, CD_MFACE); data->sphere_radius = epsilon; } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 706eece108c..120e1360d48 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -44,6 +44,7 @@ #include "BKE_mesh.h" #include "BKE_multires.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" @@ -76,8 +77,12 @@ typedef struct { MVert *mvert; MEdge *medge; MFace *mface; + MLoop *mloop; + MPoly *mpoly; } CDDerivedMesh; +DMFaceIter *cdDM_newFaceIter(DerivedMesh *source); + /**************** DerivedMesh interface functions ****************/ static int cdDM_getNumVerts(DerivedMesh *dm) { @@ -89,11 +94,16 @@ static int cdDM_getNumEdges(DerivedMesh *dm) return dm->numEdgeData; } -static int cdDM_getNumFaces(DerivedMesh *dm) +static int cdDM_getNumTessFaces(DerivedMesh *dm) { return dm->numFaceData; } +static int cdDM_getNumFaces(DerivedMesh *dm) +{ + return dm->numPolyData; +} + static void cdDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) { CDDerivedMesh *cddm = (CDDerivedMesh *)dm; @@ -255,7 +265,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *a CDDerivedMesh *cddm = (CDDerivedMesh*) dm; MVert *mvert = cddm->mvert; MFace *mface = cddm->mface; - float *nors= dm->getFaceDataArray(dm, CD_NORMAL); + float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL); int a, glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1; #define PASSVERT(index) { \ @@ -391,8 +401,8 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, CDDerivedMesh *cddm = (CDDerivedMesh*) dm; MVert *mv = cddm->mvert; MFace *mf = cddm->mface; - MCol *mcol = dm->getFaceDataArray(dm, CD_MCOL); - float *nors= dm->getFaceDataArray(dm, CD_NORMAL); + MCol *mcol = dm->getTessFaceDataArray(dm, CD_MCOL); + float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL); MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE); int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX); @@ -483,7 +493,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us MVert *mv = cddm->mvert; MFace *mf = cddm->mface; MCol *mc; - float *nors= dm->getFaceDataArray(dm, CD_NORMAL); + float *nors= dm->getTessFaceDataArray(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); @@ -574,11 +584,11 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo DMVertexAttribs attribs; MVert *mvert = cddm->mvert; MFace *mface = cddm->mface; - MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE); - float (*nors)[3] = dm->getFaceDataArray(dm, CD_NORMAL); + MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); + float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL); int a, b, dodraw, smoothnormal, matnr, new_matnr; int transp, new_transp, orig_transp; - int orig, *index = dm->getFaceDataArray(dm, CD_ORIGINDEX); + int orig, *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); matnr = -1; smoothnormal = 0; @@ -769,37 +779,45 @@ static void cdDM_foreachMappedFaceCenter( { CDDerivedMesh *cddm = (CDDerivedMesh*)dm; MVert *mv = cddm->mvert; - MFace *mf = cddm->mface; - int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX); - - for(i = 0; i < dm->numFaceData; i++, mf++) { + MPoly *mf = cddm->mpoly; + MLoop *ml = cddm->mloop; + float (*cents)[3]; + float (*nors)[3]; + int *flens; + int i, j, orig, *index; + int maxf=0; + + index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX); + mf = cddm->mpoly; + for(i = 0; i < dm->numPolyData; i++, mf++) { float cent[3]; float no[3]; if (index) { orig = *index++; if(orig == ORIGINDEX_NONE) continue; - } - else + } else orig = i; + + ml = &cddm->mloop[mf->loopstart]; + cent[0] = cent[1] = cent[2] = 0.0f; + for (j=0; j<mf->totloop; j++, ml++) { + VecAddf(cent, cent, mv[ml->v].co); + } + VecMulf(cent, 1.0f / (float)j); - VECCOPY(cent, mv[mf->v1].co); - VecAddf(cent, cent, mv[mf->v2].co); - VecAddf(cent, cent, mv[mf->v3].co); - - if (mf->v4) { - CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co, - mv[mf->v3].co, mv[mf->v4].co, no); - VecAddf(cent, cent, mv[mf->v4].co); - VecMulf(cent, 0.25f); + ml = &cddm->mloop[mf->loopstart]; + if (j > 3) { + CalcNormFloat4(mv[ml->v].co, mv[(ml+1)->v].co, + mv[(ml+2)->v].co, mv[(ml+3)->v].co, no); } else { - CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co, - mv[mf->v3].co, no); - VecMulf(cent, 0.33333333333f); + CalcNormFloat(mv[ml->v].co, mv[(ml+1)->v].co, + mv[(ml+2)->v].co, no); } func(userData, orig, cent, no); } + } static void cdDM_release(DerivedMesh *dm) @@ -822,21 +840,24 @@ static CDDerivedMesh *cdDM_create(const char *desc) dm->getMinMax = cdDM_getMinMax; dm->getNumVerts = cdDM_getNumVerts; - dm->getNumFaces = cdDM_getNumFaces; dm->getNumEdges = cdDM_getNumEdges; + dm->getNumTessFaces = cdDM_getNumTessFaces; + dm->getNumFaces = cdDM_getNumFaces; + + dm->newFaceIter = cdDM_newFaceIter; dm->getVert = cdDM_getVert; dm->getEdge = cdDM_getEdge; - dm->getFace = cdDM_getFace; + dm->getTessFace = cdDM_getFace; dm->copyVertArray = cdDM_copyVertArray; dm->copyEdgeArray = cdDM_copyEdgeArray; - dm->copyFaceArray = cdDM_copyFaceArray; + dm->copyTessFaceArray = cdDM_copyFaceArray; dm->getVertData = DM_get_vert_data; dm->getEdgeData = DM_get_edge_data; - dm->getFaceData = DM_get_face_data; + dm->getTessFaceData = DM_get_face_data; dm->getVertDataArray = DM_get_vert_data_layer; dm->getEdgeDataArray = DM_get_edge_data_layer; - dm->getFaceDataArray = DM_get_face_data_layer; + dm->getTessFaceDataArray = DM_get_face_data_layer; dm->getVertCos = cdDM_getVertCos; dm->getVertCo = cdDM_getVertCo; @@ -866,24 +887,29 @@ static CDDerivedMesh *cdDM_create(const char *desc) return cddm; } -DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces) +DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces, int numLoops, int numPolys) { CDDerivedMesh *cddm = cdDM_create("CDDM_new dm"); DerivedMesh *dm = &cddm->dm; - DM_init(dm, numVerts, numEdges, numFaces); + DM_init(dm, numVerts, numEdges, numFaces, numLoops, numPolys); CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts); CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges); CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces); + CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, numPolys); CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts); CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges); CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces); + CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops); + CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys); cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE); + cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP); + cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); return dm; } @@ -898,11 +924,13 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob) /* this does a referenced copy, the only new layers being ORIGINDEX, * with an exception for fluidsim */ - DM_init(dm, mesh->totvert, mesh->totedge, mesh->totface); + DM_init(dm, mesh->totvert, mesh->totedge, mesh->totface, + mesh->totloop, mesh->totpoly); CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert); CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge); CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface); + CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totpoly); dm->deformedOnly = 1; @@ -914,10 +942,16 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob) mesh->totedge); CustomData_merge(&mesh->fdata, &dm->faceData, mask, alloctype, mesh->totface); + CustomData_merge(&mesh->ldata, &dm->loopData, mask, alloctype, + mesh->totloop); + CustomData_merge(&mesh->pdata, &dm->polyData, mask, alloctype, + mesh->totpoly); cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE); + cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP); + cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); index = CustomData_get_layer(&dm->vertData, CD_ORIGINDEX); for(i = 0; i < mesh->totvert; ++i, ++index) @@ -931,6 +965,10 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob) for(i = 0; i < mesh->totface; ++i, ++index) *index = i; + index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX); + for(i = 0; i < mesh->totpoly; ++i, ++index) + *index = i; + return dm; } @@ -938,7 +976,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me) { DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts), BLI_countlist(&em->edges), - BLI_countlist(&em->faces)); + BLI_countlist(&em->faces), 0, 0); CDDerivedMesh *cddm = (CDDerivedMesh*)dm; EditVert *eve; EditEdge *eed; @@ -956,6 +994,8 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me) CD_CALLOC, dm->numEdgeData); */ CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH, CD_CALLOC, dm->numFaceData); + CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH, + CD_CALLOC, dm->numFaceData); /* set eve->hash to vert index */ for(i = 0, eve = em->verts.first; eve; eve = eve->next, ++i) @@ -1012,7 +1052,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me) /* CustomData_from_em_block(&em->edata, &dm->edgeData, eed->data, i); */ } - index = dm->getFaceDataArray(dm, CD_ORIGINDEX); + index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); for(i = 0, efa = em->faces.first; i < dm->numFaceData; i++, efa = efa->next, index++) { MFace *mf = &mface[i]; @@ -1033,6 +1073,321 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me) return dm; } + +static void loops_to_customdata_corners(BMesh *bm, CustomData *facedata, + int cdindex, BMLoop *l3[3], + int numCol, int numTex) +{ + int i, j; + BMLoop *l; + BMFace *f = l3[0]->f; + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + + for(i=0; i < numTex; i++){ + texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i); + texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i); + + texface->tpage = texpoly->tpage; + texface->flag = texpoly->flag; + texface->transp = texpoly->transp; + texface->mode = texpoly->mode; + texface->tile = texpoly->tile; + texface->unwrap = texpoly->unwrap; + + for (j=0; j<3; i++) { + l = l3[j]; + mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i); + texface->uv[j][0] = mloopuv->uv[0]; + texface->uv[j][1] = mloopuv->uv[1]; + } + } + + for(i=0; i < numCol; i++){ + mcol = CustomData_get_n(facedata, CD_MCOL, cdindex, i); + + for (j=0; j<3; j++) { + l = l3[j]; + mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i); + mcol[j].r = mloopcol->r; + mcol[j].g = mloopcol->g; + mcol[j].b = mloopcol->b; + mcol[j].a = mloopcol->a; + } + } +} + +DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me) +{ + DerivedMesh *dm = CDDM_new(em->bm->totvert, em->bm->totedge, + em->tottri, em->bm->totloop, em->bm->totface); + CDDerivedMesh *cddm = (CDDerivedMesh*)dm; + BMesh *bm = em->bm; + BMIter iter, liter; + BMVert *eve; + BMEdge *eed; + BMFace *efa; + MVert *mvert = cddm->mvert; + MEdge *medge = cddm->medge; + MFace *mface = cddm->mface; + MLoop *mloop = cddm->mloop; + MPoly *mpoly = cddm->mpoly; + int numCol = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL); + int numTex = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY); + int i, j, *index, add_orig; + + dm->deformedOnly = 1; + + /*don't add origindex layer if one already exists*/ + add_orig = !CustomData_has_layer(&em->bm->pdata, CD_ORIGINDEX); + + CustomData_merge(&em->bm->vdata, &dm->vertData, CD_MASK_DERIVEDMESH, + CD_CALLOC, dm->numVertData); + CustomData_merge(&em->bm->edata, &dm->edgeData, CD_MASK_DERIVEDMESH, + CD_CALLOC, dm->numEdgeData); + CustomData_merge(&em->bm->pdata, &dm->faceData, CD_MASK_DERIVEDMESH, + CD_CALLOC, dm->numFaceData); + CustomData_merge(&em->bm->ldata, &dm->loopData, CD_MASK_DERIVEDMESH, + CD_CALLOC, dm->numLoopData); + CustomData_merge(&em->bm->pdata, &dm->polyData, CD_MASK_DERIVEDMESH, + CD_CALLOC, dm->numPolyData); + + /*add tesselation mface and mcol layers as necassary*/ + for (i=0; i<numTex; i++) { + CustomData_add_layer(&dm->faceData, CD_MTFACE, CD_CALLOC, NULL, em->tottri); + } + + for (i=0; i<numCol; i++) { + CustomData_add_layer(&dm->faceData, CD_MCOL, CD_CALLOC, NULL, em->tottri); + } + + /* set vert index */ + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter), i++) + BMINDEX_SET(eve, i); + + index = dm->getVertDataArray(dm, CD_ORIGINDEX); + + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter), i++, index++) { + MVert *mv = &mvert[i]; + + VECCOPY(mv->co, eve->co); + + BMINDEX_SET(eve, i); + + mv->no[0] = eve->no[0] * 32767.0; + mv->no[1] = eve->no[1] * 32767.0; + mv->no[2] = eve->no[2] * 32767.0; + mv->bweight = (unsigned char) (eve->bweight * 255.0f); + + mv->mat_nr = 0; + mv->flag = BMFlags_To_MEFlags(eve); + + if (add_orig) *index = i; + + CustomData_from_bmesh_block(&bm->vdata, &dm->vertData, eve->head.data, i); + } + + index = dm->getEdgeDataArray(dm, CD_ORIGINDEX); + eed = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); + for (i=0; eed; eed=BMIter_Step(&iter), i++, index++) { + MEdge *med = &medge[i]; + + BMINDEX_SET(eed, i); + + med->v1 = BMINDEX_GET(eed->v1); + med->v2 = BMINDEX_GET(eed->v2); + med->crease = (unsigned char) (eed->crease * 255.0f); + med->bweight = (unsigned char) (eed->bweight * 255.0f); + med->flag = ME_EDGEDRAW|ME_EDGERENDER; + + med->flag = BMFlags_To_MEFlags(eed); + + CustomData_from_bmesh_block(&bm->edata, &dm->edgeData, eed->head.data, i); + if (add_orig) *index = i; + } + + efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); + for (i=0; efa; i++, efa=BMIter_Step(&iter)) { + BMINDEX_SET(efa, i); + } + + index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + for(i = 0; i < dm->numFaceData; i++, index++) { + MFace *mf = &mface[i]; + BMLoop **l = em->looptris[i]; + efa = l[0]->f; + + mf->v1 = BMINDEX_GET(l[0]->v); + mf->v2 = BMINDEX_GET(l[1]->v); + mf->v3 = BMINDEX_GET(l[2]->v); + mf->v4 = 0; + mf->mat_nr = efa->mat_nr; + mf->flag = BMFlags_To_MEFlags(efa); + + *index = add_orig ? BMINDEX_GET(efa) : *(int*)CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_ORIGINDEX); + + loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numTex); + test_index_face(mf, &dm->faceData, i, 3); + } + + index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX); + j = 0; + efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); + for (i=0; efa; i++, efa=BMIter_Step(&iter), index++) { + BMLoop *l; + MPoly *mp = &mpoly[i]; + + mp->totloop = efa->len; + mp->flag = BMFlags_To_MEFlags(efa); + mp->loopstart = j; + mp->mat_nr = efa->mat_nr; + + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) { + mloop->v = BMINDEX_GET(l->v); + mloop->e = BMINDEX_GET(l->e); + CustomData_from_bmesh_block(&bm->ldata, &dm->loopData, l->head.data, j); + + j++; + mloop++; + } + + CustomData_from_bmesh_block(&bm->pdata, &dm->polyData, efa->head.data, i); + + if (add_orig) *index = i; + } + + return dm; +} + +typedef struct CDDM_LoopIter { + DMLoopIter head; + CDDerivedMesh *cddm; + int len, i; +} CDDM_LoopIter; + +typedef struct CDDM_FaceIter { + DMFaceIter head; + CDDerivedMesh *cddm; + CDDM_LoopIter liter; +} CDDM_FaceIter; + +void cddm_freeiter(void *self) +{ + MEM_freeN(self); +} + +void cddm_stepiter(void *self) +{ + CDDM_FaceIter *iter = self; + MPoly *mp; + + iter->head.index++; + if (iter->head.index >= iter->cddm->dm.numPolyData) { + iter->head.done = 1; + return; + } + + mp = iter->cddm->mpoly + iter->head.index; + + iter->head.flags = mp->flag; + iter->head.mat_nr = mp->mat_nr; + iter->head.len = mp->totloop; +} + +void *cddm_faceiter_getcddata(void *self, int type, int layer) +{ + CDDM_FaceIter *iter = self; + + if (layer == -1) return CustomData_get(&iter->cddm->dm.polyData, + iter->head.index, type); + else return CustomData_get_n(&iter->cddm->dm.polyData, type, + iter->head.index, layer); +} + +void *cddm_loopiter_getcddata(void *self, int type, int layer) +{ + CDDM_FaceIter *iter = self; + + if (layer == -1) return CustomData_get(&iter->cddm->dm.loopData, + iter->head.index, type); + else return CustomData_get_n(&iter->cddm->dm.loopData, type, + iter->head.index, layer); +} + +void *cddm_loopiter_getvertcddata(void *self, int type, int layer) +{ + CDDM_FaceIter *iter = self; + + if (layer == -1) return CustomData_get(&iter->cddm->dm.vertData, + iter->cddm->mloop[iter->head.index].v, + type); + else return CustomData_get_n(&iter->cddm->dm.vertData, type, + iter->cddm->mloop[iter->head.index].v, layer); +} + +DMLoopIter *cddmiter_get_loopiter(void *self) +{ + CDDM_FaceIter *iter = self; + CDDM_LoopIter *liter = &iter->liter; + MPoly *mp = iter->cddm->mpoly + iter->head.index; + + liter->i = -1; + liter->len = iter->head.len; + liter->head.index = mp->loopstart-1; + liter->head.done = 0; + + liter->head.step(liter); + + return (DMLoopIter*) liter; +} + +void cddm_loopiter_step(void *self) +{ + CDDM_LoopIter *liter = self; + MLoop *ml; + + liter->i++; + liter->head.index++; + + if (liter->i == liter->len) { + liter->head.done = 1; + return; + } + + ml = liter->cddm->mloop + liter->head.index; + + liter->head.eindex = ml->e; + liter->head.v = liter->cddm->mvert[ml->v]; + liter->head.vindex = ml->v; +} + +DMFaceIter *cdDM_newFaceIter(DerivedMesh *source) +{ + CDDerivedMesh *cddm = (CDDerivedMesh*) source; + CDDM_FaceIter *iter = MEM_callocN(sizeof(CDDM_FaceIter), "DMFaceIter from cddm"); + + iter->head.free = cddm_freeiter; + iter->head.step = cddm_stepiter; + iter->head.getCDData = cddm_faceiter_getcddata; + iter->head.getLoopsIter = cddmiter_get_loopiter; + + iter->liter.head.step = cddm_loopiter_step; + iter->liter.head.getLoopCDData = cddm_loopiter_getcddata; + iter->liter.head.getVertCDData = cddm_loopiter_getvertcddata; + iter->liter.cddm = cddm; + + iter->cddm = cddm; + iter->head.index = -1; + iter->head.step(iter); + + return (DMFaceIter*) iter; +} + DerivedMesh *CDDM_copy(DerivedMesh *source) { CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm"); @@ -1040,44 +1395,59 @@ DerivedMesh *CDDM_copy(DerivedMesh *source) int numVerts = source->numVertData; int numEdges = source->numEdgeData; int numFaces = source->numFaceData; + int numLoops = source->numLoopData; + int numPolys = source->numPolyData; /* this initializes dm, and copies all non mvert/medge/mface layers */ - DM_from_template(dm, source, numVerts, numEdges, numFaces); + DM_from_template(dm, source, numVerts, numEdges, numFaces, + numLoops, numPolys); dm->deformedOnly = source->deformedOnly; CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts); CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges); CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numFaces); + CustomData_copy_data(&source->loopData, &dm->loopData, 0, 0, numLoops); + CustomData_copy_data(&source->polyData, &dm->polyData, 0, 0, numPolys); /* now add mvert/medge/mface layers */ cddm->mvert = source->dupVertArray(source); cddm->medge = source->dupEdgeArray(source); - cddm->mface = source->dupFaceArray(source); + cddm->mface = source->dupTessFaceArray(source); CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts); CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges); CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numFaces); + + DM_DupPolys(source, dm); + + cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP); + cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); return dm; } DerivedMesh *CDDM_from_template(DerivedMesh *source, - int numVerts, int numEdges, int numFaces) + int numVerts, int numEdges, int numFaces, + int numLoops, int numPolys) { CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest"); DerivedMesh *dm = &cddm->dm; /* this does a copy of all non mvert/medge/mface layers */ - DM_from_template(dm, source, numVerts, numEdges, numFaces); + DM_from_template(dm, source, numVerts, numEdges, numFaces, numLoops, numPolys); /* now add mvert/medge/mface layers */ CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts); CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges); CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces); + CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops); + CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys); cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE); + cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP); + cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); return dm; } @@ -1138,7 +1508,7 @@ void CDDM_calc_normals(DerivedMesh *dm) NULL, dm->numFaceData); /* calculate face normals and add to vertex normals */ - mf = CDDM_get_faces(dm); + mf = CDDM_get_tessfaces(dm); for(i = 0; i < numFaces; i++, mf++) { float *f_no = face_nors[i]; @@ -1263,7 +1633,7 @@ MEdge *CDDM_get_edge(DerivedMesh *dm, int index) return &((CDDerivedMesh*)dm)->medge[index]; } -MFace *CDDM_get_face(DerivedMesh *dm, int index) +MFace *CDDM_get_tessface(DerivedMesh *dm, int index) { return &((CDDerivedMesh*)dm)->mface[index]; } @@ -1278,11 +1648,85 @@ MEdge *CDDM_get_edges(DerivedMesh *dm) return ((CDDerivedMesh*)dm)->medge; } -MFace *CDDM_get_faces(DerivedMesh *dm) +MFace *CDDM_get_tessfaces(DerivedMesh *dm) { return ((CDDerivedMesh*)dm)->mface; } +void CDDM_tessfaces_to_faces(DerivedMesh *dm) +{ + /*converts mfaces to mpolys/mloops*/ + CDDerivedMesh *cddm = (CDDerivedMesh*)dm; + MFace *mf; + MEdge *me; + MLoop *ml; + MPoly *mp; + EdgeHash *eh = BLI_edgehash_new(); + int i, l, totloop, *index1, *index2; + + me = cddm->medge; + for (i=0; i<cddm->dm.numEdgeData; i++, me++) { + BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i)); + } + + mf = cddm->mface; + totloop = 0; + for (i=0; i<cddm->dm.numFaceData; i++, mf++) { + totloop += mf->v4 ? 4 : 3; + } + + CustomData_free(&cddm->dm.polyData, cddm->dm.numPolyData); + CustomData_free(&cddm->dm.loopData, cddm->dm.numLoopData); + + cddm->dm.numLoopData = totloop; + cddm->dm.numPolyData = cddm->dm.numFaceData; + + if (!totloop) return; + + cddm->mloop = MEM_callocN(sizeof(MLoop)*totloop, "cddm->mloop in CDDM_tessfaces_to_faces"); + cddm->mpoly = MEM_callocN(sizeof(MPoly)*cddm->dm.numFaceData, "cddm->mpoly in CDDM_tessfaces_to_faces"); + + CustomData_add_layer(&cddm->dm.loopData, CD_MLOOP, CD_ASSIGN, cddm->mloop, totloop); + CustomData_add_layer(&cddm->dm.polyData, CD_MPOLY, CD_ASSIGN, cddm->mpoly, cddm->dm.numPolyData); + CustomData_merge(&cddm->dm.faceData, &cddm->dm.polyData, + CD_MASK_DERIVEDMESH, CD_DUPLICATE, cddm->dm.numFaceData); + + index1 = CustomData_get_layer(&cddm->dm.faceData, CD_ORIGINDEX); + index2 = CustomData_get_layer(&cddm->dm.polyData, CD_ORIGINDEX); + + mf = cddm->mface; + mp = cddm->mpoly; + ml = cddm->mloop; + l = 0; + for (i=0; i<cddm->dm.numFaceData; i++, mf++, mp++) { + mp->flag = mf->flag; + mp->loopstart = l; + mp->mat_nr = mf->mat_nr; + mp->totloop = mf->v4 ? 4 : 3; + + ml->v = mf->v1; + ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); + ml++, l++; + + ml->v = mf->v2; + ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v2, mf->v3)); + ml++, l++; + + ml->v = mf->v3; + ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v3, mf->v4?mf->v4:mf->v1)); + ml++, l++; + + if (mf->v4) { + ml->v = mf->v4; + ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v4, mf->v1)); + ml++, l++; + } + + } + + BLI_edgehash_free(eh, NULL); +} + /* Multires DerivedMesh, extends CDDM */ typedef struct MultiresDM { CDDerivedMesh cddm; @@ -1337,7 +1781,9 @@ static void MultiresDM_release(DerivedMesh *dm) } } -DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, int numVerts, int numEdges, int numFaces) +DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, + int numVerts, int numEdges, int numFaces, + int numLoops, int numPolys) { MultiresDM *mrdm = MEM_callocN(sizeof(MultiresDM), "MultiresDM"); CDDerivedMesh *cddm = cdDM_create("MultiresDM CDDM"); @@ -1355,7 +1801,8 @@ DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, int numVerts MVert *mvert; int i; - DM_from_template(dm, orig, numVerts, numEdges, numFaces); + DM_from_template(dm, orig, numVerts, numEdges, numFaces, + numLoops, numPolys); CustomData_free_layers(&dm->faceData, CD_MDISPS, numFaces); disps = CustomData_get_layer(&orig->faceData, CD_MDISPS); @@ -1369,7 +1816,7 @@ DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, int numVerts VecCopyf(mrdm->orco[i], mvert[i].co); } else - DM_init(dm, numVerts, numEdges, numFaces); + DM_init(dm, numVerts, numEdges, numFaces, numLoops, numPolys); CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts); CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges); @@ -1472,3 +1919,4 @@ 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 089dafeb8c7..b16a046cd58 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -1017,8 +1017,8 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh *dm ) { unsigned int numverts = dm->getNumVerts ( dm ); - unsigned int numfaces = dm->getNumFaces ( dm ); - MFace *mface = CDDM_get_faces(dm); + unsigned int numfaces = dm->getNumTessFaces ( dm ); + MFace *mface = CDDM_get_tessfaces(dm); unsigned int i = 0; /* Allocate our vertices. */ @@ -1130,9 +1130,9 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) int i = 0; int numverts = dm->getNumVerts ( dm ); int numedges = dm->getNumEdges ( dm ); - int numfaces = dm->getNumFaces ( dm ); + int numfaces = dm->getNumTessFaces ( dm ); MEdge *medge = CDDM_get_edges ( dm ); - MFace *mface = CDDM_get_faces ( dm ); + MFace *mface = CDDM_get_tessfaces ( dm ); int index2 = 0; // our second vertex index LinkNode **edgelist = NULL; EdgeHash *edgehash = NULL; diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 88e73a00ba7..f1420db706f 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -66,6 +66,7 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_idprop.h" +#include "BKE_mesh.h" #include "BKE_shrinkwrap.h" #include "BKE_mesh.h" diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 705d0b66d7f..0173e660e18 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -45,6 +45,8 @@ #include "MEM_guardedalloc.h" +#include "bmesh.h" + #include <math.h> #include <string.h> @@ -257,6 +259,7 @@ static void layerInterp_tface(void **sources, float *weights, } *tf = *(MTFace *)sources[0]; + for(j = 0; j < 4; ++j) { tf->uv[j][0] = uv[j][0]; tf->uv[j][1] = uv[j][1]; @@ -726,6 +729,8 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL}, {sizeof(MCol)*4, "MCol", 4, "WeightCol", NULL, NULL, layerInterp_mcol, layerSwap_mcol, layerDefault_mcol}, + {sizeof(MPoly), "MPoly", 1, "NGon Face", NULL, NULL, NULL, NULL, NULL}, + {sizeof(MLoop), "MLoop", 1, "NGon Face-Vertex", NULL, NULL, NULL, NULL, NULL}, }; const char *LAYERTYPENAMES[CD_NUMTYPES] = { @@ -735,19 +740,22 @@ const char *LAYERTYPENAMES[CD_NUMTYPES] = { "CDMloopCol", "CDTangent", "CDMDisps", "CDWeightMCol"}; const CustomDataMask CD_MASK_BAREMESH = - CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE; + CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE | CD_MASK_MPOLY; 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_MDISPS; + CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS | + CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP; const CustomDataMask CD_MASK_EDITMESH = - CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | + CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MLOOPUV | + CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | 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_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_WEIGHT_MCOL; -const CustomDataMask CD_MASK_BMESH = +const CustomDataMask CD_MASK_BMESH = CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR; const CustomDataMask CD_MASK_FACECORNERS = CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | @@ -800,7 +808,7 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest, if(layer->flag & CD_FLAG_NOCOPY) continue; else if(!((int)mask & (int)(1 << (int)type))) continue; - else if(number < CustomData_number_of_layers(dest, type)) continue; + else if(number+1 < CustomData_number_of_layers(dest, type)) continue; if((alloctype == CD_ASSIGN) && (layer->flag & CD_FLAG_NOFREE)) newlayer = customData_add_layer__internal(dest, type, CD_REFERENCE, @@ -1480,6 +1488,19 @@ void *CustomData_get(const CustomData *data, int index, int type) return (char *)data->layers[layer_index].data + offset; } +void *CustomData_get_n(const CustomData *data, int type, int index, int n) +{ + int layer_index; + int offset; + + /* get the layer index of the first layer of type */ + layer_index = CustomData_get_layer_index(data, type); + if(layer_index < 0) return NULL; + + offset = layerType_getInfo(type)->size * index; + return (char *)data->layers[layer_index].data + offset; +} + void *CustomData_get_layer(const CustomData *data, int type) { /* get the layer index of the active layer of type */ @@ -1814,16 +1835,17 @@ void CustomData_from_em_block(const CustomData *source, CustomData *dest, /*Bmesh functions*/ /*needed to convert to/from different face reps*/ -void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata) +void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, + int totloop, int totpoly) { int i; for(i=0; i < fdata->totlayer; i++){ if(fdata->layers[i].type == CD_MTFACE){ - CustomData_add_layer(pdata, CD_MTEXPOLY, CD_CALLOC, &(fdata->layers[i].name), 0); - CustomData_add_layer(ldata, CD_MLOOPUV, CD_CALLOC, &(fdata->layers[i].name), 0); + CustomData_add_layer(pdata, CD_MTEXPOLY, CD_CALLOC, &(fdata->layers[i].name), totpoly); + CustomData_add_layer(ldata, CD_MLOOPUV, CD_CALLOC, &(fdata->layers[i].name), totloop); } else if(fdata->layers[i].type == CD_MCOL) - CustomData_add_layer(ldata, CD_MLOOPCOL, CD_CALLOC, &(fdata->layers[i].name), 0); + CustomData_add_layer(ldata, CD_MLOOPCOL, CD_CALLOC, &(fdata->layers[i].name), totloop); } } void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total){ @@ -1843,6 +1865,54 @@ void CustomData_bmesh_init_pool(CustomData *data, int allocsize){ if(data->totlayer)data->pool = BLI_mempool_create(data->totsize, allocsize, allocsize); } +void CustomData_bmesh_merge(CustomData *source, CustomData *dest, + int mask, int alloctype, BMesh *bm, int type) +{ + BMHeader *h; + BMIter iter; + CustomData destold = *dest; + void *tmp; + int i, t; + + CustomData_merge(source, dest, mask, alloctype, 0); + CustomData_bmesh_init_pool(dest, 512); + + switch (type) { + case BM_VERT: + t = BM_VERTS_OF_MESH; break; + case BM_EDGE: + t = BM_EDGES_OF_MESH; break; + case BM_LOOP: + t = BM_LOOPS_OF_FACE; break; + case BM_FACE: + t = BM_FACES_OF_MESH; break; + } + + if (t != BM_LOOPS_OF_FACE) { + /*ensure all current elements follow new customdata layout*/ + BM_ITER(h, &iter, bm, t, NULL) { + CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp); + CustomData_bmesh_free_block(&destold, &h->data); + h->data = tmp; + } + } else { + BMFace *f; + BMLoop *l; + BMIter liter; + + /*ensure all current elements follow new customdata layout*/ + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) { + CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp); + CustomData_bmesh_free_block(&destold, &h->data); + h->data = tmp; + } + } + } + + if (destold.pool) BLI_mempool_destroy(destold.pool); +} + void CustomData_bmesh_free_block(CustomData *data, void **block) { const LayerTypeInfo *typeInfo; diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index cdf4b90cee1..3136630ce93 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -526,10 +526,10 @@ static void mesh_create_shadedColors(Render *re, Object *ob, int onlyForMesh, un dm = mesh_get_derived_final(RE_GetScene(re), ob, dataMask); mvert = dm->getVertArray(dm); - mface = dm->getFaceArray(dm); - nors = dm->getFaceDataArray(dm, CD_NORMAL); + mface = dm->getTessFaceArray(dm); + nors = dm->getTessFaceDataArray(dm, CD_NORMAL); totvert = dm->getNumVerts(dm); - totface = dm->getNumFaces(dm); + totface = dm->getNumTessFaces(dm); orco= dm->getVertDataArray(dm, CD_ORCO); if (onlyForMesh) { diff --git a/source/blender/blenkernel/intern/editderivedbmesh.c b/source/blender/blenkernel/intern/editderivedbmesh.c new file mode 100644 index 00000000000..fa9747ec54f --- /dev/null +++ b/source/blender/blenkernel/intern/editderivedbmesh.c @@ -0,0 +1,1526 @@ +/** + * $Id: editderivedbmesh.c 18571 2009-01-19 06:04:57Z joeedh $ + * + * ***** 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 Tbmple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "PIL_time.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_effect_types.h" +#include "DNA_mesh_types.h" +#include "DNA_key_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force.h" +#include "DNA_object_fluidsim.h" // N_T +#include "DNA_scene_types.h" // N_T +#include "DNA_texture_types.h" +#include "DNA_view3d_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_particle_types.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_editVert.h" +#include "BLI_edgehash.h" +#include "BLI_linklist.h" +#include "BLI_memarena.h" +#include "BLI_scanfill.h" +#include "BLI_ghash.h" + +#include "BKE_cdderivedmesh.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#include "BKE_deform.h" +#include "BKE_displist.h" +#include "BKE_effect.h" +#include "BKE_fluidsim.h" +#include "BKE_global.h" +#include "BKE_key.h" +#include "BKE_material.h" +#include "BKE_modifier.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_subsurf.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" +#include "BKE_particle.h" +#include "BKE_tessmesh.h" + +#include "BLO_sys_types.h" // for intptr_t support + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_draw.h" +#include "GPU_extensions.h" +#include "GPU_material.h" + +#include "bmesh.h" + +BMEditMesh *BMEdit_Create(BMesh *bm) +{ + BMEditMesh *tm = MEM_callocN(sizeof(BMEditMesh), "tm"); + + tm->bm = bm; + + BMEdit_RecalcTesselation(tm); + + return tm; +} + +BMEditMesh *BMEdit_Copy(BMEditMesh *tm) +{ + BMEditMesh *tm2 = MEM_callocN(sizeof(BMEditMesh), "tm2"); + *tm2 = *tm; + + tm2->derivedCage = tm2->derivedFinal = NULL; + + tm2->looptris = NULL; + tm2->bm = BM_Copy_Mesh(tm->bm); + BMEdit_RecalcTesselation(tm2); + + tm2->vert_index = NULL; + tm2->edge_index = NULL; + tm2->face_index = NULL; + + return tm2; +} + +static void BMEdit_RecalcTesselation_intern(BMEditMesh *tm) +{ + BMesh *bm = tm->bm; + BMLoop **looptris = NULL; + V_DYNDECLARE(looptris); + BMIter iter, liter; + BMFace *f; + BMLoop *l; + int i = 0, j; + + if (tm->looptris) MEM_freeN(tm->looptris); + + f = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); + for ( ; f; f=BMIter_Step(&iter)) { + /*don't consider two-edged faces*/ + if (f->len < 3) continue; + + if (f->len <= 4) { + /*triangle fan for quads. should be recoded to + just add one tri for tris, and two for quads, + but this code works for now too.*/ + l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f); + for (; l; l=BMIter_Step(&liter)) { + if (l == f->loopbase) continue; + if ((BMLoop*)l->head.next == f->loopbase) continue; + + V_GROW(looptris); + V_GROW(looptris); + V_GROW(looptris); + + looptris[i*3] = l; + looptris[i*3+1] = (BMLoop*)l->head.next; + looptris[i*3+2] = f->loopbase; + + i += 1; + } + } else { + /*scanfill time*/ + EditVert *v, *lastv=NULL, *firstv=NULL; + EditEdge *e; + EditFace *efa; + + l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f); + for (j=0; l; l=BMIter_Step(&liter), j++) { + /*mark order*/ + l->head.eflag2 = j; + + v = BLI_addfillvert(l->v->co); + v->tmp.p = l; + + if (lastv) { + e = BLI_addfilledge(lastv, v); + } + + lastv = v; + if (firstv==NULL) firstv = v; + } + + /*complete the loop*/ + BLI_addfilledge(firstv, v); + + BLI_edgefill(0, 0); + + for (efa = fillfacebase.first; efa; efa=efa->next) { + V_GROW(looptris); + V_GROW(looptris); + V_GROW(looptris); + + looptris[i*3] = efa->v1->tmp.p; + looptris[i*3+1] = efa->v2->tmp.p; + looptris[i*3+2] = efa->v3->tmp.p; + + if (looptris[i*3]->head.eflag2 > looptris[i*3+1]->head.eflag2); + SWAP(BMLoop*, looptris[i*3], looptris[i*3+1]); + if (looptris[i*3+1]->head.eflag2 > looptris[i*3+2]->head.eflag2); + SWAP(BMLoop*, looptris[i*3+1], looptris[i*3+2]); + if (looptris[i*3]->head.eflag2 > looptris[i*3+1]->head.eflag2); + SWAP(BMLoop*, looptris[i*3], looptris[i*3+1]); + + i += 1; + } + BLI_end_edgefill(); + } + } + + tm->tottri = i; + tm->looptris = looptris; +} + +void BMEdit_RecalcTesselation(BMEditMesh *tm) +{ + BMEdit_RecalcTesselation_intern(tm); + + if (tm->derivedFinal && tm->derivedFinal == tm->derivedCage) { + if (tm->derivedFinal->recalcTesselation) + tm->derivedFinal->recalcTesselation(tm->derivedFinal); + } else if (tm->derivedFinal) { + if (tm->derivedCage->recalcTesselation) + tm->derivedCage->recalcTesselation(tm->derivedCage); + if (tm->derivedFinal->recalcTesselation) + tm->derivedFinal->recalcTesselation(tm->derivedFinal); + } +} + +/*does not free the BMEditMesh struct itself*/ +void BMEdit_Free(BMEditMesh *em) +{ + if(em->derivedFinal) { + if (em->derivedFinal!=em->derivedCage) { + em->derivedFinal->needsFree= 1; + em->derivedFinal->release(em->derivedFinal); + } + em->derivedFinal= NULL; + } + if(em->derivedCage) { + em->derivedCage->needsFree= 1; + em->derivedCage->release(em->derivedCage); + em->derivedCage= NULL; + } + + em->retopo_paint_data= NULL; + + if (em->looptris) MEM_freeN(em->looptris); + + if (em->vert_index) MEM_freeN(em->vert_index); + if (em->edge_index) MEM_freeN(em->edge_index); + if (em->face_index) MEM_freeN(em->face_index); + + BM_Free_Mesh(em->bm); +} + + +/* +ok, basic design: + +the bmesh derivedmesh exposes the mesh as triangles. it stores pointers +to three loops per triangle. the derivedmesh stores a cache of tesselations +for each face. this cache will smartly update as needed (though at first +it'll simply be more brute force). keeping track of face/edge counts may +be a small problbm. + +this won't be the most efficient thing, considering that internal edges and +faces of tesselations are exposed. looking up an edge by index in particular +is likely to be a little slow. +*/ + +typedef struct EditDerivedBMesh { + DerivedMesh dm; + + Object *ob; + BMEditMesh *tc; + + float (*vertexCos)[3]; + float (*vertexNos)[3]; + float (*faceNos)[3]; + + /*lookup caches; these are rebuilt on dm->RecalcTesselation() + (or when the derivedmesh is created, of course)*/ + GHash *vhash, *ehash, *fhash; + BMVert **vtable; + BMEdge **etable; + BMFace **ftable; + + /*private variables, for number of verts/edges/faces + within the above hash/table members*/ + int tv, te, tf; +} EditDerivedBMesh; + +static void bmdm_recalc_lookups(EditDerivedBMesh *bmdm) +{ + BMIter iter; + BMHeader *h; + int a, i, iters[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH}; + + bmdm->tv = bmdm->tc->bm->totvert; + bmdm->te = bmdm->tc->bm->totedge; + bmdm->tf = bmdm->tc->bm->totface; + + if (bmdm->vhash) BLI_ghash_free(bmdm->vhash, NULL, NULL); + if (bmdm->ehash) BLI_ghash_free(bmdm->ehash, NULL, NULL); + if (bmdm->fhash) BLI_ghash_free(bmdm->fhash, NULL, NULL); + + bmdm->vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + bmdm->ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + bmdm->fhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + if (bmdm->vtable) MEM_freeN(bmdm->vtable); + if (bmdm->etable) MEM_freeN(bmdm->etable); + if (bmdm->ftable) MEM_freeN(bmdm->ftable); + + if (bmdm->tc->bm->totvert) + bmdm->vtable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totvert, "bmdm->vtable"); + else bmdm->vtable = NULL; + + if (bmdm->tc->bm->totedge) + bmdm->etable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totedge, "bmdm->etable"); + else bmdm->etable = NULL; + + if (bmdm->tc->bm->totface) + bmdm->ftable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totface, "bmdm->ftable"); + else bmdm->ftable = NULL; + + for (a=0; a<3; a++) { + h = BMIter_New(&iter, bmdm->tc->bm, iters[a], NULL); + for (i=0; h; h=BMIter_Step(&iter), i++) { + switch (a) { + case 0: + bmdm->vtable[i] = (BMVert*) h; + BLI_ghash_insert(bmdm->vhash, h, SET_INT_IN_POINTER(i)); + break; + case 1: + bmdm->etable[i] = (BMEdge*) h; + BLI_ghash_insert(bmdm->ehash, h, SET_INT_IN_POINTER(i)); + break; + case 2: + bmdm->ftable[i] = (BMFace*) h; + BLI_ghash_insert(bmdm->fhash, h, SET_INT_IN_POINTER(i)); + break; + + } + } + } +} + +static void bmDM_recalcTesselation(DerivedMesh *dm) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + + bmdm_recalc_lookups(bmdm); +} + +static void bmDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + BMVert *eve; + BMIter iter; + int i; + + eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; i++, eve=BMIter_Step(&iter)) { + if (bmdm->vertexCos) { + func(userData, i, bmdm->vertexCos[i], bmdm->vertexNos[i], NULL); + } else { + func(userData, i, eve->co, eve->no, NULL); + } + } +} +static void bmDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + BMEdge *eed; + BMIter iter; + int i; + + if (bmdm->vertexCos) { + BMVert *eve; + BMIter viter; + + eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&viter), i++) { + BMINDEX_SET(eve, i); + } + + eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL); + for(i=0; eed; i++,eed=BMIter_Step(&iter)) + func(userData, i, + bmdm->vertexCos[BMINDEX_GET(eve)], + bmdm->vertexCos[BMINDEX_GET(eve)]); + } else { + eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL); + for(i=0; eed; i++,eed=BMIter_Step(&iter)) + func(userData, i, eed->v1->co, eed->v2->co); + } + +} + +static void bmDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + BMEdge *eed; + BMIter iter; + int i; + + if (bmdm->vertexCos) { + BMVert *eve; + BMIter viter; + + eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&viter)) { + BMINDEX_SET(eve, i); + } + + glBegin(GL_LINES); + eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL); + for(i=0; eed; i++,eed=BMIter_Step(&iter)) { + if(!setDrawOptions || setDrawOptions(userData, i)) { + glVertex3fv(bmdm->vertexCos[BMINDEX_GET(eed->v1)]); + glVertex3fv(bmdm->vertexCos[BMINDEX_GET(eed->v2)]); + } + } + glEnd(); + + } else { + glBegin(GL_LINES); + eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL); + for(i=0; eed; i++,eed=BMIter_Step(&iter)) { + if(!setDrawOptions || setDrawOptions(userData, i)) { + glVertex3fv(eed->v1->co); + glVertex3fv(eed->v2->co); + } + } + glEnd(); + } +} + +static void bmDM_drawEdges(DerivedMesh *dm, int drawLooseEdges) +{ + bmDM_drawMappedEdges(dm, NULL, NULL); +} + +static void bmDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + BMEdge *eed; + BMIter iter; + int i; + + if (bmdm->vertexCos) { + BMVert *eve; + + eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter), i++) + BMINDEX_SET(eve, i); + + glBegin(GL_LINES); + eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL); + for(i=0; eed; i++,eed=BMIter_Step(&iter)) { + if(!setDrawOptions || setDrawOptions(userData, i)) { + setDrawInterpOptions(userData, i, 0.0); + glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(eed->v1)]); + setDrawInterpOptions(userData, i, 1.0); + glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(eed->v2)]); + } + } + glEnd(); + } else { + glBegin(GL_LINES); + eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL); + for(i=0; eed; i++,eed=BMIter_Step(&iter)) { + if(!setDrawOptions || setDrawOptions(userData, i)) { + setDrawInterpOptions(userData, i, 0.0); + glVertex3fv(eed->v1->co); + setDrawInterpOptions(userData, i, 1.0); + glVertex3fv(eed->v2->co); + } + } + glEnd(); + } +} + +static void bmDM_drawUVEdges(DerivedMesh *dm) +{ +#if 0 + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + BMFace *efa; + MTFace *tf; + + glBegin(GL_LINES); + for(efa= bmdm->tc->bm->faces.first; efa; efa= efa->next) { + tf = CustomData_bm_get(&bmdm->tc->bm->pdata, efa->data, CD_MTFACE); + + if(tf && !(efa->h)) { + glVertex2fv(tf->uv[0]); + glVertex2fv(tf->uv[1]); + + glVertex2fv(tf->uv[1]); + glVertex2fv(tf->uv[2]); + + if (!efa->v4) { + glVertex2fv(tf->uv[2]); + glVertex2fv(tf->uv[0]); + } else { + glVertex2fv(tf->uv[2]); + glVertex2fv(tf->uv[3]); + glVertex2fv(tf->uv[3]); + glVertex2fv(tf->uv[0]); + } + } + } + glEnd(); +#endif +} + +static void bmDM__calcFaceCent(BMesh *bm, BMFace *efa, float cent[3], + float (*vertexCos)[3]) +{ + BMIter iter; + BMLoop *l; + int tot = 0; + + cent[0] = cent[1] = cent[2] = 0.0f; + + /*simple (and stupid) median (average) based method :/ */ + + l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa); + for (; l; l=BMIter_Step(&iter)) { + VECADD(cent, cent, l->v->co); + tot++; + } + + if (tot==0) return; + VECMUL(cent, 1.0f/(float)tot); +} + +static void bmDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + BMVert *eve; + BMFace *efa; + BMIter iter; + float cent[3]; + int i; + + if (bmdm->vertexCos) { + eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter)); + BMINDEX_SET(eve, i); + } + + efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL); + for (i=0; efa; efa=BMIter_Step(&iter), i++) { + bmDM__calcFaceCent(bmdm->tc->bm, efa, cent, bmdm->vertexCos); + func(userData, i, cent, bmdm->vertexCos?bmdm->faceNos[i]:efa->no); + } +} + +static void bmDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + BMFace *efa; + BMIter iter; + int i, draw; + + if (bmdm->vertexCos) { + BMVert *eve; + + eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter)) + BMINDEX_SET(eve, i); + + efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL); + for (i=0; efa; efa=BMIter_Step(&iter), i++) + BMINDEX_SET(efa, i); + + for (i=0; i<bmdm->tc->tottri; i++) { + BMLoop **l = bmdm->tc->looptris[i]; + int drawSmooth; + + drawSmooth = (efa->head.flag & BM_SMOOTH); + efa = l[0]->f; + + draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BMINDEX_GET(efa), &drawSmooth); + if(draw) { + if (draw==2) { /* enabled with stipple */ + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(stipple_quarttone); + } + + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + + glBegin(GL_TRIANGLES); + + if (!drawSmooth) { + glNormal3fv(efa->no); + glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[0]->v)]); + glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[1]->v)]); + glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[2]->v)]); + } else { + glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[0]->v)]); + glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[0]->v)]); + glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[1]->v)]); + glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[1]->v)]); + glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[2]->v)]); + glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[2]->v)]); + } + glEnd(); + + if (draw==2) + glDisable(GL_POLYGON_STIPPLE); + } + } + } else { + efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL); + for (i=0; efa; efa=BMIter_Step(&iter), i++) + BMINDEX_SET(efa, i); + + for (i=0; i<bmdm->tc->tottri; i++) { + BMLoop **l = bmdm->tc->looptris[i]; + int drawSmooth; + + efa = l[0]->f; + + drawSmooth = (efa->head.flag & BM_SMOOTH); + + draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BMINDEX_GET(efa), &drawSmooth); + if(draw) { + if (draw==2) { /* enabled with stipple */ + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(stipple_quarttone); + } + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + + glBegin(GL_TRIANGLES); + if (!drawSmooth) { + glNormal3fv(efa->no); + glVertex3fv(l[0]->v->co); + glVertex3fv(l[1]->v->co); + glVertex3fv(l[2]->v->co); + } else { + glNormal3fv(l[0]->v->no); + glVertex3fv(l[0]->v->co); + glNormal3fv(l[1]->v->no); + glVertex3fv(l[1]->v->co); + glNormal3fv(l[2]->v->no); + glVertex3fv(l[2]->v->co); + } + glEnd(); + + if (draw==2) + glDisable(GL_POLYGON_STIPPLE); + } + } + } +} + +static void bmDM_drawFacesTex_common(DerivedMesh *dm, + int (*drawParams)(MTFace *tface, MCol *mcol, int matnr), + int (*drawParamsMapped)(void *userData, int index), + void *userData) +{ +#if 0 + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + BMesh *bm= bmdm->tc->bm; + float (*vertexCos)[3]= bmdm->vertexCos; + float (*vertexNos)[3]= bmdm->vertexNos; + BMFace *efa; + BMIter iter; + int i; + + /* always use smooth shading even for flat faces, else vertex colors wont interpolate */ + glShadeModel(GL_SMOOTH); + + if (vertexCos) { + BMVert *eve; + + for (i=0,eve=bm->verts.first; eve; eve= eve->next) + BMINDEX_SET(eve, i++); + + for (i=0,efa= bm->faces.first; efa; i++,efa= efa->next) { + MTFace *tf= CustomData_bm_get(&bm->pdata, efa->data, CD_MTFACE); + MCol *mcol= CustomData_bm_get(&bm->pdata, efa->data, CD_MCOL); + unsigned char *cp= NULL; + int drawSmooth= (efa->flag & ME_SMOOTH); + int flag; + + if(drawParams) + flag= drawParams(tf, mcol, efa->mat_nr); + else if(drawParamsMapped) + flag= drawParamsMapped(userData, i); + else + flag= 1; + + if(flag != 0) { /* flag 0 == the face is hidden or invisible */ + + /* we always want smooth here since otherwise vertex colors dont interpolate */ + if (mcol) { + if (flag==1) { + cp= (unsigned char*)mcol; + } + } else { + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + } + + glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); + if (!drawSmooth) { + glNormal3fv(bmdm->faceNos[i]); + + if(tf) glTexCoord2fv(tf->uv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glVertex3fv(vertexCos[(int) efa->v1->tmp.l]); + + if(tf) glTexCoord2fv(tf->uv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glVertex3fv(vertexCos[(int) efa->v2->tmp.l]); + + if(tf) glTexCoord2fv(tf->uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glVertex3fv(vertexCos[(int) efa->v3->tmp.l]); + + if(efa->v4) { + if(tf) glTexCoord2fv(tf->uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glVertex3fv(vertexCos[(int) efa->v4->tmp.l]); + } + } else { + if(tf) glTexCoord2fv(tf->uv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glNormal3fv(vertexNos[(int) efa->v1->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v1->tmp.l]); + + if(tf) glTexCoord2fv(tf->uv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glNormal3fv(vertexNos[(int) efa->v2->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v2->tmp.l]); + + if(tf) glTexCoord2fv(tf->uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glNormal3fv(vertexNos[(int) efa->v3->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v3->tmp.l]); + + if(efa->v4) { + if(tf) glTexCoord2fv(tf->uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glNormal3fv(vertexNos[(int) efa->v4->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v4->tmp.l]); + } + } + glEnd(); + } + } + } else { + for (i=0,efa= bm->faces.first; efa; i++,efa= efa->next) { + MTFace *tf= CustomData_bm_get(&bm->pdata, efa->data, CD_MTFACE); + MCol *mcol= CustomData_bm_get(&bm->pdata, efa->data, CD_MCOL); + unsigned char *cp= NULL; + int drawSmooth= (efa->flag & ME_SMOOTH); + int flag; + + if(drawParams) + flag= drawParams(tf, mcol, efa->mat_nr); + else if(drawParamsMapped) + flag= drawParamsMapped(userData, i); + else + flag= 1; + + if(flag != 0) { /* flag 0 == the face is hidden or invisible */ + /* we always want smooth here since otherwise vertex colors dont interpolate */ + if (mcol) { + if (flag==1) { + cp= (unsigned char*)mcol; + } + } else { + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + } + + glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); + if (!drawSmooth) { + glNormal3fv(efa->n); + + if(tf) glTexCoord2fv(tf->uv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glVertex3fv(efa->v1->co); + + if(tf) glTexCoord2fv(tf->uv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glVertex3fv(efa->v2->co); + + if(tf) glTexCoord2fv(tf->uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glVertex3fv(efa->v3->co); + + if(efa->v4) { + if(tf) glTexCoord2fv(tf->uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glVertex3fv(efa->v4->co); + } + } else { + if(tf) glTexCoord2fv(tf->uv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glNormal3fv(efa->v1->no); + glVertex3fv(efa->v1->co); + + if(tf) glTexCoord2fv(tf->uv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glNormal3fv(efa->v2->no); + glVertex3fv(efa->v2->co); + + if(tf) glTexCoord2fv(tf->uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glNormal3fv(efa->v3->no); + glVertex3fv(efa->v3->co); + + if(efa->v4) { + if(tf) glTexCoord2fv(tf->uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glNormal3fv(efa->v4->no); + glVertex3fv(efa->v4->co); + } + } + glEnd(); + } + } + } +#endif +} + +static void bmDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr)) +{ + bmDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL); +} + +static void bmDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) +{ + bmDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData); +} + +static void bmDM_drawMappedFacesGLSL(DerivedMesh *dm, + int (*setMaterial)(int, void *attribs), + int (*setDrawOptions)(void *userData, int index), void *userData) +{ +#if 0 + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + BMesh *bm= bmdm->tc->bm; + float (*vertexCos)[3]= bmdm->vertexCos; + float (*vertexNos)[3]= bmdm->vertexNos; + BMVert *eve; + BMFace *efa; + DMVertexAttribs attribs; + GPUVertexAttribs gattribs; + MTFace *tf; + int transp, new_transp, orig_transp, tfoffset; + int i, b, matnr, new_matnr, dodraw, layer; + + dodraw = 0; + matnr = -1; + + transp = GPU_get_material_blend_mode(); + orig_transp = transp; + layer = CustomData_get_layer_index(&bm->pdata, CD_MTFACE); + tfoffset = (layer == -1)? -1: bm->pdata.layers[layer].offset; + + memset(&attribs, 0, sizeof(attribs)); + + /* always use smooth shading even for flat faces, else vertex colors wont interpolate */ + glShadeModel(GL_SMOOTH); + + for (i=0,eve=bm->verts.first; eve; eve= eve->next) + BMINDEX_SET(eve, i++); + +#define PASSATTRIB(efa, eve, vert) { \ + if(attribs.totorco) { \ + float *orco = attribs.orco.array[BMINDEX_GET(eve)]; \ + glVertexAttrib3fvARB(attribs.orco.glIndex, orco); \ + } \ + for(b = 0; b < attribs.tottface; b++) { \ + MTFace *_tf = (MTFace*)((char*)efa->data + attribs.tface[b].bmOffset); \ + glVertexAttrib2fvARB(attribs.tface[b].glIndex, _tf->uv[vert]); \ + } \ + for(b = 0; b < attribs.totmcol; b++) { \ + MCol *cp = (MCol*)((char*)efa->data + attribs.mcol[b].bmOffset); \ + GLubyte col[4]; \ + col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a; \ + glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, col); \ + } \ + if(attribs.tottang) { \ + float *tang = attribs.tang.array[i*4 + vert]; \ + glVertexAttrib3fvARB(attribs.tang.glIndex, tang); \ + } \ +} + + for (i=0,efa= bm->faces.first; efa; i++,efa= efa->next) { + int drawSmooth= (efa->flag & ME_SMOOTH); + + if(setDrawOptions && !setDrawOptions(userData, i)) + continue; + + new_matnr = efa->mat_nr + 1; + if(new_matnr != matnr) { + dodraw = setMaterial(matnr = new_matnr, &gattribs); + if(dodraw) + DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs); + } + + if(tfoffset != -1) { + tf = (MTFace*)((char*)efa->data)+tfoffset; + new_transp = tf->transp; + + if(new_transp != transp) { + if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID) + GPU_set_material_blend_mode(orig_transp); + else + GPU_set_material_blend_mode(new_transp); + transp = new_transp; + } + } + + if(dodraw) { + glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); + if (!drawSmooth) { + if(vertexCos) glNormal3fv(bmdm->faceNos[i]); + else glNormal3fv(efa->n); + + PASSATTRIB(efa, efa->v1, 0); + if(vertexCos) glVertex3fv(vertexCos[(int) efa->v1->tmp.l]); + else glVertex3fv(efa->v1->co); + + PASSATTRIB(efa, efa->v2, 1); + if(vertexCos) glVertex3fv(vertexCos[(int) efa->v2->tmp.l]); + else glVertex3fv(efa->v2->co); + + PASSATTRIB(efa, efa->v3, 2); + if(vertexCos) glVertex3fv(vertexCos[(int) efa->v3->tmp.l]); + else glVertex3fv(efa->v3->co); + + if(efa->v4) { + PASSATTRIB(efa, efa->v4, 3); + if(vertexCos) glVertex3fv(vertexCos[(int) efa->v4->tmp.l]); + else glVertex3fv(efa->v4->co); + } + } else { + PASSATTRIB(efa, efa->v1, 0); + if(vertexCos) { + glNormal3fv(vertexNos[(int) efa->v1->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v1->tmp.l]); + } + else { + glNormal3fv(efa->v1->no); + glVertex3fv(efa->v1->co); + } + + PASSATTRIB(efa, efa->v2, 1); + if(vertexCos) { + glNormal3fv(vertexNos[(int) efa->v2->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v2->tmp.l]); + } + else { + glNormal3fv(efa->v2->no); + glVertex3fv(efa->v2->co); + } + + PASSATTRIB(efa, efa->v3, 2); + if(vertexCos) { + glNormal3fv(vertexNos[(int) efa->v3->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v3->tmp.l]); + } + else { + glNormal3fv(efa->v3->no); + glVertex3fv(efa->v3->co); + } + + if(efa->v4) { + PASSATTRIB(efa, efa->v4, 3); + if(vertexCos) { + glNormal3fv(vertexNos[(int) efa->v4->tmp.l]); + glVertex3fv(vertexCos[(int) efa->v4->tmp.l]); + } + else { + glNormal3fv(efa->v4->no); + glVertex3fv(efa->v4->co); + } + } + } + glEnd(); + } + } +#endif +} + +static void bmDM_drawFacesGLSL(DerivedMesh *dm, + int (*setMaterial)(int, void *attribs)) +{ + dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL); +} + +static void bmDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + BMVert *eve; + BMIter iter; + int i; + + if (bmdm->tc->bm->verts.first) { + eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter), i++) { + if (bmdm->vertexCos) { + DO_MINMAX(bmdm->vertexCos[i], min_r, max_r); + } else { + DO_MINMAX(eve->co, min_r, max_r); + } + } + } else { + min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0; + } +} +static int bmDM_getNumVerts(DerivedMesh *dm) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + + return bmdm->tc->bm->totvert; +} + +static int bmDM_getNumEdges(DerivedMesh *dm) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + + return bmdm->tc->bm->totedge; +} + +static int bmDM_getNumTessFaces(DerivedMesh *dm) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + + return bmdm->tc->tottri; +} + +static int bmDM_getNumFaces(DerivedMesh *dm) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + + return bmdm->tc->bm->totface; +} + +static int bmvert_to_mvert(BMVert *ev, MVert *vert_r) +{ + VECCOPY(vert_r->co, ev->co); + + vert_r->no[0] = (short)(ev->no[0] * 32767.0f); + vert_r->no[1] = (short)(ev->no[1] * 32767.0f); + vert_r->no[2] = (short)(ev->no[2] * 32767.0f); + + /* TODO what to do with vert_r->flag and vert_r->mat_nr? */ + vert_r->flag = BMFlags_To_MEFlags(ev); + vert_r->mat_nr = 0; + vert_r->bweight = (unsigned char) (ev->bweight*255.0f); +} + +static void bmDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) +{ + BMVert *ev; + BMIter iter; + int i; + + if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tv) { + printf("error in bmDM_getVert.\n"); + return; + } + + ev = ((EditDerivedBMesh *)dm)->vtable[index]; + bmvert_to_mvert(ev, vert_r); +} + +static void bmDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) +{ + EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; + BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm; + BMEdge *e; + BMVert *ev, *v1, *v2; + BMIter iter; + int i; + + if (index < 0 || index >= ((EditDerivedBMesh *)dm)->te) { + printf("error in bmDM_getEdge.\n"); + return; + } + + e = bmdm->etable[index]; + + edge_r->crease = (unsigned char) (e->crease*255.0f); + edge_r->bweight = (unsigned char) (e->bweight*255.0f); + /* TODO what to do with edge_r->flag? */ + edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER; + edge_r->flag |= BMFlags_To_MEFlags(e); +#if 0 + /* this needs setup of f2 field */ + if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE; +#endif + + edge_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v1)); + edge_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v2)); +} + +static void bmDM_getTessFace(DerivedMesh *dm, int index, MFace *face_r) +{ + EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; + BMesh *bm = bmdm->tc->bm; + BMFace *ef; + BMIter iter; + BMLoop **l; + int i; + + if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tf) { + printf("error in bmDM_getTessFace.\n"); + return; + } + + l = ((EditDerivedBMesh *)dm)->tc->looptris[index]; + + ef = l[0]->f; + + face_r->mat_nr = (unsigned char) ef->mat_nr; + face_r->flag = BMFlags_To_MEFlags(ef); + + face_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[0]->v)); + face_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[1]->v)); + face_r->v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[2]->v)); + face_r->v4 = 0; + + test_index_face(face_r, NULL, 0, 3); +} + +static void bmDM_copyVertArray(DerivedMesh *dm, MVert *vert_r) +{ + BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm; + BMVert *ev; + BMIter iter; + + ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for( ; ev; ev = BMIter_Step(&iter), ++vert_r) { + VECCOPY(vert_r->co, ev->co); + + vert_r->no[0] = (short) (ev->no[0] * 32767.0); + vert_r->no[1] = (short) (ev->no[1] * 32767.0); + vert_r->no[2] = (short) (ev->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 = BMFlags_To_MEFlags(ev); + vert_r->bweight = (unsigned char) (ev->bweight*255.0f); + } +} + +static void bmDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r) +{ + BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm; + BMEdge *ee; + BMIter iter; + BMVert *ev; + int i; + + /* store vertex indices in tmp union */ + ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (i=0; ev; ev=BMIter_Step(&iter), i++) + BMINDEX_SET(ev, i); + + ee = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); + for( ; ee; ee=BMIter_Step(&iter)) { + edge_r->crease = (unsigned char) (ee->crease*255.0f); + edge_r->bweight = (unsigned char) (ee->bweight*255.0f); + /* TODO what to do with edge_r->flag? */ + edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER; + if (ee->head.flag & BM_SEAM) edge_r->flag |= ME_SEAM; + if (ee->head.flag & BM_SHARP) edge_r->flag |= ME_SHARP; +#if 0 + /* this needs setup of f2 field */ + if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE; +#endif + + edge_r->v1 = (int)BMINDEX_GET(ee->v1); + edge_r->v2 = (int)BMINDEX_GET(ee->v2); + } +} + +static void bmDM_copyFaceArray(DerivedMesh *dm, MFace *face_r) +{ + EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; + BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm; + BMFace *ef; + BMVert *ev; + BMIter iter; + BMLoop **l; + int i; + + /* store vertexes indices in tmp union */ + ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (i=0; ev; ev=BMIter_Step(&iter), i++) + BMINDEX_SET(ev, i); + + for (i=0; i<bmdm->tc->tottri; i++) { + l = bmdm->tc->looptris[i]; + ef = l[0]->f; + + face_r->mat_nr = (unsigned char) ef->mat_nr; + + /*HACK/TODO: need to convert this*/ + face_r->flag = ef->head.flag; + + face_r->v1 = BMINDEX_GET(l[0]->v); + face_r->v2 = BMINDEX_GET(l[1]->v); + face_r->v3 = BMINDEX_GET(l[2]->v); + face_r->v4 = 0; + + test_index_face(face_r, NULL, 0, 3); + } +} + +static void *bmDM_getFaceDataArray(DerivedMesh *dm, int type) +{ + EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm; + BMesh *bm= bmdm->tc->bm; + BMFace *efa; + char *data, *bmdata; + void *datalayer; + int index, offset, size, i; + + datalayer = DM_get_face_data_layer(dm, type); + if(datalayer) + return datalayer; + + /* layers are store per face for editmesh, we convert to a tbmporary + * data layer array in the derivedmesh when these are requested */ + if(type == CD_MTFACE || type == CD_MCOL) { + index = CustomData_get_layer_index(&bm->pdata, type); + + if(index != -1) { + offset = bm->pdata.layers[index].offset; + size = CustomData_sizeof(type); + + DM_add_face_layer(dm, type, CD_CALLOC, NULL); + index = CustomData_get_layer_index(&dm->faceData, type); + dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY; + + data = datalayer = DM_get_face_data_layer(dm, type); + for (i=0; i<bmdm->tc->tottri; i++, data+=size) { + efa = bmdm->tc->looptris[i][0]->f; + /*BMESH_TODO: need to still add tface data, + derived from the loops.*/ + bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, type); + memcpy(data, bmdata, size); + } + } + } + + return datalayer; +} + +typedef struct bmDM_loopIter { + DMLoopIter head; + + BMFace *f; + BMLoop *l, *nextl; + BMIter iter; + BMesh *bm; +} bmDM_loopIter; + +typedef struct bmDM_faceIter { + DMFaceIter head; + + BMFace *f, *nextf; + BMIter iter; + BMesh *bm; + + bmDM_loopIter loopiter; +} bmDM_faceIter; + +void bmDM_faceIterStep(void *self) +{ + bmDM_faceIter *iter = self; + + iter->f = iter->nextf; + + iter->head.mat_nr = iter->f->mat_nr; + iter->head.flags = BMFlags_To_MEFlags(iter->f); + iter->head.index++; + + iter->nextf = BMIter_Step(&iter->iter); + + if (!iter->nextf) iter->head.done = 1; +} + +void *bmDM_getFaceCDData(void *self, int type, int layer) +{ + bmDM_faceIter *iter = self; + + if (layer == -1) + return CustomData_bmesh_get(&iter->bm->pdata, iter->f->head.data, type); + else return CustomData_bmesh_get_n(&iter->bm->pdata, iter->f->head.data, type, layer); +} + +void bmDM_loopIterStep(void *self) +{ + bmDM_loopIter *iter = self; + + iter->l = iter->nextl; + + bmvert_to_mvert(iter->l->v, &iter->head.v); + iter->head.index++; + iter->head.vindex = BMINDEX_GET(iter->l->v); + iter->head.eindex = BMINDEX_GET(iter->l->e); + + iter->nextl = BMIter_Step(&iter->iter); + + if (!iter->nextl) iter->head.done = 1; +} + +void *bmDM_getLoopCDData(void *self, int type, int layer) +{ + bmDM_loopIter *iter = self; + + if (layer == -1) + return CustomData_bmesh_get(&iter->bm->ldata, iter->l->head.data, type); + else return CustomData_bmesh_get_n(&iter->bm->ldata, iter->l->head.data, type, layer); +} + +void *bmDM_getVertCDData(void *self, int type, int layer) +{ + bmDM_loopIter *iter = self; + + if (layer == -1) + return CustomData_bmesh_get(&iter->bm->vdata, iter->l->v->head.data, type); + else return CustomData_bmesh_get_n(&iter->bm->vdata, iter->l->v->head.data, type, layer); +} + +void bmDM_iterFree(void *self) +{ + MEM_freeN(self); +} + +void bmDM_nulliterFree(void *self) +{ +} + +DMLoopIter *bmDM_newLoopsIter(void *faceiter) +{ + bmDM_faceIter *fiter = faceiter; + bmDM_loopIter *iter = &fiter->loopiter; + + memset(&fiter->loopiter, 0, sizeof(bmDM_loopIter)); + + iter->bm = fiter->bm; + iter->f = fiter->f; + iter->nextl = BMIter_New(&iter->iter, iter->bm, BM_LOOPS_OF_FACE, iter->f); + + iter->head.step = bmDM_loopIterStep; + iter->head.getLoopCDData = bmDM_getLoopCDData; + iter->head.getVertCDData = bmDM_getVertCDData; + + bmvert_to_mvert(iter->nextl->v, &iter->head.v); + iter->head.vindex = BMINDEX_GET(iter->nextl->v); + iter->head.eindex = BMINDEX_GET(iter->nextl->e); + + return (DMLoopIter*) iter; +} + +static DMFaceIter *bmDM_getFaceIter(void *dm) +{ + EditDerivedBMesh *bmdm= dm; + bmDM_faceIter *iter = MEM_callocN(sizeof(bmDM_faceIter), "bmDM_faceIter"); + BMIter biter; + BMVert *v; + BMEdge *e; + int i; + + iter->bm = bmdm->tc->bm; + iter->f = iter->nextf = BMIter_New(&iter->iter, iter->bm, BM_FACES_OF_MESH, NULL); + + iter->head.step = bmDM_faceIterStep; + iter->head.free = bmDM_iterFree; + iter->head.getCDData = bmDM_getFaceCDData; + iter->head.getLoopsIter = bmDM_newLoopsIter; + + iter->head.mat_nr = iter->f->mat_nr; + iter->head.flags = BMFlags_To_MEFlags(iter->f); + + /*set up vert/edge indices*/ + i = 0; + BM_ITER(v, &biter, iter->bm, BM_VERTS_OF_MESH, NULL) { + BMINDEX_SET(v, i); + i++; + } + + i = 0; + BM_ITER(e, &biter, iter->bm, BM_EDGES_OF_MESH, NULL) { + BMINDEX_SET(e, i); + i++; + } + + return (DMFaceIter*) iter; +} + +static void bmDM_release(void *dm) +{ + EditDerivedBMesh *bmdm= dm; + + if (DM_release(dm)) { + if (bmdm->vertexCos) { + MEM_freeN(bmdm->vertexCos); + MEM_freeN(bmdm->vertexNos); + MEM_freeN(bmdm->faceNos); + } + + BLI_ghash_free(bmdm->fhash, NULL, NULL); + BLI_ghash_free(bmdm->ehash, NULL, NULL); + BLI_ghash_free(bmdm->vhash, NULL, NULL); + + if (bmdm->vtable) MEM_freeN(bmdm->vtable); + if (bmdm->etable) MEM_freeN(bmdm->etable); + if (bmdm->ftable) MEM_freeN(bmdm->ftable); + + MEM_freeN(bmdm); + } +} + +DerivedMesh *getEditDerivedBMesh(BMEditMesh *em, Object *ob, + float (*vertexCos)[3]) +{ + EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), "bmdm"); + BMesh *bm = em->bm; + + bmdm->tc = em; + + DM_init((DerivedMesh*)bmdm, em->bm->totvert, em->bm->totedge, em->tottri, + em->bm->totloop, em->bm->totface); + + bmdm->dm.getMinMax = bmDM_getMinMax; + + bmdm->dm.getNumVerts = bmDM_getNumVerts; + bmdm->dm.getNumEdges = bmDM_getNumEdges; + bmdm->dm.getNumTessFaces = bmDM_getNumTessFaces; + bmdm->dm.getNumFaces = bmDM_getNumFaces; + + bmdm->dm.getVert = bmDM_getVert; + bmdm->dm.getEdge = bmDM_getEdge; + bmdm->dm.getTessFace = bmDM_getTessFace; + bmdm->dm.copyVertArray = bmDM_copyVertArray; + bmdm->dm.copyEdgeArray = bmDM_copyEdgeArray; + bmdm->dm.copyTessFaceArray = bmDM_copyFaceArray; + bmdm->dm.getTessFaceDataArray = bmDM_getFaceDataArray; + + bmdm->dm.newFaceIter = bmDM_getFaceIter; + bmdm->dm.recalcTesselation = bmDM_recalcTesselation; + + bmdm->dm.foreachMappedVert = bmDM_foreachMappedVert; + bmdm->dm.foreachMappedEdge = bmDM_foreachMappedEdge; + bmdm->dm.foreachMappedFaceCenter = bmDM_foreachMappedFaceCenter; + + bmdm->dm.drawEdges = bmDM_drawEdges; + bmdm->dm.drawMappedEdges = bmDM_drawMappedEdges; + bmdm->dm.drawMappedEdgesInterp = bmDM_drawMappedEdgesInterp; + bmdm->dm.drawMappedFaces = bmDM_drawMappedFaces; + bmdm->dm.drawMappedFacesTex = bmDM_drawMappedFacesTex; + bmdm->dm.drawMappedFacesGLSL = bmDM_drawMappedFacesGLSL; + bmdm->dm.drawFacesTex = bmDM_drawFacesTex; + bmdm->dm.drawFacesGLSL = bmDM_drawFacesGLSL; + bmdm->dm.drawUVEdges = bmDM_drawUVEdges; + + bmdm->dm.release = bmDM_release; + + bmdm->vertexCos = vertexCos; + + if(CustomData_has_layer(&bm->vdata, CD_MDEFORMVERT)) { + BMIter iter; + BMVert *eve; + int i; + + DM_add_vert_layer(&bmdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL); + + eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter), i++) + DM_set_vert_data(&bmdm->dm, i, CD_MDEFORMVERT, + CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_MDEFORMVERT)); + } + + if(vertexCos) { + BMVert *eve; + BMIter iter; + int totface = bm->totface; + int i; + + eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter), i++) + BMINDEX_SET(eve, i); + + bmdm->vertexNos = MEM_callocN(sizeof(*bmdm->vertexNos)*i, "bmdm_vno"); + bmdm->faceNos = MEM_mallocN(sizeof(*bmdm->faceNos)*totface, "bmdm_vno"); + + for (i=0; i<bmdm->tc->tottri; i++) { + BMLoop **l = bmdm->tc->looptris[i]; + float *v1 = vertexCos[(int) BMINDEX_GET(l[0]->v)]; + float *v2 = vertexCos[(int) BMINDEX_GET(l[1]->v)]; + float *v3 = vertexCos[(int) BMINDEX_GET(l[2]->v)]; + float *no = bmdm->faceNos[i]; + + CalcNormFloat(v1, v2, v3, no); + VecAddf(bmdm->vertexNos[BMINDEX_GET(l[0]->v)], bmdm->vertexNos[BMINDEX_GET(l[0]->v)], no); + VecAddf(bmdm->vertexNos[BMINDEX_GET(l[1]->v)], bmdm->vertexNos[BMINDEX_GET(l[1]->v)], no); + VecAddf(bmdm->vertexNos[BMINDEX_GET(l[2]->v)], bmdm->vertexNos[BMINDEX_GET(l[2]->v)], no); + } + + eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter), i++) { + float *no = bmdm->vertexNos[i]; + /* following Mesh convention; we use vertex coordinate itself + * for normal in this case */ + if (Normalize(no)==0.0) { + VECCOPY(no, vertexCos[i]); + Normalize(no); + } + } + } + + bmdm_recalc_lookups(bmdm); + + return (DerivedMesh*) bmdm; +} diff --git a/source/blender/blenkernel/intern/exotic.c b/source/blender/blenkernel/intern/exotic.c index c7a8b150d3a..5566851db43 100644 --- a/source/blender/blenkernel/intern/exotic.c +++ b/source/blender/blenkernel/intern/exotic.c @@ -1851,8 +1851,8 @@ static void write_vert_stl(Object *ob, MVert *verts, int index, FILE *fpSTL) static int write_derivedmesh_stl(FILE *fpSTL, Object *ob, DerivedMesh *dm) { MVert *mvert = dm->getVertArray(dm); - MFace *mface = dm->getFaceArray(dm); - int i, numfacets = 0, totface = dm->getNumFaces(dm); + MFace *mface = dm->getTessFaceArray(dm); + int i, numfacets = 0, totface = dm->getNumTessFaces(dm); float zero[3] = {0.0f, 0.0f, 0.0f}; for (i=0; i<totface; i++, mface++) { diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c index 2b4032af503..6c684994e30 100644 --- a/source/blender/blenkernel/intern/fluidsim.c +++ b/source/blender/blenkernel/intern/fluidsim.c @@ -298,7 +298,7 @@ static DerivedMesh *fluidsim_read_obj(char *filename) return NULL; } - dm = CDDM_new(numverts, 0, numfaces); + dm = CDDM_new(numverts, 0, numfaces, 0, 0); if(!dm) { @@ -355,7 +355,7 @@ static DerivedMesh *fluidsim_read_obj(char *filename) printf("Fluidsim: error in reading data from file.\n"); // read triangles from file - mface = CDDM_get_faces(dm); + mface = CDDM_get_tessfaces(dm); for(i=0; i<numfaces; i++) { int face[4]; @@ -391,6 +391,7 @@ static DerivedMesh *fluidsim_read_obj(char *filename) CDDM_apply_vert_normals(dm, (short (*)[3])normals); MEM_freeN(normals); + CDDM_tessfaces_to_faces(dm); // CDDM_calc_normals(result); return dm; @@ -458,12 +459,12 @@ DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifie } // assign material + flags to new dm - mface = orgdm->getFaceArray(orgdm); + mface = orgdm->getTessFaceArray(orgdm); mat_nr = mface[0].mat_nr; flag = mface[0].flag; - mface = dm->getFaceArray(dm); - numfaces = dm->getNumFaces(dm); + mface = dm->getTessFaceArray(dm); + numfaces = dm->getNumTessFaces(dm); for(i=0; i<numfaces; i++) { mface[i].mat_nr = mat_nr; @@ -617,9 +618,9 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob, //dm = mesh_create_derived_no_deform(ob,NULL); mvert = dm->getVertArray(dm); - mface = dm->getFaceArray(dm); + mface = dm->getTessFaceArray(dm); totvert = dm->getNumVerts(dm); - totface = dm->getNumFaces(dm); + totface = dm->getNumTessFaces(dm); *numVertices = totvert; verts = MEM_callocN( totvert*3*sizeof(float), "elbeemmesh_vertices"); diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c deleted file mode 100644 index 64558d0b456..00000000000 --- a/source/blender/blenkernel/intern/fmodifier.c +++ /dev/null @@ -1,1197 +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) 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/mesh.c b/source/blender/blenkernel/intern/mesh.c index 3facf975992..8f67fdc74d2 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -66,19 +66,24 @@ /* -- */ #include "BKE_object.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #include "BLI_blenlib.h" #include "BLI_editVert.h" #include "BLI_arithb.h" +#include "bmesh.h" EditMesh *BKE_mesh_get_editmesh(Mesh *me) { - return me->edit_mesh; + return bmesh_to_editmesh(me->edit_btmesh->bm); } void BKE_mesh_end_editmesh(Mesh *me, EditMesh *em) { + BM_Free_Mesh(me->edit_btmesh->bm); + me->edit_btmesh->bm = editmesh_to_bmesh(em); + BMEdit_RecalcTesselation(me->edit_btmesh); } @@ -93,6 +98,13 @@ void mesh_update_customdata_pointers(Mesh *me) me->mface = CustomData_get_layer(&me->fdata, CD_MFACE); me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL); me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); + + me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY); + me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP); + + me->mtpoly = CustomData_get_layer(&me->pdata, CD_MTEXPOLY); + me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL); + me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); } /* Note: unlinking is called when me->id.us is 0, question remains how @@ -141,12 +153,14 @@ void free_mesh(Mesh *me) CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); + CustomData_free(&me->ldata, me->totloop); + CustomData_free(&me->pdata, me->totpoly); if(me->mat) MEM_freeN(me->mat); if(me->bb) MEM_freeN(me->bb); if(me->mselect) MEM_freeN(me->mselect); - if(me->edit_mesh) MEM_freeN(me->edit_mesh); + if(me->edit_btmesh) MEM_freeN(me->edit_btmesh); } void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount) @@ -205,6 +219,7 @@ Mesh *copy_mesh(Mesh *me) { Mesh *men; MTFace *tface; + MTexPoly *txface; int a, i; men= copy_libblock(me); @@ -218,6 +233,8 @@ Mesh *copy_mesh(Mesh *me) CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert); CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge); CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface); + CustomData_copy(&me->ldata, &men->ldata, CD_MASK_MESH, CD_DUPLICATE, men->totloop); + CustomData_copy(&me->pdata, &men->pdata, CD_MASK_MESH, CD_DUPLICATE, men->totpoly); mesh_update_customdata_pointers(men); /* ensure indirect linked data becomes lib-extern */ @@ -230,7 +247,17 @@ Mesh *copy_mesh(Mesh *me) id_lib_extern((ID*)tface->tpage); } } - + + for(i=0; i<me->pdata.totlayer; i++) { + if(me->pdata.layers[i].type == CD_MTEXPOLY) { + txface= (MTexPoly*)me->pdata.layers[i].data; + + for(a=0; a<me->totpoly; a++, txface++) + if(txface->tpage) + id_lib_extern((ID*)txface->tpage); + } + } + men->mselect= NULL; men->bb= MEM_dupallocN(men->bb); @@ -241,12 +268,43 @@ Mesh *copy_mesh(Mesh *me) return men; } +BMesh *BKE_mesh_to_bmesh(Mesh *me) +{ + BMesh *bm; + int allocsize[4] = {512,512,2048,512}; + + bm = BM_Make_Mesh(allocsize); + + BMO_CallOpf(bm, "mesh_to_bmesh mesh=%p", me); + + return bm; +} + void make_local_tface(Mesh *me) { MTFace *tface; + MTexPoly *txface; Image *ima; int a, i; + for(i=0; i<me->pdata.totlayer; i++) { + if(me->pdata.layers[i].type == CD_MTEXPOLY) { + txface= (MTexPoly*)me->fdata.layers[i].data; + + for(a=0; a<me->totpoly; a++, txface++) { + /* special case: ima always local immediately */ + if(txface->tpage) { + ima= txface->tpage; + if(ima->id.lib) { + ima->id.lib= 0; + ima->id.flag= LIB_LOCAL; + new_id(0, (ID *)ima, 0); + } + } + } + } + } + for(i=0; i<me->fdata.totlayer; i++) { if(me->fdata.layers[i].type == CD_MTFACE) { tface= (MTFace*)me->fdata.layers[i].data; @@ -264,6 +322,7 @@ void make_local_tface(Mesh *me) } } } + } void make_local_mesh(Mesh *me) diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 046dfcc9f87..fc4788d9ff3 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -24,7 +24,8 @@ * Ton Roosendaal, * Ben Batt, * Brecht Van Lommel, -* Campbell Barton +* Campbell Barton, +* Joseph Eagar * * ***** END GPL LICENSE BLOCK ***** * @@ -100,6 +101,7 @@ #include "BKE_subsurf.h" #include "BKE_texture.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #include "depsgraph_private.h" #include "BKE_deform.h" @@ -263,12 +265,12 @@ static void curveModifier_deformVerts( } static void curveModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = derivedData; - if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + if(!derivedData) dm = CDDM_from_BMEditMesh(editData, ob->data); curveModifier_deformVerts(md, ob, dm, vertexCos, numVerts, 0, 0); @@ -355,12 +357,12 @@ static void latticeModifier_deformVerts( } static void latticeModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = derivedData; - if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + if(!derivedData) dm = CDDM_from_BMEditMesh(editData, ob->data); latticeModifier_deformVerts(md, ob, dm, vertexCos, numVerts, 0, 0); @@ -416,7 +418,7 @@ static DerivedMesh *subsurfModifier_applyModifier( } static DerivedMesh *subsurfModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData) { SubsurfModifierData *smd = (SubsurfModifierData*) md; @@ -484,7 +486,7 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, "build modifier edgeMap"); for(i = 0; i < maxEdges; ++i) edgeMap[i] = i; - maxFaces = dm->getNumFaces(dm); + maxFaces = dm->getNumTessFaces(dm); faceMap = MEM_callocN(sizeof(*faceMap) * maxFaces, "build modifier faceMap"); for(i = 0; i < maxFaces; ++i) faceMap[i] = i; @@ -497,7 +499,7 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, } CLAMP(frac, 0.0, 1.0); - numFaces = dm->getNumFaces(dm) * frac; + numFaces = dm->getNumTessFaces(dm) * frac; numEdges = dm->getNumEdges(dm) * frac; /* if there's at least one face, build based on faces */ @@ -513,7 +515,7 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, */ for(i = 0; i < numFaces; ++i) { MFace mf; - dm->getFace(dm, faceMap[i], &mf); + dm->getTessFace(dm, faceMap[i], &mf); if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1))) BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v1), @@ -589,7 +591,7 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, * the mesh */ result = CDDM_from_template(dm, BLI_ghash_size(vertHash), - BLI_ghash_size(edgeHash), numFaces); + BLI_ghash_size(edgeHash), numFaces, 0, 0); /* copy the vertices across */ for(hashIter = BLI_ghashIterator_new(vertHash); @@ -630,8 +632,8 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, MFace *dest; int orig_v4; - dm->getFace(dm, faceMap[i], &source); - dest = CDDM_get_face(result, i); + dm->getTessFace(dm, faceMap[i], &source); + dest = CDDM_get_tessface(result, i); orig_v4 = source.v4; @@ -641,13 +643,14 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, if(source.v4) source.v4 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v4))); - DM_copy_face_data(dm, result, faceMap[i], i, 1); + DM_copy_tessface_data(dm, result, faceMap[i], i, 1); *dest = source; test_index_face(dest, &result->faceData, i, (orig_v4 ? 4 : 3)); } CDDM_calc_normals(result); + CDDM_tessfaces_to_faces(result); BLI_ghash_free(vertHash, NULL, NULL); BLI_ghash_free(edgeHash, NULL, NULL); @@ -655,7 +658,7 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, MEM_freeN(vertMap); MEM_freeN(edgeMap); MEM_freeN(faceMap); - + return result; } @@ -719,7 +722,7 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob, /* get original number of verts, edges, and faces */ maxVerts= dm->getNumVerts(dm); maxEdges= dm->getNumEdges(dm); - maxFaces= dm->getNumFaces(dm); + maxFaces= dm->getNumTessFaces(dm); /* check if we can just return the original mesh * - must have verts and therefore verts assigned to vgroups to do anything useful @@ -913,7 +916,7 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob, for (i = 0; i < maxFaces; i++) { MFace mf; - dm->getFace(dm, i, &mf); + dm->getTessFace(dm, i, &mf); /* all verts must be available */ if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)) && @@ -930,7 +933,7 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob, /* now we know the number of verts, edges and faces, * we can create the new (reduced) mesh */ - result = CDDM_from_template(dm, numVerts, numEdges, numFaces); + result = CDDM_from_template(dm, numVerts, numEdges, numFaces, 0, 0); /* using ghash-iterators, map data into new mesh */ @@ -984,8 +987,8 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob, int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter)); int orig_v4; - dm->getFace(dm, oldIndex, &source); - dest = CDDM_get_face(result, newIndex); + dm->getTessFace(dm, oldIndex, &source); + dest = CDDM_get_tessface(result, newIndex); orig_v4 = source.v4; @@ -995,7 +998,7 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob, if (source.v4) source.v4 = GET_INT_FROM_POINTER(BLI_ghash_lookup(vertHash, SET_INT_IN_POINTER(source.v4))); - DM_copy_face_data(dm, result, oldIndex, newIndex, 1); + DM_copy_tessface_data(dm, result, oldIndex, newIndex, 1); *dest = source; test_index_face(dest, &result->faceData, newIndex, (orig_v4 ? 4 : 3)); @@ -1010,6 +1013,8 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob, BLI_ghash_free(edgeHash, NULL, NULL); BLI_ghash_free(faceHash, NULL, NULL); + CDDM_tessfaces_to_faces(result); + /* return the new mesh */ return result; } @@ -1157,6 +1162,7 @@ static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum) } } +#if 0 static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, Scene *scene, Object *ob, DerivedMesh *dm, int initFlags) @@ -1259,18 +1265,18 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, */ finalVerts = dm->getNumVerts(dm) * count; finalEdges = dm->getNumEdges(dm) * count; - finalFaces = dm->getNumFaces(dm) * count; + finalFaces = dm->getNumTessFaces(dm) * count; if(start_cap) { finalVerts += start_cap->getNumVerts(start_cap); finalEdges += start_cap->getNumEdges(start_cap); - finalFaces += start_cap->getNumFaces(start_cap); + finalFaces += start_cap->getNumTessFaces(start_cap); } if(end_cap) { finalVerts += end_cap->getNumVerts(end_cap); finalEdges += end_cap->getNumEdges(end_cap); - finalFaces += end_cap->getNumFaces(end_cap); + finalFaces += end_cap->getNumTessFaces(end_cap); } - result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces); + result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces, 0, 0); /* calculate the offset matrix of the final copy (for merging) */ MTC_Mat4One(final_offset); @@ -1421,15 +1427,15 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, } } - maxFaces = dm->getNumFaces(dm); - mface = CDDM_get_faces(result); + maxFaces = dm->getNumTessFaces(dm); + mface = CDDM_get_tessfaces(result); for (i=0; i < maxFaces; i++) { MFace inMF; MFace *mf = &mface[numFaces]; - dm->getFace(dm, i, &inMF); + dm->getTessFace(dm, i, &inMF); - DM_copy_face_data(dm, result, i, numFaces, 1); + DM_copy_tessface_data(dm, result, i, numFaces, 1); *mf = inMF; mf->v1 = indexMap[inMF.v1].new; @@ -1465,7 +1471,7 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, { MFace *mf2 = &mface[numFaces]; - DM_copy_face_data(dm, result, i, numFaces, 1); + DM_copy_tessface_data(dm, result, i, numFaces, 1); *mf2 = *mf; mf2->v1 = calc_mapping(indexMap, inMF.v1, j); @@ -1498,10 +1504,10 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, capVerts = start_cap->getNumVerts(start_cap); capEdges = start_cap->getNumEdges(start_cap); - capFaces = start_cap->getNumFaces(start_cap); + capFaces = start_cap->getNumTessFaces(start_cap); cap_mvert = start_cap->getVertArray(start_cap); cap_medge = start_cap->getEdgeArray(start_cap); - cap_mface = start_cap->getFaceArray(start_cap); + cap_mface = start_cap->getTessFaceArray(start_cap); Mat4Invert(startoffset, offset); @@ -1560,9 +1566,9 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, numEdges++; } } - origindex = result->getFaceDataArray(result, CD_ORIGINDEX); + origindex = result->getTessFaceDataArray(result, CD_ORIGINDEX); for(i = 0; i < capFaces; i++) { - DM_copy_face_data(start_cap, result, i, numFaces, 1); + DM_copy_tessface_data(start_cap, result, i, numFaces, 1); mface[numFaces] = cap_mface[i]; mface[numFaces].v1 = vert_map[mface[numFaces].v1]; mface[numFaces].v2 = vert_map[mface[numFaces].v2]; @@ -1599,10 +1605,10 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, capVerts = end_cap->getNumVerts(end_cap); capEdges = end_cap->getNumEdges(end_cap); - capFaces = end_cap->getNumFaces(end_cap); + capFaces = end_cap->getNumTessFaces(end_cap); cap_mvert = end_cap->getVertArray(end_cap); cap_medge = end_cap->getEdgeArray(end_cap); - cap_mface = end_cap->getFaceArray(end_cap); + cap_mface = end_cap->getTessFaceArray(end_cap); Mat4MulMat4(endoffset, final_offset, offset); @@ -1661,9 +1667,9 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, numEdges++; } } - origindex = result->getFaceDataArray(result, CD_ORIGINDEX); + origindex = result->getTessFaceDataArray(result, CD_ORIGINDEX); for(i = 0; i < capFaces; i++) { - DM_copy_face_data(end_cap, result, i, numFaces, 1); + DM_copy_tessface_data(end_cap, result, i, numFaces, 1); mface[numFaces] = cap_mface[i]; mface[numFaces].v1 = vert_map[mface[numFaces].v1]; mface[numFaces].v2 = vert_map[mface[numFaces].v2]; @@ -1694,6 +1700,8 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, CDDM_lower_num_verts(result, numVerts); CDDM_lower_num_edges(result, numEdges); CDDM_lower_num_faces(result, numFaces); + + CDDM_tessfaces_to_faces(result); return result; } @@ -1714,11 +1722,19 @@ static DerivedMesh *arrayModifier_applyModifier( } static DerivedMesh *arrayModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData) { return arrayModifier_applyModifier(md, ob, derivedData, 0, 1); } +#endif + +DerivedMesh *arrayModifier_applyModifier(ModifierData *md, Object *ob, + DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc); +DerivedMesh *arrayModifier_applyModifierEM(ModifierData *md, Object *ob, + BMEditMesh *editData, + DerivedMesh *derivedData); /* Mirror */ @@ -1877,6 +1893,7 @@ void vertgroup_flip_name (char *name, int strip_number) sprintf (name, "%s%s%s%s", prefix, replace, suffix, number); } +#if 0 static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, Object *ob, DerivedMesh *dm, @@ -1889,7 +1906,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, int numVerts, numEdges, numFaces; int maxVerts = dm->getNumVerts(dm); int maxEdges = dm->getNumEdges(dm); - int maxFaces = dm->getNumFaces(dm); + int maxFaces = dm->getNumTessFaces(dm); int vector_size=0, j, a, b; bDeformGroup *def, *defb; bDeformGroup **vector_def = NULL; @@ -1900,7 +1917,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap"); - result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2); + result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2, 0, 0); if (mmd->flag & MOD_MIR_VGROUP) { @@ -2035,11 +2052,11 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, for(i = 0; i < maxFaces; i++) { MFace inMF; - MFace *mf = CDDM_get_face(result, numFaces); + MFace *mf = CDDM_get_tessface(result, numFaces); - dm->getFace(dm, i, &inMF); + dm->getTessFace(dm, i, &inMF); - DM_copy_face_data(dm, result, i, numFaces, 1); + DM_copy_tessface_data(dm, result, i, numFaces, 1); *mf = inMF; numFaces++; @@ -2052,10 +2069,10 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, || indexMap[inMF.v2][1] || indexMap[inMF.v3][1] || (mf->v4 && indexMap[inMF.v4][1])) { - MFace *mf2 = CDDM_get_face(result, numFaces); + MFace *mf2 = CDDM_get_tessface(result, numFaces); static int corner_indices[4] = {2, 1, 0, 3}; - DM_copy_face_data(dm, result, i, numFaces, 1); + DM_copy_tessface_data(dm, result, i, numFaces, 1); *mf2 = *mf; mf2->v1 += indexMap[inMF.v1][1]; @@ -2065,7 +2082,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, /* mirror UVs if enabled */ if(mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) { - MTFace *tf = result->getFaceData(result, numFaces, CD_MTFACE); + MTFace *tf = result->getTessFaceData(result, numFaces, CD_MTFACE); if(tf) { int j; for(j = 0; j < 4; ++j) { @@ -2079,7 +2096,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, /* Flip face normal */ SWAP(int, mf2->v1, mf2->v3); - DM_swap_face_data(result, numFaces, corner_indices); + DM_swap_tessface_data(result, numFaces, corner_indices); test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3); numFaces++; @@ -2094,8 +2111,11 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, CDDM_lower_num_edges(result, numEdges); CDDM_lower_num_faces(result, numFaces); + CDDM_tessfaces_to_faces(result); + return result; } +#endif static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd, Object *ob, DerivedMesh *dm, @@ -2137,7 +2157,7 @@ static DerivedMesh *mirrorModifier_applyModifier( } static DerivedMesh *mirrorModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData) { return mirrorModifier_applyModifier(md, ob, derivedData, 0, 1); @@ -2428,7 +2448,7 @@ static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm) totvert = dm->getNumVerts(dm); totedge = dm->getNumEdges(dm); - totface = dm->getNumFaces(dm); + totface = dm->getNumTessFaces(dm); mesh = smoothmesh_new(totvert, totedge, totface, totvert, totedge, totface); @@ -2460,7 +2480,7 @@ static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm) MVert v1, v2, v3; int j; - dm->getFace(dm, i, &mf); + dm->getTessFace(dm, i, &mf); dm->getVert(dm, mf.v1, &v1); dm->getVert(dm, mf.v2, &v2); @@ -2502,11 +2522,12 @@ static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh) { DerivedMesh *result = CDDM_from_template(mesh->dm, mesh->num_verts, - mesh->num_edges, - mesh->num_faces); + mesh->num_edges, + mesh->num_faces, + 0, 0); MVert *new_verts = CDDM_get_verts(result); MEdge *new_edges = CDDM_get_edges(result); - MFace *new_faces = CDDM_get_faces(result); + MFace *new_faces = CDDM_get_tessfaces(result); int i; for(i = 0; i < mesh->num_verts; ++i) { @@ -2533,9 +2554,9 @@ static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh) SmoothFace *face = &mesh->faces[i]; MFace *newMF = &new_faces[face->newIndex]; - DM_copy_face_data(mesh->dm, result, + DM_copy_tessface_data(mesh->dm, result, face->oldIndex, face->newIndex, 1); - mesh->dm->getFace(mesh->dm, face->oldIndex, newMF); + mesh->dm->getTessFace(mesh->dm, face->oldIndex, newMF); newMF->v1 = face->edges[0]->verts[face->flip[0]]->newIndex; newMF->v2 = face->edges[1]->verts[face->flip[1]]->newIndex; @@ -2548,6 +2569,8 @@ static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh) } } + CDDM_tessfaces_to_faces(result); + return result; } @@ -3360,7 +3383,7 @@ static DerivedMesh *edgesplitModifier_applyModifier( } static DerivedMesh *edgesplitModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData) { return edgesplitModifier_applyModifier(md, ob, derivedData, 0, 1); @@ -3444,7 +3467,7 @@ static DerivedMesh *bevelModifier_applyModifier( } static DerivedMesh *bevelModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData) { return bevelModifier_applyModifier(md, ob, derivedData, 0, 1); @@ -3580,12 +3603,12 @@ static void get_texture_coords(DisplaceModifierData *dmd, Object *ob, /* UVs need special handling, since they come from faces */ if(texmapping == MOD_DISP_MAP_UV) { - if(dm->getFaceDataArray(dm, CD_MTFACE)) { - MFace *mface = dm->getFaceArray(dm); + if(dm->getTessFaceDataArray(dm, CD_MTFACE)) { + MFace *mface = dm->getTessFaceArray(dm); MFace *mf; char *done = MEM_callocN(sizeof(*done) * numVerts, "get_texture_coords done"); - int numFaces = dm->getNumFaces(dm); + int numFaces = dm->getNumTessFaces(dm); char uvname[32]; MTFace *tf; @@ -3772,13 +3795,13 @@ static void displaceModifier_deformVerts( } static void displaceModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; if(derivedData) dm = CDDM_copy(derivedData); - else dm = CDDM_from_editmesh(editData, ob->data); + else dm = CDDM_from_BMEditMesh(editData, ob->data); CDDM_apply_vert_coords(dm, vertexCos); CDDM_calc_normals(dm); @@ -3898,7 +3921,7 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, if(num_projectors == 0) return dm; /* make sure there are UV layers available */ - if(!dm->getFaceDataArray(dm, CD_MTFACE)) return dm; + if(!dm->getTessFaceDataArray(dm, CD_MTFACE)) return dm; /* make sure we're using an existing layer */ validate_layer_name(&dm->faceData, CD_MTFACE, umd->uvlayer_name, uvname); @@ -4004,8 +4027,8 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, for(i = 0, co = coords; i < numVerts; ++i, ++co) Mat4MulVec3Project(projectors[0].projmat, *co); - mface = dm->getFaceArray(dm); - numFaces = dm->getNumFaces(dm); + mface = dm->getTessFaceArray(dm); + numFaces = dm->getNumTessFaces(dm); /* apply coords as UVs, and apply image if tfaces are new */ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) { @@ -4103,7 +4126,7 @@ static DerivedMesh *uvprojectModifier_applyModifier( } static DerivedMesh *uvprojectModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData) { return uvprojectModifier_applyModifier(md, ob, derivedData, 0, 1); @@ -4139,9 +4162,9 @@ static DerivedMesh *decimateModifier_applyModifier( int a, numTris; mvert = dm->getVertArray(dm); - mface = dm->getFaceArray(dm); + mface = dm->getTessFaceArray(dm); totvert = dm->getNumVerts(dm); - totface = dm->getNumFaces(dm); + totface = dm->getNumTessFaces(dm); numTris = 0; for (a=0; a<totface; a++) { @@ -4217,7 +4240,7 @@ static DerivedMesh *decimateModifier_applyModifier( } if(lod.vertex_num>2) { - mface = CDDM_get_faces(result); + mface = CDDM_get_tessfaces(result); for(a=0; a<lod.face_num; a++) { MFace *mf = &mface[a]; int *tri = &lod.triangle_index_buffer[a*3]; @@ -4456,13 +4479,13 @@ static void smoothModifier_deformVerts( } static void smoothModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; if(derivedData) dm = CDDM_copy(derivedData); - else dm = CDDM_from_editmesh(editData, ob->data); + else dm = CDDM_from_BMEditMesh(editData, ob->data); CDDM_apply_vert_coords(dm, vertexCos); CDDM_calc_normals(dm); @@ -5037,14 +5060,14 @@ static void castModifier_deformVerts( } static void castModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = derivedData; CastModifierData *cmd = (CastModifierData *)md; if (!dm && ob->type == OB_MESH) - dm = CDDM_from_editmesh(editData, ob->data); + dm = CDDM_from_BMEditMesh(editData, ob->data); if (cmd->type == MOD_CAST_TYPE_CUBOID) { castModifier_cuboid_do(cmd, ob, dm, vertexCos, numVerts); @@ -5181,12 +5204,12 @@ static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob, /* UVs need special handling, since they come from faces */ if(texmapping == MOD_WAV_MAP_UV) { - if(dm->getFaceDataArray(dm, CD_MTFACE)) { - MFace *mface = dm->getFaceArray(dm); + if(dm->getTessFaceDataArray(dm, CD_MTFACE)) { + MFace *mface = dm->getTessFaceArray(dm); MFace *mf; char *done = MEM_callocN(sizeof(*done) * numVerts, "get_texture_coords done"); - int numFaces = dm->getNumFaces(dm); + int numFaces = dm->getNumTessFaces(dm); char uvname[32]; MTFace *tf; @@ -5443,7 +5466,7 @@ static void waveModifier_deformVerts( } static void waveModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; @@ -5452,7 +5475,7 @@ static void waveModifier_deformVertsEM( if(!wmd->texture && !wmd->defgrp_name[0] && !(wmd->flag & MOD_WAVE_NORM)) dm = derivedData; else if(derivedData) dm = CDDM_copy(derivedData); - else dm = CDDM_from_editmesh(editData, ob->data); + else dm = CDDM_from_BMEditMesh(editData, ob->data); if(wmd->flag & MOD_WAVE_NORM) { CDDM_apply_vert_coords(dm, vertexCos); @@ -5543,13 +5566,13 @@ static void armatureModifier_deformVerts( } static void armatureModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { ArmatureModifierData *amd = (ArmatureModifierData*) md; DerivedMesh *dm = derivedData; - if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + if(!derivedData) dm = CDDM_from_BMEditMesh(editData, ob->data); armature_deform_verts(amd->object, ob, dm, vertexCos, NULL, numVerts, amd->deformflag, NULL, amd->defgrp_name); @@ -5558,14 +5581,14 @@ static void armatureModifier_deformVertsEM( } static void armatureModifier_deformMatricesEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts) { ArmatureModifierData *amd = (ArmatureModifierData*) md; DerivedMesh *dm = derivedData; - if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + if(!derivedData) dm = CDDM_from_BMEditMesh(editData, ob->data); armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts, amd->deformflag, NULL, amd->defgrp_name); @@ -5761,12 +5784,12 @@ static void hookModifier_deformVerts( } static void hookModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = derivedData; - if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + if(!derivedData) dm = CDDM_from_BMEditMesh(editData, ob->data); hookModifier_deformVerts(md, ob, derivedData, vertexCos, numVerts, 0, 0); @@ -6018,8 +6041,8 @@ static void collisionModifier_deformVerts( collmd->numverts = numverts; - collmd->mfaces = dm->dupFaceArray(dm); - collmd->numfaces = dm->getNumFaces(dm); + collmd->mfaces = dm->dupTessFaceArray(dm); + collmd->numfaces = dm->getNumTessFaces(dm); // create bounding box hierarchy collmd->bvhtree = bvhtree_build_from_mvert(collmd->mfaces, collmd->numfaces, collmd->x, numverts, ob->pd->pdef_sboft); @@ -6218,8 +6241,8 @@ static DerivedMesh *booleanModifier_applyModifier( 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) - && bmd->object && dm->getNumFaces(dm) > 3) { + if(dm && (derivedData->getNumTessFaces(derivedData) > 3) + && bmd->object && dm->getNumTessFaces(dm) > 3) { DerivedMesh *result = NewBooleanDerivedMesh(dm, bmd->object, derivedData, ob, 1 + bmd->operation); @@ -6378,7 +6401,7 @@ static void particleSystemModifier_deformVerts( /* report change in mesh structure */ if(psmd->dm->getNumVerts(psmd->dm)!=psmd->totdmvert || psmd->dm->getNumEdges(psmd->dm)!=psmd->totdmedge || - psmd->dm->getNumFaces(psmd->dm)!=psmd->totdmface){ + psmd->dm->getNumTessFaces(psmd->dm)!=psmd->totdmface){ /* in file read dm hasn't really changed but just wasn't saved in file */ psys->recalc |= PSYS_RECALC_RESET; @@ -6386,7 +6409,7 @@ static void particleSystemModifier_deformVerts( psmd->totdmvert= psmd->dm->getNumVerts(psmd->dm); psmd->totdmedge= psmd->dm->getNumEdges(psmd->dm); - psmd->totdmface= psmd->dm->getNumFaces(psmd->dm); + psmd->totdmface= psmd->dm->getNumTessFaces(psmd->dm); } if(psys){ @@ -6401,12 +6424,12 @@ static void particleSystemModifier_deformVerts( * updates is coded */ #if 0 static void particleSystemModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = derivedData; - if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + if(!derivedData) dm = CDDM_from_BMEditMesh(editData, ob->data); particleSystemModifier_deformVerts(md, ob, dm, vertexCos, numVerts); @@ -6526,7 +6549,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier( pars=psys->particles; totvert=dm->getNumVerts(dm); - totface=dm->getNumFaces(dm); + totface=dm->getNumTessFaces(dm); maxvert=totvert*totpart; maxface=totface*totpart; @@ -6542,7 +6565,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier( max_co=max_r[track]; } - result = CDDM_from_template(dm, maxvert,dm->getNumEdges(dm)*totpart,maxface); + result = CDDM_from_template(dm, maxvert,dm->getNumEdges(dm)*totpart,maxface, 0, 0); mvert=result->getVertArray(result); orig_mvert=dm->getVertArray(dm); @@ -6614,8 +6637,8 @@ static DerivedMesh * particleInstanceModifier_applyModifier( VECADD(mv->co,mv->co,state.co); } - mface=result->getFaceArray(result); - orig_mface=dm->getFaceArray(dm); + mface=result->getTessFaceArray(result); + orig_mface=dm->getTessFaceArray(dm); for(i=0; i<maxface; i++){ MFace *inMF; @@ -6645,7 +6668,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier( } inMF = orig_mface + i%totface; - DM_copy_face_data(dm, result, i%totface, i, 1); + DM_copy_tessface_data(dm, result, i%totface, i, 1); *mf = *inMF; mf->v1+=(i/totface)*totvert; @@ -6662,14 +6685,15 @@ static DerivedMesh * particleInstanceModifier_applyModifier( end_latt_deform(psys->lattice); psys->lattice= NULL; } - + + CDDM_tessfaces_to_faces(result); if(size) MEM_freeN(size); return result; } static DerivedMesh *particleInstanceModifier_applyModifierEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData) { return particleInstanceModifier_applyModifier(md, ob, derivedData, 0, 1); @@ -6728,8 +6752,8 @@ static void explodeModifier_createFacepa(ExplodeModifierData *emd, int i,p,v1,v2,v3,v4=0; mvert = dm->getVertArray(dm); - mface = dm->getFaceArray(dm); - totface= dm->getNumFaces(dm); + mface = dm->getTessFaceArray(dm); + totface= dm->getNumTessFaces(dm); totvert= dm->getNumVerts(dm); totpart= psmd->psys->totpart; @@ -6811,12 +6835,12 @@ static int edgesplit_get(EdgeHash *edgehash, int v1, int v2) static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, DerivedMesh *dm){ DerivedMesh *splitdm; MFace *mf=0,*df1=0,*df2=0,*df3=0; - MFace *mface=CDDM_get_faces(dm); + MFace *mface=CDDM_get_tessfaces(dm); MVert *dupve, *mv; EdgeHash *edgehash; EdgeHashIterator *ehi; int totvert=dm->getNumVerts(dm); - int totface=dm->getNumFaces(dm); + int totface=dm->getNumTessFaces(dm); int *facesplit = MEM_callocN(sizeof(int)*totface,"explode_facesplit"); int *vertpa = MEM_callocN(sizeof(int)*totvert,"explode_vertpa2"); @@ -6902,14 +6926,14 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive else if(*fs==4){ totfsplit+=3; - mf=dm->getFaceData(dm,i,CD_MFACE);//CDDM_get_face(dm,i); + mf=dm->getTessFaceData(dm,i,CD_MFACE);//CDDM_get_tessface(dm,i); if(vertpa[mf->v1]!=vertpa[mf->v2] && vertpa[mf->v2]!=vertpa[mf->v3]) totin++; } } - splitdm= CDDM_from_template(dm, totesplit+totin, dm->getNumEdges(dm),totface+totfsplit); + splitdm= CDDM_from_template(dm, totesplit+totin, dm->getNumEdges(dm),totface+totfsplit, 0, 0); /* copy new faces & verts (is it really this painful with custom data??) */ for(i=0; i<totvert; i++){ @@ -6924,10 +6948,10 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive for(i=0; i<totface; i++){ MFace source; MFace *dest; - dm->getFace(dm, i, &source); - dest = CDDM_get_face(splitdm, i); + dm->getTessFace(dm, i, &source); + dest = CDDM_get_tessface(splitdm, i); - DM_copy_face_data(dm, splitdm, i, i, 1); + DM_copy_tessface_data(dm, splitdm, i, i, 1); *dest = source; } @@ -6961,7 +6985,7 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive curdupin=totesplit; for(i=0,fs=facesplit; i<totface; i++,fs++){ if(*fs){ - mf=CDDM_get_face(splitdm,i); + mf=CDDM_get_tessface(splitdm,i); v1=vertpa[mf->v1]; v2=vertpa[mf->v2]; @@ -6969,8 +6993,8 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive v4=vertpa[mf->v4]; /* ouch! creating new faces & remapping them to new verts is no fun */ if(*fs==1){ - df1=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df1=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df1=*mf; curdupface++; @@ -6993,13 +7017,13 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive test_index_face(df1, &splitdm->faceData, curdupface, (df1->v4 ? 4 : 3)); } if(*fs==2){ - df1=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df1=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df1=*mf; curdupface++; - df2=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df2=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df2=*mf; curdupface++; @@ -7070,18 +7094,18 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive test_index_face(df1, &splitdm->faceData, curdupface-1, (df1->v4 ? 4 : 3)); } else if(*fs==3){ - df1=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df1=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df1=*mf; curdupface++; - df2=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df2=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df2=*mf; curdupface++; - df3=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df3=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df3=*mf; curdupface++; @@ -7171,18 +7195,18 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive VecMulf(dupve->co,0.25); - df1=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df1=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df1=*mf; curdupface++; - df2=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df2=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df2=*mf; curdupface++; - df3=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df3=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df3=*mf; curdupface++; @@ -7211,18 +7235,18 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive test_index_face(df1, &splitdm->faceData, curdupface-1, (df1->v4 ? 4 : 3)); } else{ - df1=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df1=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df1=*mf; curdupface++; - df2=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df2=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df2=*mf; curdupface++; - df3=CDDM_get_face(splitdm,curdupface); - DM_copy_face_data(splitdm,splitdm,i,curdupface,1); + df3=CDDM_get_tessface(splitdm,curdupface); + DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1); *df3=*mf; curdupface++; @@ -7276,7 +7300,8 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive BLI_edgehash_free(edgehash, NULL); MEM_freeN(facesplit); MEM_freeN(vertpa); - + + CDDM_tessfaces_to_faces(splitdm); return splitdm; } @@ -7298,7 +7323,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, int totdup=0,totvert=0,totface=0,totpart=0; int i, j, v, mindex=0; - totface= dm->getNumFaces(dm); + totface= dm->getNumTessFaces(dm); totvert= dm->getNumVerts(dm); totpart= psmd->psys->totpart; @@ -7320,7 +7345,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, else mindex = totvert+facepa[i]; - mf=CDDM_get_face(dm,i); + mf=CDDM_get_tessface(dm,i); /* set face vertices to exist in particle group */ BLI_edgehash_insert(vertpahash, mf->v1, mindex, NULL); @@ -7339,7 +7364,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, BLI_edgehashIterator_free(ehi); /* the final duplicated vertices */ - explode= CDDM_from_template(dm, totdup, 0,totface); + explode= CDDM_from_template(dm, totdup, 0,totface, 0, 0); /*dupvert= CDDM_get_verts(explode);*/ /* getting back to object space */ @@ -7405,8 +7430,8 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, if(pa->alive==PARS_DEAD && (emd->flag&eExplodeFlag_Dead)==0) continue; } - dm->getFace(dm,i,&source); - mf=CDDM_get_face(explode,i); + dm->getTessFace(dm,i,&source); + mf=CDDM_get_tessface(explode,i); orig_v4 = source.v4; @@ -7421,7 +7446,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, if(source.v4) source.v4 = edgesplit_get(vertpahash, source.v4, mindex); - DM_copy_face_data(dm,explode,i,i,1); + DM_copy_tessface_data(dm,explode,i,i,1); *mf = source; @@ -7442,6 +7467,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd, psmd->psys->lattice= NULL; } + CDDM_tessfaces_to_faces(explode); return explode; } @@ -7475,7 +7501,7 @@ static DerivedMesh * explodeModifier_applyModifier( if(emd->facepa==0 || psmd->flag&eParticleSystemFlag_Pars || emd->flag&eExplodeFlag_CalcFaces - || MEM_allocN_len(emd->facepa)/sizeof(int) != dm->getNumFaces(dm)){ + || MEM_allocN_len(emd->facepa)/sizeof(int) != dm->getNumTessFaces(dm)){ if(psmd->flag & eParticleSystemFlag_Pars) psmd->flag &= ~eParticleSystemFlag_Pars; @@ -7718,10 +7744,10 @@ static void meshdeformModifier_do( { MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; Mesh *me= ob->data; + BMEditMesh *bem = me->edit_btmesh; 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]; @@ -7731,11 +7757,10 @@ static void meshdeformModifier_do( return; /* get cage derivedmesh */ - if(em) { - tmpdm= editmesh_get_derived_cage_and_final(md->scene, ob, em, &cagedm, 0); + if(bem) { + tmpdm= editbmesh_get_derived_cage_and_final(md->scene, ob, bem, &cagedm, 0); if(tmpdm) tmpdm->release(tmpdm); - BKE_mesh_end_editmesh(me, em); } else cagedm= mmd->object->derivedFinal; @@ -7897,13 +7922,13 @@ static void meshdeformModifier_deformVerts( } static void meshdeformModifier_deformVertsEM( - ModifierData *md, Object *ob, EditMesh *editData, + ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm; if(!derivedData && ob->type == OB_MESH) - dm = CDDM_from_editmesh(editData, ob->data); + dm = CDDM_from_BMEditMesh(editData, ob->data); else dm = derivedData; @@ -8055,7 +8080,7 @@ static void shrinkwrapModifier_deformVerts(ModifierData *md, Object *ob, Derived dm->release(dm); } -static void shrinkwrapModifier_deformVertsEM(ModifierData *md, Object *ob, EditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +static void shrinkwrapModifier_deformVertsEM(ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = NULL; CustomDataMask dataMask = shrinkwrapModifier_requiredDataMask(ob, md); @@ -8063,7 +8088,7 @@ static void shrinkwrapModifier_deformVertsEM(ModifierData *md, Object *ob, EditM if(dataMask) { if(derivedData) dm = CDDM_copy(derivedData); - else if(ob->type==OB_MESH) dm = CDDM_from_editmesh(editData, ob->data); + else if(ob->type==OB_MESH) dm = CDDM_from_BMEditMesh(editData, ob->data); else if(ob->type==OB_LATTICE) dm = NULL; else return; @@ -8170,7 +8195,7 @@ static void simpledeformModifier_deformVerts(ModifierData *md, Object *ob, Deriv } -static void simpledeformModifier_deformVertsEM(ModifierData *md, Object *ob, EditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +static void simpledeformModifier_deformVertsEM(ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { DerivedMesh *dm = NULL; CustomDataMask dataMask = simpledeformModifier_requiredDataMask(ob, md); @@ -8179,7 +8204,7 @@ static void simpledeformModifier_deformVertsEM(ModifierData *md, Object *ob, Edi if(dataMask) { if(derivedData) dm = CDDM_copy(derivedData); - else if(ob->type==OB_MESH) dm = CDDM_from_editmesh(editData, ob->data); + else if(ob->type==OB_MESH) dm = CDDM_from_BMEditMesh(editData, ob->data); else if(ob->type==OB_LATTICE) dm = NULL; else return; diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c new file mode 100644 index 00000000000..b3ce91855b2 --- /dev/null +++ b/source/blender/blenkernel/intern/modifiers_bmesh.c @@ -0,0 +1,568 @@ +/* +* $Id: modifier_bmesh.c 20831 2009-06-12 14:02:37Z joeedh $ +* +* ***** 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) 2005 by the Blender Foundation. +* All rights reserved. +* +* Contributor(s): Joseph Eagar +* +* ***** END GPL LICENSE BLOCK ***** +* +* Modifier stack implementation. +* +* BKE_modifier.h contains the function prototypes for this file. +* +*/ + +#include "string.h" +#include "stdarg.h" +#include "math.h" +#include "float.h" +#include "ctype.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_kdopbvh.h" +#include "BLI_kdtree.h" +#include "BLI_linklist.h" +#include "BLI_rand.h" +#include "BLI_edgehash.h" +#include "BLI_ghash.h" +#include "BLI_memarena.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_cloth_types.h" +#include "DNA_curve_types.h" +#include "DNA_effect_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_force.h" +#include "DNA_particle_types.h" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" + +#include "BLI_editVert.h" + +#include "MTC_matrixops.h" +#include "MTC_vectorops.h" + +#include "BKE_main.h" +#include "BKE_anim.h" +#include "BKE_bmesh.h" +// XXX #include "BKE_booleanops.h" +#include "BKE_cloth.h" +#include "BKE_collision.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_curve.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#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" +#include "BKE_mesh.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_particle.h" +#include "BKE_pointcache.h" +#include "BKE_softbody.h" +#include "BKE_subsurf.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" +#include "BKE_tessmesh.h" + +#include "depsgraph_private.h" +#include "BKE_deform.h" +#include "BKE_shrinkwrap.h" +#include "BKE_simple_deform.h" + +#include "CCGSubSurf.h" +#include "RE_shader_ext.h" +#include "LOD_decimation.h" + +/*converts a cddm to a BMEditMesh. if existing is non-NULL, the + new geometry will be put in there.*/ +BMEditMesh *CDDM_To_BMesh(DerivedMesh *dm, BMEditMesh *existing) +{ + int allocsize[4] = {512, 512, 2048, 512}; + BMesh *bm, bmold; /*bmold is for storing old customdata layout*/ + BMEditMesh *em = existing; + MVert *mv; + MEdge *me; + DMFaceIter *dfiter; + DMLoopIter *dliter; + BMVert *v, **vtable, **verts=NULL; + BMEdge *e, **etable, **edges=NULL; + BMFace *f; + BMIter liter, iter; + V_DECLARE(verts); + V_DECLARE(edges); + void *tmp; + int numTex, numCol; + int i, j, k, tot, totvert, totedge, totface; + + if (em) bm = em->bm; + else bm = BM_Make_Mesh(allocsize); + + bmold = *bm; + + /*merge custom data layout*/ + CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_BMESH|CD_MASK_ORIGINDEX, CD_CALLOC, bm, BM_VERT); + CustomData_bmesh_merge(&dm->edgeData, &bm->edata, CD_MASK_BMESH|CD_MASK_ORIGINDEX, CD_CALLOC, bm, BM_EDGE); + CustomData_bmesh_merge(&dm->loopData, &bm->ldata, CD_MASK_BMESH|CD_MASK_ORIGINDEX, CD_CALLOC, bm, BM_LOOP); + CustomData_bmesh_merge(&dm->polyData, &bm->pdata, CD_MASK_BMESH|CD_MASK_ORIGINDEX, CD_CALLOC, bm, BM_FACE); + + /*needed later*/ + numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); + + totvert = dm->getNumVerts(dm); + totedge = dm->getNumEdges(dm); + totface = dm->getNumFaces(dm); + + vtable = MEM_callocN(sizeof(void**)*totvert, "vert table in BMDM_Copy"); + etable = MEM_callocN(sizeof(void**)*totedge, "edge table in BMDM_Copy"); + + /*do verts*/ + mv = dm->dupVertArray(dm); + for (i=0; i<totvert; i++, mv++) { + v = BM_Make_Vert(bm, mv->co, NULL); + + v->bweight = mv->bweight; + VECCOPY(v->no, mv->no); + v->head.flag = MEFlags_To_BMFlags(mv->flag, BM_VERT); + + CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data); + vtable[i] = v; + } + + /*do edges*/ + me = dm->dupEdgeArray(dm); + for (i=0; i<totedge; i++, me++) { + e = BM_Make_Edge(bm, vtable[me->v1], vtable[me->v2], NULL, 0); + + e->bweight = me->bweight; + e->crease = me->crease; + e->head.flag = MEFlags_To_BMFlags(me->flag, BM_EDGE); + + CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data); + etable[i] = e; + } + + k = 0; + dfiter = dm->newFaceIter(dm); + for (; !dfiter->done; dfiter->step(dfiter)) { + BMLoop *l; + + V_RESET(verts); + V_RESET(edges); + + dliter = dfiter->getLoopsIter(dfiter); + for (j=0; !dliter->done; dliter->step(dliter), j++) { + V_GROW(verts); + V_GROW(edges); + + verts[j] = vtable[dliter->vindex]; + edges[j] = etable[dliter->eindex]; + } + + f = BM_Make_Ngon(bm, verts[0], verts[1], edges, dfiter->len, 0); + f->head.flag = MEFlags_To_BMFlags(dfiter->flags, BM_FACE); + + if (!f) + continue; + + dliter = dfiter->getLoopsIter(dfiter); + l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f); + for (j=0; l; l=BMIter_Step(&liter)) { + CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, k, &l->head.data); + k += 1; + } + + CustomData_to_bmesh_block(&dm->polyData, &bm->pdata, + dfiter->index, &f->head.data); + } + + MEM_freeN(vtable); + MEM_freeN(etable); + + if (!em) em = BMEdit_Create(bm); + else BMEdit_RecalcTesselation(em); + + return em; +} + +float vertarray_size(MVert *mvert, int numVerts, int axis); + + +typedef struct IndexMapEntry { + /* the new vert index that this old vert index maps to */ + int new; + /* -1 if this vert isn't merged, otherwise the old vert index it + * should be replaced with + */ + int merge; + /* 1 if this vert's first copy is merged with the last copy of its + * merge target, otherwise 0 + */ + short merge_final; +} IndexMapEntry; + +/* indexMap - an array of IndexMap entries + * oldIndex - the old index to map + * copyNum - the copy number to map to (original = 0, first copy = 1, etc.) + */ +static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum) +{ + if(indexMap[oldIndex].merge < 0) { + /* vert wasn't merged, so use copy of this vert */ + return indexMap[oldIndex].new + copyNum; + } else if(indexMap[oldIndex].merge == oldIndex) { + /* vert was merged with itself */ + return indexMap[oldIndex].new; + } else { + /* vert was merged with another vert */ + /* follow the chain of merges to the end, or until we've passed + * a number of vertices equal to the copy number + */ + if(copyNum <= 0) + return indexMap[oldIndex].new; + else + return calc_mapping(indexMap, indexMap[oldIndex].merge, + copyNum - 1); + } +} + +static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, + Scene *scene, Object *ob, DerivedMesh *dm, + int initFlags) +{ + DerivedMesh *cddm = CDDM_copy(dm); + BMEditMesh *em = CDDM_To_BMesh(cddm, NULL); + BMOperator op, oldop, weldop; + int i, j, indexLen; + /* offset matrix */ + float offset[4][4]; + float final_offset[4][4]; + float tmp_mat[4][4]; + float length = amd->length; + int count = amd->count; + int numVerts, numEdges, numFaces; + int maxVerts, maxEdges, maxFaces; + int finalVerts, finalEdges, finalFaces; + int *indexMap; + DerivedMesh *result, *start_cap = NULL, *end_cap = NULL; + MVert *src_mvert; + + /* need to avoid infinite recursion here */ + if(amd->start_cap && amd->start_cap != ob) + 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(scene, amd->end_cap, CD_MASK_MESH); + + MTC_Mat4One(offset); + + src_mvert = cddm->getVertArray(dm); + maxVerts = cddm->getNumVerts(dm); + + if(amd->offset_type & MOD_ARR_OFF_CONST) + VecAddf(offset[3], offset[3], amd->offset); + if(amd->offset_type & MOD_ARR_OFF_RELATIVE) { + for(j = 0; j < 3; j++) + offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, + maxVerts, j); + } + + if((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) { + float obinv[4][4]; + float result_mat[4][4]; + + if(ob) + MTC_Mat4Invert(obinv, ob->obmat); + else + MTC_Mat4One(obinv); + + MTC_Mat4MulSerie(result_mat, offset, + obinv, amd->offset_ob->obmat, + NULL, NULL, NULL, NULL, NULL); + MTC_Mat4CpyMat4(offset, result_mat); + } + + if(amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) { + Curve *cu = amd->curve_ob->data; + if(cu) { + float tmp_mat[3][3]; + float scale; + + object_to_mat3(amd->curve_ob, tmp_mat); + scale = Mat3ToScalef(tmp_mat); + + if(!cu->path) { + cu->flag |= CU_PATH; // needed for path & bevlist + makeDispListCurveTypes(scene, amd->curve_ob, 0); + } + if(cu->path) + length = scale*cu->path->totdist; + } + } + + /* calculate the maximum number of copies which will fit within the + prescribed length */ + if(amd->fit_type == MOD_ARR_FITLENGTH + || amd->fit_type == MOD_ARR_FITCURVE) + { + float dist = sqrt(MTC_dot3Float(offset[3], offset[3])); + + if(dist > 1e-6f) + /* this gives length = first copy start to last copy end + add a tiny offset for floating point rounding errors */ + count = (length + 1e-6f) / dist; + else + /* if the offset has no translation, just make one copy */ + count = 1; + } + + if(count < 1) + count = 1; + + /* allocate memory for count duplicates (including original) plus + * start and end caps + */ + finalVerts = dm->getNumVerts(dm) * count; + finalEdges = dm->getNumEdges(dm) * count; + finalFaces = dm->getNumFaces(dm) * count; + if(start_cap) { + finalVerts += start_cap->getNumVerts(start_cap); + finalEdges += start_cap->getNumEdges(start_cap); + finalFaces += start_cap->getNumFaces(start_cap); + } + if(end_cap) { + finalVerts += end_cap->getNumVerts(end_cap); + finalEdges += end_cap->getNumEdges(end_cap); + finalFaces += end_cap->getNumFaces(end_cap); + } + + /* calculate the offset matrix of the final copy (for merging) */ + MTC_Mat4One(final_offset); + + for(j=0; j < count - 1; j++) { + MTC_Mat4MulMat4(tmp_mat, final_offset, offset); + MTC_Mat4CpyMat4(final_offset, tmp_mat); + } + + cddm->needsFree = 1; + cddm->release(cddm); + + BMO_Init_Op(&weldop, "weldverts"); + BMO_InitOpf(em->bm, &op, "dupe geom=%avef"); + oldop = op; + for (j=0; j < count; j++) { + BMVert *v, *v2; + BMOpSlot *s1; + BMOpSlot *s2; + + BMO_InitOpf(em->bm, &op, "dupe geom=%s", &oldop, j==0 ? "geom" : "newout"); + BMO_Exec_Op(em->bm, &op); + + s1 = BMO_GetSlot(&op, "geom"); + s2 = BMO_GetSlot(&op, "newout"); + + BMO_CallOpf(em->bm, "transform mat=%m4 verts=%s", offset, &op, "newout"); + + #define _E(s, i) ((BMVert**)(s)->data.buf)[i] + + /*calculate merge mapping*/ + if (j == 0) { + BMOperator findop; + BMOIter oiter; + BMIter iter; + BMVert *v, *v2; + BMHeader *h; + + BMO_InitOpf(em->bm, &findop, + "finddoubles verts=%av dist=%f keepverts=%s", + amd->merge_dist, &op, "geom"); + + i = 0; + BMO_ITER(h, &oiter, em->bm, &op, "geom", BM_ALL) { + BMINDEX_SET(h, i); + i++; + } + + BMO_ITER(h, &oiter, em->bm, &op, "newout", BM_ALL) { + BMINDEX_SET(h, i); + i++; + } + + BMO_Exec_Op(em->bm, &findop); + + indexLen = i; + indexMap = MEM_callocN(sizeof(int)*indexLen, "indexMap"); + + /*element type argument doesn't do anything here*/ + BMO_ITER(v, &oiter, em->bm, &findop, "targetmapout", 0) { + v2 = BMO_IterMapValp(&oiter); + + /*make sure merge pairs are duplicate-to-duplicate*/ + /*if (BMINDEX_GET(v) >= s1->len && BMINDEX_GET(v2) >= s1->len) + continue; + else if (BMINDEX_GET(v) < s1->len && BMINDEX_GET(v2) < s1->len) + continue;*/ + + indexMap[BMINDEX_GET(v)] = BMINDEX_GET(v2)+1; + } + + BMO_Finish_Op(em->bm, &findop); + } + + /*generate merge mappping using index map. we do this by using the + operator slots as lookup arrays.*/ + #define E(i) (i) < s1->len ? _E(s1, i) : _E(s2, (i)-s1->len) + + for (i=0; i<indexLen; i++) { + if (!indexMap[i]) continue; + + v = E(i); + v2 = E(indexMap[i]-1); + + BMO_Insert_MapPointer(em->bm, &weldop, "targetmap", v, v2); + } + + #undef E + #undef _E + + BMO_Finish_Op(em->bm, &oldop); + oldop = op; + } + + if (j > 0) BMO_Finish_Op(em->bm, &op); + + BMO_Exec_Op(em->bm, &weldop); + BMO_Finish_Op(em->bm, &weldop); + + //BMO_CallOpf(em->bm, "removedoubles verts=%av dist=%f", amd->merge_dist); + + BMEdit_RecalcTesselation(em); + cddm = CDDM_from_BMEditMesh(em, NULL); + + BMEdit_Free(em); + MEM_freeN(indexMap); + + return cddm; +} + +DerivedMesh *arrayModifier_applyModifier(ModifierData *md, Object *ob, + DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + DerivedMesh *result; + ArrayModifierData *amd = (ArrayModifierData*) md; + + result = arrayModifier_doArray(amd, md->scene, ob, derivedData, 0); + + //if(result != derivedData) + // CDDM_calc_normals(result); + + return result; +} + +DerivedMesh *arrayModifier_applyModifierEM(ModifierData *md, Object *ob, + BMEditMesh *editData, + DerivedMesh *derivedData) +{ + return arrayModifier_applyModifier(md, ob, derivedData, 0, 1); +} + +/* Mirror */ + +DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, + Object *ob, + DerivedMesh *dm, + int initFlags, + int axis) +{ + int i; + float tolerance = mmd->tolerance; + DerivedMesh *result, *cddm; + BMEditMesh *em; + BMesh *bm; + int numVerts, numEdges, numFaces; + int maxVerts = dm->getNumVerts(dm); + int maxEdges = dm->getNumEdges(dm); + int maxFaces = dm->getNumTessFaces(dm); + int vector_size=0, j, a, b; + bDeformGroup *def, *defb; + bDeformGroup **vector_def = NULL; + int (*indexMap)[2]; + float mtx[4][4], imtx[4][4]; + + cddm = CDDM_copy(dm); + em = CDDM_To_BMesh(dm, NULL); + + cddm->needsFree = 1; + cddm->release(cddm); + + /*convienence variable*/ + bm = em->bm; + + numVerts = numEdges = numFaces = 0; + indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap"); + result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2, 0, 0); + + if (mmd->flag & MOD_MIR_VGROUP) { + /* calculate the number of deformedGroups */ + for(vector_size = 0, def = ob->defbase.first; def; + def = def->next, vector_size++); + + /* load the deformedGroups for fast access */ + vector_def = + (bDeformGroup **)MEM_mallocN(sizeof(bDeformGroup*) * vector_size, + "group_index"); + for(a = 0, def = ob->defbase.first; def; def = def->next, a++) { + vector_def[a] = def; + } + } + + if (mmd->mirror_ob) { + float obinv[4][4]; + + Mat4Invert(obinv, mmd->mirror_ob->obmat); + Mat4MulMat4(mtx, ob->obmat, obinv); + Mat4Invert(imtx, mtx); + } + + + + BMEdit_RecalcTesselation(em); + result = CDDM_from_BMEditMesh(em, NULL); + + BMEdit_Free(em); + + return result; +} diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 5def910ddef..03838e3c258 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -469,7 +469,7 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int dista mrdm = multires_dm_create_from_derived(&mmd_sub, orig, me, 0, 0); totsubvert = mrdm->getNumVerts(mrdm); totsubedge = mrdm->getNumEdges(mrdm); - totsubface = mrdm->getNumFaces(mrdm); + totsubface = mrdm->getNumTessFaces(mrdm); orig->needsFree = 1; orig->release(orig); @@ -1198,7 +1198,7 @@ static void multiresModifier_update(DerivedMesh *dm) 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); + dm->getNumTessFaces(dm), 1); subco_dm->release(subco_dm); orig->release(orig); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 02c0d46a73f..82eca760a60 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -96,6 +96,7 @@ #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_mesh.h" +#include "BKE_tessmesh.h" #include "BKE_mball.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -862,7 +863,7 @@ void free_lamp(Lamp *la) BKE_free_animdata((ID *)la); - curvemapping_free(la->curfalloff); + curvemapping_free(la->curfalloff); BKE_previewimg_free(&la->preview); BKE_icon_delete(&la->id); @@ -2314,12 +2315,11 @@ void object_handle_update(Scene *scene, Object *ob) /* includes all keys and modifiers */ if(ob->type==OB_MESH) { - EditMesh *em = BKE_mesh_get_editmesh(ob->data); + BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh; - // here was vieweditdatamask? XXX + // 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); } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index cefeafcdd50..8e0e948f0a4 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -697,9 +697,9 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot) return tot; mvert= dm->getVertArray(dm); - mface= dm->getFaceArray(dm); - origindex= dm->getFaceDataArray(dm, CD_ORIGINDEX); - totface= dm->getNumFaces(dm); + mface= dm->getTessFaceArray(dm); + origindex= dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + totface= dm->getNumTessFaces(dm); totorigface= me->totface; if(totface == 0 || totorigface == 0 || origindex == NULL) @@ -1347,7 +1347,7 @@ float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int index, case PART_FROM_FACE: case PART_FROM_VOLUME: { - MFace *mf=dm->getFaceData(dm,index,CD_MFACE); + MFace *mf=dm->getTessFaceData(dm,index,CD_MFACE); return interpolate_particle_value(values[mf->v1],values[mf->v2],values[mf->v3],values[mf->v4],fw,mf->v4); } @@ -1395,11 +1395,11 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, float * int quad, findex, totface; float uv[2], (*faceuv)[2]; - mface = dm->getFaceDataArray(dm, CD_MFACE); - origindex = dm->getFaceDataArray(dm, CD_ORIGINDEX); - osface = dm->getFaceDataArray(dm, CD_ORIGSPACE); + mface = dm->getTessFaceDataArray(dm, CD_MFACE); + origindex = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE); - totface = dm->getNumFaces(dm); + totface = dm->getNumTessFaces(dm); if(osface==NULL || origindex==NULL) { /* Assume we dont need osface data */ @@ -1468,7 +1468,7 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_ *mapindex = index; } else { /* FROM_FACE/FROM_VOLUME */ - if(index >= dm->getNumFaces(dm)) + if(index >= dm->getNumTessFaces(dm)) return 0; *mapindex = index; @@ -1492,15 +1492,15 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_ i = index_dmcache; - if(i== DMCACHE_NOTFOUND || i >= dm->getNumFaces(dm)) + if(i== DMCACHE_NOTFOUND || i >= dm->getNumTessFaces(dm)) return 0; *mapindex = i; /* modify the original weights to become * weights for the derived mesh face */ - osface= dm->getFaceDataArray(dm, CD_ORIGSPACE); - mface= dm->getFaceData(dm, i, CD_MFACE); + osface= dm->getTessFaceDataArray(dm, CD_ORIGSPACE); + mface= dm->getTessFaceData(dm, i, CD_MFACE); if(osface == NULL) mapfw[0]= mapfw[1]= mapfw[2]= mapfw[3]= 0.0f; @@ -1558,7 +1558,7 @@ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache MTFace *mtface; MVert *mvert; - mface=dm->getFaceData(dm,mapindex,CD_MFACE); + mface=dm->getTessFaceData(dm,mapindex,CD_MFACE); mvert=dm->getVertDataArray(dm,CD_MVERT); mtface=CustomData_get_layer(&dm->faceData,CD_MTFACE); @@ -2946,10 +2946,10 @@ static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float m int i = pa->num_dmcache==DMCACHE_NOTFOUND ? pa->num : pa->num_dmcache; - if (i==-1 || i >= dm->getNumFaces(dm)) { Mat4One(mat); return; } + if (i==-1 || i >= dm->getNumTessFaces(dm)) { Mat4One(mat); return; } - mface=dm->getFaceData(dm,i,CD_MFACE); - osface=dm->getFaceData(dm,i,CD_ORIGSPACE); + mface=dm->getTessFaceData(dm,i,CD_MFACE); + osface=dm->getTessFaceData(dm,i,CD_ORIGSPACE); if(orco && (orcodata=dm->getVertDataArray(dm, CD_ORCO))) { VECCOPY(v[0], orcodata[mface->v1]); @@ -3309,7 +3309,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, fl if(pa) { i= (pa->num_dmcache==DMCACHE_NOTFOUND)? pa->num: pa->num_dmcache; - if(i >= dm->getNumFaces(dm)) + if(i >= dm->getNumTessFaces(dm)) i = -1; } else @@ -3321,7 +3321,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, fl texco[2]= 0.0f; } else { - mf= dm->getFaceData(dm, i, CD_MFACE); + mf= dm->getTessFaceData(dm, i, CD_MFACE); psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco); @@ -3962,7 +3962,7 @@ void psys_get_dupli_texture(Object *ob, ParticleSettings *part, ParticleSystemMo if(part->childtype == PART_CHILD_FACES) { mtface= CustomData_get_layer(&psmd->dm->faceData, CD_MTFACE); if(mtface) { - mface= psmd->dm->getFaceData(psmd->dm, cpa->num, CD_MFACE); + mface= psmd->dm->getTessFaceData(psmd->dm, cpa->num, CD_MFACE); mtface += cpa->num; psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv); } @@ -3982,11 +3982,11 @@ void psys_get_dupli_texture(Object *ob, ParticleSettings *part, ParticleSystemMo num= pa->num_dmcache; if(num == DMCACHE_NOTFOUND) - if(pa->num < psmd->dm->getNumFaces(psmd->dm)) + if(pa->num < psmd->dm->getNumTessFaces(psmd->dm)) num= pa->num; if(mtface && num != DMCACHE_NOTFOUND) { - mface= psmd->dm->getFaceData(psmd->dm, num, CD_MFACE); + mface= psmd->dm->getTessFaceData(psmd->dm, num, CD_MFACE); mtface += num; psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv); } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 56ca3e8e22b..9004f4b9973 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -410,7 +410,7 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys) int amax= from==PART_FROM_FACE ? 3 : 1; totface=dm->getNumFaces(dm); - mface=dm->getFaceDataArray(dm,CD_MFACE); + mface=dm->getTessFaceDataArray(dm,CD_MFACE); for(a=0; a<amax; a++){ if(a==0){ a0mul=res*res; a1mul=res; a2mul=1; } @@ -419,7 +419,7 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys) for(a1=0; a1<size[(a+1)%3]; a1++){ for(a2=0; a2<size[(a+2)%3]; a2++){ - mface=dm->getFaceDataArray(dm,CD_MFACE); + mface=dm->getTessFaceDataArray(dm,CD_MFACE); pa=psys->particles + a1*a1mul + a2*a2mul; VECCOPY(co1,pa->fuv); @@ -633,7 +633,7 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C MFace *mface; pa->num = i = ctx->index[p]; - mface = dm->getFaceData(dm,i,CD_MFACE); + mface = dm->getTessFaceData(dm,i,CD_MFACE); switch(distr){ case PART_DISTR_JIT: @@ -672,7 +672,7 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C min_d=2.0; intersect=0; - for(i=0,mface=dm->getFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++){ + for(i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++){ if(i==pa->num) continue; v1=mvert[mface->v1].co; @@ -734,7 +734,7 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C return; } - mf= dm->getFaceData(dm, ctx->index[p], CD_MFACE); + mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE); //switch(distr){ // case PART_DISTR_JIT: @@ -1165,7 +1165,7 @@ int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, Derive orcodata= dm->getVertDataArray(dm, CD_ORCO); for(i=0; i<tot; i++){ - MFace *mf=dm->getFaceData(dm,i,CD_MFACE); + MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE); if(orcodata) { VECCOPY(co1, orcodata[mf->v1]); @@ -1234,7 +1234,7 @@ int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, Derive } else { /* PART_FROM_FACE / PART_FROM_VOLUME */ for(i=0;i<tot; i++){ - MFace *mf=dm->getFaceData(dm,i,CD_MFACE); + MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE); tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3]; if(mf->v4) { @@ -1309,7 +1309,7 @@ int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, Derive } else { if(dm->numFaceData) - COMPARE_ORIG_INDEX= dm->getFaceDataArray(dm, CD_ORIGINDEX); + COMPARE_ORIG_INDEX= dm->getTessFaceDataArray(dm, CD_ORIGINDEX); } if(COMPARE_ORIG_INDEX) { @@ -3031,7 +3031,7 @@ int psys_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, float *vert_cos } totface=dm->getNumFaces(dm); - mface=dm->getFaceDataArray(dm,CD_MFACE); + mface=dm->getTessFaceDataArray(dm,CD_MFACE); mvert=dm->getVertDataArray(dm,CD_MVERT); /* lets intersect the faces */ @@ -3472,7 +3472,7 @@ static int boid_see_mesh(ListBase *lb, Scene *scene, Object *pob, ParticleSystem psys_enable_all(ob); } - mface=dm->getFaceDataArray(dm,CD_MFACE); + mface=dm->getTessFaceDataArray(dm,CD_MFACE); mface+=min_face; mvert=dm->getVertDataArray(dm,CD_MVERT); diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 27357d92aae..577156ef453 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -50,6 +50,8 @@ #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_subsurf.h" +#include "BKE_mesh.h" +#include "BKE_tessmesh.h" #include "BLI_arithb.h" #include "BLI_kdtree.h" @@ -98,14 +100,13 @@ typedef void ( *Shrinkwrap_ForeachVertexCallback) (DerivedMesh *target, float *c DerivedMesh *object_get_derived_final(struct Scene *scene, Object *ob, CustomDataMask dataMask) { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); + BMEditMesh *em = me->edit_btmesh; if (em) { DerivedMesh *final = NULL; - editmesh_get_derived_cage_and_final(scene, ob, em, &final, dataMask); - - BKE_mesh_end_editmesh(me, em); + editbmesh_get_derived_cage_and_final(scene, ob, em, &final, dataMask); + return final; } else diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index bc6b487080c..3e6f30cde36 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -247,11 +247,11 @@ static ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm) /* first some paranoia checks */ if (!dm) return NULL; - if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return NULL; + if (!dm->getNumVerts(dm) || !dm->getNumTessFaces(dm)) return NULL; pccd_M = MEM_mallocN(sizeof(ccd_Mesh),"ccd_Mesh"); pccd_M->totvert = dm->getNumVerts(dm); - pccd_M->totface = dm->getNumFaces(dm); + pccd_M->totface = dm->getNumTessFaces(dm); pccd_M->savety = CCD_SAVETY; pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f; pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f; @@ -280,7 +280,7 @@ static ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm) } /* alloc and copy faces*/ - pccd_M->mface = dm->dupFaceArray(dm); + pccd_M->mface = dm->dupTessFaceArray(dm); /* OBBs for idea1 */ pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax)*pccd_M->totface,"ccd_Mesh_Faces_mima"); @@ -343,10 +343,10 @@ static void ccd_mesh_update(Object *ob,ccd_Mesh *pccd_M, DerivedMesh *dm) /* first some paranoia checks */ if (!dm) return ; - if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return ; + if (!dm->getNumVerts(dm) || !dm->getNumTessFaces(dm)) return ; if ((pccd_M->totvert != dm->getNumVerts(dm)) || - (pccd_M->totface != dm->getNumFaces(dm))) return; + (pccd_M->totface != dm->getNumTessFaces(dm))) return; pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f; pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 6e95fe7ebc7..61f10239148 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -231,10 +231,11 @@ static void get_face_uv_map_vert(UvVertMap *vmap, struct MFace *mf, int fi, CCGV } static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MTFace *tface) { - MFace *mface = dm->getFaceArray(dm); +#if 0 + MFace *mface = dm->getTessFaceArray(dm); MVert *mvert = dm->getVertArray(dm); int totvert = dm->getNumVerts(dm); - int totface = dm->getNumFaces(dm); + int totface = dm->getNumTessFaces(dm); int i, j, seam; UvMapVert *v; UvVertMap *vmap; @@ -324,6 +325,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, free_uv_vert_map(vmap); ccgSubSurf_processSync(ss); +#endif return 1; } @@ -349,7 +351,7 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, } /* get some info from CCGSubsurf */ - totface = ccgSubSurf_getNumFaces(uvss); + totface = ccgSubSurf_getNumTessFaces(uvss); edgeSize = ccgSubSurf_getEdgeSize(uvss); gridSize = ccgSubSurf_getGridSize(uvss); gridFaces = gridSize - 1; @@ -427,7 +429,7 @@ static unsigned int ss_getEdgeFlags(CCGSubSurf *ss, CCGEdge *e, int ssFromEditme } #endif -/* face weighting */ + static void calc_ss_weights(int gridFaces, FaceVertWeight **qweight, FaceVertWeight **tweight) { @@ -471,6 +473,61 @@ static void calc_ss_weights(int gridFaces, } } +/* face weighting */ +typedef struct FaceVertWeightEntry { + FaceVertWeight *weight; + int valid; +} FaceVertWeightEntry; + +typedef struct WeightTable { + FaceVertWeightEntry *weight_table; + int len; +} WeightTable; + +static FaceVertWeight *get_ss_weights(WeightTable *wtable, int gridFaces, int faceLen) +{ + int i; + + /*ensure we have at least the triangle and quad weights*/ + if (wtable->len < 4) { + wtable->weight_table = MEM_callocN(sizeof(FaceVertWeightEntry)*5, "weight table alloc"); + wtable->len = 5; + + calc_ss_weights(gridFaces, &wtable->weight_table[4].weight, &wtable->weight_table[3].weight); + wtable->weight_table[4].valid = wtable->weight_table[3].valid = 1; + } + + if (wtable->len <= faceLen) { + void *tmp = MEM_callocN(sizeof(FaceVertWeightEntry)*(faceLen+1), "weight table alloc 2"); + + memcpy(tmp, wtable->weight_table, sizeof(FaceVertWeightEntry)*wtable->len); + MEM_freeN(wtable->weight_table); + + wtable->weight_table = tmp; + wtable->len = faceLen+1; + } + + if (!wtable->weight_table[faceLen].valid) { + /*ok, need to calculate weights here*/ + wtable->weight_table[faceLen].weight = + MEM_callocN(sizeof(FaceVertWeight)*gridFaces*gridFaces, + "vert face weight"); + wtable->weight_table[faceLen].valid = 1; + } + + return wtable->weight_table[faceLen].weight; +} + +void free_ss_weights(WeightTable *wtable) +{ + int i; + + for (i=0; i<wtable->len; i++) { + if (wtable->weight_table[i].valid) + MEM_freeN(wtable->weight_table[i].weight); + } +} + static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, int drawInteriorEdges, int useSubsurfUv, DerivedMesh *dm, MultiresSubsurf *ms) @@ -481,6 +538,8 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, int gridFaces = gridSize - 1; int edgeBase, faceBase; int i, j, k, S, x, y, index; + int *vertIdx = NULL; + V_DECLARE(vertIdx); CCGVertIterator *vi; CCGEdgeIterator *ei; CCGFaceIterator *fi; @@ -490,11 +549,13 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, int totvert, totedge, totface; MVert *mvert; MEdge *med; + float *w = NULL; + WeightTable wtable; + V_DECLARE(w); MFace *mf; int *origIndex; - FaceVertWeight *qweight, *tweight; - calc_ss_weights(gridFaces, &qweight, &tweight); + memset(&wtable, 0, sizeof(wtable)); /* vert map */ totvert = ccgSubSurf_getNumVerts(ss); @@ -516,7 +577,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))] = e; } - totface = ccgSubSurf_getNumFaces(ss); + totface = ccgSubSurf_getNumTessFaces(ss); faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap"); fi = ccgSubSurf_getFaceIterator(ss); for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { @@ -529,17 +590,17 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, if(ms) { result = MultiresDM_new(ms, dm, ccgSubSurf_getNumFinalVerts(ss), ccgSubSurf_getNumFinalEdges(ss), - ccgSubSurf_getNumFinalFaces(ss)); + ccgSubSurf_getNumFinalFaces(ss), 0, 0); } else { if(dm) { result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss), ccgSubSurf_getNumFinalEdges(ss), - ccgSubSurf_getNumFinalFaces(ss)); + ccgSubSurf_getNumFinalFaces(ss), 0, 0); } else { result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss), ccgSubSurf_getNumFinalEdges(ss), - ccgSubSurf_getNumFinalFaces(ss)); + ccgSubSurf_getNumFinalFaces(ss), 0, 0); } } @@ -551,11 +612,13 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, for(index = 0; index < totface; index++) { CCGFace *f = faceMap2[index]; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); - FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight; - int vertIdx[4]; + FaceVertWeight *weight = get_ss_weights(&wtable, gridFaces, numVerts); + + V_RESET(vertIdx); for(S = 0; S < numVerts; S++) { CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S); + V_GROW(vertIdx); vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v)); } @@ -567,17 +630,22 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, ++origIndex; i++; + V_RESET(w); + for (x=0; x<numVerts; x++) { + V_GROW(w); + } + 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; + int otherS = (numVerts >= 4) ? (S + 2) % numVerts : 3; for(x = 1; x < gridFaces; x++) { - float w[4]; w[prevS] = weight[x][0][0]; w[S] = weight[x][0][1]; w[nextS] = weight[x][0][2]; w[otherS] = weight[x][0][3]; + DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i); VecCopyf(mvert->co, ccgSubSurf_getFaceGridEdgeData(ss, f, S, x)); @@ -588,20 +656,25 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, i++; } } + + V_RESET(w); + for (x=0; x<numVerts; x++) { + V_GROW(w); + } 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(y = 1; y < gridFaces; y++) { for(x = 1; x < gridFaces; x++) { - float w[4]; w[prevS] = weight[y * gridFaces + x][0][0]; w[S] = weight[y * gridFaces + x][0][1]; w[nextS] = weight[y * gridFaces + x][0][2]; w[otherS] = weight[y * gridFaces + x][0][3]; DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i); + VecCopyf(mvert->co, ccgSubSurf_getFaceGridData(ss, f, S, x, y)); *origIndex = ORIGINDEX_NONE; @@ -611,7 +684,6 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, } } } - *((int*)ccgSubSurf_getFaceUserData(ss, f)) = faceBase; faceBase += 1 + numVerts * ((gridSize-2) + (gridSize-2) * (gridSize-2)); } @@ -627,12 +699,14 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, vertIdx[0] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v)); v = ccgSubSurf_getEdgeVert1(e); vertIdx[1] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v)); - + for(x = 1; x < edgeSize - 1; x++) { - float w[2]; - w[1] = (float) x / (edgeSize - 1); - w[0] = 1 - w[1]; - DM_interp_vert_data(dm, result, vertIdx, w, 2, i); + float w2[2]; + + w2[1] = (float) x / (edgeSize - 1); + w2[0] = 1 - w2[1]; + DM_interp_vert_data(dm, result, vertIdx, w2, 2, i); + VecCopyf(mvert->co, ccgSubSurf_getEdgeData(ss, e, x)); *origIndex = ORIGINDEX_NONE; ++mvert; @@ -737,8 +811,8 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, // load faces i = 0; - mf = CDDM_get_faces(result); - origIndex = result->getFaceData(result, 0, CD_ORIGINDEX); + mf = CDDM_get_tessfaces(result); + origIndex = result->getTessFaceData(result, 0, CD_ORIGINDEX); for(index = 0; index < totface; index++) { CCGFace *f = faceMap2[index]; @@ -750,7 +824,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, if(!ssFromEditmesh) { MFace origMFace; - dm->getFace(dm, faceIdx, &origMFace); + dm->getTessFace(dm, faceIdx, &origMFace); mat_nr = origMFace.mat_nr; flag = origMFace.flag; @@ -761,8 +835,8 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, } for(S = 0; S < numVerts; S++) { - FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight; - + FaceVertWeight *weight = get_ss_weights(&wtable, gridFaces, numVerts); + for(y = 0; y < gridFaces; y++) { for(x = 0; x < gridFaces; x++) { mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0, @@ -775,7 +849,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, edgeSize, gridSize); mf->mat_nr = mat_nr; mf->flag = flag; - +#if 0 //BMESH_TODO if(dm) { int prevS = (S - 1 + numVerts) % numVerts; int nextS = (S + 1) % numVerts; @@ -789,10 +863,11 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, w[j][otherS] = (*weight)[j][3]; } - DM_interp_face_data(dm, result, &faceIdx, NULL, + DM_interp_tessface_data(dm, result, &faceIdx, NULL, &w, 1, i); weight++; } +#endif *origIndex = mapIndex; ++mf; @@ -807,8 +882,9 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, MEM_freeN(edgeMap2); MEM_freeN(vertMap2); - MEM_freeN(tweight); - MEM_freeN(qweight); + free_ss_weights(&wtable); + + V_FREE(vertIdx); if(useSubsurfUv) { CustomData *fdata = &result->faceData; @@ -821,7 +897,9 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, } CDDM_calc_normals(result); - + CDDM_tessfaces_to_faces(result); + + V_FREE(w); return result; } @@ -829,18 +907,22 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, float (*vertexCos)[3], int useFlatSubdiv) { float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss); - CCGVertHDL fVerts[4]; + CCGVertHDL *fVerts = NULL; + V_DECLARE(fVerts); int totvert = dm->getNumVerts(dm); int totedge = dm->getNumEdges(dm); - int totface = dm->getNumFaces(dm); + int totface = dm->getNumTessFaces(dm); + int totpoly = dm->getNumFaces(dm); int i; int *index; MVert *mvert = dm->getVertArray(dm); MEdge *medge = dm->getEdgeArray(dm); - MFace *mface = dm->getFaceArray(dm); + MFace *mface = dm->getTessFaceArray(dm); MVert *mv; MEdge *me; MFace *mf; + DMFaceIter *fiter; + DMLoopIter *liter; ccgSubSurf_initFullSync(ss); @@ -872,28 +954,31 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, ((int*)ccgSubSurf_getEdgeUserData(ss, e))[1] = *index; } - - mf = mface; - index = (int *)dm->getFaceDataArray(dm, CD_ORIGINDEX); - for (i = 0; i < totface; i++, mf++, index++) { + + fiter = dm->newFaceIter(dm); + for (i=0; !fiter->done; fiter->step(fiter), i++) { CCGFace *f; + V_RESET(fVerts); - fVerts[0] = SET_INT_IN_POINTER(mf->v1); - fVerts[1] = SET_INT_IN_POINTER(mf->v2); - fVerts[2] = SET_INT_IN_POINTER(mf->v3); - fVerts[3] = SET_INT_IN_POINTER(mf->v4); + index = (int*) fiter->getCDData(fiter, CD_ORIGINDEX, -1); + liter = fiter->getLoopsIter(fiter); + + for (; !liter->done; liter->step(liter)) { + V_GROW(fVerts); + fVerts[V_COUNT(fVerts)-1] = SET_INT_IN_POINTER(liter->vindex); + } - // this is very bad, means mesh is internally consistent. - // it is not really possible to continue without modifying - // other parts of code significantly to handle missing faces. - // since this really shouldn't even be possible we just bail. - if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), fVerts[3] ? 4 : 3, + /* this is very bad, means mesh is internally inconsistent. + * it is not really possible to continue without modifying + * other parts of code significantly to handle missing faces. + * since this really shouldn't even be possible we just bail.*/ + if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), fiter->len, fVerts, &f) == eCCGError_InvalidValue) { static int hasGivenError = 0; if(!hasGivenError) { - //XXX error("Unrecoverable error in SubSurf calculation," - // " mesh is inconsistent."); + printf("Unrecoverable error in SubSurf calculation," + " mesh is inconsistent.\n"); hasGivenError = 1; } @@ -975,7 +1060,7 @@ static int ccgDM_getNumEdges(DerivedMesh *dm) { return ccgSubSurf_getNumFinalEdges(ccgdm->ss); } -static int ccgDM_getNumFaces(DerivedMesh *dm) { +static int ccgDM_getNumTessFaces(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; return ccgSubSurf_getNumFinalFaces(ccgdm->ss); @@ -989,9 +1074,9 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv) memset(mv, 0, sizeof(*mv)); - if((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) { + if((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumTessFaces(ss) > 0)) { /* this vert comes from face data */ - int lastface = ccgSubSurf_getNumFaces(ss) - 1; + int lastface = ccgSubSurf_getNumTessFaces(ss) - 1; CCGFace *f; int x, y, grid, numVerts; int offset; @@ -1064,7 +1149,7 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med) if(edgeNum < ccgdm->edgeMap[0].startEdge) { /* this edge comes from face data */ - int lastface = ccgSubSurf_getNumFaces(ss) - 1; + int lastface = ccgSubSurf_getNumTessFaces(ss) - 1; CCGFace *f; int x, y, grid, numVerts; int offset; @@ -1146,8 +1231,8 @@ static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf) int offset; int grid; int x, y; - int lastface = ccgSubSurf_getNumFaces(ss) - 1; - char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS); + int lastface = ccgSubSurf_getNumTessFaces(ss) - 1; + char *faceFlags = dm->getTessFaceDataArray(dm, CD_FLAGS); memset(mf, 0, sizeof(*mf)); @@ -1183,7 +1268,7 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert) int edgeSize = ccgSubSurf_getEdgeSize(ss); int i = 0; - totface = ccgSubSurf_getNumFaces(ss); + totface = ccgSubSurf_getNumTessFaces(ss); for(index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); @@ -1238,7 +1323,7 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge) int i = 0; int *edgeFlags = dm->getEdgeDataArray(dm, CD_FLAGS); - totface = ccgSubSurf_getNumFaces(ss); + totface = ccgSubSurf_getNumTessFaces(ss); for(index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); @@ -1308,6 +1393,138 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge) } } +struct ccgDM_faceIter; + +typedef struct ccgDM_loopIter { + DMLoopIter head; + int curloop; + CCGDerivedMesh *ccgdm; + struct ccgDM_faceIter *fiter; +} ccgDM_loopIter; + +typedef struct ccgDM_faceIter { + DMFaceIter head; + CCGDerivedMesh *ccgdm; + MFace mface; + + ccgDM_loopIter liter; +} ccgDM_faceIter; + +void ccgDM_faceIterStep(void *self) +{ + ccgDM_faceIter *fiter = self; + + if (!fiter->ccgdm || !fiter->ccgdm->ss) { + fiter->head.done = 1; + return; + } + + if (fiter->head.index >= ccgSubSurf_getNumTessFaces(fiter->ccgdm->ss)) { + fiter->head.done = 1; + return; + }; + + fiter->head.index++; + + ccgDM_getFinalFace((DerivedMesh*)fiter->ccgdm, fiter->head.index, &fiter->mface); + + fiter->head.flags = fiter->mface.flag; + fiter->head.mat_nr = fiter->mface.mat_nr; + fiter->head.len = fiter->mface.v4 ? 4 : 3; +} + +void *ccgDM_faceIterCData(void *self, int type, int layer) +{ + ccgDM_faceIter *fiter = self; + + if (layer == -1) + return CustomData_get(&fiter->ccgdm->dm.faceData, fiter->head.index, type); + else + return CustomData_get_n(&fiter->ccgdm->dm.faceData, type, fiter->head.index, layer); +} + +void ccgDM_loopIterStep(void *self) +{ + ccgDM_loopIter *liter = self; + MFace *mf = &liter->fiter->mface; + int i, in; + + if (liter->head.index >= liter->fiter->head.len) { + liter->head.done = 1; + return; + } + + liter->head.index++; + i = liter->head.index; + + switch (i) { + case 0: + in = liter->fiter->mface.v1; + break; + case 1: + in = liter->fiter->mface.v2; + break; + case 2: + in = liter->fiter->mface.v3; + break; + case 3: + in = liter->fiter->mface.v4; + break; + } + + liter->head.vindex = in; + + /*we don't set .eindex*/ + ccgDM_getFinalVert((DerivedMesh*)liter->ccgdm, in, &liter->head.v); +} + +void *ccgDM_loopIterGetVCData(void *self, int type, int layer) +{ + ccgDM_loopIter *liter = self; + + if (layer == -1) + return CustomData_get(&liter->ccgdm->dm.vertData, liter->head.vindex, type); + else return CustomData_get_n(&liter->ccgdm->dm.vertData, type, liter->head.vindex, layer); +} + +void *ccgDM_loopIterGetCData(void *self, int type, int layer) +{ + ccgDM_loopIter *liter = self; + + /*BMESH_TODO + yeek, this has to convert mface-style uv/mcols to loop-style*/ + return NULL; +} + +DMLoopIter *ccgDM_faceIterGetLIter(void *self) +{ + ccgDM_faceIter *fiter = self; + + fiter->liter.head.index = -1; + fiter->liter.head.done = 0; + fiter->liter.head.step(&fiter->liter); + + return (DMLoopIter*) &fiter->liter; +} + +DMFaceIter *ccgDM_newFaceIter(DerivedMesh *dm) +{ + ccgDM_faceIter *fiter = MEM_callocN(sizeof(ccgDM_faceIter), "ccgDM_faceIter"); + + fiter->head.free = MEM_freeN; + fiter->head.step = ccgDM_faceIterStep; + fiter->head.index = -1; + fiter->head.getCDData = ccgDM_faceIterCData; + fiter->head.getLoopsIter = ccgDM_faceIterGetLIter; + + fiter->liter.fiter = fiter; + fiter->liter.head.getLoopCDData = ccgDM_loopIterGetCData; + fiter->liter.head.getVertCDData = ccgDM_loopIterGetVCData; + fiter->liter.head.step = ccgDM_loopIterStep; + + fiter->head.step(fiter); +} + static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; @@ -1317,9 +1534,9 @@ static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface) int gridSize = ccgSubSurf_getGridSize(ss); int edgeSize = ccgSubSurf_getEdgeSize(ss); int i = 0; - char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS); + char *faceFlags = dm->getTessFaceDataArray(dm, CD_FLAGS); - totface = ccgSubSurf_getNumFaces(ss); + totface = ccgSubSurf_getNumTessFaces(ss); for(index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); @@ -1382,7 +1599,7 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) { edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))] = e; } - totface = ccgSubSurf_getNumFaces(ss); + totface = ccgSubSurf_getNumTessFaces(ss); faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap"); fi = ccgSubSurf_getFaceIterator(ss); for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { @@ -1690,7 +1907,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, v CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss); GPUVertexAttribs gattribs; DMVertexAttribs attribs; - MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE); + MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); int gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; int edgeSize = ccgSubSurf_getEdgeSize(ss); @@ -1727,7 +1944,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, v } \ } - totface = ccgSubSurf_getNumFaces(ss); + totface = ccgSubSurf_getNumTessFaces(ss); for(a = 0, i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, drawSmooth; @@ -1922,7 +2139,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, int i, totface, flag, gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; - totface = ccgSubSurf_getNumFaces(ss); + totface = ccgSubSurf_getNumTessFaces(ss); for(i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); @@ -2054,7 +2271,7 @@ static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void static void ccgDM_drawUVEdges(DerivedMesh *dm) { - MFace *mf = dm->getFaceArray(dm); + MFace *mf = dm->getTessFaceArray(dm); MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE); int i; @@ -2089,7 +2306,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *u CCGSubSurf *ss = ccgdm->ss; CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss); int i, gridSize = ccgSubSurf_getGridSize(ss); - char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS); + char *faceFlags = dm->getTessFaceDataArray(dm, CD_FLAGS); for (i=0; !ccgFaceIterator_isStopped(fi); i++,ccgFaceIterator_next(fi)) { CCGFace *f = ccgFaceIterator_getCurrent(fi); @@ -2274,6 +2491,8 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int edgeSize; int gridSize; int gridFaces; + int *vertIdx = NULL; + V_DECLARE(vertIdx); int gridSideVerts; /*int gridInternalVerts; - as yet unused */ int gridSideEdges; @@ -2285,7 +2504,8 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, DM_from_template(&ccgdm->dm, dm, ccgSubSurf_getNumFinalVerts(ss), ccgSubSurf_getNumFinalEdges(ss), - ccgSubSurf_getNumFinalFaces(ss)); + ccgSubSurf_getNumFinalFaces(ss), + 0, 0); DM_add_face_layer(&ccgdm->dm, CD_FLAGS, CD_CALLOC, NULL); DM_add_edge_layer(&ccgdm->dm, CD_FLAGS, CD_CALLOC, NULL); @@ -2294,21 +2514,24 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ccgdm->dm.getMinMax = ccgDM_getMinMax; ccgdm->dm.getNumVerts = ccgDM_getNumVerts; - ccgdm->dm.getNumFaces = ccgDM_getNumFaces; + ccgdm->dm.getNumTessFaces = ccgDM_getNumTessFaces; + ccgdm->dm.getNumFaces = ccgDM_getNumTessFaces; + + ccgdm->dm.newFaceIter = ccgDM_newFaceIter; ccgdm->dm.getNumEdges = ccgDM_getNumEdges; ccgdm->dm.getVert = ccgDM_getFinalVert; ccgdm->dm.getEdge = ccgDM_getFinalEdge; - ccgdm->dm.getFace = ccgDM_getFinalFace; + ccgdm->dm.getTessFace = ccgDM_getFinalFace; ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray; ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray; - ccgdm->dm.copyFaceArray = ccgDM_copyFinalFaceArray; + ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray; ccgdm->dm.getVertData = DM_get_vert_data; ccgdm->dm.getEdgeData = DM_get_edge_data; - ccgdm->dm.getFaceData = DM_get_face_data; + ccgdm->dm.getTessFaceData = DM_get_face_data; ccgdm->dm.getVertDataArray = DM_get_vert_data_layer; ccgdm->dm.getEdgeDataArray = DM_get_edge_data_layer; - ccgdm->dm.getFaceDataArray = DM_get_face_data_layer; + ccgdm->dm.getTessFaceDataArray = DM_get_face_data_layer; ccgdm->dm.getVertCos = ccgdm_getVertCos; ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert; @@ -2355,7 +2578,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ccgdm->edgeMap[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))].edge = e; } - totface = ccgSubSurf_getNumFaces(ss); + totface = ccgSubSurf_getNumTessFaces(ss); ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap"); fi = ccgSubSurf_getFaceIterator(ss); for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { @@ -2381,7 +2604,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, /* mvert = dm->getVertArray(dm); - as yet unused */ medge = dm->getEdgeArray(dm); - mface = dm->getFaceArray(dm); + mface = dm->getTessFaceArray(dm); vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX); /*edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX);*/ @@ -2397,7 +2620,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f)); FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight; int S, x, y; - int vertIdx[4]; ccgdm->faceMap[index].startVert = vertNum; ccgdm->faceMap[index].startEdge = edgeNum; @@ -2405,9 +2627,11 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, /* set the face base vert */ *((int*)ccgSubSurf_getFaceUserData(ss, f)) = vertNum; - + + V_RESET(vertIdx); for(S = 0; S < numVerts; S++) { CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S); + V_GROW(vertIdx); vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v)); } @@ -2418,18 +2642,22 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, ++vertOrigIndex; ++vertNum; + 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]; +#if 0 //BMESH_TODO w[prevS] = weight[x][0][0]; w[S] = weight[x][0][1]; w[nextS] = weight[x][0][2]; w[otherS] = weight[x][0][3]; DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, numVerts, vertNum); +#endif *vertOrigIndex = ORIGINDEX_NONE; ++vertOrigIndex; ++vertNum; @@ -2443,12 +2671,14 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, for(y = 1; y < gridFaces; y++) { for(x = 1; x < gridFaces; x++) { float w[4]; +#if 0 //BMESH_TODO w[prevS] = weight[y * gridFaces + x][0][0]; w[S] = weight[y * gridFaces + x][0][1]; w[nextS] = weight[y * gridFaces + x][0][2]; w[otherS] = weight[y * gridFaces + x][0][3]; DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, numVerts, vertNum); +#endif *vertOrigIndex = ORIGINDEX_NONE; ++vertOrigIndex; ++vertNum; @@ -2472,6 +2702,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, FaceVertWeight w; int j; +#if 0 //BMESH_TODO for(j = 0; j < 4; ++j) { w[j][prevS] = (*weight)[j][0]; w[j][S] = (*weight)[j][1]; @@ -2479,9 +2710,10 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, w[j][otherS] = (*weight)[j][3]; } - DM_interp_face_data(dm, &ccgdm->dm, &origIndex, NULL, + DM_interp_tessface_data(dm, &ccgdm->dm, &origIndex, NULL, &w, 1, faceNum); weight++; +#endif *faceOrigIndex = mapIndex; @@ -2572,6 +2804,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, MEM_freeN(qweight); MEM_freeN(tweight); + V_FREE(vertIdx); return ccgdm; } diff --git a/source/blender/blenkernel/intern/verse_bitmap_node.c b/source/blender/blenkernel/intern/verse_bitmap_node.c new file mode 100644 index 00000000000..d27f7a13f02 --- /dev/null +++ b/source/blender/blenkernel/intern/verse_bitmap_node.c @@ -0,0 +1,451 @@ +/** + * $Id: verse_bitmap_node.c 12931 2007-12-17 18:20:48Z theeth $ + * + * ***** BEGIN GPL/BL DUAL 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL 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 new file mode 100644 index 00000000000..a53ad2cb627 --- /dev/null +++ b/source/blender/blenkernel/intern/verse_geometry_node.c @@ -0,0 +1,2101 @@ +/** + * $Id: verse_geometry_node.c 12931 2007-12-17 18:20:48Z theeth $ + * + * ***** BEGIN GPL/BL DUAL 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL 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 new file mode 100644 index 00000000000..89b5282acfd --- /dev/null +++ b/source/blender/blenkernel/intern/verse_method.c @@ -0,0 +1,523 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. + * + * Contributor(s): Nathan Letwory. + * + * ***** END GPL/BL DUAL 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 new file mode 100644 index 00000000000..682ae773da5 --- /dev/null +++ b/source/blender/blenkernel/intern/verse_node.c @@ -0,0 +1,750 @@ +/** + * $Id: verse_node.c 12931 2007-12-17 18:20:48Z theeth $ + * + * ***** BEGIN GPL/BL DUAL 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL 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 new file mode 100644 index 00000000000..9f4dcc72237 --- /dev/null +++ b/source/blender/blenkernel/intern/verse_object_node.c @@ -0,0 +1,620 @@ +/** + * $Id: verse_object_node.c 12931 2007-12-17 18:20:48Z theeth $ + * + * ***** BEGIN GPL/BL DUAL 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL 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 new file mode 100644 index 00000000000..64d6b9885fe --- /dev/null +++ b/source/blender/blenkernel/intern/verse_session.c @@ -0,0 +1,480 @@ +/** + * $Id: verse_session.c 12931 2007-12-17 18:20:48Z theeth $ + * + * ***** BEGIN GPL/BL DUAL 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. + * + * Contributor(s): Jiri Hnidek. + * + * ***** END GPL/BL DUAL 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/nla_private.h b/source/blender/blenkernel/nla_private.h deleted file mode 100644 index 325798f325f..00000000000 --- a/source/blender/blenkernel/nla_private.h +++ /dev/null @@ -1,85 +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) 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 diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h index 787579250ed..bcc2ac3deec 100644 --- a/source/blender/blenlib/BLI_arithb.h +++ b/source/blender/blenlib/BLI_arithb.h @@ -75,6 +75,7 @@ void CalcCent3f(float *cent, float *v1, float *v2, float *v3); void CalcCent4f(float *cent, float *v1, float *v2, float *v3, float *v4); void Crossf(float *c, float *a, float *b); +void Crossd(double *c, double *a, double *b); void Projf(float *c, float *v1, float *v2); float Inpf(float *v1, float *v2); @@ -82,6 +83,7 @@ float Inp2f(float *v1, float *v2); float Normalize(float *n); float Normalize2(float *n); +double Normalize_d(double *n); float Sqrt3f(float f); double Sqrt3d(double d); @@ -267,6 +269,7 @@ void Vec2Subf(float *v, float *v1, float *v2); void Vec2Copyf(float *v1, float *v2); void Vec2Lerpf(float *target, float *a, float *b, float t); +void AxisAngleToQuatd(float *q, float *axis, double angle); void AxisAngleToQuat(float *q, float *axis, float angle); void RotationBetweenVectorsToQuat(float *q, float v1[3], float v2[3]); void vectoquat(float *vec, short axis, short upflag, float *q); diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h index 56a20d8462a..60b7f74954d 100644 --- a/source/blender/blenlib/BLI_editVert.h +++ b/source/blender/blenlib/BLI_editVert.h @@ -42,6 +42,7 @@ struct DerivedMesh; struct RetopoPaintData; +struct BLI_mempool; /* note; changing this also might affect the undo copy in editmesh.c */ typedef struct EditVert @@ -154,6 +155,8 @@ typedef struct EditMesh HashEdge *hashedgetab; /* this is for the editmesh_fastmalloc */ + struct BLI_mempool *vertpool, *edgepool, *facepool; + EditVert *allverts, *curvert; EditEdge *alledges, *curedge; EditFace *allfaces, *curface; diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 80cd507520c..d835ed18476 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -33,6 +33,7 @@ #include "MEM_guardedalloc.h" #include "BLI_ghash.h" +#include "BLI_mempool.h" #include "BLO_sys_types.h" // for intptr_t support @@ -63,6 +64,7 @@ struct GHash { GHashCmpFP cmpfp; Entry **buckets; + struct BLI_mempool *entrypool; int nbuckets, nentries, cursize; }; @@ -72,7 +74,8 @@ GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp) { GHash *gh= MEM_mallocN(sizeof(*gh), "GHash"); gh->hashfp= hashfp; gh->cmpfp= cmpfp; - + gh->entrypool = BLI_mempool_create(sizeof(Entry), 1, 32); + gh->cursize= 0; gh->nentries= 0; gh->nbuckets= hashsizes[gh->cursize]; @@ -85,7 +88,7 @@ GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp) { void BLI_ghash_insert(GHash *gh, void *key, void *val) { unsigned int hash= gh->hashfp(key)%gh->nbuckets; - Entry *e= malloc(sizeof(*e)); + Entry *e= BLI_mempool_alloc(gh->entrypool); e->key= key; e->val= val; @@ -141,7 +144,7 @@ int BLI_ghash_remove (GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFr if (keyfreefp) keyfreefp(e->key); if (valfreefp) valfreefp(e->val); - free(e); + BLI_mempool_free(gh->entrypool, e); e= n; @@ -185,13 +188,13 @@ void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreef if (keyfreefp) keyfreefp(e->key); if (valfreefp) valfreefp(e->val); - free(e); - + e= n; } } free(gh->buckets); + BLI_mempool_destroy(gh->entrypool); gh->buckets = 0; gh->nentries = 0; gh->nbuckets = 0; diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c index 7ac7b8b1791..493bbba3567 100644 --- a/source/blender/blenlib/intern/BLI_mempool.c +++ b/source/blender/blenlib/intern/BLI_mempool.c @@ -65,7 +65,8 @@ BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk) pool->chunks.first = pool->chunks.last = NULL; maxchunks = tote / pchunk; - + if (maxchunks==0) maxchunks = 1; + /*allocate the actual chunks*/ for(i=0; i < maxchunks; i++){ BLI_mempool_chunk *mpchunk = MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk"); @@ -85,6 +86,7 @@ BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk) /*set the end of this chunks memoryy to the new tail for next iteration*/ lasttail = curnode; } + /*terminate the list*/ curnode->next = NULL; return pool; diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index f111e94a141..0c7db0331e1 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -111,6 +111,26 @@ float Normalize(float *n) return d; } +/*original function from shadeoutput.c*/ +double Normalize_d(double *n) +{ + double d; + + d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2]; + + if(d>0.00000000000000001) { + d= sqrt(d); + + n[0]/=d; + n[1]/=d; + n[2]/=d; + } else { + n[0]=n[1]=n[2]= 0.0; + d= 0.0; + } + return d; +} + void Crossf(float *c, float *a, float *b) { c[0] = a[1] * b[2] - a[2] * b[1]; @@ -118,6 +138,13 @@ void Crossf(float *c, float *a, float *b) c[2] = a[0] * b[1] - a[1] * b[0]; } +void Crossd(double *c, double *a, double *b) +{ + c[0] = a[1] * b[2] - a[2] * b[1]; + c[1] = a[2] * b[0] - a[0] * b[2]; + c[2] = a[0] * b[1] - a[1] * b[0]; +} + /* Inpf returns the dot product, also called the scalar product and inner product */ float Inpf( float *v1, float *v2) { @@ -845,7 +872,7 @@ void Mat4MulVec( float mat[][4], int *vec) vec[2]=(int)(x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2]); } -void Mat4MulVecfl( float mat[][4], float *vec) +void Mat4MulVecfl(float mat[][4], float *vec) { float x,y; @@ -1404,6 +1431,28 @@ void AxisAngleToQuat(float *q, float *axis, float angle) q[3] = nor[2] * si; } +void AxisAngleToQuatd(float *q, float *axis, double angle) +{ + double nor[3]; + double si, l; + + nor[0] = axis[0]; + nor[1] = axis[1]; + nor[2] = axis[2]; + + l = sqrt(nor[0]*nor[0] + nor[1]*nor[1] + nor[2]*nor[2]); + nor[0] /= l; + nor[1] /= l; + nor[2] /= l; + + angle /= 2; + si = sin(angle); + q[0] = cos(angle); + q[1] = nor[0] * si; + q[2] = nor[1] * si; + q[3] = nor[2] * si; +} + void vectoquat(float *vec, short axis, short upflag, float *q) { float q2[4], nor[3], *fp, mat[3][3], angle, si, co, x2, y2, z2, len1; diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c index 603c85655d7..8976059d153 100644 --- a/source/blender/blenlib/intern/edgehash.c +++ b/source/blender/blenlib/intern/edgehash.c @@ -62,20 +62,19 @@ struct EdgeHash { /***/ EdgeHash *BLI_edgehash_new(void) { - EdgeHash *eh= MEM_mallocN(sizeof(*eh), "EdgeHash"); + EdgeHash *eh= MEM_callocN(sizeof(*eh), "EdgeHash"); eh->cursize= 0; eh->nentries= 0; eh->nbuckets= hashsizes[eh->cursize]; - eh->buckets= malloc(eh->nbuckets*sizeof(*eh->buckets)); - memset(eh->buckets, 0, eh->nbuckets*sizeof(*eh->buckets)); + eh->buckets= MEM_callocN(eh->nbuckets*sizeof(*eh->buckets), "eh buckets 2"); return eh; } void BLI_edgehash_insert(EdgeHash *eh, int v0, int v1, void *val) { unsigned int hash; - Entry *e= malloc(sizeof(*e)); + Entry *e= MEM_callocN(sizeof(*e), "edgehash e"); if (v1<v0) { v0 ^= v1; @@ -95,7 +94,7 @@ void BLI_edgehash_insert(EdgeHash *eh, int v0, int v1, void *val) { int i, nold= eh->nbuckets; eh->nbuckets= hashsizes[++eh->cursize]; - eh->buckets= malloc(eh->nbuckets*sizeof(*eh->buckets)); + eh->buckets= MEM_mallocN(eh->nbuckets*sizeof(*eh->buckets), "eh buckets"); memset(eh->buckets, 0, eh->nbuckets*sizeof(*eh->buckets)); for (i=0; i<nold; i++) { @@ -110,7 +109,7 @@ void BLI_edgehash_insert(EdgeHash *eh, int v0, int v1, void *val) { } } - free(old); + MEM_freeN(old); } } @@ -155,7 +154,7 @@ void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp) { Entry *n= e->next; if (valfreefp) valfreefp(e->val); - free(e); + MEM_freeN(e); e= n; } @@ -168,7 +167,7 @@ void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp) { void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp) { BLI_edgehash_clear(eh, valfreefp); - free(eh->buckets); + MEM_freeN(eh->buckets); MEM_freeN(eh); } @@ -182,7 +181,7 @@ struct EdgeHashIterator { }; EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) { - EdgeHashIterator *ehi= malloc(sizeof(*ehi)); + EdgeHashIterator *ehi= MEM_mallocN(sizeof(*ehi), "eh iter"); ehi->eh= eh; ehi->curEntry= NULL; ehi->curBucket= -1; @@ -195,7 +194,7 @@ EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) { return ehi; } void BLI_edgehashIterator_free(EdgeHashIterator *ehi) { - free(ehi); + MEM_freeN(ehi); } void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, int *v0_r, int *v1_r) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 06092cc97d4..5cc9698f79a 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3118,6 +3118,26 @@ static void lib_link_customdata_mtface(FileData *fd, Mesh *me, CustomData *fdata } +static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata, int totface) +{ + int i; + + for(i=0; i<pdata->totlayer; i++) { + CustomDataLayer *layer = &pdata->layers[i]; + + if(layer->type == CD_MTEXPOLY) { + MTexPoly *tf= layer->data; + int i; + + for (i=0; i<totface; i++, tf++) { + tf->tpage= newlibadr(fd, me->id.lib, tf->tpage); + if(tf->tpage && tf->tpage->id.us==0) + tf->tpage->id.us= 1; + } + } + } +} + static void lib_link_mesh(FileData *fd, Main *main) { Mesh *me; @@ -3144,6 +3164,7 @@ static void lib_link_mesh(FileData *fd, Main *main) me->texcomesh= newlibadr_us(fd, me->id.lib, me->texcomesh); lib_link_customdata_mtface(fd, me, &me->fdata, me->totface); + lib_link_customdata_mtpoly(fd, me, &me->pdata, me->totpoly); if(me->mr && me->mr->levels.first) lib_link_customdata_mtface(fd, me, &me->mr->fdata, ((MultiresLevel*)me->mr->levels.first)->totface); @@ -3199,6 +3220,124 @@ static void direct_link_customdata(FileData *fd, CustomData *data, int count) } } + +void bmesh_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, int numCol) +{ + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + MFace *mf; + int i; + + for(i=0; i < numTex; i++){ + texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i); + texpoly = CustomData_get_n(&me->pdata, CD_MTEXPOLY, findex, i); + mf = me->mface + findex; + + texpoly->tpage = texface->tpage; + texpoly->flag = texface->flag; + texpoly->transp = texface->transp; + texpoly->mode = texface->mode; + texpoly->tile = texface->tile; + texpoly->unwrap = texface->unwrap; + + mloopuv = CustomData_get_n(&me->ldata, CD_MLOOPUV, loopstart, i); + mloopuv->uv[0] = texface->uv[0][0]; mloopuv->uv[1] = texface->uv[0][1]; mloopuv++; + mloopuv->uv[0] = texface->uv[1][0]; mloopuv->uv[1] = texface->uv[1][1]; mloopuv++; + mloopuv->uv[0] = texface->uv[2][0]; mloopuv->uv[1] = texface->uv[2][1]; mloopuv++; + + if (mf->v4) { + mloopuv->uv[0] = texface->uv[3][0]; mloopuv->uv[1] = texface->uv[3][1]; mloopuv++; + } + } + + for(i=0; i < numCol; i++){ + mf = me->mface + findex; + mloopcol = CustomData_get_n(&me->ldata, CD_MLOOPCOL, loopstart, i); + mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i); + + mloopcol->r = mcol[0].r; mloopcol->g = mcol[0].g; mloopcol->b = mcol[0].b; mloopcol->a = mcol[0].a; mloopcol++; + mloopcol->r = mcol[1].r; mloopcol->g = mcol[1].g; mloopcol->b = mcol[1].b; mloopcol->a = mcol[1].a; mloopcol++; + mloopcol->r = mcol[2].r; mloopcol->g = mcol[2].g; mloopcol->b = mcol[2].b; mloopcol->a = mcol[2].a; mloopcol++; + if (mf->v4) { + mloopcol->r = mcol[3].r; mloopcol->g = mcol[3].g; mloopcol->b = mcol[3].b; mloopcol->a = mcol[3].a; mloopcol++; + } + } +} + +static void convert_mfaces_to_mpolys(Mesh *mesh) +{ + MFace *mf; + MLoop *ml; + MPoly *mp; + MEdge *me; + EdgeHash *eh; + int numTex, numCol; + int i, j, totloop; + + mesh->totpoly = mesh->totface; + mesh->mpoly = MEM_callocN(sizeof(MPoly)*mesh->totpoly, "mpoly converted"); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_ASSIGN, mesh->mpoly, mesh->totpoly); + + numTex = CustomData_number_of_layers(&mesh->fdata, CD_MTFACE); + numCol = CustomData_number_of_layers(&mesh->fdata, CD_MCOL); + + totloop = 0; + mf = mesh->mface; + for (i=0; i<mesh->totface; i++, mf++) { + totloop += mf->v4 ? 4 : 3; + } + + mesh->totloop = totloop; + mesh->mloop = MEM_callocN(sizeof(MLoop)*mesh->totloop, "mloop converted"); + + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_ASSIGN, mesh->mloop, totloop); + CustomData_to_bmeshpoly(&mesh->fdata, &mesh->pdata, &mesh->ldata, + mesh->totloop, mesh->totpoly); + + eh = BLI_edgehash_new(); + + /*build edge hash*/ + me = mesh->medge; + for (i=0; i<mesh->totedge; i++, me++) { + BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i)); + } + + j = 0; /*current loop index*/ + ml = mesh->mloop; + mf = mesh->mface; + mp = mesh->mpoly; + for (i=0; i<mesh->totface; i++, mf++, mp++) { + mp->loopstart = j; + + mp->totloop = mf->v4 ? 4 : 3; + + mp->mat_nr = mf->mat_nr; + mp->flag = mf->flag; + + #define ML(v1, v2) {ml->v = mf->##v1; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->##v1, mf->##v2)); ml++; j++;} + + ML(v1, v2); + ML(v2, v3); + if (mf->v4) { + ML(v3, v4); + ML(v4, v1); + } else { + ML(v3, v1); + } + + #undef ML + + bmesh_corners_to_loops(mesh, i, mp->loopstart, numTex, numCol); + } + + /*BMESH_TODO now to deal with fgons*/ + + BLI_edgehash_free(eh, NULL); +} + static void direct_link_mesh(FileData *fd, Mesh *mesh) { mesh->mat= newdataadr(fd, mesh->mat); @@ -3207,12 +3346,17 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh) mesh->mvert= newdataadr(fd, mesh->mvert); mesh->medge= newdataadr(fd, mesh->medge); mesh->mface= newdataadr(fd, mesh->mface); + mesh->mloop= newdataadr(fd, mesh->mloop); + mesh->mpoly= newdataadr(fd, mesh->mpoly); mesh->tface= newdataadr(fd, mesh->tface); mesh->mtface= newdataadr(fd, mesh->mtface); mesh->mcol= newdataadr(fd, mesh->mcol); mesh->msticky= newdataadr(fd, mesh->msticky); mesh->dvert= newdataadr(fd, mesh->dvert); - + mesh->mloopcol= newdataadr(fd, mesh->mloopcol); + mesh->mloopuv= newdataadr(fd, mesh->mloopuv); + mesh->mtpoly= newdataadr(fd, mesh->mtpoly); + /* Partial-mesh visibility (do this before using totvert, totface, or totedge!) */ mesh->pv= newdataadr(fd, mesh->pv); if(mesh->pv) { @@ -3229,10 +3373,12 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh) direct_link_customdata(fd, &mesh->vdata, mesh->pv ? mesh->pv->totvert : mesh->totvert); direct_link_customdata(fd, &mesh->edata, mesh->pv ? mesh->pv->totedge : mesh->totedge); direct_link_customdata(fd, &mesh->fdata, mesh->pv ? mesh->pv->totface : mesh->totface); - + direct_link_customdata(fd, &mesh->ldata, mesh->totloop); + direct_link_customdata(fd, &mesh->pdata, mesh->totpoly); + mesh->bb= NULL; mesh->mselect = NULL; - mesh->edit_mesh= NULL; + mesh->edit_btmesh= NULL; /* Multires data */ mesh->mr= newdataadr(fd, mesh->mr); @@ -3282,6 +3428,11 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh) SWITCH_INT(tf->col[3]); } } + + /*check if we need to convert mfaces to mpolys*/ + if (mesh->totface && !mesh->totpoly) { + convert_mfaces_to_mpolys(mesh); + } } /* ************ READ LATTICE ***************** */ diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ebec409ddf4..c7cc1aacb18 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1404,6 +1404,8 @@ static void write_meshs(WriteData *wd, ListBase *idbase) write_customdata(wd, mesh->totvert, &mesh->vdata, -1, 0); write_customdata(wd, mesh->totedge, &mesh->edata, -1, 0); write_customdata(wd, mesh->totface, &mesh->fdata, -1, 0); + write_customdata(wd, mesh->totloop, &mesh->ldata, -1, 0); + write_customdata(wd, mesh->totpoly, &mesh->pdata, -1, 0); } /* PMV data */ diff --git a/source/blender/bmesh/SConscript b/source/blender/bmesh/SConscript new file mode 100644 index 00000000000..d7cfa9ca942 --- /dev/null +++ b/source/blender/bmesh/SConscript @@ -0,0 +1,38 @@ +#!/usr/bin/python +Import ('env') + +cflags='' +""" +sources = ['intern/bmesh_eulers.c'] +sources.append('intern/bmesh_mesh.c') +sources.append('intern/bmesh_polygon.c') +sources.append('intern/bmesh_structure.c') +sources.append('intern/bmesh_marking.c') + +sources.append('intern/bmesh_construct.c') +sources.append('intern/bmesh_interp.c') +sources.append('intern/bmesh_filters.c') +sources.append('intern/bmesh_iterators.c') +sources.append('intern/bmesh_mods.c') +sources.append('intern/bmesh_queries.c') +sources.append('intern/bmesh_operators.c') +""" +#sources.append('api/BME_walkers.c') + + +sources = env.Glob('intern/*.c') +sources += env.Glob('operators/*.c') + +#sources += env.Glob('tools/*.c') + +incs = ['#/intern/guardedalloc'] +incs.append('../blenlib') +incs.append('../makesdna') +incs.append('../blenkernel') +incs.append('./') +incs.append('./intern') +incs.append('../editors/mesh') +incs.append('../editors/include') + +defs = [] +env.BlenderLib ( libname = 'bf_bmesh', sources = sources, includes = Split(incs), libtype = 'core', defines=defs, priority=100, compileflags=cflags ) diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h new file mode 100644 index 00000000000..443e04c8711 --- /dev/null +++ b/source/blender/bmesh/bmesh.h @@ -0,0 +1,355 @@ +/** + * bmesh.h jan 2007 + * + * BMesh API. + * + * $Id: BKE_bmesh.h,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle, Levi Schooley. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BMESH_H +#define BMESH_H + +#include "DNA_listBase.h" +#include "DNA_customdata_types.h" +#include "DNA_scene_types.h" +#include "BLI_mempool.h" +#include "BKE_customdata.h" + +/* +short introduction: + +the bmesh structure is a boundary representation, supporting non-manifold +locally modifiable topology. the API is designed to allow clean, maintainable +code, that never (or almost never) directly inspects the underlying structure. + +The API includes iterators, including many useful topological iterators; +walkers, which walk over a mesh, without the risk of hitting the recursion +limit; operators, which are logical, reusable mesh modules; topological +modification functions (like split face, join faces, etc), which are used for +topological manipulations; and some (not yet finished) geometric utility +functions. + +some definitions: + +tool flags: private flags for tools. each operator has it's own private + tool flag "layer", which it can use to flag elements. + tool flags are also used by various other parts of the api. +header flags: stores persistent flags, such as selection state, hide state, + etc. be careful of touching these. +*/ + +/*forward declarations*/ +struct BMVert; +struct BMEdge; +struct BMFace; +struct BMLoop; +struct BMOperator; +struct Mesh; +struct EditMesh; + +/* + * BMHeader + * + * All mesh elements begin with a BMHeader. This structure + * hold several types of data + * + * 1: The type of the element (vert, edge, loop or face) + * 2: Persistant flags/markings (sharp, seam, select, hidden, ect) + * 3: Unique ID in the bmesh. + * 4: some elements for internal record keeping. + * +*/ + +/*BMHeader->type*/ +#define BM_VERT 1 +#define BM_EDGE 2 +#define BM_FACE 4 +#define BM_LOOP 8 +#define BM_ALL (BM_VERT | BM_EDGE | BM_FACE | BM_LOOP) + +/*BMHeader->flag*/ +#define BM_SELECT (1<<0) + +#define BM_SEAM (1<<1) +#define BM_FGON (1<<2) +#define BM_HIDDEN (1<<3) +#define BM_SHARP (1<<4) +#define BM_SMOOTH (1<<5) +#define BM_ACTIVE (1<<6) +#define BM_NONORMCALC (1<<7) + +typedef struct BMHeader { + struct BMHeader *next, *prev; + int EID; /*Consider removing this/making it ifdeffed for debugging*/ + + /*don't confuse this with tool flags. this flag + member is what "header flag" means.*/ + int flag; + int type; + int eflag1, eflag2; /*Flags used by eulers. Try and get rid of/minimize some of these*/ + + //this can only be used to store a temporary index. don't use it for anything else. + //use the BMINDEX_GET and BMINDEX_SET macros!! + int index; + struct BMFlagLayer *flags; /*Dynamically allocated block of flag layers for operators to use*/ + void *data; /*customdata*/ +} BMHeader; + +typedef struct BMFlagLayer { + int f1; + short mask, pflag; +} BMFlagLayer; + +#define BM_OVERLAP (1<<14) /*used by bmesh_verts_in_face*/ +#define BM_EDGEVERT (1<<15) /*used by bmesh_make_ngon*/ + +/* + * BMNode + * + * Used for circular/linked list functions that form basis of + * adjacency system in BMesh. This should probably be hidden + * somewhere since tool authors never need to know about it. + * +*/ + +typedef struct BMNode { + struct BMNode *next, *prev; + void *data; +} BMNode; + +typedef struct BMesh { + ListBase verts, edges, polys; + struct BLI_mempool *vpool; + struct BLI_mempool *epool; + struct BLI_mempool *lpool; + struct BLI_mempool *ppool; + struct BMVert **vtar; + struct BMEdge **edar; + struct BMLoop **lpar; + struct BMFace **plar; + int vtarlen, edarlen, lparlen, plarlen; + int totvert, totedge, totface, totloop; + int totvertsel, totedgesel, totfacesel; + int nextv, nexte, nextp, nextl; + struct CustomData vdata, edata, pdata, ldata; + int selectmode; /*now uses defines in DNA_scene_types.h*/ + struct BLI_mempool *flagpool; /*memory pool for dynamically allocated flag layers*/ + int stackdepth; /*current depth of operator stack*/ + int totflags, walkers; /*total number of tool flag layers*/ + ListBase errorstack; + + /*active face pointer*/ + struct BMFace *act_face; +} BMesh; + +typedef struct BMVert { + struct BMHeader head; + float co[3]; + float no[3]; + struct BMEdge *edge; + void *tmp; /*what?*/ + float bweight; /*please, someone just get rid of me...*/ +} BMVert; + +typedef struct BMEdge { + struct BMHeader head; + struct BMVert *v1, *v2; + struct BMNode d1, d2; + struct BMLoop *loop; + float crease, bweight; /*make these custom data.... no really, please....*/ +} BMEdge; + +typedef struct BMLoop { + struct BMHeader head; + struct BMNode radial; + struct BMVert *v; + struct BMEdge *e; + struct BMFace *f; +} BMLoop; + +typedef struct BMFace { + struct BMHeader head; + struct BMLoop *loopbase; + int len; + float no[3]; + + /*custom data again*/ + short mat_nr; +} BMFace; + +/*stub */ +void bmesh_error(void); + +/*Mesh Level Ops */ +struct BMesh *BM_Make_Mesh(int allocsize[4]); +BMesh *BM_Copy_Mesh(BMesh *bmold); +void BM_Free_Mesh(struct BMesh *bm); + +/*frees mesh, but not actual BMesh struct*/ +void BM_Free_Mesh_Data(BMesh *bm); +void BM_Compute_Normals(struct BMesh *bm); + +/*Construction*/ +struct BMVert *BM_Make_Vert(struct BMesh *bm, float co[3], struct BMVert *example); +struct BMEdge *BM_Make_Edge(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMEdge *example, int nodouble); +struct BMFace *BM_Make_Quadtriangle(struct BMesh *bm, struct BMVert **verts, BMEdge **edges, int len, struct BMFace *example, int nodouble); + +/*more easier to use version of BM_Make_Quadtriangle. + creates edges if necassary.*/ +BMFace *BM_Make_QuadTri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, + BMVert *v4, BMFace *example, int nodouble); + +/*makes an ngon from an unordered list of edges. v1 and v2 must be the verts +defining edges[0], and define the winding of the new face.*/ +struct BMFace *BM_Make_Ngon(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMEdge **edges, int len, int nodouble); + +/*stuff for dealing with header flags*/ +#define BM_TestHFlag(ele, f) (((BMHeader*)ele)->flag & (f)) +#define BM_SetHFlag(ele, f) (((BMHeader*)ele)->flag = ((BMHeader*)ele)->flag | (f)) +#define BM_ClearHFlag(ele, f) (((BMHeader*)ele)->flag = ((BMHeader*)ele)->flag & ~(f)) + +/*stuff for setting indices in elements.*/ +#define BMINDEX_SET(ele, i) (((BMHeader*)ele)->index = i) +#define BMINDEX_GET(ele) ((BMHeader*)ele)->index + +/*copies loop data from adjacent faces*/ +void BM_Face_CopyShared(BMesh *bm, BMFace *f); + +/*copies attributes, e.g. customdata, header flags, etc, from one element + to another of the same type.*/ +void BM_Copy_Attributes(struct BMesh *source_mesh, struct BMesh *target_mesh, void *source, void *target); + +/*remove tool flagged elements*/ +void BM_remove_tagged_faces(struct BMesh *bm, int flag); +void BM_remove_tagged_edges(struct BMesh *bm, int flag); +void BM_remove_tagged_verts(struct BMesh *bm, int flag); + + +/*Modification*/ +/*join two adjacent faces together along an edge. note that + the faces must only be joined by on edge. e is the edge you + wish to dissolve.*/ +struct BMFace *BM_Join_Faces(struct BMesh *bm, struct BMFace *f1, + struct BMFace *f2, struct BMEdge *e); + +/*split a face along two vertices. returns the newly made face, and sets + the nl member to a loop in the newly created edge.*/ +struct BMFace *BM_Split_Face(struct BMesh *bm, struct BMFace *f, + struct BMVert *v1, struct BMVert *v2, + struct BMLoop **nl, struct BMEdge *example); + +/*dissolves a vert shared only by two edges*/ +void BM_Collapse_Vert(struct BMesh *bm, struct BMEdge *ke, struct BMVert *kv, + float fac); + +/*splits an edge. ne is set to the new edge created.*/ +struct BMVert *BM_Split_Edge(struct BMesh *bm, struct BMVert *v, + struct BMEdge *e, struct BMEdge **ne, + float percent); + +/*split an edge multiple times evenly*/ +struct BMVert *BM_Split_Edge_Multi(struct BMesh *bm, struct BMEdge *e, + int numcuts); + +/*connect two verts together, through a face they share. this function may + be removed in the future.*/ +BMEdge *BM_Connect_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf); + + +/*updates a face normal*/ +void BM_Face_UpdateNormal(BMesh *bm, BMFace *f); + +/*updates face and vertex normals incident on an edge*/ +void BM_Edge_UpdateNormals(BMesh *bm, BMEdge *e); + +/*update a vert normal (but not the faces incident on it)*/ +void BM_Vert_UpdateNormal(BMesh *bm, BMVert *v); + + +/*dissolves all faces around a vert, and removes it.*/ +int BM_Dissolve_Disk(BMesh *bm, BMVert *v); + +/*dissolves vert, in more situations then BM_Dissolve_Disk + (e.g. if the vert is part of a wire edge, etc).*/ +int BM_Dissolve_Vert(BMesh *bm, BMVert *v); + + +/*Interpolation*/ +void BM_Data_Interp_From_Verts(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMVert *v, float fac); +void BM_Data_Facevert_Edgeinterp(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMVert *v, struct BMEdge *e1, float fac); +//void bmesh_data_interp_from_face(struct BMesh *bm, struct BMFace *source, struct BMFace *target); +void BM_add_data_layer(BMesh *em, CustomData *data, int type); +void BM_free_data_layer(BMesh *em, CustomData *data, int type); + + +/*computes the centroid of a face, using the center of the bounding box*/ +int BM_Compute_Face_Center(BMesh *bm, BMFace *f, float center[3]); +void BM_SelectMode_Flush(BMesh *bm); + +/*convert an editmesh to a bmesh*/ +BMesh *editmesh_to_bmesh(struct EditMesh *em); + +/*initializes editmesh to bmesh operator, but doesn't execute. + this is used in situations where you need to get access to the + conversion operator's editmesh->bmesh mapping slot (e.g. if you + need to find the bmesh edge that corrusponds to a specific editmesh + edge).*/ +BMesh *init_editmesh_to_bmesh(struct EditMesh *em, struct BMOperator *op); + +/*converts a bmesh to an editmesh*/ +struct EditMesh *bmesh_to_editmesh(BMesh *bm); + +/*convert between bmesh and Mesh flags*/ +int BMFlags_To_MEFlags(void *element); + +/*convert between Mesh and bmesh flags + type must be BM_VERT/BM_EDGE/BM_FACE, + and represents the type of the element + parameter (the three defines map to + MVert, MEdge, and MPoly, respectively).*/ +int MEFlags_To_BMFlags(int flag, int type); + +/*convert MLoop*** in a bmface to mtface and mcol in + an MFace*/ +void BM_loops_to_corners(BMesh *bm, struct Mesh *me, int findex, + BMFace *f, int numTex, int numCol); + +/*include the rest of the API*/ +#include "bmesh_filters.h" +#include "bmesh_iterators.h" +#include "bmesh_marking.h" +#include "bmesh_operator_api.h" +#include "bmesh_operators.h" +#include "bmesh_error.h" +#include "bmesh_queries.h" +#include "bmesh_walkers.h" + +#endif /* BMESH_H */ diff --git a/source/blender/bmesh/bmesh_error.h b/source/blender/bmesh/bmesh_error.h new file mode 100644 index 00000000000..77204f57e0d --- /dev/null +++ b/source/blender/bmesh/bmesh_error.h @@ -0,0 +1,53 @@ +#ifndef _BMESH_ERROR_H +#define _BMESH_ERROR_H + +/*----------- bmop error system ----------*/ + +/*pushes an error onto the bmesh error stack. + if msg is null, then the default message for the errorcode is used.*/ +void BMO_RaiseError(BMesh *bm, BMOperator *owner, int errcode, char *msg); + +/*gets the topmost error from the stack. + returns error code or 0 if no error.*/ +int BMO_GetError(BMesh *bm, char **msg, BMOperator **op); +int BMO_HasError(BMesh *bm); + +/*same as geterror, only pops the error off the stack as well*/ +int BMO_PopError(BMesh *bm, char **msg, BMOperator **op); +void BMO_ClearStack(BMesh *bm); + +#if 0 +//this is meant for handling errors, like self-intersection test failures. +//it's dangerous to handle errors in general though, so disabled for now. + +/*catches an error raised by the op pointed to by catchop. + errorcode is either the errorcode, or BMERR_ALL for any + error.*/ +int BMO_CatchOpError(BMesh *bm, BMOperator *catchop, int errorcode, char **msg); +#endif + +/*------ error code defines -------*/ + +/*error messages*/ +#define BMERR_SELF_INTERSECTING 1 +#define BMERR_DISSOLVEDISK_FAILED 2 +#define BMERR_CONNECTVERT_FAILED 3 +#define BMERR_WALKER_FAILED 4 +#define BMERR_DISSOLVEFACES_FAILED 5 +#define BMERR_DISSOLVEVERTS_FAILED 6 +#define BMERR_TESSELATION 7 +#define BMERR_NONMANIFOLD 8 + +static char *bmop_error_messages[] = { + 0, + "Self intersection error", + "Could not dissolve vert", + "Could not connect vertices", + "Could not traverse mesh", + "Could not dissolve faces", + "Could not dissolve vertices", + "Tesselation error", + "Can not deal with non-manifold geometry" +}; + +#endif /* _BMESH_ERROR_H */
\ No newline at end of file diff --git a/source/blender/bmesh/bmesh_filters.h b/source/blender/bmesh/bmesh_filters.h new file mode 100644 index 00000000000..9eed4e509fa --- /dev/null +++ b/source/blender/bmesh/bmesh_filters.h @@ -0,0 +1,4 @@ +#ifndef BM_FILTER_H +#define BM_FILTER_H + +#endif diff --git a/source/blender/bmesh/bmesh_iterators.h b/source/blender/bmesh/bmesh_iterators.h new file mode 100644 index 00000000000..7c3f91f2334 --- /dev/null +++ b/source/blender/bmesh/bmesh_iterators.h @@ -0,0 +1,70 @@ +/* + * BMESH ITERATORS + * + * The functions and structures in this file + * provide a unified method for iterating over + * the elements of a mesh and answering simple + * adjacency queries. Tool authors should use + * the iterators provided in this file instead + * of inspecting the structure directly. + * +*/ + +#ifndef BM_ITERATORS_H +#define BM_ITERATORS_H + +/*Defines for passing to BMIter_New. + + "OF" can be substituted for "around" + so BM_VERTS_OF_MESH_OF_FACE means "vertices + around a face." + */ + +/*these iterator over all elements of a specific + type in the mesh.*/ +#define BM_VERTS_OF_MESH 1 +#define BM_EDGES_OF_MESH 2 +#define BM_FACES_OF_MESH 3 + +#define BM_ITER(ele, iter, bm, type, data) \ + ele = BMIter_New(iter, bm, type, data); \ + for ( ; ele; ele=BMIter_Step(iter)) + +/*these are topological iterators.*/ +#define BM_EDGES_OF_VERT 4 +#define BM_FACES_OF_VERT 5 +#define BM_FACES_OF_EDGE 6 +#define BM_VERTS_OF_FACE 7 +#define BM_FACEVERTS_OF_FACE 8 +#define BM_EDGES_OF_FACE 9 +#define BM_LOOPS_OF_FACE 10 + +/*iterate through loops around this loop, which are fetched + from the other faces in the radial cycle surrounding the + input loop's edge.*/ +#define BM_LOOPS_OF_LOOP 11 + + +/*Iterator Structure*/ +typedef struct BMIter{ + struct BMVert *firstvert, *nextvert, *vdata; + struct BMEdge *firstedge, *nextedge, *edata; + struct BMLoop *firstloop, *nextloop, *ldata, *l; + struct BMFace *firstpoly, *nextpoly, *pdata; + struct BMesh *bm; + void (*begin)(struct BMIter *iter); + void *(*step)(struct BMIter *iter); + union{ + void *p; + int i; + long l; + float f; + }filter; + int type, count; +}BMIter; + +void *BMIter_New(struct BMIter *iter, struct BMesh *bm, int type, void *data); +void *BMIter_Step(struct BMIter *iter); +void *BMIter_AtIndex(struct BMesh *bm, int type, void *data, int index); + +#endif diff --git a/source/blender/bmesh/bmesh_marking.h b/source/blender/bmesh/bmesh_marking.h new file mode 100644 index 00000000000..1074b057eba --- /dev/null +++ b/source/blender/bmesh/bmesh_marking.h @@ -0,0 +1,16 @@ +#ifndef BM_MARKING_H +#define BM_MARKING_H + +/*Selection code*/ +void BM_Select_Vert(struct BMesh *bm, struct BMVert *v, int select); +void BM_Select_Edge(struct BMesh *bm, struct BMEdge *e, int select); +void BM_Select_Face(struct BMesh *bm, struct BMFace *f, int select); +void BM_Selectmode_Set(struct BMesh *bm, int selectmode); + +/*counts number of elements with flag set*/ +int BM_CountFlag(struct BMesh *bm, int type, int flag); + +void BM_Select(struct BMesh *bm, void *element, int select); +int BM_Is_Selected(BMesh *bm, void *element); + +#endif diff --git a/source/blender/bmesh/bmesh_operator_api.h b/source/blender/bmesh/bmesh_operator_api.h new file mode 100644 index 00000000000..0c0e0db0e6e --- /dev/null +++ b/source/blender/bmesh/bmesh_operator_api.h @@ -0,0 +1,338 @@ +#ifndef _BMESH_OPERATOR_H +#define _BMESH_OPERATOR_H + +#include "BLI_memarena.h" +#include "BLI_ghash.h" + +#include <stdarg.h> + +/* +operators represent logical, executable mesh modules. all topological +operations involving a bmesh has to go through them. + +operators are nested, as are tool flags, which are private to an operator +when it's executed. tool flags are allocated in layers, one per operator +execution, and are used for all internal flagging a tool needs to do. + +each operator has a series of "slots," which can be of the following types: +* simple numerical types +* arrays of elements (e.g. arrays of faces). +* hash mappings. + +each slot is identified by a slot code, as are each operator. +operators, and their slots, are defined in bmesh_opdefines.c (with their +execution functions prototyped in bmesh_operators_private.h), with all their +operator code and slot codes defined in bmesh_operators.h. see +bmesh_opdefines.c and the BMOpDefine struct for how to define new operators. + +in general, operators are fed arrays of elements, created using either +BM_HeaderFlag_To_Slot or BM_Flag_To_Slot (or through one of the format +specifyers in BMO_CallOpf or BMO_InitOpf). Note that multiple element +types (e.g. faces and edges) can be fed to the same slot array. Operators +act on this data, and possibly spit out data into output slots. + +some notes: +* operators should never read from header flags (e.g. element->head.flag). for + example, if you want an operator to only operate on selected faces, you + should use BM_HeaderFlag_To_Slot to put the selected elements into a slot. +* when you read from an element slot array or mapping, you can either tool-flag + all the elements in it, or read them using an iterator APi (which is + semantically similar to the iterator api in bmesh_iterators.h). +*/ + +struct GHashIterator; + +/*slot type arrays are terminated by the last member + having a slot type of 0.*/ +#define BMOP_OPSLOT_SENTINEL 0 +#define BMOP_OPSLOT_INT 1 +#define BMOP_OPSLOT_FLT 2 +#define BMOP_OPSLOT_PNT 3 +#define BMOP_OPSLOT_MAT 4 +#define BMOP_OPSLOT_VEC 7 + +/*after BMOP_OPSLOT_VEC, everything is + + dynamically allocated arrays. we + leave a space in the identifiers + for future growth. + + */ +//it's very important this remain a power of two +#define BMOP_OPSLOT_ELEMENT_BUF 8 +#define BMOP_OPSLOT_MAPPING 9 +#define BMOP_OPSLOT_TYPES 10 + +/*please ignore all these structures, don't touch them in tool code, except + for when your defining an operator with BMOpDefine.*/ + +typedef struct BMOpSlot{ + int slottype; + int len; + int flag; + int index; /*index within slot array*/ + union { + int i; + float f; + void *p; + float vec[3]; + void *buf; + GHash *ghash; + } data; +}BMOpSlot; + +#define BMOP_MAX_SLOTS 16 /*way more than probably needed*/ + +typedef struct BMOperator { + int type; + int slottype; + int needflag; + struct BMOpSlot slots[BMOP_MAX_SLOTS]; + void (*exec)(struct BMesh *bm, struct BMOperator *op); + MemArena *arena; +} BMOperator; + +#define MAX_SLOTNAME 32 + +typedef struct slottype { + int type; + char name[MAX_SLOTNAME]; +} slottype; + +typedef struct BMOpDefine { + char *name; + slottype slottypes[BMOP_MAX_SLOTS]; + void (*exec)(BMesh *bm, BMOperator *op); + int flag; /*doesn't do anything right now*/ +} BMOpDefine; + +/*------------- Operator API --------------*/ + +/*data types that use pointers (arrays, etc) should never + have it set directly. and never use BMO_Set_Pnt to + pass in a list of edges or any arrays, really.*/ + +void BMO_Init_Op(struct BMOperator *op, char *opname); + +/*executes an operator, pushing and popping a new tool flag + layer as appropriate.*/ +void BMO_Exec_Op(struct BMesh *bm, struct BMOperator *op); + +/*finishes an operator (though note the operator's tool flag is removed + after it finishes executing in BMO_Exec_Op).*/ +void BMO_Finish_Op(struct BMesh *bm, struct BMOperator *op); + + +/*tool flag API. never, ever ever should tool code put junk in + header flags (element->head.flag), nor should they use + element->head.eflag1/eflag2. instead, use this api to set + flags. + + if you need to store a value per element, use a + ghash or a mapping slot to do it.*/ +/*flags 15 and 16 (1<<14 and 1<<15) are reserved for bmesh api use*/ +void BMO_SetFlag(struct BMesh *bm, void *element, int flag); +void BMO_ClearFlag(struct BMesh *bm, void *element, int flag); +int BMO_TestFlag(struct BMesh *bm, void *element, int flag); + +/*count the number of elements with a specific flag. type + can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE.*/ +int BMO_CountFlag(struct BMesh *bm, int flag, int type); + +/*---------formatted operator initialization/execution-----------*/ +/* + this system is used to execute or initialize an operator, + using a formatted-string system. + + for example, BMO_CallOpf(bm, "del geom=%hf context=%d", BM_SELECT, DEL_FACES); + . . .will execute the delete operator, feeding in selected faces, deleting them. + + the basic format for the format string is: + [operatorname] [slotname]=%[code] [slotname]=%[code] + + as in printf, you pass in one additional argument to the function + for every code. + + the formatting codes are: + %d - put int in slot + %f - put float in slot + %p - put pointer in slot + %h[f/e/v] - put elements with a header flag in slot. + the letters after %h define which element types to use, + so e.g. %hf will do faces, %hfe will do faces and edges, + %hv will do verts, etc. must pass in at least one + element type letter. + %f[f/e/v] - same as %h, except it deals with tool flags instead of + header flags. + %a[f/e/v] - pass all elements (of types specified by f/e/v) to the + slot. + %v - pointer to a float vector of length 3. + %m[3/4] - matrix, 3/4 refers to the matrix size, 3 or 4. the + corrusponding argument must be a pointer to + a float matrix. + %s - copy a slot from another op, instead of mapping to one + argument, it maps to two, a pointer to an operator and + a slot name. +*/ +/*executes an operator*/ +int BMO_CallOpf(BMesh *bm, char *fmt, ...); + +/*initializes, but doesn't execute an operator. this is so you can + gain access to the outputs of the operator. note that you have + to execute/finitsh (BMO_Exec_Op and BMO_Finish_Op) yourself.*/ +int BMO_InitOpf(BMesh *bm, BMOperator *op, char *fmt, ...); + +/*va_list version, used to implement the above two functions, + plus EDBM_CallOpf in bmeshutils.c.*/ +int BMO_VInitOpf(BMesh *bm, BMOperator *op, char *fmt, va_list vlist); + +/*get a point to a slot. this may be removed layer on from the public API.*/ +BMOpSlot *BMO_GetSlot(struct BMOperator *op, char *slotname); + +/*copies the data of a slot from one operator to another. src and dst are the + source/destination slot codes, respectively.*/ +void BMO_CopySlot(struct BMOperator *source_op, struct BMOperator *dest_op, + char *src, char *dst); + + +void BMO_Set_Float(struct BMOperator *op, char *slotname, float f); +float BMO_Get_Float(BMOperator *op, char *slotname); +void BMO_Set_Int(struct BMOperator *op, char *slotname, int i); +int BMO_Get_Int(BMOperator *op, char *slotname); + +/*don't pass in arrays that are supposed to map to elements this way. + + so, e.g. passing in list of floats per element in another slot is bad. + passing in, e.g. pointer to an editmesh for the conversion operator is fine + though.*/ +void BMO_Set_Pnt(struct BMOperator *op, char *slotname, void *p); +void *BMO_Get_Pnt(BMOperator *op, char *slotname); +void BMO_Set_Vec(struct BMOperator *op, char *slotname, float *vec); +void BMO_Get_Vec(BMOperator *op, char *slotname, float *vec_out); + +/*only supports square mats*/ +/*size must be 3 or 4; this api is meant only for transformation matrices. + note that internally the matrix is stored in 4x4 form, and it's safe to + call whichever BMO_Get_Mat* function you want.*/ +void BMO_Set_Mat(struct BMOperator *op, char *slotname, float *mat, int size); +void BMO_Get_Mat4(struct BMOperator *op, char *slotname, float mat[4][4]); +void BMO_Get_Mat3(struct BMOperator *op, char *slotname, float mat[3][3]); + +/*puts every element of type type (which is a bitmask) with tool flag flag, + into a slot.*/ +void BMO_Flag_To_Slot(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag, int type); + +/*tool-flags all elements inside an element slot array with flag flag.*/ +void BMO_Flag_Buffer(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag); +/*clears tool-flag flag from all elements inside a slot array.*/ +void BMO_Unflag_Buffer(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag); + +/*tool-flags all elements inside an element slot array with flag flag.*/ +void BMO_HeaderFlag_Buffer(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag); +/*clears tool-flag flag from all elements inside a slot array.*/ +void BMO_UnHeaderFlag_Buffer(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag); + +/*puts every element of type type (which is a bitmask) with header flag + flag, into a slot.*/ +void BMO_HeaderFlag_To_Slot(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag, int type); + +/*counts number of elements inside a slot array.*/ +int BMO_CountSlotBuf(struct BMesh *bm, struct BMOperator *op, char *slotname); + + +/*inserts a key/value mapping into a mapping slot. note that it copies the + value, it doesn't store a reference to it.*/ +void BMO_Insert_Mapping(BMesh *bm, BMOperator *op, char *slotname, + void *element, void *data, int len); + +/*inserts a key/float mapping pair into a mapping slot.*/ +void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, char *slotname, + void *element, float val); + +//returns 1 if the specified pointer is in the map. +int BMO_InMap(BMesh *bm, BMOperator *op, char *slotname, void *element); + +/*returns a point to the value of a specific key.*/ +void *BMO_Get_MapData(BMesh *bm, BMOperator *op, char *slotname, void *element); + +/*returns the float part of a key/float pair.*/ +float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, char *slotname, void *element); + +/*flags all elements in a mapping. note that the mapping must only have + bmesh elements in it.*/ +void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op, + char *slotname, int flag); + +/*pointer versoins of BMO_Get_MapFloat and BMO_Insert_MapFloat. + + do NOT use these for non-operator-api-allocated memory! instead + use BMO_Get_MapData and BMO_Insert_Mapping, which copies the data.*/ +void BMO_Insert_MapPointer(BMesh *bm, BMOperator *op, char *slotname, + void *key, void *val); +void *BMO_Get_MapPointer(BMesh *bm, BMOperator *op, char *slotname, + void *key); + +/*this part of the API is used to iterate over element buffer or + mapping slots. + + for example, iterating over the faces in a slot is: + + BMOIter oiter; + BMFace *f; + + f = BMO_IterNew(&oiter, bm, some_operator, "slotname", BM_FACE); + for (; f; f=BMO_IterStep(&oiter)) { + /do something with the face + } + + another example, iterating over a mapping: + BMOIter oiter; + void *key; + void *val; + + key = BMO_IterNew(&oiter, bm, some_operator, "slotname", 0); + for (; key; key=BMO_IterStep(&oiter)) { + val = BMO_IterMapVal(&oiter); + //do something with the key/val pair + //note that val is a pointer to the val data, + //whether it's a float, pointer, whatever. + // + // so to get a pointer, for example, use: + // *((void**)BMO_IterMapVal(&oiter)); + //or something like that. + } + + */ + +/*contents of this structure are private, + don't directly access.*/ +typedef struct BMOIter { + BMOpSlot *slot; + int cur; //for arrays + struct GHashIterator giter; + void *val; + int restrict; +} BMOIter; + +/*restrictmask restricts the iteration to certain element types + (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating + over an element buffer (not a mapping).*/ +void *BMO_IterNew(BMOIter *iter, BMesh *bm, BMOperator *op, + char *slotname, int restrictmask); +void *BMO_IterStep(BMOIter *iter); + +/*returns a pointer to the key value when iterating over mappings. + remember for pointer maps this will be a pointer to a pointer.*/ +void *BMO_IterMapVal(BMOIter *iter); + +/*use this for pointer mappings*/ +void *BMO_IterMapValp(BMOIter *iter); + +/*use this for float mappings*/ +float BMO_IterMapValf(BMOIter *iter); + +#define BMO_ITER(ele, iter, bm, op, slotname, restrict) \ + ele = BMO_IterNew(iter, bm, op, slotname, restrict); \ + for ( ; ele; ele=BMO_IterStep(iter)) + +#endif /* _BMESH_OPERATOR_H */
\ No newline at end of file diff --git a/source/blender/bmesh/bmesh_operators.h b/source/blender/bmesh/bmesh_operators.h new file mode 100644 index 00000000000..3ef229f00c6 --- /dev/null +++ b/source/blender/bmesh/bmesh_operators.h @@ -0,0 +1,40 @@ +#ifndef BM_OPERATORS_H +#define BM_OPERATORS_H + +/*--------defines/enumerations for specific operators-------*/ + +/*del operator "context" slot values*/ +enum { + DEL_VERTS = 1, + DEL_EDGES, + DEL_ONLYFACES, + DEL_EDGESFACES, + DEL_FACES, + DEL_ALL , + DEL_ONLYTAGGED, +}; + +extern BMOpDefine *opdefines[]; +extern int bmesh_total_ops; + +/*------specific operator helper functions-------*/ + +/*executes the duplicate operation, feeding elements of + type flag etypeflag and header flag flag to it. note, + to get more useful information (such as the mapping from + original to new elements) you should run the dupe op manually.*/ +struct Object; +struct EditMesh; + +void BMOP_DupeFromFlag(struct BMesh *bm, int etypeflag, int flag); +void BM_esubdivideflag(struct Object *obedit, BMesh *bm, int flag, float smooth, + float fractal, int beauty, int numcuts, int seltype); +void BM_extrudefaceflag(BMesh *bm, int flag); + +/*this next one return 1 if they did anything, or zero otherwise. + they're kindof a hackish way to integrate with fkey, until + such time as fkey is completely bmeshafied.*/ +/*this doesn't display errors to the user, btw*/ +int BM_ConnectVerts(struct EditMesh *em, int flag); + +#endif diff --git a/source/blender/bmesh/bmesh_queries.h b/source/blender/bmesh/bmesh_queries.h new file mode 100644 index 00000000000..ee2b8605a17 --- /dev/null +++ b/source/blender/bmesh/bmesh_queries.h @@ -0,0 +1,86 @@ +#ifndef BMESH_QUERIES_H +#define BMESH_QUERIES_H +#include <stdio.h> + +/*Queries*/ +/*counts number of elements of type type are in the mesh.*/ +int BM_Count_Element(struct BMesh *bm, int type); + +/*returns true if v is in f*/ +int BM_Vert_In_Face(struct BMFace *f, struct BMVert *v); + +// int BM_VERTS_OF_MESH_In_Face(struct BMFace *f, struct BMVert **varr, int len); +int BM_Verts_In_Face(struct BMesh *bm, struct BMFace *f, struct BMVert **varr, int len); + +int BM_Edge_In_Face(struct BMFace *f, struct BMEdge *e); + +int BM_Vert_In_Edge(struct BMVert *v1, struct BMVert *v2, BMEdge *e); + + +/*get opposing vert from v in edge e.*/ +struct BMVert *BM_OtherEdgeVert(struct BMEdge *e, struct BMVert *v); + +/*finds other loop that shares v with e's loop in f.*/ +struct BMLoop *BM_OtherFaceLoop(BMEdge *e, BMFace *f, BMVert *v); + +//#define BM_OtherEdgeVert(e, v) (v==e->v1?e->v2:e->v1) + +/*returns the edge existing between v1 and v2, or NULL if there isn't one.*/ +struct BMEdge *BM_Edge_Exist(struct BMVert *v1, struct BMVert *v2); + + +/*returns number of edges aroudn a vert*/ +int BM_Vert_EdgeCount(struct BMVert *v); + +/*returns number of faces around an edge*/ +int BM_Edge_FaceCount(struct BMEdge *e); + +/*returns number of faces around a vert.*/ +int BM_Vert_FaceCount(struct BMVert *v); + + +/*returns true if v is a wire vert*/ +int BM_Wire_Vert(struct BMesh *bm, struct BMVert *v); + +/*returns true if e is a wire edge*/ +int BM_Wire_Edge(struct BMesh *bm, struct BMEdge *e); + +/*returns true if v is part of a non-manifold edge in the mesh, + I believe this includes if it's part of both a wire edge and + a face.*/ +int BM_Nonmanifold_Vert(struct BMesh *bm, struct BMVert *v); + +/*returns true if e is shared by more then two faces.*/ +int BM_Nonmanifold_Edge(struct BMesh *bm, struct BMEdge *e); + +/*returns true if e is a boundary edge, e.g. has only 1 face bordering it.*/ +int BM_Boundary_Edge(struct BMEdge *e); + + +/*returns angle of two faces surrounding an edge. note there must be + exactly two faces sharing the edge.*/ +float BM_Face_Angle(struct BMesh *bm, struct BMEdge *e); + +/*checks overlapping of existing faces with the verts in varr.*/ +int BM_Exist_Face_Overlaps(struct BMesh *bm, struct BMVert **varr, int len, struct BMFace **existface); + +/*checks if a face defined by varr already exists.*/ +int BM_Face_Exists(BMesh *bm, BMVert **varr, int len, BMFace **existface); + + +/*returns number of edges f1 and f2 share.*/ +int BM_Face_Sharededges(struct BMFace *f1, struct BMFace *f2); + +/*returns number of faces e1 and e2 share.*/ +int BM_Edge_Share_Faces(struct BMEdge *e1, struct BMEdge *e2); + +/*checks if a face is valid in the data structure*/ +int BM_Validate_Face(BMesh *bm, BMFace *face, FILE *err); + +/*each pair of loops defines a new edge, a split. this function goes + through and sets pairs that are geometrically invalid to null. a + split is invalid, if it forms a concave angle or it intersects other + edges in the face.*/ +void BM_LegalSplits(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len); + +#endif diff --git a/source/blender/bmesh/bmesh_walkers.h b/source/blender/bmesh/bmesh_walkers.h new file mode 100644 index 00000000000..2fdb9e18a3a --- /dev/null +++ b/source/blender/bmesh/bmesh_walkers.h @@ -0,0 +1,64 @@ +#ifndef BM_WALKERS_H +#define BM_WALKERS_H + +#include "BLI_ghash.h" + +/* + NOTE: do NOT modify topology while walking a mesh! +*/ + +/*Walkers*/ +typedef struct BMWalker { + BLI_mempool *stack; + BMesh *bm; + void *currentstate; + void (*begin) (struct BMWalker *walker, void *start); + void *(*yield)(struct BMWalker *walker); + void *(*step) (struct BMWalker *walker); + int restrictflag; + GHash *visithash; +} BMWalker; + +/*initialize a walker. searchmask restricts some (not all) walkers to + elements with a specific tool flag set.*/ +void BMW_Init(struct BMWalker *walker, BMesh *bm, int type, int searchmask); +void *BMW_Begin(BMWalker *walker, void *start); +void *BMW_Step(struct BMWalker *walker); +void BMW_End(struct BMWalker *walker); + +/* +example of usage, walking over an island of tool flagged faces: + +BMWalker walker; +BMFace *f; + +BMW_Init(&walker, bm, BMW_ISLAND, SOME_OP_FLAG); +f = BMW_Begin(&walker, some_start_face); +for (; f; f=BMW_Step(&walker)) { + //do something with f +} +BMW_End(&walker); +*/ + +enum { + /*walk over connected geometry. can restrict to a search flag, + or not, it's optional.*/ + BMW_SHELL, + /*walk over an edge loop. search flag doesn't do anything.*/ + BMW_LOOP, + BMW_FACELOOP, + BMW_EDGERING, + /*#define BMW_RING 2 + #define BMW_UVISLANDS 3*/ + /*walk over an island of flagged faces. note, that this doesn't work on + non-manifold geometry. it might be better to rewrite this to extract + boundary info from the island walker, rather then directly walking + over the boundary. raises an error if it encouters nonmanifold + geometry.*/ + BMW_ISLANDBOUND, + /*walk over all faces in an island of tool flagged faces.*/ + BMW_ISLAND, + BMW_MAXWALKERS, +}; + +#endif
\ No newline at end of file diff --git a/source/blender/bmesh/editmesh_tools.c b/source/blender/bmesh/editmesh_tools.c new file mode 100644 index 00000000000..e2b83c6e111 --- /dev/null +++ b/source/blender/bmesh/editmesh_tools.c @@ -0,0 +1,7244 @@ +/** + * $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) 2004 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Johnny Matthews, Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* + +editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c + +*/ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "MEM_guardedalloc.h" + +#include "BMF_Api.h" +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_key_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" +#include "BLI_rand.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_heap.h" + +#include "BKE_depsgraph.h" +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_utildefines.h" +#include "BKE_bmesh.h" + +#ifdef WITH_VERSE +#include "BKE_verse.h" +#endif + +#include "BIF_cursors.h" +#include "BIF_editmesh.h" +#include "BIF_gl.h" +#include "BIF_glutil.h" +#include "BIF_graphics.h" +#include "BIF_interface.h" +#include "BIF_mywindow.h" +#include "BIF_screen.h" +#include "BIF_space.h" +#include "BIF_resources.h" +#include "BIF_toolbox.h" +#include "BIF_transform.h" +#include "transform.h" + +#ifdef WITH_VERSE +#include "BIF_verse.h" +#endif + +#include "BDR_drawobject.h" +#include "BDR_editobject.h" + +#include "BSE_view.h" +#include "BSE_edit.h" + +#include "blendef.h" +#include "multires.h" +#include "mydevice.h" + +#include "editmesh.h" + +#include "MTC_vectorops.h" + +#include "PIL_time.h" + +#include "BLO_sys_types.h" // for intptr_t support + +/* local prototypes ---------------*/ +void bevel_menu(void); +static void free_tagged_edges_faces(EditEdge *eed, EditFace *efa); + +/********* qsort routines *********/ + + +typedef struct xvertsort { + float x; + EditVert *v1; +} xvertsort; + +static int vergxco(const void *v1, const void *v2) +{ + const xvertsort *x1=v1, *x2=v2; + + if( x1->x > x2->x ) return 1; + else if( x1->x < x2->x) return -1; + return 0; +} + +struct facesort { + uintptr_t x; + struct EditFace *efa; +}; + + +static int vergface(const void *v1, const void *v2) +{ + const struct facesort *x1=v1, *x2=v2; + + if( x1->x > x2->x ) return 1; + else if( x1->x < x2->x) return -1; + return 0; +} + + +/* *********************************** */ + +void convert_to_triface(int direction) +{ + EditMesh *em = G.editMesh; + EditFace *efa, *efan, *next; + float fac; + + if(multires_test()) return; + + efa= em->faces.last; + while(efa) { + next= efa->prev; + if(efa->v4) { + if(efa->f & SELECT) { + /* choose shortest diagonal for split */ + fac= VecLenf(efa->v1->co, efa->v3->co) - VecLenf(efa->v2->co, efa->v4->co); + /* this makes sure exact squares get split different in both cases */ + if( (direction==0 && fac<FLT_EPSILON) || (direction && fac>0.0f) ) { + efan= EM_face_from_faces(efa, NULL, 0, 1, 2, -1); + if(efa->f & SELECT) EM_select_face(efan, 1); + efan= EM_face_from_faces(efa, NULL, 0, 2, 3, -1); + if(efa->f & SELECT) EM_select_face(efan, 1); + } + else { + efan= EM_face_from_faces(efa, NULL, 0, 1, 3, -1); + if(efa->f & SELECT) EM_select_face(efan, 1); + efan= EM_face_from_faces(efa, NULL, 1, 2, 3, -1); + if(efa->f & SELECT) EM_select_face(efan, 1); + } + + BLI_remlink(&em->faces, efa); + free_editface(efa); + } + } + efa= next; + } + + EM_fgon_flags(); // redo flags and indices for fgons + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + BIF_undo_push("Convert Quads to Triangles"); + +} + +int removedoublesflag(short flag, short automerge, float limit) /* return amount */ +{ + /* + flag - Test with vert->flags + automerge - Alternative operation, merge unselected into selected. + Used for "Auto Weld" mode. warning. + limit - Quick manhattan distance between verts. + */ + + EditMesh *em = G.editMesh; + /* all verts with (flag & 'flag') are being evaluated */ + EditVert *eve, *v1, *nextve; + EditEdge *eed, *e1, *nexted; + EditFace *efa, *nextvl; + xvertsort *sortblock, *sb, *sb1; + struct facesort *vlsortblock, *vsb, *vsb1; + int a, b, test, amount; + + if(multires_test()) return 0; + + + /* flag 128 is cleared, count */ + + /* Normal non weld operation */ + eve= em->verts.first; + amount= 0; + while(eve) { + eve->f &= ~128; + if(eve->h==0 && (automerge || (eve->f & flag))) amount++; + eve= eve->next; + } + if(amount==0) return 0; + + /* allocate memory and qsort */ + sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub"); + eve= em->verts.first; + while(eve) { + if(eve->h==0 && (automerge || (eve->f & flag))) { + sb->x= eve->co[0]+eve->co[1]+eve->co[2]; + sb->v1= eve; + sb++; + } + eve= eve->next; + } + qsort(sortblock, amount, sizeof(xvertsort), vergxco); + + + /* test for doubles */ + sb= sortblock; + if (automerge) { + for(a=0; a<amount; a++, sb++) { + eve= sb->v1; + if( (eve->f & 128)==0 ) { + sb1= sb+1; + for(b=a+1; b<amount && (eve->f & 128)==0; b++, sb1++) { + if(sb1->x - sb->x > limit) break; + + /* when automarge, only allow unselected->selected */ + v1= sb1->v1; + if( (v1->f & 128)==0 ) { + if ((eve->f & flag)==0 && (v1->f & flag)==1) { + if( (float)fabs(v1->co[0]-eve->co[0])<=limit && + (float)fabs(v1->co[1]-eve->co[1])<=limit && + (float)fabs(v1->co[2]-eve->co[2])<=limit) + { /* unique bit */ + eve->f|= 128; + eve->tmp.v = v1; + } + } else if( (eve->f & flag)==1 && (v1->f & flag)==0 ) { + if( (float)fabs(v1->co[0]-eve->co[0])<=limit && + (float)fabs(v1->co[1]-eve->co[1])<=limit && + (float)fabs(v1->co[2]-eve->co[2])<=limit) + { /* unique bit */ + v1->f|= 128; + v1->tmp.v = eve; + } + } + } + } + } + } + } else { + for(a=0; a<amount; a++, sb++) { + eve= sb->v1; + if( (eve->f & 128)==0 ) { + sb1= sb+1; + for(b=a+1; b<amount; b++, sb1++) { + /* first test: simpel dist */ + if(sb1->x - sb->x > limit) break; + v1= sb1->v1; + + /* second test: is vertex allowed */ + if( (v1->f & 128)==0 ) { + if( (float)fabs(v1->co[0]-eve->co[0])<=limit && + (float)fabs(v1->co[1]-eve->co[1])<=limit && + (float)fabs(v1->co[2]-eve->co[2])<=limit) + { + v1->f|= 128; + v1->tmp.v = eve; + } + } + } + } + } + } + MEM_freeN(sortblock); + + if (!automerge) + for(eve = em->verts.first; eve; eve=eve->next) + if((eve->f & flag) && (eve->f & 128)) + EM_data_interp_from_verts(eve, eve->tmp.v, eve->tmp.v, 0.5f); + + /* test edges and insert again */ + eed= em->edges.first; + while(eed) { + eed->f2= 0; + eed= eed->next; + } + eed= em->edges.last; + while(eed) { + nexted= eed->prev; + + if(eed->f2==0) { + if( (eed->v1->f & 128) || (eed->v2->f & 128) ) { + remedge(eed); + + if(eed->v1->f & 128) eed->v1 = eed->v1->tmp.v; + if(eed->v2->f & 128) eed->v2 = eed->v2->tmp.v; + e1= addedgelist(eed->v1, eed->v2, eed); + + if(e1) { + e1->f2= 1; + if(eed->f & SELECT) + e1->f |= SELECT; + } + if(e1!=eed) free_editedge(eed); + } + } + eed= nexted; + } + + /* first count amount of test faces */ + efa= (struct EditFace *)em->faces.first; + amount= 0; + while(efa) { + efa->f1= 0; + if(efa->v1->f & 128) efa->f1= 1; + else if(efa->v2->f & 128) efa->f1= 1; + else if(efa->v3->f & 128) efa->f1= 1; + else if(efa->v4 && (efa->v4->f & 128)) efa->f1= 1; + + if(efa->f1==1) amount++; + efa= efa->next; + } + + /* test faces for double vertices, and if needed remove them */ + efa= (struct EditFace *)em->faces.first; + while(efa) { + nextvl= efa->next; + if(efa->f1==1) { + + if(efa->v1->f & 128) efa->v1= efa->v1->tmp.v; + if(efa->v2->f & 128) efa->v2= efa->v2->tmp.v; + if(efa->v3->f & 128) efa->v3= efa->v3->tmp.v; + if(efa->v4 && (efa->v4->f & 128)) efa->v4= efa->v4->tmp.v; + + test= 0; + if(efa->v1==efa->v2) test+=1; + if(efa->v2==efa->v3) test+=2; + if(efa->v3==efa->v1) test+=4; + if(efa->v4==efa->v1) test+=8; + if(efa->v3==efa->v4) test+=16; + if(efa->v2==efa->v4) test+=32; + + if(test) { + if(efa->v4) { + if(test==1 || test==2) { + efa->v2= efa->v3; + efa->v3= efa->v4; + efa->v4= 0; + + EM_data_interp_from_faces(efa, NULL, efa, 0, 2, 3, 3); + + test= 0; + } + else if(test==8 || test==16) { + efa->v4= 0; + test= 0; + } + else { + BLI_remlink(&em->faces, efa); + free_editface(efa); + amount--; + } + } + else { + BLI_remlink(&em->faces, efa); + free_editface(efa); + amount--; + } + } + + if(test==0) { + /* set edge pointers */ + efa->e1= findedgelist(efa->v1, efa->v2); + efa->e2= findedgelist(efa->v2, efa->v3); + if(efa->v4==0) { + efa->e3= findedgelist(efa->v3, efa->v1); + efa->e4= 0; + } + else { + efa->e3= findedgelist(efa->v3, efa->v4); + efa->e4= findedgelist(efa->v4, efa->v1); + } + } + } + efa= nextvl; + } + + /* double faces: sort block */ + /* count again, now all selected faces */ + amount= 0; + efa= em->faces.first; + while(efa) { + efa->f1= 0; + if(faceselectedOR(efa, 1)) { + efa->f1= 1; + amount++; + } + efa= efa->next; + } + + if(amount) { + /* double faces: sort block */ + vsb= vlsortblock= MEM_mallocN(sizeof(struct facesort)*amount, "sortremovedoub"); + efa= em->faces.first; + while(efa) { + if(efa->f1 & 1) { + if(efa->v4) vsb->x= (uintptr_t) MIN4( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3, (uintptr_t)efa->v4); + else vsb->x= (uintptr_t) MIN3( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3); + + vsb->efa= efa; + vsb++; + } + efa= efa->next; + } + + qsort(vlsortblock, amount, sizeof(struct facesort), vergface); + + vsb= vlsortblock; + for(a=0; a<amount; a++) { + efa= vsb->efa; + if( (efa->f1 & 128)==0 ) { + vsb1= vsb+1; + + for(b=a+1; b<amount; b++) { + + /* first test: same pointer? */ + if(vsb->x != vsb1->x) break; + + /* second test: is test permitted? */ + efa= vsb1->efa; + if( (efa->f1 & 128)==0 ) { + if( compareface(efa, vsb->efa)) efa->f1 |= 128; + + } + vsb1++; + } + } + vsb++; + } + + MEM_freeN(vlsortblock); + + /* remove double faces */ + efa= (struct EditFace *)em->faces.first; + while(efa) { + nextvl= efa->next; + if(efa->f1 & 128) { + BLI_remlink(&em->faces, efa); + free_editface(efa); + } + efa= nextvl; + } + } + + /* remove double vertices */ + a= 0; + eve= (struct EditVert *)em->verts.first; + while(eve) { + nextve= eve->next; + if(automerge || eve->f & flag) { + if(eve->f & 128) { + a++; + BLI_remlink(&em->verts, eve); + free_editvert(eve); + } + } + eve= nextve; + } + +#ifdef WITH_VERSE + if((a>0) && (G.editMesh->vnode)) { + sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode); + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); + } +#endif + + return a; /* amount */ +} + +/* called from buttons */ +static void xsortvert_flag__doSetX(void *userData, EditVert *eve, int x, int y, int index) +{ + xvertsort *sortblock = userData; + + sortblock[index].x = x; +} +void xsortvert_flag(int flag) +{ + EditMesh *em = G.editMesh; + /* all verts with (flag & 'flag') are sorted */ + EditVert *eve; + xvertsort *sortblock; + ListBase tbase; + int i, amount = BLI_countlist(&em->verts); + + if(multires_test()) return; + + sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort"); + for (i=0,eve=em->verts.first; eve; i++,eve=eve->next) + if(eve->f & flag) + sortblock[i].v1 = eve; + mesh_foreachScreenVert(xsortvert_flag__doSetX, sortblock, 0); + qsort(sortblock, amount, sizeof(xvertsort), vergxco); + + /* make temporal listbase */ + tbase.first= tbase.last= 0; + for (i=0; i<amount; i++) { + eve = sortblock[i].v1; + + if (eve) { + BLI_remlink(&em->verts, eve); + BLI_addtail(&tbase, eve); + } + } + + addlisttolist(&em->verts, &tbase); + + MEM_freeN(sortblock); + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + + BIF_undo_push("Xsort"); + +} + +/* called from buttons */ +void hashvert_flag(int flag) +{ + /* switch vertex order using hash table */ + EditMesh *em = G.editMesh; + EditVert *eve; + struct xvertsort *sortblock, *sb, onth, *newsort; + ListBase tbase; + int amount, a, b; + + if(multires_test()) return; + + /* count */ + eve= em->verts.first; + amount= 0; + while(eve) { + if(eve->f & flag) amount++; + eve= eve->next; + } + if(amount==0) return; + + /* allocate memory */ + sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub"); + eve= em->verts.first; + while(eve) { + if(eve->f & flag) { + sb->v1= eve; + sb++; + } + eve= eve->next; + } + + BLI_srand(1); + + sb= sortblock; + for(a=0; a<amount; a++, sb++) { + b= (int)(amount*BLI_drand()); + if(b>=0 && b<amount) { + newsort= sortblock+b; + onth= *sb; + *sb= *newsort; + *newsort= onth; + } + } + + /* make temporal listbase */ + tbase.first= tbase.last= 0; + sb= sortblock; + while(amount--) { + eve= sb->v1; + BLI_remlink(&em->verts, eve); + BLI_addtail(&tbase, eve); + sb++; + } + + addlisttolist(&em->verts, &tbase); + + MEM_freeN(sortblock); +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + BIF_undo_push("Hash"); + +} + +/* generic extern called extruder */ +void extrude_mesh(void) +{ + float nor[3]= {0.0, 0.0, 0.0}; + short nr, transmode= 0; + + TEST_EDITMESH + if(multires_test()) return; + + if(G.scene->selectmode & SCE_SELECT_VERTEX) { + if(G.totvertsel==0) nr= 0; + else if(G.totvertsel==1) nr= 4; + else if(G.totedgesel==0) nr= 4; + else if(G.totfacesel==0) + nr= pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4"); + else if(G.totfacesel==1) + nr= pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4"); + else + nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4"); + } + else if(G.scene->selectmode & SCE_SELECT_EDGE) { + if (G.totedgesel==0) nr = 0; + else if (G.totedgesel==1) nr = 3; + else if(G.totfacesel==0) nr = 3; + else if(G.totfacesel==1) + nr= pupmenu("Extrude %t|Region %x1|Only Edges%x3"); + else + nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3"); + } + else { + if (G.totfacesel == 0) nr = 0; + else if (G.totfacesel == 1) nr = 1; + else + nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2"); + } + + if(nr<1) return; + + if(nr==1) transmode= extrudeflag(SELECT, nor); + else if(nr==4) transmode= extrudeflag_verts_indiv(SELECT, nor); + else if(nr==3) transmode= extrudeflag_edges_indiv(SELECT, nor); + else transmode= extrudeflag_face_indiv(SELECT, nor); + + if(transmode==0) { + error("No valid selection"); + } + else { + EM_fgon_flags(); + countall(); + + /* We need to force immediate calculation here because + * transform may use derived objects (which are now stale). + * + * This shouldn't be necessary, derived queries should be + * automatically building this data if invalid. Or something. + */ + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + object_handle_update(G.obedit); + + /* individual faces? */ + BIF_TransformSetUndo("Extrude"); + if(nr==2) { + initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR); + Transform(); + } + else { + initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR); + if(transmode=='n') { + Mat4MulVecfl(G.obedit->obmat, nor); + VecSubf(nor, nor, G.obedit->obmat[3]); + BIF_setSingleAxisConstraint(nor, "along normal"); + } + Transform(); + } + } + +} + +void split_mesh(void) +{ + + TEST_EDITMESH + if(multires_test()) return; + + if(okee(" Split ")==0) return; + + waitcursor(1); + + /* make duplicate first */ + adduplicateflag(SELECT); + /* old faces have flag 128 set, delete them */ + delfaceflag(128); + recalc_editnormals(); + + waitcursor(0); + + countall(); + allqueue(REDRAWVIEW3D, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + + BIF_undo_push("Split"); + +} + +void extrude_repeat_mesh(int steps, float offs) +{ + float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0}; + short a; + + TEST_EDITMESH + if(multires_test()) return; + + /* dvec */ + dvec[0]= G.vd->persinv[2][0]; + dvec[1]= G.vd->persinv[2][1]; + dvec[2]= G.vd->persinv[2][2]; + Normalize(dvec); + dvec[0]*= offs; + dvec[1]*= offs; + dvec[2]*= offs; + + /* base correction */ + Mat3CpyMat4(bmat, G.obedit->obmat); + Mat3Inv(tmat, bmat); + Mat3MulVecfl(tmat, dvec); + + for(a=0; a<steps; a++) { + extrudeflag(SELECT, nor); + translateflag(SELECT, dvec); + } + + recalc_editnormals(); + + EM_fgon_flags(); + countall(); + + allqueue(REDRAWVIEW3D, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + + BIF_undo_push("Extrude Repeat"); +} + +void spin_mesh(int steps, float degr, float *dvec, int mode) +{ + EditMesh *em = G.editMesh; + EditVert *eve,*nextve; + float nor[3]= {0.0, 0.0, 0.0}; + float *curs, si,n[3],q[4],cmat[3][3],imat[3][3], tmat[3][3]; + float cent[3],bmat[3][3]; + float phi; + short a,ok; + + TEST_EDITMESH + if(multires_test()) return; + + /* imat and center and size */ + Mat3CpyMat4(bmat, G.obedit->obmat); + Mat3Inv(imat,bmat); + + curs= give_cursor(); + VECCOPY(cent, curs); + cent[0]-= G.obedit->obmat[3][0]; + cent[1]-= G.obedit->obmat[3][1]; + cent[2]-= G.obedit->obmat[3][2]; + Mat3MulVecfl(imat, cent); + + phi= degr*M_PI/360.0; + phi/= steps; + if(G.scene->toolsettings->editbutflag & B_CLOCKWISE) phi= -phi; + + if(dvec) { + n[0]= G.vd->viewinv[1][0]; + n[1]= G.vd->viewinv[1][1]; + n[2]= G.vd->viewinv[1][2]; + } else { + n[0]= G.vd->viewinv[2][0]; + n[1]= G.vd->viewinv[2][1]; + n[2]= G.vd->viewinv[2][2]; + } + Normalize(n); + + q[0]= (float)cos(phi); + si= (float)sin(phi); + q[1]= n[0]*si; + q[2]= n[1]*si; + q[3]= n[2]*si; + QuatToMat3(q, cmat); + + Mat3MulMat3(tmat,cmat,bmat); + Mat3MulMat3(bmat,imat,tmat); + + if(mode==0) if(G.scene->toolsettings->editbutflag & B_KEEPORIG) adduplicateflag(1); + ok= 1; + + for(a=0;a<steps;a++) { + if(mode==0) ok= extrudeflag(SELECT, nor); + else adduplicateflag(SELECT); + if(ok==0) { + error("No valid vertices are selected"); + break; + } + rotateflag(SELECT, cent, bmat); + if(dvec) { + Mat3MulVecfl(bmat,dvec); + translateflag(SELECT, dvec); + } + } + + if(ok==0) { + /* no vertices or only loose ones selected, remove duplicates */ + eve= em->verts.first; + while(eve) { + nextve= eve->next; + if(eve->f & SELECT) { + BLI_remlink(&em->verts,eve); + free_editvert(eve); + } + eve= nextve; + } + } + recalc_editnormals(); + + EM_fgon_flags(); + countall(); + allqueue(REDRAWVIEW3D, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + + + if(dvec==NULL) BIF_undo_push("Spin"); +} + +void screw_mesh(int steps, int turns) +{ + EditMesh *em = G.editMesh; + EditVert *eve,*v1=0,*v2=0; + EditEdge *eed; + float dvec[3], nor[3]; + + TEST_EDITMESH + if(multires_test()) return; + + /* clear flags */ + eve= em->verts.first; + while(eve) { + eve->f1= 0; + eve= eve->next; + } + /* edges set flags in verts */ + eed= em->edges.first; + while(eed) { + if(eed->v1->f & SELECT) { + if(eed->v2->f & SELECT) { + /* watch: f1 is a byte */ + if(eed->v1->f1<2) eed->v1->f1++; + if(eed->v2->f1<2) eed->v2->f1++; + } + } + eed= eed->next; + } + /* find two vertices with eve->f1==1, more or less is wrong */ + eve= em->verts.first; + while(eve) { + if(eve->f1==1) { + if(v1==0) v1= eve; + else if(v2==0) v2= eve; + else { + v1=0; + break; + } + } + eve= eve->next; + } + if(v1==0 || v2==0) { + error("You have to select a string of connected vertices too"); + return; + } + + /* calculate dvec */ + dvec[0]= ( (v1->co[0]- v2->co[0]) )/(steps); + dvec[1]= ( (v1->co[1]- v2->co[1]) )/(steps); + dvec[2]= ( (v1->co[2]- v2->co[2]) )/(steps); + + VECCOPY(nor, G.obedit->obmat[2]); + + if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.000) { + dvec[0]= -dvec[0]; + dvec[1]= -dvec[1]; + dvec[2]= -dvec[2]; + } + + spin_mesh(turns*steps, turns*360, dvec, 0); + + BIF_undo_push("Spin"); +} + + +static void erase_edges(ListBase *l) +{ + EditEdge *ed, *nexted; + + ed = (EditEdge *) l->first; + while(ed) { + nexted= ed->next; + if( (ed->v1->f & SELECT) || (ed->v2->f & SELECT) ) { + remedge(ed); + free_editedge(ed); + } + ed= nexted; + } +} + +static void erase_faces(ListBase *l) +{ + EditFace *f, *nextf; + + f = (EditFace *) l->first; + + while(f) { + nextf= f->next; + if( faceselectedOR(f, SELECT) ) { + BLI_remlink(l, f); + free_editface(f); + } + f = nextf; + } +} + +static void erase_vertices(ListBase *l) +{ + EditVert *v, *nextv; + + v = (EditVert *) l->first; + while(v) { + nextv= v->next; + if(v->f & 1) { + BLI_remlink(l, v); + free_editvert(v); + } + v = nextv; + } +} + +void delete_mesh(void) +{ + EditMesh *em = G.editMesh; + EditFace *efa, *nextvl; + EditVert *eve,*nextve; + EditEdge *eed,*nexted; + short event; + int count; + char *str="Erase"; + + TEST_EDITMESH + if(multires_test()) return; + + event= pupmenu("Erase %t|Vertices%x10|Edges%x1|Faces%x2|All%x3|Edges & Faces%x4|Only Faces%x5|Edge Loop%x6"); + if(event<1) return; + + if(event==10 ) { + str= "Erase Vertices"; + erase_edges(&em->edges); + erase_faces(&em->faces); + erase_vertices(&em->verts); + } + else if(event==6) { + if(!EdgeLoopDelete()) + return; + + str= "Erase Edge Loop"; + } + else if(event==4) { + str= "Erase Edges & Faces"; + efa= em->faces.first; + while(efa) { + nextvl= efa->next; + /* delete only faces with 1 or more edges selected */ + count= 0; + if(efa->e1->f & SELECT) count++; + if(efa->e2->f & SELECT) count++; + if(efa->e3->f & SELECT) count++; + if(efa->e4 && (efa->e4->f & SELECT)) count++; + if(count) { + BLI_remlink(&em->faces, efa); + free_editface(efa); + } + efa= nextvl; + } + eed= em->edges.first; + while(eed) { + nexted= eed->next; + if(eed->f & SELECT) { + remedge(eed); + free_editedge(eed); + } + eed= nexted; + } + efa= em->faces.first; + while(efa) { + nextvl= efa->next; + event=0; + if( efa->v1->f & SELECT) event++; + if( efa->v2->f & SELECT) event++; + if( efa->v3->f & SELECT) event++; + if(efa->v4 && (efa->v4->f & SELECT)) event++; + + if(event>1) { + BLI_remlink(&em->faces, efa); + free_editface(efa); + } + efa= nextvl; + } + } + else if(event==1) { + str= "Erase Edges"; + // faces first + efa= em->faces.first; + while(efa) { + nextvl= efa->next; + event=0; + if( efa->e1->f & SELECT) event++; + if( efa->e2->f & SELECT) event++; + if( efa->e3->f & SELECT) event++; + if(efa->e4 && (efa->e4->f & SELECT)) event++; + + if(event) { + BLI_remlink(&em->faces, efa); + free_editface(efa); + } + efa= nextvl; + } + eed= em->edges.first; + while(eed) { + nexted= eed->next; + if(eed->f & SELECT) { + remedge(eed); + free_editedge(eed); + } + eed= nexted; + } + /* to remove loose vertices: */ + eed= em->edges.first; + while(eed) { + if( eed->v1->f & SELECT) eed->v1->f-=SELECT; + if( eed->v2->f & SELECT) eed->v2->f-=SELECT; + eed= eed->next; + } + eve= em->verts.first; + while(eve) { + nextve= eve->next; + if(eve->f & SELECT) { + BLI_remlink(&em->verts,eve); + free_editvert(eve); + } + eve= nextve; + } + + } + else if(event==2) { + str="Erase Faces"; + delfaceflag(SELECT); + } + else if(event==3) { + str= "Erase All"; + if(em->verts.first) free_vertlist(&em->verts); + if(em->edges.first) free_edgelist(&em->edges); + if(em->faces.first) free_facelist(&em->faces); + if(em->selected.first) BLI_freelistN(&(em->selected)); + } + else if(event==5) { + str= "Erase Only Faces"; + efa= em->faces.first; + while(efa) { + nextvl= efa->next; + if(efa->f & SELECT) { + BLI_remlink(&em->faces, efa); + free_editface(efa); + } + efa= nextvl; + } + } + + EM_fgon_flags(); // redo flags and indices for fgons + + countall(); + allqueue(REDRAWVIEW3D, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + BIF_undo_push(str); +} + + +/* Got this from scanfill.c. You will need to juggle around the + * callbacks for the scanfill.c code a bit for this to work. */ +void fill_mesh(void) +{ + EditMesh *em = G.editMesh; + EditVert *eve,*v1; + EditEdge *eed,*e1,*nexted; + EditFace *efa,*nextvl, *efan; + short ok; + + if(G.obedit==0 || (G.obedit->type!=OB_MESH)) return; + if(multires_test()) return; + + waitcursor(1); + + /* copy all selected vertices */ + eve= em->verts.first; + while(eve) { + if(eve->f & SELECT) { + v1= BLI_addfillvert(eve->co); + eve->tmp.v= v1; + v1->tmp.v= eve; + v1->xs= 0; // used for counting edges + } + eve= eve->next; + } + /* copy all selected edges */ + eed= em->edges.first; + while(eed) { + if( (eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) { + e1= BLI_addfilledge(eed->v1->tmp.v, eed->v2->tmp.v); + e1->v1->xs++; + e1->v2->xs++; + } + eed= eed->next; + } + /* from all selected faces: remove vertices and edges to prevent doubles */ + /* all edges add values, faces subtract, + then remove edges with vertices ->xs<2 */ + efa= em->faces.first; + ok= 0; + while(efa) { + nextvl= efa->next; + if( faceselectedAND(efa, 1) ) { + efa->v1->tmp.v->xs--; + efa->v2->tmp.v->xs--; + efa->v3->tmp.v->xs--; + if(efa->v4) efa->v4->tmp.v->xs--; + ok= 1; + + } + efa= nextvl; + } + if(ok) { /* there are faces selected */ + eed= filledgebase.first; + while(eed) { + nexted= eed->next; + if(eed->v1->xs<2 || eed->v2->xs<2) { + BLI_remlink(&filledgebase,eed); + } + eed= nexted; + } + } + + if(BLI_edgefill(0, (G.obedit && G.obedit->actcol)?(G.obedit->actcol-1):0)) { + efa= fillfacebase.first; + while(efa) { + /* normals default pointing up */ + efan= addfacelist(efa->v3->tmp.v, efa->v2->tmp.v, + efa->v1->tmp.v, 0, NULL, NULL); + if(efan) EM_select_face(efan, 1); + efa= efa->next; + } + } + + BLI_end_edgefill(); + + waitcursor(0); + EM_select_flush(); + countall(); + allqueue(REDRAWVIEW3D, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + + BIF_undo_push("Fill"); +} +/*GB*/ +/*-------------------------------------------------------------------------------*/ +/*--------------------------- Edge Based Subdivide ------------------------------*/ + +#define EDGENEW 2 +#define FACENEW 2 +#define EDGEINNER 4 +#define EDGEOLD 8 + +/*used by faceloop cut to select only edges valid for edge slide*/ +#define DOUBLEOPFILL 16 + +/* calculates offset for co, based on fractal, sphere or smooth settings */ +static void alter_co(float *co, EditEdge *edge, float rad, int beauty, float perc) +{ + float vec1[3], fac; + + if(beauty & B_SMOOTH) { + /* we calculate an offset vector vec1[], to be added to *co */ + float len, fac, nor[3], nor1[3], nor2[3]; + + VecSubf(nor, edge->v1->co, edge->v2->co); + len= 0.5f*Normalize(nor); + + VECCOPY(nor1, edge->v1->no); + VECCOPY(nor2, edge->v2->no); + + /* cosine angle */ + fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ; + + vec1[0]= fac*nor1[0]; + vec1[1]= fac*nor1[1]; + vec1[2]= fac*nor1[2]; + + /* cosine angle */ + fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ; + + vec1[0]+= fac*nor2[0]; + vec1[1]+= fac*nor2[1]; + vec1[2]+= fac*nor2[2]; + + vec1[0]*= rad*len; + vec1[1]*= rad*len; + vec1[2]*= rad*len; + + co[0] += vec1[0]; + co[1] += vec1[1]; + co[2] += vec1[2]; + } + else { + if(rad > 0.0) { /* subdivide sphere */ + Normalize(co); + co[0]*= rad; + co[1]*= rad; + co[2]*= rad; + } + else if(rad< 0.0) { /* fractal subdivide */ + fac= rad* VecLenf(edge->v1->co, edge->v2->co); + vec1[0]= fac*(float)(0.5-BLI_drand()); + vec1[1]= fac*(float)(0.5-BLI_drand()); + vec1[2]= fac*(float)(0.5-BLI_drand()); + VecAddf(co, co, vec1); + } + + } +} + +/* assumes in the edge is the correct interpolated vertices already */ +/* percent defines the interpolation, rad and beauty are for special options */ +/* results in new vertex with correct coordinate, vertex normal and weight group info */ +static EditVert *subdivide_edge_addvert(EditEdge *edge, float rad, int beauty, float percent) +{ + EditVert *ev; + float co[3]; + + co[0] = (edge->v2->co[0]-edge->v1->co[0])*percent + edge->v1->co[0]; + co[1] = (edge->v2->co[1]-edge->v1->co[1])*percent + edge->v1->co[1]; + co[2] = (edge->v2->co[2]-edge->v1->co[2])*percent + edge->v1->co[2]; + + /* offset for smooth or sphere or fractal */ + alter_co(co, edge, rad, beauty, percent); + + /* clip if needed by mirror modifier */ + if (edge->v1->f2) { + if ( edge->v1->f2 & edge->v2->f2 & 1) { + co[0]= 0.0f; + } + if ( edge->v1->f2 & edge->v2->f2 & 2) { + co[1]= 0.0f; + } + if ( edge->v1->f2 & edge->v2->f2 & 4) { + co[2]= 0.0f; + } + } + + ev = addvertlist(co, NULL); + + /* vert data (vgroups, ..) */ + EM_data_interp_from_verts(edge->v1, edge->v2, ev, percent); + + /* normal */ + ev->no[0] = (edge->v2->no[0]-edge->v1->no[0])*percent + edge->v1->no[0]; + ev->no[1] = (edge->v2->no[1]-edge->v1->no[1])*percent + edge->v1->no[1]; + ev->no[2] = (edge->v2->no[2]-edge->v1->no[2])*percent + edge->v1->no[2]; + Normalize(ev->no); + + return ev; +} + +static void flipvertarray(EditVert** arr, short size) +{ + EditVert *hold; + int i; + + for(i=0; i<size/2; i++) { + hold = arr[i]; + arr[i] = arr[size-i-1]; + arr[size-i-1] = hold; + } +} + +static void facecopy(EditFace *source, EditFace *target) +{ + EditMesh *em= G.editMesh; + float *v1 = source->v1->co, *v2 = source->v2->co, *v3 = source->v3->co; + float *v4 = source->v4? source->v4->co: NULL; + float w[4][4]; + + CustomData_em_copy_data(&em->fdata, &em->fdata, source->data, &target->data); + + target->mat_nr = source->mat_nr; + target->flag = source->flag; + target->h = source->h; + + InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v1->co, w[0]); + InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v2->co, w[1]); + InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v3->co, w[2]); + if (target->v4) + InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v4->co, w[3]); + + CustomData_em_interp(&em->fdata, &source->data, NULL, (float*)w, 1, target->data); +} + +static void fill_quad_single(EditFace *efa, struct GHash *gh, int numcuts, int seltype) +{ + EditEdge *cedge=NULL; + EditVert *v[4], **verts; + EditFace *hold; + short start=0, end, left, right, vertsize,i; + + v[0] = efa->v1; + v[1] = efa->v2; + v[2] = efa->v3; + v[3] = efa->v4; + + if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} + else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} + else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} + else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;} + + // Point verts to the array of new verts for cedge + verts = BLI_ghash_lookup(gh, cedge); + //This is the index size of the verts array + vertsize = numcuts+2; + + // Is the original v1 the same as the first vert on the selected edge? + // if not, the edge is running the opposite direction in this face so flip + // the array to the correct direction + + if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);} + end = (start+1)%4; + left = (start+2)%4; + right = (start+3)%4; + + /* + We should have something like this now + + end start + 3 2 1 0 + |---*---*---| + | | + | | + | | + ------------- + left right + + where start,end,left, right are indexes of EditFace->v1, etc (stored in v) + and 0,1,2... are the indexes of the new verts stored in verts + + We will fill this case like this or this depending on even or odd cuts + + |---*---*---| |---*---| + | / \ | | / \ | + | / \ | | / \ | + |/ \| |/ \| + ------------- --------- + */ + + // Make center face + if(vertsize % 2 == 0) { + hold = addfacelist(verts[(vertsize-1)/2],verts[((vertsize-1)/2)+1],v[left],v[right], NULL,NULL); + hold->e2->f2 |= EDGEINNER; + hold->e4->f2 |= EDGEINNER; + }else{ + hold = addfacelist(verts[(vertsize-1)/2],v[left],v[right],NULL, NULL,NULL); + hold->e1->f2 |= EDGEINNER; + hold->e3->f2 |= EDGEINNER; + } + facecopy(efa,hold); + + // Make side faces + for(i=0;i<(vertsize-1)/2;i++) { + hold = addfacelist(verts[i],verts[i+1],v[right],NULL,NULL,NULL); + facecopy(efa,hold); + if(i+1 != (vertsize-1)/2) { + if(seltype == SUBDIV_SELECT_INNER) { + hold->e2->f2 |= EDGEINNER; + } + } + hold = addfacelist(verts[vertsize-2-i],verts[vertsize-1-i],v[left],NULL,NULL,NULL); + facecopy(efa,hold); + if(i+1 != (vertsize-1)/2) { + if(seltype == SUBDIV_SELECT_INNER) { + hold->e3->f2 |= EDGEINNER; + } + } + } +} + +static void fill_tri_single(EditFace *efa, struct GHash *gh, int numcuts, int seltype) +{ + EditEdge *cedge=NULL; + EditVert *v[3], **verts; + EditFace *hold; + short start=0, end, op, vertsize,i; + + v[0] = efa->v1; + v[1] = efa->v2; + v[2] = efa->v3; + + if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} + else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} + else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} + + // Point verts to the array of new verts for cedge + verts = BLI_ghash_lookup(gh, cedge); + //This is the index size of the verts array + vertsize = numcuts+2; + + // Is the original v1 the same as the first vert on the selected edge? + // if not, the edge is running the opposite direction in this face so flip + // the array to the correct direction + + if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);} + end = (start+1)%3; + op = (start+2)%3; + + /* + We should have something like this now + + end start + 3 2 1 0 + |---*---*---| + \ | + \ | + \ | + \ | + \ | + \ | + |op + + where start,end,op are indexes of EditFace->v1, etc (stored in v) + and 0,1,2... are the indexes of the new verts stored in verts + + We will fill this case like this or this depending on even or odd cuts + + 3 2 1 0 + |---*---*---| + \ \ \ | + \ \ \ | + \ \ \ | + \ \ \| + \ \\| + \ | + |op + */ + + // Make side faces + for(i=0;i<(vertsize-1);i++) { + hold = addfacelist(verts[i],verts[i+1],v[op],NULL,NULL,NULL); + if(i+1 != vertsize-1) { + if(seltype == SUBDIV_SELECT_INNER) { + hold->e2->f2 |= EDGEINNER; + } + } + facecopy(efa,hold); + } +} + +static void fill_quad_double_op(EditFace *efa, struct GHash *gh, int numcuts) +{ + EditEdge *cedge[2]={NULL, NULL}; + EditVert *v[4], **verts[2]; + EditFace *hold; + short start=0, end, left, right, vertsize,i; + + v[0] = efa->v1; + v[1] = efa->v2; + v[2] = efa->v3; + v[3] = efa->v4; + + if(efa->e1->f & SELECT) { cedge[0] = efa->e1; cedge[1] = efa->e3; start = 0;} + else if(efa->e2->f & SELECT) { cedge[0] = efa->e2; cedge[1] = efa->e4; start = 1;} + + // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] + verts[0] = BLI_ghash_lookup(gh, cedge[0]); + verts[1] = BLI_ghash_lookup(gh, cedge[1]); + //This is the index size of the verts array + vertsize = numcuts+2; + + // Is the original v1 the same as the first vert on the selected edge? + // if not, the edge is running the opposite direction in this face so flip + // the array to the correct direction + + if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} + end = (start+1)%4; + left = (start+2)%4; + right = (start+3)%4; + if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);} + /* + We should have something like this now + + end start + 3 2 1 0 + |---*---*---| + | | + | | + | | + |---*---*---| + 0 1 2 3 + left right + + We will fill this case like this or this depending on even or odd cuts + + |---*---*---| + | | | | + | | | | + | | | | + |---*---*---| + */ + + // Make side faces + for(i=0;i<vertsize-1;i++) { + hold = addfacelist(verts[0][i],verts[0][i+1],verts[1][vertsize-2-i],verts[1][vertsize-1-i],NULL,NULL); + if(i < vertsize-2) { + hold->e2->f2 |= EDGEINNER; + hold->e2->f2 |= DOUBLEOPFILL; + } + facecopy(efa,hold); + } +} + +static void fill_quad_double_adj_path(EditFace *efa, struct GHash *gh, int numcuts) +{ + EditEdge *cedge[2]={NULL, NULL}; + EditVert *v[4], **verts[2]; + EditFace *hold; + short start=0, start2=0, vertsize,i; + + v[0] = efa->v1; + v[1] = efa->v2; + v[2] = efa->v3; + v[3] = efa->v4; + + if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;} + if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;} + if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3;} + if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0;} + + // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] + verts[0] = BLI_ghash_lookup(gh, cedge[0]); + verts[1] = BLI_ghash_lookup(gh, cedge[1]); + //This is the index size of the verts array + vertsize = numcuts+2; + + // Is the original v1 the same as the first vert on the selected edge? + // if not, the edge is running the opposite direction in this face so flip + // the array to the correct direction + + if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} + if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} + /* + We should have something like this now + + end start + 3 2 1 0 + start2 0|---*---*---| + | | + 1* | + | | + 2* | + | | + end2 3|-----------| + + We will fill this case like this or this depending on even or odd cuts + |---*---*---| + | / / / | + * / / | + | / / | + * / | + | / | + |-----------| + */ + + // Make outside tris + hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); + /* when ctrl is depressed, only want verts on the cutline selected */ + if (G.qual != LR_CTRLKEY) + hold->e3->f2 |= EDGEINNER; + facecopy(efa,hold); + hold = addfacelist(verts[0][0],verts[1][vertsize-1],v[(start2+2)%4],NULL,NULL,NULL); + /* when ctrl is depressed, only want verts on the cutline selected */ + if (G.qual != LR_CTRLKEY) + hold->e1->f2 |= EDGEINNER; + facecopy(efa,hold); + //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) { + // hold->e1->h |= EM_FGON; + //} + // Make side faces + + for(i=0;i<numcuts;i++) { + hold = addfacelist(verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL); + hold->e2->f2 |= EDGEINNER; + facecopy(efa,hold); + } + //EM_fgon_flags(); + +} + +static void fill_quad_double_adj_fan(EditFace *efa, struct GHash *gh, int numcuts) +{ + EditEdge *cedge[2]={NULL, NULL}; + EditVert *v[4], *op=NULL, **verts[2]; + EditFace *hold; + short start=0, start2=0, vertsize,i; + + v[0] = efa->v1; + v[1] = efa->v2; + v[2] = efa->v3; + v[3] = efa->v4; + + if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;} + if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;} + if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;} + if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;} + + + // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] + verts[0] = BLI_ghash_lookup(gh, cedge[0]); + verts[1] = BLI_ghash_lookup(gh, cedge[1]); + //This is the index size of the verts array + vertsize = numcuts+2; + + // Is the original v1 the same as the first vert on the selected edge? + // if not, the edge is running the opposite direction in this face so flip + // the array to the correct direction + + if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} + if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} + /* + We should have something like this now + + end start + 3 2 1 0 + start2 0|---*---*---| + | | + 1* | + | | + 2* | + | | + end2 3|-----------|op + + We will fill this case like this or this (warning horrible ascii art follows) + |---*---*---| + | \ \ \ | + *---\ \ \ | + | \ \ \ \| + *---- \ \ \ | + | --- \\\| + |-----------| + */ + + for(i=0;i<=numcuts;i++) { + hold = addfacelist(op,verts[1][numcuts-i],verts[1][numcuts-i+1],NULL,NULL,NULL); + hold->e1->f2 |= EDGEINNER; + facecopy(efa,hold); + + hold = addfacelist(op,verts[0][i],verts[0][i+1],NULL,NULL,NULL); + hold->e3->f2 |= EDGEINNER; + facecopy(efa,hold); + } +} + +static void fill_quad_double_adj_inner(EditFace *efa, struct GHash *gh, int numcuts) +{ + EditEdge *cedge[2]={NULL, NULL}; + EditVert *v[4], *op=NULL, **verts[2],**inner; + EditFace *hold; + short start=0, start2=0, vertsize,i; + float co[3]; + + v[0] = efa->v1; + v[1] = efa->v2; + v[2] = efa->v3; + v[3] = efa->v4; + + if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;} + if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;} + if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;} + if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;} + + + // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] + verts[0] = BLI_ghash_lookup(gh, cedge[0]); + verts[1] = BLI_ghash_lookup(gh, cedge[1]); + //This is the index size of the verts array + vertsize = numcuts+2; + + // Is the original v1 the same as the first vert on the selected edge? + // if not, the edge is running the opposite direction in this face so flip + // the array to the correct direction + + if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} + if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} + /* + We should have something like this now + + end start + 3 2 1 0 + start2 0|---*---*---| + | | + 1* | + | | + 2* | + | | + end2 3|-----------|op + + We will fill this case like this or this (warning horrible ascii art follows) + |---*-----*---| + | * / | + * \ / | + | * | + | / \ | + * \ | + | \ | + |-------------| + */ + + // Add Inner Vert(s) + inner = MEM_mallocN(sizeof(EditVert*)*numcuts,"New inner verts"); + + for(i=0;i<numcuts;i++) { + co[0] = (verts[0][numcuts-i]->co[0] + verts[1][i+1]->co[0] ) / 2 ; + co[1] = (verts[0][numcuts-i]->co[1] + verts[1][i+1]->co[1] ) / 2 ; + co[2] = (verts[0][numcuts-i]->co[2] + verts[1][i+1]->co[2] ) / 2 ; + inner[i] = addvertlist(co, NULL); + inner[i]->f2 |= EDGEINNER; + + EM_data_interp_from_verts(verts[0][numcuts-i], verts[1][i+1], inner[i], 0.5f); + } + + // Add Corner Quad + hold = addfacelist(verts[0][numcuts+1],verts[1][1],inner[0],verts[0][numcuts],NULL,NULL); + hold->e2->f2 |= EDGEINNER; + hold->e3->f2 |= EDGEINNER; + facecopy(efa,hold); + // Add Bottom Quads + hold = addfacelist(verts[0][0],verts[0][1],inner[numcuts-1],op,NULL,NULL); + hold->e2->f2 |= EDGEINNER; + facecopy(efa,hold); + + hold = addfacelist(op,inner[numcuts-1],verts[1][numcuts],verts[1][numcuts+1],NULL,NULL); + hold->e2->f2 |= EDGEINNER; + facecopy(efa,hold); + + //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) { + // hold->e1->h |= EM_FGON; + //} + // Add Fill Quads (if # cuts > 1) + + for(i=0;i<numcuts-1;i++) { + hold = addfacelist(inner[i],verts[1][i+1],verts[1][i+2],inner[i+1],NULL,NULL); + hold->e1->f2 |= EDGEINNER; + hold->e3->f2 |= EDGEINNER; + facecopy(efa,hold); + + hold = addfacelist(inner[i],inner[i+1],verts[0][numcuts-1-i],verts[0][numcuts-i],NULL,NULL); + hold->e2->f2 |= EDGEINNER; + hold->e4->f2 |= EDGEINNER; + facecopy(efa,hold); + + //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) { + // hold->e1->h |= EM_FGON; + //} + } + + //EM_fgon_flags(); + + MEM_freeN(inner); +} + +static void fill_tri_double(EditFace *efa, struct GHash *gh, int numcuts) +{ + EditEdge *cedge[2]={NULL, NULL}; + EditVert *v[3], **verts[2]; + EditFace *hold; + short start=0, start2=0, vertsize,i; + + v[0] = efa->v1; + v[1] = efa->v2; + v[2] = efa->v3; + + if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;} + if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;} + if(efa->e3->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e1; start = 2; start2 = 0;} + + // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] + verts[0] = BLI_ghash_lookup(gh, cedge[0]); + verts[1] = BLI_ghash_lookup(gh, cedge[1]); + //This is the index size of the verts array + vertsize = numcuts+2; + + // Is the original v1 the same as the first vert on the selected edge? + // if not, the edge is running the opposite direction in this face so flip + // the array to the correct direction + + if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} + if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} + /* + We should have something like this now + + end start + 3 2 1 0 + start2 0|---*---*---| + | / + 1* / + | / + 2* / + | / + end2 3| + + We will fill this case like this or this depending on even or odd cuts + |---*---*---| + | / / / + * / / + | / / + * / + | / + | + */ + + // Make outside tri + hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); + hold->e3->f2 |= EDGEINNER; + facecopy(efa,hold); + // Make side faces + + for(i=0;i<numcuts;i++) { + hold = addfacelist(verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL); + hold->e2->f2 |= EDGEINNER; + facecopy(efa,hold); + } +} + +static void fill_quad_triple(EditFace *efa, struct GHash *gh, int numcuts) +{ + EditEdge *cedge[3]={0}; + EditVert *v[4], **verts[3]; + EditFace *hold; + short start=0, start2=0, start3=0, vertsize, i, repeats; + + v[0] = efa->v1; + v[1] = efa->v2; + v[2] = efa->v3; + v[3] = efa->v4; + + if(!(efa->e1->f & SELECT)) { + cedge[0] = efa->e2; + cedge[1] = efa->e3; + cedge[2] = efa->e4; + start = 1;start2 = 2;start3 = 3; + } + if(!(efa->e2->f & SELECT)) { + cedge[0] = efa->e3; + cedge[1] = efa->e4; + cedge[2] = efa->e1; + start = 2;start2 = 3;start3 = 0; + } + if(!(efa->e3->f & SELECT)) { + cedge[0] = efa->e4; + cedge[1] = efa->e1; + cedge[2] = efa->e2; + start = 3;start2 = 0;start3 = 1; + } + if(!(efa->e4->f & SELECT)) { + cedge[0] = efa->e1; + cedge[1] = efa->e2; + cedge[2] = efa->e3; + start = 0;start2 = 1;start3 = 2; + } + // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] + verts[0] = BLI_ghash_lookup(gh, cedge[0]); + verts[1] = BLI_ghash_lookup(gh, cedge[1]); + verts[2] = BLI_ghash_lookup(gh, cedge[2]); + //This is the index size of the verts array + vertsize = numcuts+2; + + // Is the original v1 the same as the first vert on the selected edge? + // if not, the edge is running the opposite direction in this face so flip + // the array to the correct direction + + if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} + if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} + if(verts[2][0] != v[start3]) {flipvertarray(verts[2],numcuts+2);} + /* + We should have something like this now + + start2 + 3 2 1 0 + start3 0|---*---*---|3 + | | + 1* *2 + | | + 2* *1 + | | + 3|-----------|0 start + + We will fill this case like this or this depending on even or odd cuts + there are a couple of differences. For odd cuts, there is a tri in the + middle as well as 1 quad at the bottom (not including the extra quads + for odd cuts > 1 + + For even cuts, there is a quad in the middle and 2 quads on the bottom + + they are numbered here for clarity + + 1 outer tris and bottom quads + 2 inner tri or quad + 3 repeating quads + + |---*---*---*---| + |1/ / \ \ 1| + |/ 3 / \ 3 \| + * / 2 \ * + | / \ | + |/ \ | + *---------------* + | 3 | + | | + *---------------* + | | + | 1 | + | | + |---------------| + + |---*---*---*---*---| + | 1/ / \ \ 1| + | / / \ \ | + |/ 3 / \ 3 \| + * / \ * + | / \ | + | / 2 \ | + |/ \| + *-------------------* + | | + | 3 | + | | + *-------------------* + | | + | 1 | + | | + *-------------------* + | | + | 1 | + | | + |-------------------| + + */ + + // Make outside tris + hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); + hold->e3->f2 |= EDGEINNER; + facecopy(efa,hold); + hold = addfacelist(verts[1][vertsize-2],verts[1][vertsize-1],verts[2][1],NULL,NULL,NULL); + hold->e3->f2 |= EDGEINNER; + facecopy(efa,hold); + // Make bottom quad + hold = addfacelist(verts[0][0],verts[0][1],verts[2][vertsize-2],verts[2][vertsize-1],NULL,NULL); + hold->e2->f2 |= EDGEINNER; + facecopy(efa,hold); + //If it is even cuts, add the 2nd lower quad + if(numcuts % 2 == 0) { + hold = addfacelist(verts[0][1],verts[0][2],verts[2][vertsize-3],verts[2][vertsize-2],NULL,NULL); + hold->e2->f2 |= EDGEINNER; + facecopy(efa,hold); + // Also Make inner quad + hold = addfacelist(verts[1][numcuts/2],verts[1][(numcuts/2)+1],verts[2][numcuts/2],verts[0][(numcuts/2)+1],NULL,NULL); + hold->e3->f2 |= EDGEINNER; + //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) { + // hold->e3->h |= EM_FGON; + //} + facecopy(efa,hold); + repeats = (numcuts / 2) -1; + } else { + // Make inner tri + hold = addfacelist(verts[1][(numcuts/2)+1],verts[2][(numcuts/2)+1],verts[0][(numcuts/2)+1],NULL,NULL,NULL); + hold->e2->f2 |= EDGEINNER; + //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) { + // hold->e2->h |= EM_FGON; + //} + facecopy(efa,hold); + repeats = ((numcuts+1) / 2)-1; + } + + // cuts for 1 and 2 do not have the repeating quads + if(numcuts < 3) {repeats = 0;} + for(i=0;i<repeats;i++) { + //Make side repeating Quads + hold = addfacelist(verts[1][i+1],verts[1][i+2],verts[0][vertsize-i-3],verts[0][vertsize-i-2],NULL,NULL); + hold->e2->f2 |= EDGEINNER; + facecopy(efa,hold); + hold = addfacelist(verts[1][vertsize-i-3],verts[1][vertsize-i-2],verts[2][i+1],verts[2][i+2],NULL,NULL); + hold->e4->f2 |= EDGEINNER; + facecopy(efa,hold); + } + // Do repeating bottom quads + for(i=0;i<repeats;i++) { + if(numcuts % 2 == 1) { + hold = addfacelist(verts[0][1+i],verts[0][2+i],verts[2][vertsize-3-i],verts[2][vertsize-2-i],NULL,NULL); + } else { + hold = addfacelist(verts[0][2+i],verts[0][3+i],verts[2][vertsize-4-i],verts[2][vertsize-3-i],NULL,NULL); + } + hold->e2->f2 |= EDGEINNER; + facecopy(efa,hold); + } + //EM_fgon_flags(); +} + +static void fill_quad_quadruple(EditFace *efa, struct GHash *gh, int numcuts, float rad, int beauty) +{ + EditVert **verts[4], ***innerverts; + EditFace *hold; + EditEdge temp; + short vertsize, i, j; + + // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] + verts[0] = BLI_ghash_lookup(gh, efa->e1); + verts[1] = BLI_ghash_lookup(gh, efa->e2); + verts[2] = BLI_ghash_lookup(gh, efa->e3); + verts[3] = BLI_ghash_lookup(gh, efa->e4); + + //This is the index size of the verts array + vertsize = numcuts+2; + + // Is the original v1 the same as the first vert on the selected edge? + // if not, the edge is running the opposite direction in this face so flip + // the array to the correct direction + + if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);} + if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);} + if(verts[2][0] == efa->v3) {flipvertarray(verts[2],numcuts+2);} + if(verts[3][0] == efa->v4) {flipvertarray(verts[3],numcuts+2);} + /* + We should have something like this now + 1 + + 3 2 1 0 + 0|---*---*---|0 + | | + 1* *1 + 2 | | 4 + 2* *2 + | | + 3|---*---*---|3 + 3 2 1 0 + + 3 + // we will fill a 2 dim array of editvert*s to make filling easier + // the innervert order is shown + + 0 0---1---2---3 + | | | | + 1 0---1---2---3 + | | | | + 2 0---1---2---3 + | | | | + 3 0---1---2---3 + + */ + innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts outer array"); + for(i=0;i<numcuts+2;i++) { + innerverts[i] = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts inner array"); + } + + // first row is e1 last row is e3 + for(i=0;i<numcuts+2;i++) { + innerverts[0][i] = verts[0][(numcuts+1)-i]; + innerverts[numcuts+1][i] = verts[2][(numcuts+1)-i]; + } + + for(i=1;i<=numcuts;i++) { + /* we create a fake edge for the next loop */ + temp.v2 = innerverts[i][0] = verts[1][i]; + temp.v1 = innerverts[i][numcuts+1] = verts[3][i]; + + for(j=1;j<=numcuts;j++) { + float percent= (float)j/(float)(numcuts+1); + + innerverts[i][(numcuts+1)-j]= subdivide_edge_addvert(&temp, rad, beauty, percent); + } + } + // Fill with faces + for(i=0;i<numcuts+1;i++) { + for(j=0;j<numcuts+1;j++) { + hold = addfacelist(innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],innerverts[i+1][j+1],NULL,NULL); + hold->e1->f2 = EDGENEW; + hold->e2->f2 = EDGENEW; + hold->e3->f2 = EDGENEW; + hold->e4->f2 = EDGENEW; + + if(i != 0) { hold->e1->f2 |= EDGEINNER; } + if(j != 0) { hold->e2->f2 |= EDGEINNER; } + if(i != numcuts) { hold->e3->f2 |= EDGEINNER; } + if(j != numcuts) { hold->e4->f2 |= EDGEINNER; } + + facecopy(efa,hold); + } + } + // Clean up our dynamic multi-dim array + for(i=0;i<numcuts+2;i++) { + MEM_freeN(innerverts[i]); + } + MEM_freeN(innerverts); +} + +static void fill_tri_triple(EditFace *efa, struct GHash *gh, int numcuts, float rad, int beauty) +{ + EditVert **verts[3], ***innerverts; + short vertsize, i, j; + EditFace *hold; + EditEdge temp; + + // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] + verts[0] = BLI_ghash_lookup(gh, efa->e1); + verts[1] = BLI_ghash_lookup(gh, efa->e2); + verts[2] = BLI_ghash_lookup(gh, efa->e3); + + //This is the index size of the verts array + vertsize = numcuts+2; + + // Is the original v1 the same as the first vert on the selected edge? + // if not, the edge is running the opposite direction in this face so flip + // the array to the correct direction + + if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);} + if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);} + if(verts[2][0] != efa->v3) {flipvertarray(verts[2],numcuts+2);} + /* + We should have something like this now + 3 + + 3 2 1 0 + 0|---*---*---|3 + | / + 1 1* *2 + | / + 2* *1 2 + | / + 3|/ + 0 + + we will fill a 2 dim array of editvert*s to make filling easier + + 3 + + 0 0---1---2---3---4 + | / | / |/ | / + 1 0---1----2---3 + 1 | / | / | / + 2 0----1---2 2 + | / | / + |/ |/ + 3 0---1 + | / + |/ + 4 0 + + */ + + innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"tri-tri subdiv inner verts outer array"); + for(i=0;i<numcuts+2;i++) { + innerverts[i] = MEM_mallocN(sizeof(EditVert*)*((numcuts+2)-i),"tri-tri subdiv inner verts inner array"); + } + //top row is e3 backwards + for(i=0;i<numcuts+2;i++) { + innerverts[0][i] = verts[2][(numcuts+1)-i]; + } + + for(i=1;i<=numcuts+1;i++) { + //fake edge, first vert is from e1, last is from e2 + temp.v1= innerverts[i][0] = verts[0][i]; + temp.v2= innerverts[i][(numcuts+1)-i] = verts[1][(numcuts+1)-i]; + + for(j=1;j<(numcuts+1)-i;j++) { + float percent= (float)j/(float)((numcuts+1)-i); + + innerverts[i][((numcuts+1)-i)-j]= subdivide_edge_addvert(&temp, rad, beauty, 1-percent); + } + } + + // Now fill the verts with happy little tris :) + for(i=0;i<=numcuts+1;i++) { + for(j=0;j<(numcuts+1)-i;j++) { + //We always do the first tri + hold = addfacelist(innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],NULL,NULL,NULL); + hold->e1->f2 |= EDGENEW; + hold->e2->f2 |= EDGENEW; + hold->e3->f2 |= EDGENEW; + if(i != 0) { hold->e1->f2 |= EDGEINNER; } + if(j != 0) { hold->e2->f2 |= EDGEINNER; } + if(j+1 != (numcuts+1)-i) {hold->e3->f2 |= EDGEINNER;} + + facecopy(efa,hold); + //if there are more to come, we do the 2nd + if(j+1 <= numcuts-i) { + hold = addfacelist(innerverts[i+1][j],innerverts[i+1][j+1],innerverts[i][j+1],NULL,NULL,NULL); + facecopy(efa,hold); + hold->e1->f2 |= EDGENEW; + hold->e2->f2 |= EDGENEW; + hold->e3->f2 |= EDGENEW; + } + } + } + + // Clean up our dynamic multi-dim array + for(i=0;i<numcuts+2;i++) { + MEM_freeN(innerverts[i]); + } + MEM_freeN(innerverts); +} + +//Next two fill types are for knife exact only and are provided to allow for knifing through vertices +//This means there is no multicut! +static void fill_quad_doublevert(EditFace *efa, int v1, int v2){ + EditFace *hold; + /* + Depending on which two vertices have been knifed through (v1 and v2), we + triangulate like the patterns below. + X-------| |-------X + | \ | | / | + | \ | | / | + | \ | | / | + --------X X-------- + */ + + if(v1 == 1 && v2 == 3){ + hold= addfacelist(efa->v1, efa->v2, efa->v3, 0, efa, NULL); + hold->e1->f2 |= EDGENEW; + hold->e2->f2 |= EDGENEW; + hold->e3->f2 |= EDGENEW; + hold->e3->f2 |= EDGEINNER; + facecopy(efa, hold); + + hold= addfacelist(efa->v1, efa->v3, efa->v4, 0, efa, NULL); + hold->e1->f2 |= EDGENEW; + hold->e2->f2 |= EDGENEW; + hold->e3->f2 |= EDGENEW; + hold->e1->f2 |= EDGEINNER; + facecopy(efa, hold); + } + else{ + hold= addfacelist(efa->v1, efa->v2, efa->v4, 0, efa, NULL); + hold->e1->f2 |= EDGENEW; + hold->e2->f2 |= EDGENEW; + hold->e3->f2 |= EDGENEW; + hold->e2->f2 |= EDGEINNER; + facecopy(efa, hold); + + hold= addfacelist(efa->v2, efa->v3, efa->v4, 0, efa, NULL); + hold->e1->f2 |= EDGENEW; + hold->e2->f2 |= EDGENEW; + hold->e3->f2 |= EDGENEW; + hold->e3->f2 |= EDGEINNER; + facecopy(efa, hold); + } +} + +static void fill_quad_singlevert(EditFace *efa, struct GHash *gh) +{ + EditEdge *cedge=NULL; + EditVert *v[4], **verts; + EditFace *hold; + short start=0, end, left, right, vertsize; + + v[0] = efa->v1; + v[1] = efa->v2; + v[2] = efa->v3; + v[3] = efa->v4; + + if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} + else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} + else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} + else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;} + + // Point verts to the array of new verts for cedge + verts = BLI_ghash_lookup(gh, cedge); + //This is the index size of the verts array + vertsize = 3; + + // Is the original v1 the same as the first vert on the selected edge? + // if not, the edge is running the opposite direction in this face so flip + // the array to the correct direction + + if(verts[0] != v[start]) {flipvertarray(verts,3);} + end = (start+1)%4; + left = (start+2)%4; + right = (start+3)%4; + +/* + We should have something like this now + + end start + 2 1 0 + |-----*-----| + | | + | | + | | + ------------- + left right + + where start,end,left, right are indexes of EditFace->v1, etc (stored in v) + and 0,1,2 are the indexes of the new verts stored in verts. We fill like + this, depending on whether its vertex 'left' or vertex 'right' thats + been knifed through... + + |---*---| |---*---| + | / | | \ | + | / | | \ | + |/ | | \| + X-------- --------X +*/ + + if(v[left]->f1){ + //triangle is composed of cutvert, end and left + hold = addfacelist(verts[1],v[end],v[left],NULL, NULL,NULL); + hold->e1->f2 |= EDGENEW; + hold->e2->f2 |= EDGENEW; + hold->e3->f2 |= EDGENEW; + hold->e3->f2 |= EDGEINNER; + facecopy(efa, hold); + + //quad is composed of cutvert, left, right and start + hold = addfacelist(verts[1],v[left],v[right],v[start], NULL, NULL); + hold->e1->f2 |= EDGENEW; + hold->e2->f2 |= EDGENEW; + hold->e3->f2 |= EDGENEW; + hold->e4->f2 |= EDGENEW; + hold->e1->f2 |= EDGEINNER; + facecopy(efa, hold); + } + else if(v[right]->f1){ + //triangle is composed of cutvert, right and start + hold = addfacelist(verts[1],v[right],v[start], NULL, NULL, NULL); + hold->e1->f2 |= EDGENEW; + hold->e2->f2 |= EDGENEW; + hold->e3->f2 |= EDGENEW; + hold->e1->f2 |= EDGEINNER; + facecopy(efa, hold); + //quad is composed of cutvert, end, left, right + hold = addfacelist(verts[1],v[end], v[left], v[right], NULL, NULL); + hold->e1->f2 |= EDGENEW; + hold->e2->f2 |= EDGENEW; + hold->e3->f2 |= EDGENEW; + hold->e4->f2 |= EDGENEW; + hold->e4->f2 |= EDGEINNER; + facecopy(efa, hold); + } + +} + +// This function takes an example edge, the current point to create and +// the total # of points to create, then creates the point and return the +// editvert pointer to it. +static EditVert *subdivideedgenum(EditEdge *edge, int curpoint, int totpoint, float rad, int beauty) +{ + EditVert *ev; + float percent; + + if (beauty & (B_PERCENTSUBD) && totpoint == 1) + //percent=(float)(edge->tmp.l)/32768.0f; + percent= edge->tmp.fp; + else + percent= (float)curpoint/(float)(totpoint+1); + + ev= subdivide_edge_addvert(edge, rad, beauty, percent); + ev->f = edge->v1->f; + + return ev; +} + +#if 1 +#include "bmesh.h" + +void esubdivideflag(int flag, float rad, int beauty, int numcuts, int seltype) +{ + BMesh *bm; + BMOperator subdop, conv; + EditMesh *em = G.editMesh; + BMEdge **list, *bed; + BMIter iter; + int tot; + + /*convert from editmesh*/ + bm = editmesh_to_bmesh(G.editMesh); + + BMO_Init_Op(&subdop, BMOP_ESUBDIVIDE); + for (tot=0, bed=BMIter_New(&iter, bm, BM_EDGES, NULL); bed; bed=BMIter_Step(&iter)) { + if (BM_Is_Selected(bm, bed)) tot++; + } + + list = MEM_callocN(sizeof(void*)*tot, "vert ptr list"); + + for (tot=0, bed=BMIter_New(&iter, bm, BM_EDGES, NULL); bed; bed=BMIter_Step(&iter)) { + if (BM_Is_Selected(bm, bed)) list[tot++] = bed; + } + + BMO_Set_PntBuf(&subdop, BMOP_ESUBDIVIDE_EDGES, list, tot); + BMO_Exec_Op(bm, &subdop); + BMO_Finish_Op(bm, &subdop); + + free_editMesh(G.editMesh); + bmesh_to_editmesh(bm); + BM_Free_Mesh(bm); + + if (list) MEM_freeN(list); +} +#else +void esubdivideflag(int flag, float rad, int beauty, int numcuts, int seltype) +{ + EditMesh *em = G.editMesh; + EditFace *ef; + EditEdge *eed, *cedge, *sort[4]; + EditVert *eve, **templist; + struct GHash *gh; + float length[4], v1mat[3], v2mat[3], v3mat[3], v4mat[3]; + int i, j, edgecount, touchcount, facetype,hold; + ModifierData *md= G.obedit->modifiers.first; + + if(multires_test()) return; + + //Set faces f1 to 0 cause we need it later + for(ef=em->faces.first;ef;ef = ef->next) ef->f1 = 0; + for(eve=em->verts.first; eve; eve=eve->next) { + if(!(beauty & B_KNIFE)) /* knife sets this flag for vertex cuts */ + eve->f1 = 0; + eve->f2 = 0; + } + + for (; md; md=md->next) { + if (md->type==eModifierType_Mirror) { + MirrorModifierData *mmd = (MirrorModifierData*) md; + + if(mmd->flag & MOD_MIR_CLIPPING) { + for (eve= em->verts.first; eve; eve= eve->next) { + eve->f2= 0; + switch(mmd->axis){ + case 0: + if (fabs(eve->co[0]) < mmd->tolerance) + eve->f2 |= 1; + break; + case 1: + if (fabs(eve->co[1]) < mmd->tolerance) + eve->f2 |= 2; + break; + case 2: + if (fabs(eve->co[2]) < mmd->tolerance) + eve->f2 |= 4; + break; + } + } + } + } + } + + //Flush vertex flags upward to the edges + for(eed = em->edges.first;eed;eed = eed->next) { + //if(eed->f & flag && eed->v1->f == eed->v2->f) { + // eed->f |= eed->v1->f; + // } + eed->f2 = 0; + if(eed->f & flag) { + eed->f2 |= EDGEOLD; + } + } + + // We store an array of verts for each edge that is subdivided, + // we put this array as a value in a ghash which is keyed by the EditEdge* + + // Now for beauty subdivide deselect edges based on length + if(beauty & B_BEAUTY) { + for(ef = em->faces.first;ef;ef = ef->next) { + if(!ef->v4) { + continue; + } + if(ef->f & SELECT) { + VECCOPY(v1mat, ef->v1->co); + VECCOPY(v2mat, ef->v2->co); + VECCOPY(v3mat, ef->v3->co); + VECCOPY(v4mat, ef->v4->co); + Mat4Mul3Vecfl(G.obedit->obmat, v1mat); + Mat4Mul3Vecfl(G.obedit->obmat, v2mat); + Mat4Mul3Vecfl(G.obedit->obmat, v3mat); + Mat4Mul3Vecfl(G.obedit->obmat, v4mat); + + length[0] = VecLenf(v1mat, v2mat); + length[1] = VecLenf(v2mat, v3mat); + length[2] = VecLenf(v3mat, v4mat); + length[3] = VecLenf(v4mat, v1mat); + sort[0] = ef->e1; + sort[1] = ef->e2; + sort[2] = ef->e3; + sort[3] = ef->e4; + + + // Beauty Short Edges + if(beauty & B_BEAUTY_SHORT) { + for(j=0;j<2;j++) { + hold = -1; + for(i=0;i<4;i++) { + if(length[i] < 0) { + continue; + } else if(hold == -1) { + hold = i; + } else { + if(length[hold] < length[i]) { + hold = i; + } + } + } + sort[hold]->f &= ~SELECT; + sort[hold]->f2 |= EDGENEW; + length[hold] = -1; + } + } + + // Beauty Long Edges + else { + for(j=0;j<2;j++) { + hold = -1; + for(i=0;i<4;i++) { + if(length[i] < 0) { + continue; + } else if(hold == -1) { + hold = i; + } else { + if(length[hold] > length[i]) { + hold = i; + } + } + } + sort[hold]->f &= ~SELECT; + sort[hold]->f2 |= EDGENEW; + length[hold] = -1; + } + } + } + } + } + + gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + // If we are knifing, We only need the selected edges that were cut, so deselect if it was not cut + if(beauty & B_KNIFE) { + for(eed= em->edges.first;eed;eed=eed->next) { + if( eed->tmp.fp == 0 ) { + EM_select_edge(eed,0); + } + } + } + // So for each edge, if it is selected, we allocate an array of size cuts+2 + // so we can have a place for the v1, the new verts and v2 + for(eed=em->edges.first;eed;eed = eed->next) { + if(eed->f & flag) { + templist = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"vertlist"); + templist[0] = eed->v1; + for(i=0;i<numcuts;i++) { + // This function creates the new vert and returns it back + // to the array + templist[i+1] = subdivideedgenum(eed, i+1, numcuts, rad, beauty); + //while we are here, we can copy edge info from the original edge + cedge = addedgelist(templist[i],templist[i+1],eed); + // Also set the edge f2 to EDGENEW so that we can use this info later + cedge->f2 = EDGENEW; + } + templist[i+1] = eed->v2; + //Do the last edge too + cedge = addedgelist(templist[i],templist[i+1],eed); + cedge->f2 = EDGENEW; + // Now that the edge is subdivided, we can put its verts in the ghash + BLI_ghash_insert(gh, eed, templist); + } + } + + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + // Now for each face in the mesh we need to figure out How many edges were cut + // and which filling method to use for that face + for(ef = em->faces.first;ef;ef = ef->next) { + edgecount = 0; + facetype = 3; + if(ef->e1->f & flag) {edgecount++;} + if(ef->e2->f & flag) {edgecount++;} + if(ef->e3->f & flag) {edgecount++;} + if(ef->v4) { + facetype = 4; + if(ef->e4->f & flag) {edgecount++;} + } + if(facetype == 4) { + switch(edgecount) { + case 0: + if(beauty & B_KNIFE && numcuts == 1){ + /*Test for when knifing through two opposite verts but no edges*/ + touchcount = 0; + if(ef->v1->f1) touchcount++; + if(ef->v2->f1) touchcount++; + if(ef->v3->f1) touchcount++; + if(ef->v4->f1) touchcount++; + if(touchcount == 2){ + if(ef->v1->f1 && ef->v3->f1){ + ef->f1 = SELECT; + fill_quad_doublevert(ef, 1, 3); + } + else if(ef->v2->f1 && ef->v4->f1){ + ef->f1 = SELECT; + fill_quad_doublevert(ef, 2, 4); + } + } + } + break; + + case 1: + if(beauty & B_KNIFE && numcuts == 1){ + /*Test for when knifing through an edge and one vert*/ + touchcount = 0; + if(ef->v1->f1) touchcount++; + if(ef->v2->f1) touchcount++; + if(ef->v3->f1) touchcount++; + if(ef->v4->f1) touchcount++; + + if(touchcount == 1){ + if( (ef->e1->f & flag && ( !ef->e1->v1->f1 && !ef->e1->v2->f1 )) || + (ef->e2->f & flag && ( !ef->e2->v1->f1 && !ef->e2->v2->f1 )) || + (ef->e3->f & flag && ( !ef->e3->v1->f1 && !ef->e3->v2->f1 )) || + (ef->e4->f & flag && ( !ef->e4->v1->f1 && !ef->e4->v2->f1 )) ){ + + ef->f1 = SELECT; + fill_quad_singlevert(ef, gh); + } + else{ + ef->f1 = SELECT; + fill_quad_single(ef, gh, numcuts, seltype); + } + } + else{ + ef->f1 = SELECT; + fill_quad_single(ef, gh, numcuts, seltype); + } + } + else{ + ef->f1 = SELECT; + fill_quad_single(ef, gh, numcuts, seltype); + } + break; + case 2: ef->f1 = SELECT; + // if there are 2, we check if edge 1 and 3 are either both on or off that way + // we can tell if the selected pair is Adjacent or Opposite of each other + if((ef->e1->f & flag && ef->e3->f & flag) || + (ef->e2->f & flag && ef->e4->f & flag)) { + fill_quad_double_op(ef, gh, numcuts); + }else{ + switch(G.scene->toolsettings->cornertype) { + case 0: fill_quad_double_adj_path(ef, gh, numcuts); break; + case 1: fill_quad_double_adj_inner(ef, gh, numcuts); break; + case 2: fill_quad_double_adj_fan(ef, gh, numcuts); break; + } + + } + break; + case 3: ef->f1 = SELECT; + fill_quad_triple(ef, gh, numcuts); + break; + case 4: ef->f1 = SELECT; + fill_quad_quadruple(ef, gh, numcuts, rad, beauty); + break; + } + } else { + switch(edgecount) { + case 0: break; + case 1: ef->f1 = SELECT; + fill_tri_single(ef, gh, numcuts, seltype); + break; + case 2: ef->f1 = SELECT; + fill_tri_double(ef, gh, numcuts); + break; + case 3: ef->f1 = SELECT; + fill_tri_triple(ef, gh, numcuts, rad, beauty); + break; + } + } + } + + // Delete Old Edges and Faces + for(eed = em->edges.first;eed;eed = eed->next) { + if(BLI_ghash_haskey(gh,eed)) { + eed->f1 = SELECT; + } else { + eed->f1 = 0; + } + } + free_tagged_edges_faces(em->edges.first, em->faces.first); + + if(seltype == SUBDIV_SELECT_ORIG && G.qual != LR_CTRLKEY) { + /* bugfix: vertex could get flagged as "not-selected" + // solution: clear flags before, not at the same time as setting SELECT flag -dg + */ + for(eed = em->edges.first;eed;eed = eed->next) { + if(!(eed->f2 & EDGENEW || eed->f2 & EDGEOLD)) { + eed->f &= !flag; + EM_select_edge(eed,0); + } + } + for(eed = em->edges.first;eed;eed = eed->next) { + if(eed->f2 & EDGENEW || eed->f2 & EDGEOLD) { + eed->f |= flag; + EM_select_edge(eed,1); + } + } + } else if ((seltype == SUBDIV_SELECT_INNER || seltype == SUBDIV_SELECT_INNER_SEL)|| G.qual == LR_CTRLKEY) { + for(eed = em->edges.first;eed;eed = eed->next) { + if(eed->f2 & EDGEINNER) { + eed->f |= flag; + EM_select_edge(eed,1); + if(eed->v1->f & EDGEINNER) eed->v1->f |= SELECT; + if(eed->v2->f & EDGEINNER) eed->v2->f |= SELECT; + }else{ + eed->f &= !flag; + EM_select_edge(eed,0); + } + } + } else if(seltype == SUBDIV_SELECT_LOOPCUT){ + for(eed = em->edges.first;eed;eed = eed->next) { + if(eed->f2 & DOUBLEOPFILL){ + eed->f |= flag; + EM_select_edge(eed,1); + }else{ + eed->f &= !flag; + EM_select_edge(eed,0); + } + } + } + if(G.scene->selectmode & SCE_SELECT_VERTEX) { + for(eed = em->edges.first;eed;eed = eed->next) { + if(eed->f & SELECT) { + eed->v1->f |= SELECT; + eed->v2->f |= SELECT; + } + } + } + + //fix hide flags for edges. First pass, hide edges of hidden faces + for(ef=em->faces.first; ef; ef=ef->next){ + if(ef->h){ + ef->e1->h |= 1; + ef->e2->h |= 1; + ef->e3->h |= 1; + if(ef->e4) ef->e4->h |= 1; + } + } + //second pass: unhide edges of visible faces adjacent to hidden faces + for(ef=em->faces.first; ef; ef=ef->next){ + if(ef->h == 0){ + ef->e1->h &= ~1; + ef->e2->h &= ~1; + ef->e3->h &= ~1; + if(ef->e4) ef->e4->h &= ~1; + } + } + + // Free the ghash and call MEM_freeN on all the value entries to return + // that memory + BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); + + EM_selectmode_flush(); + for(ef=em->faces.first;ef;ef = ef->next) { + if(ef->e4) { + if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && + (ef->e3->f & SELECT && ef->e4->f & SELECT) ) { + ef->f |= SELECT; + } + } else { + if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && ef->e3->f & SELECT) { + ef->f |= SELECT; + } + } + } + + recalc_editnormals(); + countall(); + allqueue(REDRAWVIEW3D, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); +} +#endif + +static int count_selected_edges(EditEdge *ed) +{ + int totedge = 0; + while(ed) { + ed->tmp.p = 0; + if( ed->f & SELECT ) totedge++; + ed= ed->next; + } + return totedge; +} + +/* hurms, as if this makes code readable! It's pointerpointer hiding... (ton) */ +typedef EditFace *EVPtr; +typedef EVPtr EVPTuple[2]; + +/** builds EVPTuple array efaa of face tuples (in fact pointers to EditFaces) + sharing one edge. + arguments: selected edge list, face list. + Edges will also be tagged accordingly (see eed->f2) */ + +static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa) +{ + EditEdge *e1, *e2, *e3; + EVPtr *evp; + int i = 0; + + /* run through edges, if selected, set pointer edge-> facearray */ + while(eed) { + eed->f2= 0; + eed->f1= 0; + if( eed->f & SELECT ) { + eed->tmp.p = (EditVert *) (&efaa[i]); + i++; + } + else eed->tmp.p = NULL; + + eed= eed->next; + } + + + /* find edges pointing to 2 faces by procedure: + + - run through faces and their edges, increase + face counter e->f1 for each face + */ + + while(efa) { + efa->f1= 0; + if(efa->v4==0 && (efa->f & SELECT)) { /* if selected triangle */ + e1= efa->e1; + e2= efa->e2; + e3= efa->e3; + if(e1->f2<3 && e1->tmp.p) { + if(e1->f2<2) { + evp= (EVPtr *) e1->tmp.p; + evp[(int)e1->f2] = efa; + } + e1->f2+= 1; + } + if(e2->f2<3 && e2->tmp.p) { + if(e2->f2<2) { + evp= (EVPtr *) e2->tmp.p; + evp[(int)e2->f2]= efa; + } + e2->f2+= 1; + } + if(e3->f2<3 && e3->tmp.p) { + if(e3->f2<2) { + evp= (EVPtr *) e3->tmp.p; + evp[(int)e3->f2]= efa; + } + e3->f2+= 1; + } + } + else { + /* set to 3 to make sure these are not flipped or joined */ + efa->e1->f2= 3; + efa->e2->f2= 3; + efa->e3->f2= 3; + if (efa->e4) efa->e4->f2= 3; + } + + efa= efa->next; + } + return i; +} + + +/* returns vertices of two adjacent triangles forming a quad + - can be righthand or lefthand + + 4-----3 + |\ | + | \ 2 | <- efa1 + | \ | + efa-> | 1 \ | + | \| + 1-----2 + +*/ +#define VTEST(face, num, other) \ + (face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3) + +static void givequadverts(EditFace *efa, EditFace *efa1, EditVert **v1, EditVert **v2, EditVert **v3, EditVert **v4, int *vindex) +{ + if VTEST(efa, 1, efa1) { + *v1= efa->v1; + *v2= efa->v2; + vindex[0]= 0; + vindex[1]= 1; + } + else if VTEST(efa, 2, efa1) { + *v1= efa->v2; + *v2= efa->v3; + vindex[0]= 1; + vindex[1]= 2; + } + else if VTEST(efa, 3, efa1) { + *v1= efa->v3; + *v2= efa->v1; + vindex[0]= 2; + vindex[1]= 0; + } + + if VTEST(efa1, 1, efa) { + *v3= efa1->v1; + *v4= efa1->v2; + vindex[2]= 0; + vindex[3]= 1; + } + else if VTEST(efa1, 2, efa) { + *v3= efa1->v2; + *v4= efa1->v3; + vindex[2]= 1; + vindex[3]= 2; + } + else if VTEST(efa1, 3, efa) { + *v3= efa1->v3; + *v4= efa1->v1; + vindex[2]= 2; + vindex[3]= 0; + } + else + *v3= *v4= NULL; +} + +/* Helper functions for edge/quad edit features*/ +static void untag_edges(EditFace *f) +{ + f->e1->f1 = 0; + f->e2->f1 = 0; + f->e3->f1 = 0; + if (f->e4) f->e4->f1 = 0; +} + +/** remove and free list of tagged edges and faces */ +static void free_tagged_edges_faces(EditEdge *eed, EditFace *efa) +{ + EditMesh *em= G.editMesh; + EditEdge *nexted; + EditFace *nextvl; + + while(efa) { + nextvl= efa->next; + if(efa->f1) { + BLI_remlink(&em->faces, efa); + free_editface(efa); + } + else + /* avoid deleting edges that are still in use */ + untag_edges(efa); + efa= nextvl; + } + + while(eed) { + nexted= eed->next; + if(eed->f1) { + remedge(eed); + free_editedge(eed); + } + eed= nexted; + } +} + +/* note; the EM_selectmode_set() calls here illustrate how badly constructed it all is... from before the + edge/face flags, with very mixed results.... */ +void beauty_fill(void) +{ + EditMesh *em = G.editMesh; + EditVert *v1, *v2, *v3, *v4; + EditEdge *eed, *nexted; + EditEdge dia1, dia2; + EditFace *efa, *w; + // void **efaar, **efaa; + EVPTuple *efaar; + EVPtr *efaa; + float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2; + int totedge, ok, notbeauty=8, onedone, vindex[4]; + + if(multires_test()) return; + + /* - all selected edges with two faces + * - find the faces: store them in edges (using datablock) + * - per edge: - test convex + * - test edge: flip? + * - if true: remedge, addedge, all edges at the edge get new face pointers + */ + + EM_selectmode_set(); // makes sure in selectmode 'face' the edges of selected faces are selected too + + totedge = count_selected_edges(em->edges.first); + if(totedge==0) return; + + /* temp block with face pointers */ + efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill"); + + while (notbeauty) { + notbeauty--; + + ok = collect_quadedges(efaar, em->edges.first, em->faces.first); + + /* there we go */ + onedone= 0; + + eed= em->edges.first; + while(eed) { + nexted= eed->next; + + /* f2 is set in collect_quadedges() */ + if(eed->f2==2 && eed->h==0) { + + efaa = (EVPtr *) eed->tmp.p; + + /* none of the faces should be treated before, nor be part of fgon */ + ok= 1; + efa= efaa[0]; + if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; + if(efa->fgonf) ok= 0; + efa= efaa[1]; + if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; + if(efa->fgonf) ok= 0; + + if(ok) { + /* test convex */ + givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); + if(v1 && v2 && v3 && v4) { + if( convex(v1->co, v2->co, v3->co, v4->co) ) { + + /* test edges */ + if( (v1) > (v3) ) { + dia1.v1= v3; + dia1.v2= v1; + } + else { + dia1.v1= v1; + dia1.v2= v3; + } + + if( (v2) > (v4) ) { + dia2.v1= v4; + dia2.v2= v2; + } + else { + dia2.v1= v2; + dia2.v2= v4; + } + + /* testing rule: + * the area divided by the total edge lengths + */ + + len1= VecLenf(v1->co, v2->co); + len2= VecLenf(v2->co, v3->co); + len3= VecLenf(v3->co, v4->co); + len4= VecLenf(v4->co, v1->co); + len5= VecLenf(v1->co, v3->co); + len6= VecLenf(v2->co, v4->co); + + opp1= AreaT3Dfl(v1->co, v2->co, v3->co); + opp2= AreaT3Dfl(v1->co, v3->co, v4->co); + + fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5); + + opp1= AreaT3Dfl(v2->co, v3->co, v4->co); + opp2= AreaT3Dfl(v2->co, v4->co, v1->co); + + fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6); + + ok= 0; + if(fac1 > fac2) { + if(dia2.v1==eed->v1 && dia2.v2==eed->v2) { + eed->f1= 1; + efa= efaa[0]; + efa->f1= 1; + efa= efaa[1]; + efa->f1= 1; + + w= EM_face_from_faces(efaa[0], efaa[1], + vindex[0], vindex[1], 4+vindex[2], -1); + w->f |= SELECT; + + + w= EM_face_from_faces(efaa[0], efaa[1], + vindex[0], 4+vindex[2], 4+vindex[3], -1); + w->f |= SELECT; + + onedone= 1; + } + } + else if(fac1 < fac2) { + if(dia1.v1==eed->v1 && dia1.v2==eed->v2) { + eed->f1= 1; + efa= efaa[0]; + efa->f1= 1; + efa= efaa[1]; + efa->f1= 1; + + + w= EM_face_from_faces(efaa[0], efaa[1], + vindex[1], 4+vindex[2], 4+vindex[3], -1); + w->f |= SELECT; + + + w= EM_face_from_faces(efaa[0], efaa[1], + vindex[0], 4+vindex[1], 4+vindex[3], -1); + w->f |= SELECT; + + onedone= 1; + } + } + } + } + } + + } + eed= nexted; + } + + free_tagged_edges_faces(em->edges.first, em->faces.first); + + if(onedone==0) break; + + EM_selectmode_set(); // new edges/faces were added + } + + MEM_freeN(efaar); + + EM_select_flush(); + + allqueue(REDRAWVIEW3D, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + BIF_undo_push("Beauty Fill"); +} + + +/* ******************** BEGIN TRIANGLE TO QUAD ************************************* */ +static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit){ + + /*gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make*/ + /*Note: this is more complicated than it needs to be and should be cleaned up...*/ + float measure = 0.0, noA1[3], noA2[3], noB1[3], noB2[3], normalADiff, normalBDiff, + edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3], diff, + minarea, maxarea, areaA, areaB; + + /*First Test: Normal difference*/ + CalcNormFloat(v1->co, v2->co, v3->co, noA1); + CalcNormFloat(v1->co, v3->co, v4->co, noA2); + + if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0; + else normalADiff = VecAngle2(noA1, noA2); + //if(!normalADiff) normalADiff = 179; + CalcNormFloat(v2->co, v3->co, v4->co, noB1); + CalcNormFloat(v4->co, v1->co, v2->co, noB2); + + if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0; + else normalBDiff = VecAngle2(noB1, noB2); + //if(!normalBDiff) normalBDiff = 179; + + measure += (normalADiff/360) + (normalBDiff/360); + if(measure > limit) return measure; + + /*Second test: Colinearity*/ + VecSubf(edgeVec1, v1->co, v2->co); + VecSubf(edgeVec2, v2->co, v3->co); + VecSubf(edgeVec3, v3->co, v4->co); + VecSubf(edgeVec4, v4->co, v1->co); + + diff = 0.0; + + diff = ( + fabs(VecAngle2(edgeVec1, edgeVec2) - 90) + + fabs(VecAngle2(edgeVec2, edgeVec3) - 90) + + fabs(VecAngle2(edgeVec3, edgeVec4) - 90) + + fabs(VecAngle2(edgeVec4, edgeVec1) - 90)) / 360; + if(!diff) return 0.0; + + measure += diff; + if(measure > limit) return measure; + + /*Third test: Concavity*/ + areaA = AreaT3Dfl(v1->co, v2->co, v3->co) + AreaT3Dfl(v1->co, v3->co, v4->co); + areaB = AreaT3Dfl(v2->co, v3->co, v4->co) + AreaT3Dfl(v4->co, v1->co, v2->co); + + if(areaA <= areaB) minarea = areaA; + else minarea = areaB; + + if(areaA >= areaB) maxarea = areaA; + else maxarea = areaB; + + if(!maxarea) measure += 1; + else measure += (1 - (minarea / maxarea)); + + return measure; +} + +#define T2QUV_LIMIT 0.005 +#define T2QCOL_LIMIT 3 +static int compareFaceAttribs(EditFace *f1, EditFace *f2, EditEdge *eed) +{ + /*Test to see if the per-face attributes for the joining edge match within limit*/ + MTFace *tf1, *tf2; + unsigned int *col1, *col2; + short i,attrok=0, flag = G.scene->toolsettings->editbutflag, fe1[2], fe2[2]; + + tf1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MTFACE); + tf2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MTFACE); + + col1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MCOL); + col2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MCOL); + + /*store indices for faceedges*/ + f1->v1->f1 = 0; + f1->v2->f1 = 1; + f1->v3->f1 = 2; + + fe1[0] = eed->v1->f1; + fe1[1] = eed->v2->f1; + + f2->v1->f1 = 0; + f2->v2->f1 = 1; + f2->v3->f1 = 2; + + fe2[0] = eed->v1->f1; + fe2[1] = eed->v2->f1; + + /*compare faceedges for each face attribute. Additional per face attributes can be added later*/ + /*do UVs*/ + if(flag & B_JOINTRIA_UV){ + + if(tf1 == NULL || tf2 == NULL) attrok |= B_JOINTRIA_UV; + else if(tf1->tpage != tf2->tpage); /*do nothing*/ + else{ + for(i = 0; i < 2; i++){ + if(tf1->uv[fe1[i]][0] + T2QUV_LIMIT > tf2->uv[fe2[i]][0] && tf1->uv[fe1[i]][0] - T2QUV_LIMIT < tf2->uv[fe2[i]][0] && + tf1->uv[fe1[i]][1] + T2QUV_LIMIT > tf2->uv[fe2[i]][1] && tf1->uv[fe1[i]][1] - T2QUV_LIMIT < tf2->uv[fe2[i]][1]) attrok |= B_JOINTRIA_UV; + } + } + } + + /*do VCOLs*/ + if(flag & B_JOINTRIA_VCOL){ + if(!col1 || !col2) attrok |= B_JOINTRIA_VCOL; + else{ + char *f1vcol, *f2vcol; + for(i = 0; i < 2; i++){ + f1vcol = (char *)&(col1[fe1[i]]); + f2vcol = (char *)&(col2[fe2[i]]); + + /*compare f1vcol with f2vcol*/ + if( f1vcol[1] + T2QCOL_LIMIT > f2vcol[1] && f1vcol[1] - T2QCOL_LIMIT < f2vcol[1] && + f1vcol[2] + T2QCOL_LIMIT > f2vcol[2] && f1vcol[2] - T2QCOL_LIMIT < f2vcol[2] && + f1vcol[3] + T2QCOL_LIMIT > f2vcol[3] && f1vcol[3] - T2QCOL_LIMIT < f2vcol[3]) attrok |= B_JOINTRIA_VCOL; + } + } + } + + if( ((attrok & B_JOINTRIA_UV) == (flag & B_JOINTRIA_UV)) && ((attrok & B_JOINTRIA_VCOL) == (flag & B_JOINTRIA_VCOL)) ) return 1; + return 0; +} + +static int fplcmp(const void *v1, const void *v2) +{ + const EditEdge *e1= *((EditEdge**)v1), *e2=*((EditEdge**)v2); + + if( e1->crease > e2->crease) return 1; + else if( e1->crease < e2->crease) return -1; + + return 0; +} + +/*Bitflags for edges.*/ +#define T2QDELETE 1 +#define T2QCOMPLEX 2 +#define T2QJOIN 4 +void join_triangles(void) +{ + EditMesh *em=G.editMesh; + EditVert *v1, *v2, *v3, *v4, *eve; + EditEdge *eed, **edsortblock = NULL, **edb = NULL; + EditFace *efa; + EVPTuple *efaar = NULL; + EVPtr *efaa = NULL; + float *creases = NULL; + float measure; /*Used to set tolerance*/ + float limit = G.scene->toolsettings->jointrilimit; + int i, ok, totedge=0, totseledge=0, complexedges, vindex[4]; + + /*test for multi-resolution data*/ + if(multires_test()) return; + + /*if we take a long time on very dense meshes we want waitcursor to display*/ + waitcursor(1); + + totseledge = count_selected_edges(em->edges.first); + if(totseledge==0) return; + + /*abusing crease value to store weights for edge pairs. Nasty*/ + for(eed=em->edges.first; eed; eed=eed->next) totedge++; + if(totedge) creases = MEM_callocN(sizeof(float) * totedge, "Join Triangles Crease Array"); + for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++){ + creases[i] = eed->crease; + eed->crease = 0.0; + } + + /*clear temp flags*/ + for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = eve->f2 = 0; + for(eed=em->edges.first; eed; eed=eed->next) eed->f2 = eed->f1 = 0; + for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = efa->tmp.l = 0; + + /*For every selected 2 manifold edge, create pointers to its two faces.*/ + efaar= (EVPTuple *) MEM_callocN(totseledge * sizeof(EVPTuple), "Tri2Quad"); + ok = collect_quadedges(efaar, em->edges.first, em->faces.first); + complexedges = 0; + + if(ok){ + + + /*clear tmp.l flag and store number of faces that are selected and coincident to current face here.*/ + for(eed=em->edges.first; eed; eed=eed->next){ + /* eed->f2 is 2 only if this edge is part of exactly two + triangles, and both are selected, and it has EVPTuple assigned */ + if(eed->f2 == 2){ + efaa= (EVPtr *) eed->tmp.p; + efaa[0]->tmp.l++; + efaa[1]->tmp.l++; + } + } + + for(eed=em->edges.first; eed; eed=eed->next){ + if(eed->f2 == 2){ + efaa= (EVPtr *) eed->tmp.p; + v1 = v2 = v3 = v4 = NULL; + givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); + if(v1 && v2 && v3 && v4){ + /*test if simple island first. This mimics 2.42 behaviour and the tests are less restrictive.*/ + if(efaa[0]->tmp.l == 1 && efaa[1]->tmp.l == 1){ + if( convex(v1->co, v2->co, v3->co, v4->co) ){ + eed->f1 |= T2QJOIN; + efaa[0]->f1 = 1; //mark for join + efaa[1]->f1 = 1; //mark for join + } + } + else{ + + /* The face pair is part of a 'complex' island, so the rules for dealing with it are more involved. + Depending on what options the user has chosen, this face pair can be 'thrown out' based upon the following criteria: + + 1: the two faces do not share the same material + 2: the edge joining the two faces is marked as sharp. + 3: the two faces UV's do not make a good match + 4: the two faces Vertex colors do not make a good match + + If the face pair passes all the applicable tests, it is then given a 'weight' with the measure_facepair() function. + This measures things like concavity, colinearity ect. If this weight is below the threshold set by the user + the edge joining them is marked as being 'complex' and will be compared against other possible pairs which contain one of the + same faces in the current pair later. + + This technique is based upon an algorithm that Campbell Barton developed for his Tri2Quad script that was previously part of + the python scripts bundled with Blender releases. + */ + + if(G.scene->toolsettings->editbutflag & B_JOINTRIA_SHARP && eed->sharp); /*do nothing*/ + else if(G.scene->toolsettings->editbutflag & B_JOINTRIA_MAT && efaa[0]->mat_nr != efaa[1]->mat_nr); /*do nothing*/ + else if(((G.scene->toolsettings->editbutflag & B_JOINTRIA_UV) || (G.scene->toolsettings->editbutflag & B_JOINTRIA_VCOL)) && + compareFaceAttribs(efaa[0], efaa[1], eed) == 0); /*do nothing*/ + else{ + measure = measure_facepair(v1, v2, v3, v4, limit); + if(measure < limit){ + complexedges++; + eed->f1 |= T2QCOMPLEX; + eed->crease = measure; /*we dont mark edges for join yet*/ + } + } + } + } + } + } + + /*Quicksort the complex edges according to their weighting*/ + if(complexedges){ + edsortblock = edb = MEM_callocN(sizeof(EditEdge*) * complexedges, "Face Pairs quicksort Array"); + for(eed = em->edges.first; eed; eed=eed->next){ + if(eed->f1 & T2QCOMPLEX){ + *edb = eed; + edb++; + } + } + qsort(edsortblock, complexedges, sizeof(EditEdge*), fplcmp); + /*now go through and mark the edges who get the highest weighting*/ + for(edb=edsortblock, i=0; i < complexedges; edb++, i++){ + efaa = (EVPtr *)((*edb)->tmp.p); /*suspect!*/ + if( !efaa[0]->f1 && !efaa[1]->f1){ + efaa[0]->f1 = 1; //mark for join + efaa[1]->f1 = 1; //mark for join + (*edb)->f1 |= T2QJOIN; + } + } + } + + /*finally go through all edges marked for join (simple and complex) and create new faces*/ + for(eed=em->edges.first; eed; eed=eed->next){ + if(eed->f1 & T2QJOIN){ + efaa= (EVPtr *)eed->tmp.p; + v1 = v2 = v3 = v4 = NULL; + givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); + if((v1 && v2 && v3 && v4) && (exist_face(v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be adressed.*/ + /*flag for delete*/ + eed->f1 |= T2QDELETE; + /*create new quad and select*/ + efa = EM_face_from_faces(efaa[0], efaa[1], vindex[0], vindex[1], 4+vindex[2], 4+vindex[3]); + EM_select_face(efa,1); + } + else{ + efaa[0]->f1 = 0; + efaa[1]->f1 = 0; + } + } + } + } + + /*free data and cleanup*/ + if(creases){ + for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++) eed->crease = creases[i]; + MEM_freeN(creases); + } + for(eed=em->edges.first; eed; eed=eed->next){ + if(eed->f1 & T2QDELETE) eed->f1 = 1; + else eed->f1 = 0; + } + free_tagged_edges_faces(em->edges.first, em->faces.first); + if(efaar) MEM_freeN(efaar); + if(edsortblock) MEM_freeN(edsortblock); + + EM_selectmode_flush(); + countall(); + allqueue(REDRAWVIEW3D, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + #ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); + #endif + waitcursor(0); + BIF_undo_push("Convert Triangles to Quads"); +} +/* ******************** END TRIANGLE TO QUAD ************************************* */ + +#define FACE_MARKCLEAR(f) (f->f1 = 1) + +/* quick hack, basically a copy of beauty_fill */ +void edge_flip(void) +{ + EditMesh *em = G.editMesh; + EditVert *v1, *v2, *v3, *v4; + EditEdge *eed, *nexted; + EditFace *efa, *w; + //void **efaar, **efaa; + EVPTuple *efaar; + EVPtr *efaa; + int totedge, ok, vindex[4]; + + /* - all selected edges with two faces + * - find the faces: store them in edges (using datablock) + * - per edge: - test convex + * - test edge: flip? + - if true: remedge, addedge, all edges at the edge get new face pointers + */ + + EM_selectmode_flush(); // makes sure in selectmode 'face' the edges of selected faces are selected too + + totedge = count_selected_edges(em->edges.first); + if(totedge==0) return; + + /* temporary array for : edge -> face[1], face[2] */ + efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "edgeflip"); + + ok = collect_quadedges(efaar, em->edges.first, em->faces.first); + + eed= em->edges.first; + while(eed) { + nexted= eed->next; + + if(eed->f2==2) { /* points to 2 faces */ + + efaa= (EVPtr *) eed->tmp.p; + + /* don't do it if flagged */ + + ok= 1; + efa= efaa[0]; + if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; + efa= efaa[1]; + if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; + + if(ok) { + /* test convex */ + givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); + +/* + 4-----3 4-----3 + |\ | | /| + | \ 1 | | 1 / | + | \ | -> | / | + | 0 \ | | / 0 | + | \| |/ | + 1-----2 1-----2 +*/ + /* make new faces */ + if (v1 && v2 && v3) { + if( convex(v1->co, v2->co, v3->co, v4->co) ) { + if(exist_face(v1, v2, v3, v4)==0) { + /* outch this may break seams */ + w= EM_face_from_faces(efaa[0], efaa[1], vindex[0], + vindex[1], 4+vindex[2], -1); + + EM_select_face(w, 1); + + /* outch this may break seams */ + w= EM_face_from_faces(efaa[0], efaa[1], vindex[0], + 4+vindex[2], 4+vindex[3], -1); + + EM_select_face(w, 1); + } + /* tag as to-be-removed */ + FACE_MARKCLEAR(efaa[1]); + FACE_MARKCLEAR(efaa[0]); + eed->f1 = 1; + + } /* endif test convex */ + } + } + } + eed= nexted; + } + + /* clear tagged edges and faces: */ + free_tagged_edges_faces(em->edges.first, em->faces.first); + + MEM_freeN(efaar); + + allqueue(REDRAWVIEW3D, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + BIF_undo_push("Flip Triangle Edges"); + +} + +static void edge_rotate(EditEdge *eed,int dir) +{ + EditMesh *em = G.editMesh; + EditVert **verts[2]; + EditFace *face[2], *efa, *newFace[2]; + EditEdge **edges[2], **hiddenedges, *srchedge; + int facecount, p1, p2, p3, p4, fac1, fac2, i, j; + int numhidden, numshared, p[2][4]; + + /* check to make sure that the edge is only part of 2 faces */ + facecount = 0; + for(efa = em->faces.first;efa;efa = efa->next) { + if((efa->e1 == eed || efa->e2 == eed) || (efa->e3 == eed || efa->e4 == eed)) { + if(facecount >= 2) { + /* more than two faces with this edge */ + return; + } + else { + face[facecount] = efa; + facecount++; + } + } + } + + if(facecount < 2) + return; + + /* how many edges does each face have */ + if(face[0]->e4) fac1= 4; + else fac1= 3; + + if(face[1]->e4) fac2= 4; + else fac2= 3; + + /* make a handy array for verts and edges */ + verts[0]= &face[0]->v1; + edges[0]= &face[0]->e1; + verts[1]= &face[1]->v1; + edges[1]= &face[1]->e1; + + /* we don't want to rotate edges between faces that share more than one edge */ + numshared= 0; + for(i=0; i<fac1; i++) + for(j=0; j<fac2; j++) + if (edges[0][i] == edges[1][j]) + numshared++; + + if(numshared > 1) + return; + + /* coplaner faces only please */ + if(Inpf(face[0]->n,face[1]->n) <= 0.000001) + return; + + /* we want to construct an array of vertex indicis in both faces, starting at + the last vertex of the edge being rotated. + - first we find the two vertices that lie on the rotating edge + - then we make sure they are ordered according to the face vertex order + - and then we construct the array */ + p1= p2= p3= p4= 0; + + for(i=0; i<4; i++) { + if(eed->v1 == verts[0][i]) p1 = i; + if(eed->v2 == verts[0][i]) p2 = i; + if(eed->v1 == verts[1][i]) p3 = i; + if(eed->v2 == verts[1][i]) p4 = i; + } + + if((p1+1)%fac1 == p2) + SWAP(int, p1, p2); + if((p3+1)%fac2 == p4) + SWAP(int, p3, p4); + + for (i = 0; i < 4; i++) { + p[0][i]= (p1 + i)%fac1; + p[1][i]= (p3 + i)%fac2; + } + + /* create an Array of the Edges who have h set prior to rotate */ + numhidden = 0; + for(srchedge = em->edges.first;srchedge;srchedge = srchedge->next) + if(srchedge->h && ((srchedge->v1->f & SELECT) || (srchedge->v2->f & SELECT))) + numhidden++; + + hiddenedges = MEM_mallocN(sizeof(EditVert*)*numhidden+1, "RotateEdgeHiddenVerts"); + if(!hiddenedges) { + error("Malloc Was not happy!"); + return; + } + + numhidden = 0; + for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next) + if(srchedge->h && (srchedge->v1->f & SELECT || srchedge->v2->f & SELECT)) + hiddenedges[numhidden++] = srchedge; + + /* create the 2 new faces */ + if(fac1 == 3 && fac2 == 3) { + /* no need of reverse setup */ + + newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1); + newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1); + } + else if(fac1 == 4 && fac2 == 3) { + if(dir == 1) { + newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]); + newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1); + } else if (dir == 2) { + newFace[0]= EM_face_from_faces(face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]); + newFace[1]= EM_face_from_faces(face[1], face[0], 4+p[0][2], p[1][0], p[1][1], -1); + + verts[0][p[0][2]]->f |= SELECT; + verts[1][p[1][1]]->f |= SELECT; + } + } + else if(fac1 == 3 && fac2 == 4) { + if(dir == 1) { + newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1); + newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]); + } else if (dir == 2) { + newFace[0]= EM_face_from_faces(face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1); + newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], 4+p[0][2]); + + verts[0][p[0][1]]->f |= SELECT; + verts[1][p[1][2]]->f |= SELECT; + } + + } + else if(fac1 == 4 && fac2 == 4) { + if(dir == 1) { + newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]); + newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]); + } else if (dir == 2) { + newFace[0]= EM_face_from_faces(face[0], face[1], p[0][2], p[0][3], 4+p[1][1], 4+p[1][2]); + newFace[1]= EM_face_from_faces(face[1], face[0], p[1][2], p[1][3], 4+p[0][1], 4+p[0][2]); + + verts[0][p[0][2]]->f |= SELECT; + verts[1][p[1][2]]->f |= SELECT; + } + } + else + return; /* This should never happen */ + + if(dir == 1 || (fac1 == 3 && fac2 == 3)) { + verts[0][p[0][1]]->f |= SELECT; + verts[1][p[1][1]]->f |= SELECT; + } + + /* copy old edge's flags to new center edge*/ + for(srchedge=em->edges.first;srchedge;srchedge=srchedge->next) { + if((srchedge->v1->f & SELECT) && (srchedge->v2->f & SELECT)) { + srchedge->f = eed->f; + srchedge->h = eed->h; + srchedge->dir = eed->dir; + srchedge->seam = eed->seam; + srchedge->crease = eed->crease; + srchedge->bweight = eed->bweight; + } + } + + /* resetting hidden flag */ + for(numhidden--; numhidden>=0; numhidden--) + hiddenedges[numhidden]->h= 1; + + /* check for orhphan edges */ + for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next) + srchedge->f1= -1; + + /* cleanup */ + MEM_freeN(hiddenedges); + + /* get rid of the old edge and faces*/ + remedge(eed); + free_editedge(eed); + BLI_remlink(&em->faces, face[0]); + free_editface(face[0]); + BLI_remlink(&em->faces, face[1]); + free_editface(face[1]); +} + +/* only accepts 1 selected edge, or 2 selected faces */ +void edge_rotate_selected(int dir) +{ + EditEdge *eed; + EditFace *efa; + short edgeCount = 0; + + /*clear new flag for new edges, count selected edges */ + for(eed= G.editMesh->edges.first; eed; eed= eed->next) { + eed->f1= 0; + eed->f2 &= ~2; + if(eed->f & SELECT) edgeCount++; + } + + if(edgeCount>1) { + /* more selected edges, check faces */ + for(efa= G.editMesh->faces.first; efa; efa= efa->next) { + if(efa->f & SELECT) { + efa->e1->f1++; + efa->e2->f1++; + efa->e3->f1++; + if(efa->e4) efa->e4->f1++; + } + } + edgeCount= 0; + for(eed= G.editMesh->edges.first; eed; eed= eed->next) { + if(eed->f1==2) edgeCount++; + } + if(edgeCount==1) { + for(eed= G.editMesh->edges.first; eed; eed= eed->next) { + if(eed->f1==2) { + edge_rotate(eed,dir); + break; + } + } + } + else error("Select one edge or two adjacent faces"); + } + else if(edgeCount==1) { + for(eed= G.editMesh->edges.first; eed; eed= eed->next) { + if(eed->f & SELECT) { + EM_select_edge(eed, 0); + edge_rotate(eed,dir); + break; + } + } + } + else error("Select one edge or two adjacent faces"); + + + /* flush selected vertices (again) to edges/faces */ + EM_select_flush(); + + allqueue(REDRAWVIEW3D, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + +#ifdef WITH_VERSE + if(G.editMesh->vnode) + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); +#endif + + BIF_undo_push("Rotate Edge"); +} + +/******************* BEVEL CODE STARTS HERE ********************/ + +static void bevel_displace_vec(float *midvec, float *v1, float *v2, float *v3, float d, float no[3]) +{ + float a[3], c[3], n_a[3], n_c[3], mid[3], ac, ac2, fac; + + VecSubf(a, v1, v2); + VecSubf(c, v3, v2); + + Crossf(n_a, a, no); + Normalize(n_a); + Crossf(n_c, no, c); + Normalize(n_c); + + Normalize(a); + Normalize(c); + ac = Inpf(a, c); + + if (ac == 1 || ac == -1) { + midvec[0] = midvec[1] = midvec[2] = 0; + return; + } + ac2 = ac * ac; + fac = (float)sqrt((ac2 + 2*ac + 1)/(1 - ac2) + 1); + VecAddf(mid, n_c, n_a); + Normalize(mid); + VecMulf(mid, d * fac); + VecAddf(mid, mid, v2); + VecCopyf(midvec, mid); +} + +/* Finds the new point using the sinus law to extrapolate a triangle + Lots of sqrts which would not be good for a real time algo + Using the mid point of the extrapolation of both sides + Useless for coplanar quads, but that doesn't happen too often */ +static void fix_bevel_wrap(float *midvec, float *v1, float *v2, float *v3, float *v4, float d, float no[3]) +{ + float a[3], b[3], c[3], l_a, l_b, l_c, s_a, s_b, s_c, Pos1[3], Pos2[3], Dir[3]; + + VecSubf(a, v3, v2); + l_a = Normalize(a); + VecSubf(b, v4, v3); + Normalize(b); + VecSubf(c, v1, v2); + Normalize(c); + + s_b = Inpf(a, c); + s_b = (float)sqrt(1 - (s_b * s_b)); + s_a = Inpf(b, c); + s_a = (float)sqrt(1 - (s_a * s_a)); + VecMulf(a, -1); + s_c = Inpf(a, b); + s_c = (float)sqrt(1 - (s_c * s_c)); + + l_b = s_b * l_a / s_a; + l_c = s_c * l_a / s_a; + + VecMulf(b, l_b); + VecMulf(c, l_c); + + VecAddf(Pos1, v2, c); + VecAddf(Pos2, v3, b); + + VecAddf(Dir, Pos1, Pos2); + VecMulf(Dir, 0.5); + + bevel_displace_vec(midvec, v3, Dir, v2, d, no); + +} + + +static char detect_wrap(float *o_v1, float *o_v2, float *v1, float *v2, float *no) +{ + float o_a[3], a[3], o_c[3], c[3]; + + VecSubf(o_a, o_v1, o_v2); + VecSubf(a, v1, v2); + + Crossf(o_c, o_a, no); + Crossf(c, a, no); + + if (Inpf(c, o_c) <= 0) + return 1; + else + return 0; +} + +// Detects and fix a quad wrapping after the resize +// Arguments are the orginal verts followed by the final verts and then the bevel size and the normal +static void fix_bevel_quad_wrap(float *o_v1, float *o_v2, float *o_v3, float *o_v4, float *v1, float *v2, float *v3, float *v4, float d, float *no) +{ + float vec[3]; + char wrap[4]; + + // Quads can wrap partially. Watch out + wrap[0] = detect_wrap(o_v1, o_v2, v1, v2, no); // Edge 1-2 + wrap[1] = detect_wrap(o_v2, o_v3, v2, v3, no); // Edge 2-3 + wrap[2] = detect_wrap(o_v3, o_v4, v3, v4, no); // Edge 3-4 + wrap[3] = detect_wrap(o_v4, o_v1, v4, v1, no); // Edge 4-1 + + // Edge 1 inverted + if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 0) { + fix_bevel_wrap(vec, o_v2, o_v3, o_v4, o_v1, d, no); + VECCOPY(v1, vec); + VECCOPY(v2, vec); + } + // Edge 2 inverted + else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 0) { + fix_bevel_wrap(vec, o_v3, o_v4, o_v1, o_v2, d, no); + VECCOPY(v2, vec); + VECCOPY(v3, vec); + } + // Edge 3 inverted + else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) { + fix_bevel_wrap(vec, o_v4, o_v1, o_v2, o_v3, d, no); + VECCOPY(v3, vec); + VECCOPY(v4, vec); + } + // Edge 4 inverted + else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 1) { + fix_bevel_wrap(vec, o_v1, o_v2, o_v3, o_v4, d, no); + VECCOPY(v4, vec); + VECCOPY(v1, vec); + } + // Edge 2 and 4 inverted + else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 1) { + VecAddf(vec, v2, v3); + VecMulf(vec, 0.5); + VECCOPY(v2, vec); + VECCOPY(v3, vec); + VecAddf(vec, v1, v4); + VecMulf(vec, 0.5); + VECCOPY(v1, vec); + VECCOPY(v4, vec); + } + // Edge 1 and 3 inverted + else if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) { + VecAddf(vec, v1, v2); + VecMulf(vec, 0.5); + VECCOPY(v1, vec); + VECCOPY(v2, vec); + VecAddf(vec, v3, v4); + VecMulf(vec, 0.5); + VECCOPY(v3, vec); + VECCOPY(v4, vec); + } + // Totally inverted + else if (wrap[0] == 1 && wrap[1] == 1 && wrap[2] == 1 && wrap[3] == 1) { + VecAddf(vec, v1, v2); + VecAddf(vec, vec, v3); + VecAddf(vec, vec, v4); + VecMulf(vec, 0.25); + VECCOPY(v1, vec); + VECCOPY(v2, vec); + VECCOPY(v3, vec); + VECCOPY(v4, vec); + } + +} + +// Detects and fix a tri wrapping after the resize +// Arguments are the orginal verts followed by the final verts and the normal +// Triangles cannot wrap partially (not in this situation +static void fix_bevel_tri_wrap(float *o_v1, float *o_v2, float *o_v3, float *v1, float *v2, float *v3, float *no) +{ + if (detect_wrap(o_v1, o_v2, v1, v2, no)) { + float vec[3]; + VecAddf(vec, o_v1, o_v2); + VecAddf(vec, vec, o_v3); + VecMulf(vec, 1.0f/3.0f); + VECCOPY(v1, vec); + VECCOPY(v2, vec); + VECCOPY(v3, vec); + } +} + +static void bevel_shrink_faces(float d, int flag) +{ + EditMesh *em = G.editMesh; + EditFace *efa; + float vec[3], no[3], v1[3], v2[3], v3[3], v4[3]; + + /* move edges of all faces with efa->f1 & flag closer towards their centers */ + efa= em->faces.first; + while (efa) { + if (efa->f1 & flag) { + VECCOPY(v1, efa->v1->co); + VECCOPY(v2, efa->v2->co); + VECCOPY(v3, efa->v3->co); + VECCOPY(no, efa->n); + if (efa->v4 == NULL) { + bevel_displace_vec(vec, v1, v2, v3, d, no); + VECCOPY(efa->v2->co, vec); + bevel_displace_vec(vec, v2, v3, v1, d, no); + VECCOPY(efa->v3->co, vec); + bevel_displace_vec(vec, v3, v1, v2, d, no); + VECCOPY(efa->v1->co, vec); + + fix_bevel_tri_wrap(v1, v2, v3, efa->v1->co, efa->v2->co, efa->v3->co, no); + } else { + VECCOPY(v4, efa->v4->co); + bevel_displace_vec(vec, v1, v2, v3, d, no); + VECCOPY(efa->v2->co, vec); + bevel_displace_vec(vec, v2, v3, v4, d, no); + VECCOPY(efa->v3->co, vec); + bevel_displace_vec(vec, v3, v4, v1, d, no); + VECCOPY(efa->v4->co, vec); + bevel_displace_vec(vec, v4, v1, v2, d, no); + VECCOPY(efa->v1->co, vec); + + fix_bevel_quad_wrap(v1, v2, v3, v4, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, d, no); + } + } + efa= efa->next; + } +} + +static void bevel_shrink_draw(float d, int flag) +{ + EditMesh *em = G.editMesh; + EditFace *efa; + float vec[3], no[3], v1[3], v2[3], v3[3], v4[3], fv1[3], fv2[3], fv3[3], fv4[3]; + + /* move edges of all faces with efa->f1 & flag closer towards their centers */ + efa= em->faces.first; + while (efa) { + VECCOPY(v1, efa->v1->co); + VECCOPY(v2, efa->v2->co); + VECCOPY(v3, efa->v3->co); + VECCOPY(no, efa->n); + if (efa->v4 == NULL) { + bevel_displace_vec(vec, v1, v2, v3, d, no); + VECCOPY(fv2, vec); + bevel_displace_vec(vec, v2, v3, v1, d, no); + VECCOPY(fv3, vec); + bevel_displace_vec(vec, v3, v1, v2, d, no); + VECCOPY(fv1, vec); + + fix_bevel_tri_wrap(v1, v2, v3, fv1, fv2, fv3, no); + + glBegin(GL_LINES); + glVertex3fv(fv1); + glVertex3fv(fv2); + glEnd(); + glBegin(GL_LINES); + glVertex3fv(fv2); + glVertex3fv(fv3); + glEnd(); + glBegin(GL_LINES); + glVertex3fv(fv1); + glVertex3fv(fv3); + glEnd(); + } else { + VECCOPY(v4, efa->v4->co); + bevel_displace_vec(vec, v4, v1, v2, d, no); + VECCOPY(fv1, vec); + bevel_displace_vec(vec, v1, v2, v3, d, no); + VECCOPY(fv2, vec); + bevel_displace_vec(vec, v2, v3, v4, d, no); + VECCOPY(fv3, vec); + bevel_displace_vec(vec, v3, v4, v1, d, no); + VECCOPY(fv4, vec); + + fix_bevel_quad_wrap(v1, v2, v3, v4, fv1, fv2, fv3, fv4, d, no); + + glBegin(GL_LINES); + glVertex3fv(fv1); + glVertex3fv(fv2); + glEnd(); + glBegin(GL_LINES); + glVertex3fv(fv2); + glVertex3fv(fv3); + glEnd(); + glBegin(GL_LINES); + glVertex3fv(fv3); + glVertex3fv(fv4); + glEnd(); + glBegin(GL_LINES); + glVertex3fv(fv1); + glVertex3fv(fv4); + glEnd(); + } + efa= efa->next; + } +} + +static void bevel_mesh(float bsize, int allfaces) +{ + EditMesh *em = G.editMesh; +//#define BEV_DEBUG +/* Enables debug printfs and assigns material indices: */ +/* 2 = edge quad */ +/* 3 = fill polygon (vertex clusters) */ + + EditFace *efa, *example; //, *nextvl; + EditEdge *eed, *eed2; + EditVert *neweve[1024], *eve, *eve2, *eve3, *v1, *v2, *v3, *v4; //, *eve4; + //short found4, search; + //float f1, f2, f3, f4; + float cent[3], min[3], max[3]; + int a, b, c; + float limit= 0.001f; + + if(multires_test()) return; + + waitcursor(1); + + removedoublesflag(1, 0, limit); + + /* tag all original faces */ + efa= em->faces.first; + while (efa) { + efa->f1= 0; + if (faceselectedAND(efa, 1)||allfaces) { + efa->f1= 1; + efa->v1->f |= 128; + efa->v2->f |= 128; + efa->v3->f |= 128; + if (efa->v4) efa->v4->f |= 128; + } + efa->v1->f &= ~64; + efa->v2->f &= ~64; + efa->v3->f &= ~64; + if (efa->v4) efa->v4->f &= ~64; + + efa= efa->next; + } + +#ifdef BEV_DEBUG + fprintf(stderr,"bevel_mesh: split\n"); +#endif + + efa= em->faces.first; + while (efa) { + if (efa->f1 & 1) { + efa->f1-= 1; + v1= addvertlist(efa->v1->co, efa->v1); + v1->f= efa->v1->f & ~128; + efa->v1->tmp.v = v1; + + v1= addvertlist(efa->v2->co, efa->v2); + v1->f= efa->v2->f & ~128; + efa->v2->tmp.v = v1; + + v1= addvertlist(efa->v3->co, efa->v3); + v1->f= efa->v3->f & ~128; + efa->v3->tmp.v = v1; + + if (efa->v4) { + v1= addvertlist(efa->v4->co, efa->v4); + v1->f= efa->v4->f & ~128; + efa->v4->tmp.v = v1; + } + + /* Needs better adaption of creases? */ + addedgelist(efa->e1->v1->tmp.v, + efa->e1->v2->tmp.v, + efa->e1); + addedgelist(efa->e2->v1->tmp.v, + efa->e2->v2->tmp.v, + efa->e2); + addedgelist(efa->e3->v1->tmp.v, + efa->e3->v2->tmp.v, + efa->e3); + if (efa->e4) addedgelist(efa->e4->v1->tmp.v, + efa->e4->v2->tmp.v, + efa->e4); + + if(efa->v4) { + v1 = efa->v1->tmp.v; + v2 = efa->v2->tmp.v; + v3 = efa->v3->tmp.v; + v4 = efa->v4->tmp.v; + addfacelist(v1, v2, v3, v4, efa,NULL); + } else { + v1= efa->v1->tmp.v; + v2= efa->v2->tmp.v; + v3= efa->v3->tmp.v; + addfacelist(v1, v2, v3, 0, efa,NULL); + } + + efa= efa-> next; + } else { + efa= efa->next; + } + } + + for(efa= em->faces.first; efa; efa= efa->next) { + if( (efa->v1->f & 128) && (efa->v2->f & 128) && (efa->v3->f & 128) ) { + if(efa->v4==NULL || (efa->v4->f & 128)) efa->f |= 128; + } + } + + delfaceflag(128); // works with face flag now + + /* tag all faces for shrink*/ + efa= em->faces.first; + while (efa) { + if (faceselectedAND(efa, 1)||allfaces) { + efa->f1= 2; + } + efa= efa->next; + } + +#ifdef BEV_DEBUG + fprintf(stderr,"bevel_mesh: make edge quads\n"); +#endif + + /* find edges that are on each other and make quads between them */ + + eed= em->edges.first; + while(eed) { + eed->f2= eed->f1= 0; + if ( ((eed->v1->f & eed->v2->f) & 1) || allfaces) + eed->f1 |= 4; /* original edges */ + eed->tmp.v = 0; + eed= eed->next; + } + + eed= em->edges.first; + while (eed) { + if ( ((eed->f1 & 2)==0) && (eed->f1 & 4) ) { + eed2= em->edges.first; + while (eed2) { + if ( (eed2 != eed) && ((eed2->f1 & 2)==0) && (eed->f1 & 4) ) { + if ( + (eed->v1 != eed2->v1) && + (eed->v1 != eed2->v2) && + (eed->v2 != eed2->v1) && + (eed->v2 != eed2->v2) && ( + ( VecCompare(eed->v1->co, eed2->v1->co, limit) && + VecCompare(eed->v2->co, eed2->v2->co, limit) ) || + ( VecCompare(eed->v1->co, eed2->v2->co, limit) && + VecCompare(eed->v2->co, eed2->v1->co, limit) ) ) ) + { + +#ifdef BEV_DEBUG + fprintf(stderr, "bevel_mesh: edge quad\n"); +#endif + + eed->f1 |= 2; /* these edges are finished */ + eed2->f1 |= 2; + + example= NULL; + efa= em->faces.first; /* search example face (for mat_nr, ME_SMOOTH, ...) */ + while (efa) { + if ( (efa->e1 == eed) || + (efa->e2 == eed) || + (efa->e3 == eed) || + (efa->e4 && (efa->e4 == eed)) ) { + example= efa; + efa= NULL; + } + if (efa) efa= efa->next; + } + + neweve[0]= eed->v1; neweve[1]= eed->v2; + neweve[2]= eed2->v1; neweve[3]= eed2->v2; + + if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) { + efa= NULL; + + if (VecCompare(eed->v1->co, eed2->v2->co, limit)) { + efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], example,NULL); + } else { + efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], example,NULL); + } + + if(efa) { + float inp; + CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n); + inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2]; + if(inp < 0.0) flipface(efa); +#ifdef BEV_DEBUG + efa->mat_nr= 1; +#endif + } else fprintf(stderr,"bevel_mesh: error creating face\n"); + } + eed2= NULL; + } + } + if (eed2) eed2= eed2->next; + } + } + eed= eed->next; + } + + eed= em->edges.first; + while(eed) { + eed->f2= eed->f1= 0; + eed->f1= 0; + eed->v1->f1 &= ~1; + eed->v2->f1 &= ~1; + eed->tmp.v = 0; + eed= eed->next; + } + +#ifdef BEV_DEBUG + fprintf(stderr,"bevel_mesh: find clusters\n"); +#endif + + /* Look for vertex clusters */ + + eve= em->verts.first; + while (eve) { + eve->f &= ~(64|128); + eve->tmp.v = NULL; + eve= eve->next; + } + + /* eve->f: 128: first vertex in a list (->tmp.v) */ + /* 64: vertex is in a list */ + + eve= em->verts.first; + while (eve) { + eve2= em->verts.first; + eve3= NULL; + while (eve2) { + if ((eve2 != eve) && ((eve2->f & (64|128))==0)) { + if (VecCompare(eve->co, eve2->co, limit)) { + if ((eve->f & (128|64)) == 0) { + /* fprintf(stderr,"Found vertex cluster:\n *\n *\n"); */ + eve->f |= 128; + eve->tmp.v = eve2; + eve3= eve2; + } else if ((eve->f & 64) == 0) { + /* fprintf(stderr," *\n"); */ + if (eve3) eve3->tmp.v = eve2; + eve2->f |= 64; + eve3= eve2; + } + } + } + eve2= eve2->next; + if (!eve2) { + if (eve3) eve3->tmp.v = NULL; + } + } + eve= eve->next; + } + +#ifdef BEV_DEBUG + fprintf(stderr,"bevel_mesh: shrink faces\n"); +#endif + + bevel_shrink_faces(bsize, 2); + +#ifdef BEV_DEBUG + fprintf(stderr,"bevel_mesh: fill clusters\n"); +#endif + + /* Make former vertex clusters faces */ + + eve= em->verts.first; + while (eve) { + eve->f &= ~64; + eve= eve->next; + } + + eve= em->verts.first; + while (eve) { + if (eve->f & 128) { + eve->f &= ~128; + a= 0; + neweve[a]= eve; + eve2 = eve->tmp.v; + while (eve2) { + a++; + neweve[a]= eve2; + eve2 = eve2->tmp.v; + } + a++; + efa= NULL; + if (a>=3) { + example= NULL; + efa= em->faces.first; /* search example face */ + while (efa) { + if ( (efa->v1 == neweve[0]) || + (efa->v2 == neweve[0]) || + (efa->v3 == neweve[0]) || + (efa->v4 && (efa->v4 == neweve[0])) ) { + example= efa; + efa= NULL; + } + if (efa) efa= efa->next; + } +#ifdef BEV_DEBUG + fprintf(stderr,"bevel_mesh: Making %d-gon\n", a); +#endif + if (a>4) { + cent[0]= cent[1]= cent[2]= 0.0; + INIT_MINMAX(min, max); + for (b=0; b<a; b++) { + VecAddf(cent, cent, neweve[b]->co); + DO_MINMAX(neweve[b]->co, min, max); + } + cent[0]= (min[0]+max[0])/2; + cent[1]= (min[1]+max[1])/2; + cent[2]= (min[2]+max[2])/2; + eve2= addvertlist(cent, NULL); + eve2->f |= 1; + eed= em->edges.first; + while (eed) { + c= 0; + for (b=0; b<a; b++) + if ((neweve[b]==eed->v1) || (neweve[b]==eed->v2)) c++; + if (c==2) { + if(exist_face(eed->v1, eed->v2, eve2, 0)==0) { + efa= addfacelist(eed->v1, eed->v2, eve2, 0, example,NULL); +#ifdef BEV_DEBUG + efa->mat_nr= 2; +#endif + } + } + eed= eed->next; + } + } else if (a==4) { + if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) { + /* the order of vertices can be anything, three cases to check */ + if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) { + efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL); + } + else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) { + efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL); + } + else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) { + efa= addfacelist(neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL); + } + } + } + else if (a==3) { + if(exist_face(neweve[0], neweve[1], neweve[2], 0)==0) + efa= addfacelist(neweve[0], neweve[1], neweve[2], 0, example, NULL); + } + if(efa) { + float inp; + CalcNormFloat(neweve[0]->co, neweve[1]->co, neweve[2]->co, efa->n); + inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2]; + if(inp < 0.0) flipface(efa); +#ifdef BEV_DEBUG + efa->mat_nr= 2; +#endif + } + } + } + eve= eve->next; + } + + eve= em->verts.first; + while (eve) { + eve->f1= 0; + eve->f &= ~(128|64); + eve->tmp.v= NULL; + eve= eve->next; + } + + recalc_editnormals(); + waitcursor(0); + countall(); + allqueue(REDRAWVIEW3D, 0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + + removedoublesflag(1, 0, limit); + + /* flush selected vertices to edges/faces */ + EM_select_flush(); + +#undef BEV_DEBUG +} + +static void bevel_mesh_recurs(float bsize, short recurs, int allfaces) +{ + float d; + short nr; + + d= bsize; + for (nr=0; nr<recurs; nr++) { + bevel_mesh(d, allfaces); + if (nr==0) d /= 3; else d /= 2; + } +} + +void bevel_menu(void) { + BME_Mesh *bm; + BME_TransData_Head *td; + TransInfo *t; + int options, res, gbm_free = 0; + + t = BIF_GetTransInfo(); + if (!G.editBMesh) { + G.editBMesh = MEM_callocN(sizeof(*(G.editBMesh)),"bevel_menu() G.editBMesh"); + gbm_free = 1; + } + + G.editBMesh->options = BME_BEVEL_RUNNING | BME_BEVEL_SELECT; + G.editBMesh->res = 1; + + while(G.editBMesh->options & BME_BEVEL_RUNNING) { + options = G.editBMesh->options; + res = G.editBMesh->res; + bm = BME_editmesh_to_bmesh(G.editMesh); + BIF_undo_push("Pre-Bevel"); + free_editMesh(G.editMesh); + BME_bevel(bm,0.1f,res,options,0,0,&td); + BME_bmesh_to_editmesh(bm, td); + EM_selectmode_flush(); + G.editBMesh->bm = bm; + G.editBMesh->td = td; + initTransform(TFM_BEVEL,CTX_BMESH); + Transform(); + BME_free_transdata(td); + BME_free_mesh(bm); + if (t->state != TRANS_CONFIRM) { + BIF_undo(); + } + if (options == G.editBMesh->options) { + G.editBMesh->options &= ~BME_BEVEL_RUNNING; + } + } + + if (gbm_free) { + MEM_freeN(G.editBMesh); + G.editBMesh = NULL; + } +} + + +void bevel_menu_old() +{ + char Finished = 0, Canceled = 0, str[100], Recalc = 0; + short mval[2], oval[2], curval[2], event = 0, recurs = 1, nr; + float vec[3], d, drawd=0.0, center[3], fac = 1; + + getmouseco_areawin(mval); + oval[0] = mval[0]; oval[1] = mval[1]; + + // Silly hackish code to initialise the variable (warning if not done) + // while still drawing in the first iteration (and without using another variable) + curval[0] = mval[0] + 1; curval[1] = mval[1] + 1; + + // Init grabz for window to vec conversions + initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]); + window_to_3d(center, mval[0], mval[1]); + + if(button(&recurs, 1, 4, "Recursion:")==0) return; + + for (nr=0; nr<recurs-1; nr++) { + if (nr==0) fac += 1.0f/3.0f; else fac += 1.0f/(3 * nr * 2.0f); + } + + EM_set_flag_all(SELECT); + + SetBlenderCursor(SYSCURSOR); + + while (Finished == 0) + { + getmouseco_areawin(mval); + if (mval[0] != curval[0] || mval[1] != curval[1] || (Recalc == 1)) + { + Recalc = 0; + curval[0] = mval[0]; + curval[1] = mval[1]; + + window_to_3d(vec, mval[0]-oval[0], mval[1]-oval[1]); + d = Normalize(vec) / 10; + + + drawd = d * fac; + if (G.qual & LR_CTRLKEY) + drawd = (float) floor(drawd * 10.0f)/10.0f; + if (G.qual & LR_SHIFTKEY) + drawd /= 10; + + /*------------- Preview lines--------------- */ + + /* uses callback mechanism to draw it all in current area */ + scrarea_do_windraw(curarea); + + /* set window matrix to perspective, default an area returns with buttons transform */ + persp(PERSP_VIEW); + /* make a copy, for safety */ + glPushMatrix(); + /* multiply with the object transformation */ + mymultmatrix(G.obedit->obmat); + + glColor3ub(255, 255, 0); + + // PREVIEW CODE GOES HERE + bevel_shrink_draw(drawd, 2); + + /* restore matrix transform */ + glPopMatrix(); + + sprintf(str, "Bevel Size: %.4f LMB to confirm, RMB to cancel, SPACE to input directly.", drawd); + headerprint(str); + + /* this also verifies other area/windows for clean swap */ + screen_swapbuffers(); + + persp(PERSP_WIN); + + glDrawBuffer(GL_FRONT); + + BIF_ThemeColor(TH_WIRE); + + setlinestyle(3); + glBegin(GL_LINE_STRIP); + glVertex2sv(mval); + glVertex2sv(oval); + glEnd(); + setlinestyle(0); + + persp(PERSP_VIEW); + bglFlush(); // flush display for frontbuffer + glDrawBuffer(GL_BACK); + } + while(qtest()) { + short val=0; + event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle + + /* val==0 on key-release event */ + if(val && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event==ESCKEY)) { + if (event==RIGHTMOUSE || event==ESCKEY) + Canceled = 1; + Finished = 1; + } + else if (val && event==SPACEKEY) { + if (fbutton(&d, 0.000, 10.000, 10, 0, "Width:")!=0) { + drawd = d * fac; + Finished = 1; + } + } + else if (val) { + /* On any other keyboard event, recalc */ + Recalc = 1; + } + + } + } + if (Canceled==0) { + SetBlenderCursor(BC_WAITCURSOR); + bevel_mesh_recurs(drawd/fac, recurs, 1); + righthandfaces(1); + SetBlenderCursor(SYSCURSOR); + BIF_undo_push("Bevel"); + } +} + +/* *********** END BEVEL *********/ +typedef struct SlideUv { + float origuv[2]; + float *uv_up, *uv_down; + //float *fuv[4]; + LinkNode *fuv_list; +} SlideUv; + +typedef struct SlideVert { + EditEdge *up,*down; + EditVert origvert; +} SlideVert; + +int EdgeLoopDelete(void) { + + /* temporal flag setting so we keep UVs when deleting edge loops, + * this is a bit of a hack but it works how you would want in almost all cases */ + short uvcalc_flag_orig = G.scene->toolsettings->uvcalc_flag; + G.scene->toolsettings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT; + + if(!EdgeSlide(1, 1)) { + return 0; + } + + /* restore uvcalc flag */ + G.scene->toolsettings->uvcalc_flag = uvcalc_flag_orig; + + EM_select_more(); + removedoublesflag(1,0, 0.001); + EM_select_flush(); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + return 1; +} + +int EdgeSlide(short immediate, float imperc) +{ + NumInput num; + EditMesh *em = G.editMesh; + EditFace *efa; + EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL; + EditVert *ev, *nearest; + LinkNode *edgelist = NULL, *vertlist=NULL, *look; + GHash *vertgh; + + SlideVert *tempsv; + float perc = 0, percp = 0,vertdist, projectMat[4][4], viewMat[4][4]; + float shiftlabda= 0.0f,len = 0.0f; + int i = 0,j, numsel, numadded=0, timesthrough = 0, vertsel=0, prop=1, cancel = 0,flip=0; + int wasshift = 0; + + /* UV correction vars */ + GHash **uvarray= NULL; + int uvlay_tot= CustomData_number_of_layers(&G.editMesh->fdata, CD_MTFACE); + int uvlay_idx; + SlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL; + float uv_tmp[2]; + LinkNode *fuv_link; + + short event, draw=1; + short mval[2], mvalo[2]; + char str[128]; + float labda = 0.0f; + + initNumInput(&num); + + view3d_get_object_project_mat(curarea, G.obedit, projectMat, viewMat); + + mvalo[0] = -1; mvalo[1] = -1; + numsel =0; + + // Get number of selected edges and clear some flags + for(eed=em->edges.first;eed;eed=eed->next) { + eed->f1 = 0; + eed->f2 = 0; + if(eed->f & SELECT) numsel++; + } + + for(ev=em->verts.first;ev;ev=ev->next) { + ev->f1 = 0; + } + + //Make sure each edge only has 2 faces + // make sure loop doesn't cross face + for(efa=em->faces.first;efa;efa=efa->next) { + int ct = 0; + if(efa->e1->f & SELECT) { + ct++; + efa->e1->f1++; + if(efa->e1->f1 > 2) { + error("3+ face edge"); + return 0; + } + } + if(efa->e2->f & SELECT) { + ct++; + efa->e2->f1++; + if(efa->e2->f1 > 2) { + error("3+ face edge"); + return 0; + } + } + if(efa->e3->f & SELECT) { + ct++; + efa->e3->f1++; + if(efa->e3->f1 > 2) { + error("3+ face edge"); + return 0; + } + } + if(efa->e4 && efa->e4->f & SELECT) { + ct++; + efa->e4->f1++; + if(efa->e4->f1 > 2) { + error("3+ face edge"); + return 0; + } + } + // Make sure loop is not 2 edges of same face + if(ct > 1) { + error("loop crosses itself"); + return 0; + } + } + // Get # of selected verts + for(ev=em->verts.first;ev;ev=ev->next) { + if(ev->f & SELECT) vertsel++; + } + + // Test for multiple segments + if(vertsel > numsel+1) { + error("Was not a single edge loop"); + return 0; + } + + // Get the edgeloop in order - mark f1 with SELECT once added + for(eed=em->edges.first;eed;eed=eed->next) { + if((eed->f & SELECT) && !(eed->f1 & SELECT)) { + // If this is the first edge added, just put it in + if(!edgelist) { + BLI_linklist_prepend(&edgelist,eed); + numadded++; + first = eed; + last = eed; + eed->f1 = SELECT; + } else { + if(editedge_getSharedVert(eed, last)) { + BLI_linklist_append(&edgelist,eed); + eed->f1 = SELECT; + numadded++; + last = eed; + } else if(editedge_getSharedVert(eed, first)) { + BLI_linklist_prepend(&edgelist,eed); + eed->f1 = SELECT; + numadded++; + first = eed; + } + } + } + if(eed->next == NULL && numadded != numsel) { + eed=em->edges.first; + timesthrough++; + } + + // It looks like there was an unexpected case - Hopefully should not happen + if(timesthrough >= numsel*2) { + BLI_linklist_free(edgelist,NULL); + error("could not order loop"); + return 0; + } + } + + // Put the verts in order in a linklist + look = edgelist; + while(look) { + eed = look->link; + if(!vertlist) { + if(look->next) { + temp = look->next->link; + + //This is the first entry takes care of extra vert + if(eed->v1 != temp->v1 && eed->v1 != temp->v2) { + BLI_linklist_append(&vertlist,eed->v1); + eed->v1->f1 = 1; + } else { + BLI_linklist_append(&vertlist,eed->v2); + eed->v2->f1 = 1; + } + } else { + //This is the case that we only have 1 edge + BLI_linklist_append(&vertlist,eed->v1); + eed->v1->f1 = 1; + } + } + // for all the entries + if(eed->v1->f1 != 1) { + BLI_linklist_append(&vertlist,eed->v1); + eed->v1->f1 = 1; + } else if(eed->v2->f1 != 1) { + BLI_linklist_append(&vertlist,eed->v2); + eed->v2->f1 = 1; + } + look = look->next; + } + + // populate the SlideVerts + + vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + look = vertlist; + while(look) { + i=0; + j=0; + ev = look->link; + tempsv = (struct SlideVert*)MEM_mallocN(sizeof(struct SlideVert),"SlideVert"); + tempsv->up = NULL; + tempsv->down = NULL; + tempsv->origvert.co[0] = ev->co[0]; + tempsv->origvert.co[1] = ev->co[1]; + tempsv->origvert.co[2] = ev->co[2]; + tempsv->origvert.no[0] = ev->no[0]; + tempsv->origvert.no[1] = ev->no[1]; + tempsv->origvert.no[2] = ev->no[2]; + // i is total edges that vert is on + // j is total selected edges that vert is on + + for(eed=em->edges.first;eed;eed=eed->next) { + if(eed->v1 == ev || eed->v2 == ev) { + i++; + if(eed->f & SELECT) { + j++; + } + } + } + // If the vert is in the middle of an edge loop, it touches 2 selected edges and 2 unselected edges + if(i == 4 && j == 2) { + for(eed=em->edges.first;eed;eed=eed->next) { + if(editedge_containsVert(eed, ev)) { + if(!(eed->f & SELECT)) { + if(!tempsv->up) { + tempsv->up = eed; + } else if (!(tempsv->down)) { + tempsv->down = eed; + } + } + } + } + } + // If it is on the end of the loop, it touches 1 selected and as least 2 more unselected + if(i >= 3 && j == 1) { + for(eed=em->edges.first;eed;eed=eed->next) { + if(editedge_containsVert(eed, ev) && eed->f & SELECT) { + for(efa = em->faces.first;efa;efa=efa->next) { + if(editface_containsEdge(efa, eed)) { + if(editedge_containsVert(efa->e1, ev) && efa->e1 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e1; + } else if (!(tempsv->down)) { + tempsv->down = efa->e1; + } + } + if(editedge_containsVert(efa->e2, ev) && efa->e2 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e2; + } else if (!(tempsv->down)) { + tempsv->down = efa->e2; + } + } + if(editedge_containsVert(efa->e3, ev) && efa->e3 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e3; + } else if (!(tempsv->down)) { + tempsv->down = efa->e3; + } + } + if(efa->e4) { + if(editedge_containsVert(efa->e4, ev) && efa->e4 != eed) { + if(!tempsv->up) { + tempsv->up = efa->e4; + } else if (!(tempsv->down)) { + tempsv->down = efa->e4; + } + } + } + + } + } + } + } + } + if(i > 4 && j == 2) { + BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); + BLI_linklist_free(vertlist,NULL); + BLI_linklist_free(edgelist,NULL); + return 0; + } + BLI_ghash_insert(vertgh,ev,tempsv); + + look = look->next; + } + + // make sure the UPs nad DOWNs are 'faceloops' + // Also find the nearest slidevert to the cursor + getmouseco_areawin(mval); + look = vertlist; + nearest = NULL; + vertdist = -1; + while(look) { + tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); + + if(!tempsv->up || !tempsv->down) { + error("Missing rails"); + BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); + BLI_linklist_free(vertlist,NULL); + BLI_linklist_free(edgelist,NULL); + return 0; + } + + if(G.f & G_DRAW_EDGELEN) { + if(!(tempsv->up->f & SELECT)) { + tempsv->up->f |= SELECT; + tempsv->up->f2 |= 16; + } else { + tempsv->up->f2 |= ~16; + } + if(!(tempsv->down->f & SELECT)) { + tempsv->down->f |= SELECT; + tempsv->down->f2 |= 16; + } else { + tempsv->down->f2 |= ~16; + } + } + + if(look->next != NULL) { + SlideVert *sv; + + sv = BLI_ghash_lookup(vertgh,(EditVert*)look->next->link); + + if(sv) { + float tempdist, co[2]; + + if(!sharesFace(tempsv->up,sv->up)) { + EditEdge *swap; + swap = sv->up; + sv->up = sv->down; + sv->down = swap; + } + + view3d_project_float(curarea, tempsv->origvert.co, co, projectMat); + + tempdist = sqrt(pow(co[0] - mval[0],2)+pow(co[1] - mval[1],2)); + + if(vertdist < 0) { + vertdist = tempdist; + nearest = (EditVert*)look->link; + } else if ( tempdist < vertdist ) { + vertdist = tempdist; + nearest = (EditVert*)look->link; + } + } + } + + + + look = look->next; + } + + + if (uvlay_tot && (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { + int maxnum = 0; + uvarray = MEM_callocN( uvlay_tot * sizeof(GHash *), "SlideUVs Array"); + suv_last = slideuvs = MEM_callocN( uvlay_tot * (numadded+1) * sizeof(SlideUv), "SlideUVs"); /* uvLayers * verts */ + suv = NULL; + + for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { + + uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + for(ev=em->verts.first;ev;ev=ev->next) { + ev->tmp.l = 0; + } + look = vertlist; + while(look) { + float *uv_new; + tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); + + ev = look->link; + suv = NULL; + for(efa = em->faces.first;efa;efa=efa->next) { + if (ev->tmp.l != -1) { /* test for self, in this case its invalid */ + int k=-1; /* face corner */ + + /* Is this vert in the faces corner? */ + if (efa->v1==ev) k=0; + else if (efa->v2==ev) k=1; + else if (efa->v3==ev) k=2; + else if (efa->v4 && efa->v4==ev) k=3; + + if (k != -1) { + MTFace *tf = CustomData_em_get_n(&em->fdata, efa->data, CD_MTFACE, uvlay_idx); + EditVert *ev_up, *ev_down; + + uv_new = tf->uv[k]; + + if (ev->tmp.l) { + if (fabs(suv->origuv[0]-uv_new[0]) > 0.0001 || fabs(suv->origuv[1]-uv_new[1])) { + ev->tmp.l = -1; /* Tag as invalid */ + BLI_linklist_free(suv->fuv_list,NULL); + suv->fuv_list = NULL; + BLI_ghash_remove(uvarray[uvlay_idx],ev, NULL, NULL); + suv = NULL; + break; + } + } else { + ev->tmp.l = 1; + suv = suv_last; + + suv->fuv_list = NULL; + suv->uv_up = suv->uv_down = NULL; + suv->origuv[0] = uv_new[0]; + suv->origuv[1] = uv_new[1]; + + BLI_linklist_prepend(&suv->fuv_list, uv_new); + BLI_ghash_insert(uvarray[uvlay_idx],ev,suv); + + suv_last++; /* advance to next slide UV */ + maxnum++; + } + + /* Now get the uvs along the up or down edge if we can */ + if (suv) { + if (!suv->uv_up) { + ev_up = editedge_getOtherVert(tempsv->up,ev); + if (efa->v1==ev_up) suv->uv_up = tf->uv[0]; + else if (efa->v2==ev_up) suv->uv_up = tf->uv[1]; + else if (efa->v3==ev_up) suv->uv_up = tf->uv[2]; + else if (efa->v4 && efa->v4==ev_up) suv->uv_up = tf->uv[3]; + } + if (!suv->uv_down) { /* if the first face was apart of the up edge, it cant be apart of the down edge */ + ev_down = editedge_getOtherVert(tempsv->down,ev); + if (efa->v1==ev_down) suv->uv_down = tf->uv[0]; + else if (efa->v2==ev_down) suv->uv_down = tf->uv[1]; + else if (efa->v3==ev_down) suv->uv_down = tf->uv[2]; + else if (efa->v4 && efa->v4==ev_down) suv->uv_down = tf->uv[3]; + } + + /* Copy the pointers to the face UV's */ + BLI_linklist_prepend(&suv->fuv_list, uv_new); + } + } + } + } + look = look->next; + } + } /* end uv layer loop */ + } /* end uvlay_tot */ + + + + // we should have enough info now to slide + + len = 0.0f; + + percp = -1; + while(draw) { + /* For the % calculation */ + short mval[2]; + float rc[2]; + float v2[2], v3[2]; + EditVert *centerVert, *upVert, *downVert; + + getmouseco_areawin(mval); + + if (!immediate && (mval[0] == mvalo[0] && mval[1] == mvalo[1])) { + PIL_sleep_ms(10); + } else { + char *p = str;; + + mvalo[0] = mval[0]; + mvalo[1] = mval[1]; + + + tempsv = BLI_ghash_lookup(vertgh,nearest); + + centerVert = editedge_getSharedVert(tempsv->up, tempsv->down); + upVert = editedge_getOtherVert(tempsv->up, centerVert); + downVert = editedge_getOtherVert(tempsv->down, centerVert); + + view3d_project_float(curarea, upVert->co, v2, projectMat); + view3d_project_float(curarea, downVert->co, v3, projectMat); + + /* Determine the % on which the loop should be cut */ + + rc[0]= v3[0]-v2[0]; + rc[1]= v3[1]-v2[1]; + len= rc[0]*rc[0]+ rc[1]*rc[1]; + if (len==0) {len = 0.0001;} + + if ((G.qual & LR_SHIFTKEY)==0) { + wasshift = 0; + labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len; + } + else { + if (wasshift==0) { + wasshift = 1; + shiftlabda = labda; + } + labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len / 10.0 + shiftlabda; + } + + + if(labda<=0.0) labda=0.0; + else if(labda>=1.0)labda=1.0; + + perc=((1-labda)*2)-1; + + if(G.qual == 0) { + perc *= 100; + perc = floor(perc); + perc /= 100; + } else if (G.qual == LR_CTRLKEY) { + perc *= 10; + perc = floor(perc); + perc /= 10; + } + + if(prop == 0) { + len = VecLenf(upVert->co,downVert->co)*((perc+1)/2); + if(flip == 1) { + len = VecLenf(upVert->co,downVert->co) - len; + } + } + + if (hasNumInput(&num)) + { + applyNumInput(&num, &perc); + + if (prop) + { + perc = MIN2(perc, 1); + perc = MAX2(perc, -1); + } + else + { + len = MIN2(perc, VecLenf(upVert->co,downVert->co)); + len = MAX2(len, 0); + } + } + + //Adjust Edgeloop + if(immediate) { + perc = imperc; + } + percp = perc; + if(prop) { + look = vertlist; + while(look) { + EditVert *tempev; + ev = look->link; + tempsv = BLI_ghash_lookup(vertgh,ev); + + tempev = editedge_getOtherVert((perc>=0)?tempsv->up:tempsv->down, ev); + VecLerpf(ev->co, tempsv->origvert.co, tempev->co, fabs(perc)); + + if (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { + for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { + suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); + if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { + Vec2Lerpf(uv_tmp, suv->origuv, (perc>=0)?suv->uv_up:suv->uv_down, fabs(perc)); + fuv_link = suv->fuv_list; + while (fuv_link) { + VECCOPY2D(((float *)fuv_link->link), uv_tmp); + fuv_link = fuv_link->next; + } + } + } + } + + look = look->next; + } + } + else { + //Non prop code + look = vertlist; + while(look) { + float newlen; + ev = look->link; + tempsv = BLI_ghash_lookup(vertgh,ev); + newlen = (len / VecLenf(editedge_getOtherVert(tempsv->up,ev)->co,editedge_getOtherVert(tempsv->down,ev)->co)); + if(newlen > 1.0) {newlen = 1.0;} + if(newlen < 0.0) {newlen = 0.0;} + if(flip == 0) { + VecLerpf(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen)); + if (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { + /* dont do anything if no UVs */ + for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { + suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); + if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { + Vec2Lerpf(uv_tmp, suv->uv_down, suv->uv_up, fabs(newlen)); + fuv_link = suv->fuv_list; + while (fuv_link) { + VECCOPY2D(((float *)fuv_link->link), uv_tmp); + fuv_link = fuv_link->next; + } + } + } + } + } else{ + VecLerpf(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen)); + + if (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { + /* dont do anything if no UVs */ + for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { + suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); + if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { + Vec2Lerpf(uv_tmp, suv->uv_up, suv->uv_down, fabs(newlen)); + fuv_link = suv->fuv_list; + while (fuv_link) { + VECCOPY2D(((float *)fuv_link->link), uv_tmp); + fuv_link = fuv_link->next; + } + } + } + } + } + look = look->next; + } + + } + + // Highlight the Control Edges + scrarea_do_windraw(curarea); + persp(PERSP_VIEW); + glPushMatrix(); + mymultmatrix(G.obedit->obmat); + + glColor3ub(0, 255, 0); + glBegin(GL_LINES); + glVertex3fv(upVert->co); + glVertex3fv(downVert->co); + glEnd(); + + if(prop == 0) { + // draw start edge for non-prop + glPointSize(5); + glBegin(GL_POINTS); + glColor3ub(255,0,255); + if(flip) { + glVertex3fv(upVert->co); + } else { + glVertex3fv(downVert->co); + } + glEnd(); + } + + + glPopMatrix(); + + if(prop) { + p += sprintf(str, "(P)ercentage: "); + } else { + p += sprintf(str, "Non (P)rop Length: "); + } + + if (hasNumInput(&num)) + { + char num_str[20]; + + outputNumInput(&num, num_str); + p += sprintf(p, "%s", num_str); + } + else + { + if (prop) + { + p += sprintf(p, "%f", perc); + } + else + { + p += sprintf(p, "%f", len); + } + } + + + if (prop == 0) { + p += sprintf(p, ", Press (F) to flip control side"); + } + + headerprint(str); + screen_swapbuffers(); + } + if(!immediate) { + while(qtest()) { + short val=0; + event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle + + /* val==0 on key-release event */ + if (val) { + if(ELEM(event, ESCKEY, RIGHTMOUSE)) { + prop = 1; // Go back to prop mode + imperc = 0; // This is the % that gets set for immediate + immediate = 1; //Run through eval code 1 more time + cancel = 1; // Return -1 + mvalo[0] = -1; + } else if(ELEM3(event, PADENTER, LEFTMOUSE, RETKEY)) { + draw = 0; // End looping now + } else if(event==MIDDLEMOUSE) { + perc = 0; + immediate = 1; + } else if(event==PKEY) { + initNumInput(&num); /* reset num input */ + if (prop) { + prop = 0; + num.flag |= NUM_NO_NEGATIVE; + } + else { + prop = 1; + } + mvalo[0] = -1; + } else if(event==FKEY) { + (flip == 1) ? (flip = 0):(flip = 1); + mvalo[0] = -1; + } else if(ELEM(event, RIGHTARROWKEY, WHEELUPMOUSE)) { // Scroll through Control Edges + look = vertlist; + while(look) { + if(nearest == (EditVert*)look->link) { + if(look->next == NULL) { + nearest = (EditVert*)vertlist->link; + } else { + nearest = (EditVert*)look->next->link; + } + mvalo[0] = -1; + break; + } + look = look->next; + } + } else if(ELEM(event, LEFTARROWKEY, WHEELDOWNMOUSE)) { // Scroll through Control Edges + look = vertlist; + while(look) { + if(look->next) { + if(look->next->link == nearest) { + nearest = (EditVert*)look->link; + mvalo[0] = -1; + break; + } + } else { + if((EditVert*)vertlist->link == nearest) { + nearest = look->link; + mvalo[0] = -1; + break; + } + } + look = look->next; + } + } + + if (handleNumInput(&num, event)) + { + mvalo[0] = -1; /* NEED A BETTER WAY TO TRIGGER REDRAW */ + } + } + + } + } else { + draw = 0; + } + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + } + + + if(G.f & G_DRAW_EDGELEN) { + look = vertlist; + while(look) { + tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); + if(tempsv != NULL) { + tempsv->up->f &= !SELECT; + tempsv->down->f &= !SELECT; + } + look = look->next; + } + } + + force_draw(0); + + if(!immediate) + EM_automerge(0); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + scrarea_queue_winredraw(curarea); + + //BLI_ghash_free(edgesgh, freeGHash, NULL); + BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); + BLI_linklist_free(vertlist,NULL); + BLI_linklist_free(edgelist,NULL); + + if (uvlay_tot && (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { + for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { + BLI_ghash_free(uvarray[uvlay_idx], NULL, NULL); + } + MEM_freeN(uvarray); + MEM_freeN(slideuvs); + + suv = suv_last-1; + while (suv >= slideuvs) { + if (suv->fuv_list) { + BLI_linklist_free(suv->fuv_list,NULL); + } + suv--; + } + + allqueue(REDRAWIMAGE, 0); + } + + if(cancel == 1) { + return -1; + } + else { +#ifdef WITH_VERSE + if(G.editMesh->vnode) { + sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode); + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); + } +#endif + } + return 1; +} + +/* -------------------- More tools ------------------ */ + +void mesh_set_face_flags(short mode) +{ + EditMesh *em = G.editMesh; + EditFace *efa; + MTFace *tface; + short m_tex=0, m_tiles=0, m_shared=0, + m_light=0, m_invis=0, m_collision=0, + m_twoside=0, m_obcolor=0, m_halo=0, + m_billboard=0, m_shadow=0, m_text=0, + m_sort=0; + short flag = 0, change = 0; + + if (!EM_texFaceCheck()) { + error("not a mesh with uv/image layers"); + return; + } + + add_numbut(0, TOG|SHO, "Texture", 0, 0, &m_tex, NULL); + add_numbut(1, TOG|SHO, "Tiles", 0, 0, &m_tiles, NULL); + add_numbut(2, TOG|SHO, "Light", 0, 0, &m_light, NULL); + add_numbut(3, TOG|SHO, "Invisible", 0, 0, &m_invis, NULL); + add_numbut(4, TOG|SHO, "Collision", 0, 0, &m_collision, NULL); + add_numbut(5, TOG|SHO, "Shared", 0, 0, &m_shared, NULL); + add_numbut(6, TOG|SHO, "Twoside", 0, 0, &m_twoside, NULL); + add_numbut(7, TOG|SHO, "ObColor", 0, 0, &m_obcolor, NULL); + add_numbut(8, TOG|SHO, "Halo", 0, 0, &m_halo, NULL); + add_numbut(9, TOG|SHO, "Billboard", 0, 0, &m_billboard, NULL); + add_numbut(10, TOG|SHO, "Shadow", 0, 0, &m_shadow, NULL); + add_numbut(11, TOG|SHO, "Text", 0, 0, &m_text, NULL); + add_numbut(12, TOG|SHO, "Sort", 0, 0, &m_sort, NULL); + + if (!do_clever_numbuts((mode ? "Set Flags" : "Clear Flags"), 13, REDRAW)) + return; + + /* these 2 cant both be on */ + if (mode) /* are we seeting*/ + if (m_halo) + m_billboard = 0; + + if (m_tex) flag |= TF_TEX; + if (m_tiles) flag |= TF_TILES; + if (m_shared) flag |= TF_SHAREDCOL; + if (m_light) flag |= TF_LIGHT; + if (m_invis) flag |= TF_INVISIBLE; + if (m_collision) flag |= TF_DYNAMIC; + if (m_twoside) flag |= TF_TWOSIDE; + if (m_obcolor) flag |= TF_OBCOL; + if (m_halo) flag |= TF_BILLBOARD; + if (m_billboard) flag |= TF_BILLBOARD2; + if (m_shadow) flag |= TF_SHADOW; + if (m_text) flag |= TF_BMFONT; + if (m_sort) flag |= TF_ALPHASORT; + + if (flag==0) + return; + + efa= em->faces.first; + while(efa) { + if(efa->f & SELECT) { + tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + if (mode) tface->mode |= flag; + else tface->mode &= ~flag; + change = 1; + } + efa= efa->next; + } + + if (change) { + BIF_undo_push((mode ? "Set Flags" : "Clear Flags")); + + allqueue(REDRAWIMAGE, 0); + allqueue(REDRAWVIEW3D, 0); + } +} + +void mesh_set_smooth_faces(short event) +{ + EditMesh *em = G.editMesh; + EditFace *efa; + + if(G.obedit==0) return; + + if(G.obedit->type != OB_MESH) return; + + efa= em->faces.first; + while(efa) { + if(efa->f & SELECT) { + if(event==1) efa->flag |= ME_SMOOTH; + else if(event==0) efa->flag &= ~ME_SMOOTH; + } + efa= efa->next; + } + + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + + if(event==1) BIF_undo_push("Set Smooth"); + else if(event==0) BIF_undo_push("Set Solid"); +} + +/* helper to find edge for edge_rip */ +static float mesh_rip_edgedist(float mat[][4], float *co1, float *co2, short *mval) +{ + float vec1[3], vec2[3], mvalf[2]; + + view3d_project_float(curarea, co1, vec1, mat); + view3d_project_float(curarea, co2, vec2, mat); + mvalf[0]= (float)mval[0]; + mvalf[1]= (float)mval[1]; + + return PdistVL2Dfl(mvalf, vec1, vec2); +} + +/* helper for below */ +static void mesh_rip_setface(EditFace *sefa) +{ + /* put new vertices & edges in best face */ + if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v; + if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v; + if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v; + if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v; + + sefa->e1= addedgelist(sefa->v1, sefa->v2, sefa->e1); + sefa->e2= addedgelist(sefa->v2, sefa->v3, sefa->e2); + if(sefa->v4) { + sefa->e3= addedgelist(sefa->v3, sefa->v4, sefa->e3); + sefa->e4= addedgelist(sefa->v4, sefa->v1, sefa->e4); + } + else + sefa->e3= addedgelist(sefa->v3, sefa->v1, sefa->e3); + +} + +/* based on mouse cursor position, it defines how is being ripped */ +void mesh_rip(void) +{ + extern void faceloop_select(EditEdge *startedge, int select); + EditMesh *em = G.editMesh; + EditVert *eve, *nextve; + EditEdge *eed, *seed= NULL; + EditFace *efa, *sefa= NULL; + float projectMat[4][4], viewMat[4][4], vec[3], dist, mindist; + short doit= 1, mval[2],propmode,prop; + + propmode = G.scene->prop_mode; + G.scene->prop_mode = 0; + prop = G.scene->proportional; + G.scene->proportional = 0; + + /* select flush... vertices are important */ + EM_selectmode_set(); + + getmouseco_areawin(mval); + view3d_get_object_project_mat(curarea, G.obedit, projectMat, viewMat); + + /* find best face, exclude triangles and break on face select or faces with 2 edges select */ + mindist= 1000000.0f; + for(efa= em->faces.first; efa; efa=efa->next) { + if( efa->f & 1) + break; + if(efa->v4 && faceselectedOR(efa, SELECT) ) { + int totsel=0; + + if(efa->e1->f & SELECT) totsel++; + if(efa->e2->f & SELECT) totsel++; + if(efa->e3->f & SELECT) totsel++; + if(efa->e4->f & SELECT) totsel++; + + if(totsel>1) + break; + view3d_project_float(curarea, efa->cent, vec, projectMat); + dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) ); + if(dist<mindist) { + mindist= dist; + sefa= efa; + } + } + } + + if(efa) { + error("Can't perform ripping with faces selected this way"); + return; + } + if(sefa==NULL) { + error("No proper selection or faces included"); + return; + } + + + /* duplicate vertices, new vertices get selected */ + for(eve = em->verts.last; eve; eve= eve->prev) { + eve->tmp.v = NULL; + if(eve->f & SELECT) { + eve->tmp.v = addvertlist(eve->co, eve); + eve->f &= ~SELECT; + eve->tmp.v->f |= SELECT; + } + } + + /* find the best candidate edge */ + /* or one of sefa edges is selected... */ + if(sefa->e1->f & SELECT) seed= sefa->e2; + if(sefa->e2->f & SELECT) seed= sefa->e1; + if(sefa->e3->f & SELECT) seed= sefa->e2; + if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3; + + /* or we do the distance trick */ + if(seed==NULL) { + mindist= 1000000.0f; + if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) { + dist = mesh_rip_edgedist(projectMat, + sefa->e1->v1->co, + sefa->e1->v2->co, mval); + if(dist<mindist) { + seed= sefa->e1; + mindist= dist; + } + } + if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) { + dist = mesh_rip_edgedist(projectMat, + sefa->e2->v1->co, + sefa->e2->v2->co, mval); + if(dist<mindist) { + seed= sefa->e2; + mindist= dist; + } + } + if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) { + dist= mesh_rip_edgedist(projectMat, + sefa->e3->v1->co, + sefa->e3->v2->co, mval); + if(dist<mindist) { + seed= sefa->e3; + mindist= dist; + } + } + if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) { + dist= mesh_rip_edgedist(projectMat, + sefa->e4->v1->co, + sefa->e4->v2->co, mval); + if(dist<mindist) { + seed= sefa->e4; + mindist= dist; + } + } + } + + if(seed==NULL) { // never happens? + error("No proper edge found to start"); + return; + } + + faceloop_select(seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1 + + /* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */ + for(eed = em->edges.last; eed; eed= eed->prev) { + eed->tmp.v = NULL; + if((eed->v1->tmp.v) || (eed->v2->tmp.v)) { + EditEdge *newed; + + newed= addedgelist(eed->v1->tmp.v?eed->v1->tmp.v:eed->v1, + eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed); + if(eed->f & SELECT) { + eed->f &= ~SELECT; + newed->f |= SELECT; + } + eed->tmp.v = (EditVert *)newed; + } + } + + /* first clear edges to help finding neighbours */ + for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0; + + /* put new vertices & edges && flag in best face */ + mesh_rip_setface(sefa); + + /* starting with neighbours of best face, we loop over the seam */ + sefa->f1= 2; + doit= 1; + while(doit) { + doit= 0; + + for(efa= em->faces.first; efa; efa=efa->next) { + /* new vert in face */ + if (efa->v1->tmp.v || efa->v2->tmp.v || + efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) { + /* face is tagged with loop */ + if(efa->f1==1) { + mesh_rip_setface(efa); + efa->f1= 2; + doit= 1; + } + } + } + } + + /* remove loose edges, that were part of a ripped face */ + for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0; + for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0; + for(efa= em->faces.first; efa; efa=efa->next) { + efa->e1->f1= 1; + efa->e2->f1= 1; + efa->e3->f1= 1; + if(efa->e4) efa->e4->f1= 1; + } + + for(eed = em->edges.last; eed; eed= seed) { + seed= eed->prev; + if(eed->f1==0) { + if(eed->v1->tmp.v || eed->v2->tmp.v || + (eed->v1->f & SELECT) || (eed->v2->f & SELECT)) { + remedge(eed); + free_editedge(eed); + eed= NULL; + } + } + if(eed) { + eed->v1->f1= 1; + eed->v2->f1= 1; + } + } + + /* and remove loose selected vertices, that got duplicated accidentally */ + for(eve = em->verts.first; eve; eve= nextve) { + nextve= eve->next; + if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) { + BLI_remlink(&em->verts,eve); + free_editvert(eve); + } + } + + countall(); // apparently always needed when adding stuff, derived mesh + +#ifdef WITH_VERSE + if(G.editMesh->vnode) { + sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode); + sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); + } +#endif + + BIF_TransformSetUndo("Rip"); + initTransform(TFM_TRANSLATION, 0); + Transform(); + + G.scene->prop_mode = propmode; + G.scene->proportional = prop; +} + +void shape_propagate(){ + EditMesh *em = G.editMesh; + EditVert *ev = NULL; + Mesh* me = (Mesh*)G.obedit->data; + Key* ky = NULL; + KeyBlock* kb = NULL; + Base* base=NULL; + + + if(me->key){ + ky = me->key; + } else { + error("Object Has No Key"); + return; + } + + if(ky->block.first){ + for(ev = em->verts.first; ev ; ev = ev->next){ + if(ev->f & SELECT){ + for(kb=ky->block.first;kb;kb = kb->next){ + float *data; + data = kb->data; + VECCOPY(data+(ev->keyindex*3),ev->co); + } + } + } + } else { + error("Object Has No Blendshapes"); + return; + } + + //TAG Mesh Objects that share this data + for(base = G.scene->base.first; base; base = base->next){ + if(base->object && base->object->data == me){ + base->object->recalc = OB_RECALC_DATA; + } + } + + BIF_undo_push("Propagate Blendshape Verts"); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + return; +} + +void shape_copy_from_lerp(KeyBlock* thisBlock, KeyBlock* fromBlock) +{ + EditMesh *em = G.editMesh; + EditVert *ev = NULL; + short mval[2], curval[2], event = 0, finished = 0, canceled = 0, fullcopy=0 ; + float perc = 0; + char str[64]; + float *data, *odata; + + data = fromBlock->data; + odata = thisBlock->data; + + getmouseco_areawin(mval); + curval[0] = mval[0] + 1; curval[1] = mval[1] + 1; + + while (finished == 0) + { + getmouseco_areawin(mval); + if (mval[0] != curval[0] || mval[1] != curval[1]) + { + + if(mval[0] > curval[0]) + perc += 0.1; + else if(mval[0] < curval[0]) + perc -= 0.1; + + if(perc < 0) perc = 0; + if(perc > 1) perc = 1; + + curval[0] = mval[0]; + curval[1] = mval[1]; + + if(fullcopy == 1){ + perc = 1; + } + + for(ev = em->verts.first; ev ; ev = ev->next){ + if(ev->f & SELECT){ + VecLerpf(ev->co,odata+(ev->keyindex*3),data+(ev->keyindex*3),perc); + } + } + sprintf(str,"Blending at %d%c MMB to Copy at 100%c",(int)(perc*100),'%','%'); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + headerprint(str); + force_draw(0); + + if(fullcopy == 1){ + break; + } + + } else { + PIL_sleep_ms(10); + } + + while(qtest()) { + short val=0; + event= extern_qread(&val); + if(val){ + if(ELEM3(event, PADENTER, LEFTMOUSE, RETKEY)){ + finished = 1; + } + else if (event == MIDDLEMOUSE){ + fullcopy = 1; + } + else if (ELEM3(event,ESCKEY,RIGHTMOUSE,RIGHTMOUSE)){ + canceled = 1; + finished = 1; + } + } + } + } + if(!canceled) + BIF_undo_push("Copy Blendshape Verts"); + else + for(ev = em->verts.first; ev ; ev = ev->next){ + if(ev->f & SELECT){ + VECCOPY(ev->co, odata+(ev->keyindex*3)); + } + } + return; +} + + + +void shape_copy_select_from() +{ + Mesh* me = (Mesh*)G.obedit->data; + EditMesh *em = G.editMesh; + EditVert *ev = NULL; + int totverts = 0,curshape = G.obedit->shapenr; + + Key* ky = NULL; + KeyBlock *kb = NULL,*thisBlock = NULL; + int maxlen=32, nr=0, a=0; + char *menu; + + if(me->key){ + ky = me->key; + } else { + error("Object Has No Key"); + return; + } + + if(ky->block.first){ + for(kb=ky->block.first;kb;kb = kb->next){ + maxlen += 40; // Size of a block name + if(a == curshape-1){ + thisBlock = kb; + } + + a++; + } + a=0; + menu = MEM_callocN(maxlen, "Copy Shape Menu Text"); + strcpy(menu, "Copy Vert Positions from Shape %t|"); + for(kb=ky->block.first;kb;kb = kb->next){ + if(a != curshape-1){ + sprintf(menu,"%s %s %cx%d|",menu,kb->name,'%',a); + } + a++; + } + nr = pupmenu_col(menu, 20); + MEM_freeN(menu); + } else { + error("Object Has No Blendshapes"); + return; + } + + a = 0; + + for(kb=ky->block.first;kb;kb = kb->next){ + if(a == nr){ + + for(ev = em->verts.first;ev;ev = ev->next){ + totverts++; + } + + if(me->totvert != totverts){ + error("Shape Has had Verts Added/Removed, please cycle editmode before copying"); + return; + } + shape_copy_from_lerp(thisBlock,kb); + + return; + } + a++; + } + return; +} + +/* Collection Routines|Currently used by the improved merge code*/ +/* buildEdge_collection() creates a list of lists*/ +/* these lists are filled with edges that are topologically connected.*/ +/* This whole tool needs to be redone, its rather poorly implemented...*/ + +typedef struct Collection{ + struct Collection *next, *prev; + int index; + ListBase collectionbase; +} Collection; + +typedef struct CollectedEdge{ + struct CollectedEdge *next, *prev; + EditEdge *eed; +} CollectedEdge; + +#define MERGELIMIT 0.000001 + +static void build_edgecollection(ListBase *allcollections) +{ + EditEdge *eed; + Collection *edgecollection, *newcollection; + CollectedEdge *newedge; + + int currtag = 1; + short ebalanced = 0; + short collectionfound = 0; + + for (eed=G.editMesh->edges.first; eed; eed = eed->next){ + eed->tmp.l = 0; + eed->v1->tmp.l = 0; + eed->v2->tmp.l = 0; + } + + /*1st pass*/ + for(eed=G.editMesh->edges.first; eed; eed=eed->next){ + if(eed->f&SELECT){ + eed->v1->tmp.l = currtag; + eed->v2->tmp.l = currtag; + currtag +=1; + } + } + + /*2nd pass - Brute force. Loop through selected faces until there are no 'unbalanced' edges left (those with both vertices 'tmp.l' tag matching */ + while(ebalanced == 0){ + ebalanced = 1; + for(eed=G.editMesh->edges.first; eed; eed = eed->next){ + if(eed->f&SELECT){ + if(eed->v1->tmp.l != eed->v2->tmp.l) /*unbalanced*/{ + if(eed->v1->tmp.l > eed->v2->tmp.l && eed->v2->tmp.l !=0) eed->v1->tmp.l = eed->v2->tmp.l; + else if(eed->v1 != 0) eed->v2->tmp.l = eed->v1->tmp.l; + ebalanced = 0; + } + } + } + } + + /*3rd pass, set all the edge flags (unnessecary?)*/ + for(eed=G.editMesh->edges.first; eed; eed = eed->next){ + if(eed->f&SELECT) eed->tmp.l = eed->v1->tmp.l; + } + + for(eed=G.editMesh->edges.first; eed; eed=eed->next){ + if(eed->f&SELECT){ + if(allcollections->first){ + for(edgecollection = allcollections->first; edgecollection; edgecollection=edgecollection->next){ + if(edgecollection->index == eed->tmp.l){ + newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge"); + newedge->eed = eed; + BLI_addtail(&(edgecollection->collectionbase), newedge); + collectionfound = 1; + break; + } + else collectionfound = 0; + } + } + if(allcollections->first == NULL || collectionfound == 0){ + newcollection = MEM_mallocN(sizeof(Collection), "element collection"); + newcollection->index = eed->tmp.l; + newcollection->collectionbase.first = 0; + newcollection->collectionbase.last = 0; + + newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge"); + newedge->eed = eed; + + BLI_addtail(&(newcollection->collectionbase), newedge); + BLI_addtail(allcollections, newcollection); + } + } + + } +} + +static void freecollections(ListBase *allcollections) +{ + struct Collection *curcollection; + + for(curcollection = allcollections->first; curcollection; curcollection = curcollection->next) + BLI_freelistN(&(curcollection->collectionbase)); + BLI_freelistN(allcollections); +} + +/*Begin UV Edge Collapse Code + Like Edge subdivide, Edge Collapse should handle UV's intelligently, but since UV's are a per-face attribute, normal edge collapse will fail + in areas such as the boundries of 'UV islands'. So for each edge collection we need to build a set of 'welded' UV vertices and edges for it. + The welded UV edges can then be sorted and collapsed. +*/ +typedef struct wUV{ + struct wUV *next, *prev; + ListBase nodes; + float u, v; /*cached copy of UV coordinates pointed to by nodes*/ + EditVert *eve; + int f; +} wUV; + +typedef struct wUVNode{ + struct wUVNode *next, *prev; + float *u; /*pointer to original tface data*/ + float *v; /*pointer to original tface data*/ +} wUVNode; + +typedef struct wUVEdge{ + struct wUVEdge *next, *prev; + float v1uv[2], v2uv[2]; /*nasty.*/ + struct wUV *v1, *v2; /*oriented same as editedge*/ + EditEdge *eed; + int f; +} wUVEdge; + +typedef struct wUVEdgeCollect{ /*used for grouping*/ + struct wUVEdgeCollect *next, *prev; + wUVEdge *uved; + int id; +} wUVEdgeCollect; + +static void append_weldedUV(EditFace *efa, EditVert *eve, int tfindex, ListBase *uvverts) +{ + wUV *curwvert, *newwvert; + wUVNode *newnode; + int found; + MTFace *tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE); + + found = 0; + + for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ + if(curwvert->eve == eve && curwvert->u == tf->uv[tfindex][0] && curwvert->v == tf->uv[tfindex][1]){ + newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node"); + newnode->u = &(tf->uv[tfindex][0]); + newnode->v = &(tf->uv[tfindex][1]); + BLI_addtail(&(curwvert->nodes), newnode); + found = 1; + break; + } + } + + if(!found){ + newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node"); + newnode->u = &(tf->uv[tfindex][0]); + newnode->v = &(tf->uv[tfindex][1]); + + newwvert = MEM_callocN(sizeof(wUV), "Welded UV Vert"); + newwvert->u = *(newnode->u); + newwvert->v = *(newnode->v); + newwvert->eve = eve; + + BLI_addtail(&(newwvert->nodes), newnode); + BLI_addtail(uvverts, newwvert); + + } +} + +static void build_weldedUVs(ListBase *uvverts) +{ + EditFace *efa; + for(efa=G.editMesh->faces.first; efa; efa=efa->next){ + if(efa->v1->f1) append_weldedUV(efa, efa->v1, 0, uvverts); + if(efa->v2->f1) append_weldedUV(efa, efa->v2, 1, uvverts); + if(efa->v3->f1) append_weldedUV(efa, efa->v3, 2, uvverts); + if(efa->v4 && efa->v4->f1) append_weldedUV(efa, efa->v4, 3, uvverts); + } +} + +static void append_weldedUVEdge(EditFace *efa, EditEdge *eed, ListBase *uvedges) +{ + wUVEdge *curwedge, *newwedge; + int v1tfindex, v2tfindex, found; + MTFace *tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE); + + found = 0; + + if(eed->v1 == efa->v1) v1tfindex = 0; + else if(eed->v1 == efa->v2) v1tfindex = 1; + else if(eed->v1 == efa->v3) v1tfindex = 2; + else /* if(eed->v1 == efa->v4) */ v1tfindex = 3; + + if(eed->v2 == efa->v1) v2tfindex = 0; + else if(eed->v2 == efa->v2) v2tfindex = 1; + else if(eed->v2 == efa->v3) v2tfindex = 2; + else /* if(eed->v2 == efa->v4) */ v2tfindex = 3; + + for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){ + if(curwedge->eed == eed && curwedge->v1uv[0] == tf->uv[v1tfindex][0] && curwedge->v1uv[1] == tf->uv[v1tfindex][1] && curwedge->v2uv[0] == tf->uv[v2tfindex][0] && curwedge->v2uv[1] == tf->uv[v2tfindex][1]){ + found = 1; + break; //do nothing, we don't need another welded uv edge + } + } + + if(!found){ + newwedge = MEM_callocN(sizeof(wUVEdge), "Welded UV Edge"); + newwedge->v1uv[0] = tf->uv[v1tfindex][0]; + newwedge->v1uv[1] = tf->uv[v1tfindex][1]; + newwedge->v2uv[0] = tf->uv[v2tfindex][0]; + newwedge->v2uv[1] = tf->uv[v2tfindex][1]; + newwedge->eed = eed; + + BLI_addtail(uvedges, newwedge); + } +} + +static void build_weldedUVEdges(ListBase *uvedges, ListBase *uvverts) +{ + wUV *curwvert; + wUVEdge *curwedge; + EditFace *efa; + + for(efa=G.editMesh->faces.first; efa; efa=efa->next){ + if(efa->e1->f1) append_weldedUVEdge(efa, efa->e1, uvedges); + if(efa->e2->f1) append_weldedUVEdge(efa, efa->e2, uvedges); + if(efa->e3->f1) append_weldedUVEdge(efa, efa->e3, uvedges); + if(efa->e4 && efa->e4->f1) append_weldedUVEdge(efa, efa->e4, uvedges); + } + + + //link vertices: for each uvedge, search uvverts to populate v1 and v2 pointers + for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){ + for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ + if(curwedge->eed->v1 == curwvert->eve && curwedge->v1uv[0] == curwvert->u && curwedge->v1uv[1] == curwvert->v){ + curwedge->v1 = curwvert; + break; + } + } + for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ + if(curwedge->eed->v2 == curwvert->eve && curwedge->v2uv[0] == curwvert->u && curwedge->v2uv[1] == curwvert->v){ + curwedge->v2 = curwvert; + break; + } + } + } +} + +static void free_weldedUVs(ListBase *uvverts) +{ + wUV *curwvert; + for(curwvert = uvverts->first; curwvert; curwvert=curwvert->next) BLI_freelistN(&(curwvert->nodes)); + BLI_freelistN(uvverts); +} + +static void collapse_edgeuvs(void) +{ + ListBase uvedges, uvverts, allcollections; + wUVEdge *curwedge; + wUVNode *curwnode; + wUVEdgeCollect *collectedwuve, *newcollectedwuve; + Collection *wuvecollection, *newcollection; + int curtag, balanced, collectionfound= 0, vcount; + float avg[2]; + + if (!EM_texFaceCheck()) + return; + + uvverts.first = uvverts.last = uvedges.first = uvedges.last = allcollections.first = allcollections.last = NULL; + + build_weldedUVs(&uvverts); + build_weldedUVEdges(&uvedges, &uvverts); + + curtag = 0; + + for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ + curwedge->v1->f = curtag; + curwedge->v2->f = curtag; + curtag +=1; + } + + balanced = 0; + while(!balanced){ + balanced = 1; + for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ + if(curwedge->v1->f != curwedge->v2->f){ + if(curwedge->v1->f > curwedge->v2->f) curwedge->v1->f = curwedge->v2->f; + else curwedge->v2->f = curwedge->v1->f; + balanced = 0; + } + } + } + + for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next) curwedge->f = curwedge->v1->f; + + + for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ + if(allcollections.first){ + for(wuvecollection = allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){ + if(wuvecollection->index == curwedge->f){ + newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge"); + newcollectedwuve->uved = curwedge; + BLI_addtail(&(wuvecollection->collectionbase), newcollectedwuve); + collectionfound = 1; + break; + } + + else collectionfound = 0; + } + } + if(allcollections.first == NULL || collectionfound == 0){ + newcollection = MEM_callocN(sizeof(Collection), "element collection"); + newcollection->index = curwedge->f; + newcollection->collectionbase.first = 0; + newcollection->collectionbase.last = 0; + + newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge"); + newcollectedwuve->uved = curwedge; + + BLI_addtail(&(newcollection->collectionbase), newcollectedwuve); + BLI_addtail(&allcollections, newcollection); + } + } + + for(wuvecollection=allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){ + + vcount = avg[0] = avg[1] = 0; + + for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){ + avg[0] += collectedwuve->uved->v1uv[0]; + avg[1] += collectedwuve->uved->v1uv[1]; + + avg[0] += collectedwuve->uved->v2uv[0]; + avg[1] += collectedwuve->uved->v2uv[1]; + + vcount +=2; + + } + + avg[0] /= vcount; avg[1] /= vcount; + + for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){ + for(curwnode=collectedwuve->uved->v1->nodes.first; curwnode; curwnode=curwnode->next){ + *(curwnode->u) = avg[0]; + *(curwnode->v) = avg[1]; + } + for(curwnode=collectedwuve->uved->v2->nodes.first; curwnode; curwnode=curwnode->next){ + *(curwnode->u) = avg[0]; + *(curwnode->v) = avg[1]; + } + } + } + + free_weldedUVs(&uvverts); + BLI_freelistN(&uvedges); + freecollections(&allcollections); +} + +/*End UV Edge collapse code*/ + +static void collapseuvs(EditVert *mergevert) +{ + EditFace *efa; + MTFace *tf; + int uvcount; + float uvav[2]; + + if (!EM_texFaceCheck()) + return; + + uvcount = 0; + uvav[0] = 0; + uvav[1] = 0; + + for(efa = G.editMesh->faces.first; efa; efa=efa->next){ + tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE); + + if(efa->v1->f1 && ELEM(mergevert, NULL, efa->v1)) { + uvav[0] += tf->uv[0][0]; + uvav[1] += tf->uv[0][1]; + uvcount += 1; + } + if(efa->v2->f1 && ELEM(mergevert, NULL, efa->v2)){ + uvav[0] += tf->uv[1][0]; + uvav[1] += tf->uv[1][1]; + uvcount += 1; + } + if(efa->v3->f1 && ELEM(mergevert, NULL, efa->v3)){ + uvav[0] += tf->uv[2][0]; + uvav[1] += tf->uv[2][1]; + uvcount += 1; + } + if(efa->v4 && efa->v4->f1 && ELEM(mergevert, NULL, efa->v4)){ + uvav[0] += tf->uv[3][0]; + uvav[1] += tf->uv[3][1]; + uvcount += 1; + } + } + + if(uvcount > 0) { + uvav[0] /= uvcount; + uvav[1] /= uvcount; + + for(efa = G.editMesh->faces.first; efa; efa=efa->next){ + tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE); + + if(efa->v1->f1){ + tf->uv[0][0] = uvav[0]; + tf->uv[0][1] = uvav[1]; + } + if(efa->v2->f1){ + tf->uv[1][0] = uvav[0]; + tf->uv[1][1] = uvav[1]; + } + if(efa->v3->f1){ + tf->uv[2][0] = uvav[0]; + tf->uv[2][1] = uvav[1]; + } + if(efa->v4 && efa->v4->f1){ + tf->uv[3][0] = uvav[0]; + tf->uv[3][1] = uvav[1]; + } + } + } +} + +int collapseEdges(void) +{ + EditVert *eve; + EditEdge *eed; + + ListBase allcollections; + CollectedEdge *curredge; + Collection *edgecollection; + + int totedges, groupcount, mergecount,vcount; + float avgcount[3]; + + allcollections.first = 0; + allcollections.last = 0; + + mergecount = 0; + + if(multires_test()) return 0; + + build_edgecollection(&allcollections); + groupcount = BLI_countlist(&allcollections); + + + for(edgecollection = allcollections.first; edgecollection; edgecollection = edgecollection->next){ + totedges = BLI_countlist(&(edgecollection->collectionbase)); + mergecount += totedges; + avgcount[0] = 0; avgcount[1] = 0; avgcount[2] = 0; + + vcount = 0; + + for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ + avgcount[0] += ((EditEdge*)curredge->eed)->v1->co[0]; + avgcount[1] += ((EditEdge*)curredge->eed)->v1->co[1]; + avgcount[2] += ((EditEdge*)curredge->eed)->v1->co[2]; + + avgcount[0] += ((EditEdge*)curredge->eed)->v2->co[0]; + avgcount[1] += ((EditEdge*)curredge->eed)->v2->co[1]; + avgcount[2] += ((EditEdge*)curredge->eed)->v2->co[2]; + + vcount +=2; + } + + avgcount[0] /= vcount; avgcount[1] /=vcount; avgcount[2] /= vcount; + + for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ + VECCOPY(((EditEdge*)curredge->eed)->v1->co,avgcount); + VECCOPY(((EditEdge*)curredge->eed)->v2->co,avgcount); + } + + if (EM_texFaceCheck()) { + /*uv collapse*/ + for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0; + for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0; + for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ + curredge->eed->v1->f1 = 1; + curredge->eed->v2->f1 = 1; + curredge->eed->f1 = 1; + } + collapse_edgeuvs(); + } + + } + freecollections(&allcollections); + removedoublesflag(1, 0, MERGELIMIT); + /*get rid of this!*/ + countall(); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + if (EM_texFaceCheck()) + allqueue(REDRAWIMAGE, 0); + return mergecount; +} + +int merge_firstlast(int first, int uvmerge) +{ + EditVert *eve,*mergevert; + EditSelection *ese; + + if(multires_test()) return 0; + + /* do sanity check in mergemenu in edit.c ?*/ + if(first == 0){ + ese = G.editMesh->selected.last; + mergevert= (EditVert*)ese->data; + } + else{ + ese = G.editMesh->selected.first; + mergevert = (EditVert*)ese->data; + } + + if(mergevert->f&SELECT){ + for (eve=G.editMesh->verts.first; eve; eve=eve->next){ + if (eve->f&SELECT) + VECCOPY(eve->co,mergevert->co); + } + } + + if(uvmerge && CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)){ + + for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0; + for(eve=G.editMesh->verts.first; eve; eve=eve->next){ + if(eve->f&SELECT) eve->f1 = 1; + } + collapseuvs(mergevert); + } + + countall(); + return removedoublesflag(1, 0, MERGELIMIT); +} + +int merge_target(int target, int uvmerge) +{ + EditVert *eve; + + if(multires_test()) return 0; + + if(target) snap_sel_to_curs(); + else snap_to_center(); + + if(uvmerge && CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)){ + for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0; + for(eve=G.editMesh->verts.first; eve; eve=eve->next){ + if(eve->f&SELECT) eve->f1 = 1; + } + collapseuvs(NULL); + } + + countall(); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + return removedoublesflag(1, 0, MERGELIMIT); + +} +#undef MERGELIMIT + +typedef struct PathNode{ + int u; + int visited; + ListBase edges; +} PathNode; + +typedef struct PathEdge{ + struct PathEdge *next, *prev; + int v; + float w; +} PathEdge; + +void pathselect(void) +{ + EditVert *eve, *s, *t; + EditEdge *eed; + EditSelection *ese; + PathEdge *newpe, *currpe; + PathNode *currpn; + PathNode *Q; + int v, *previous, pathvert, pnindex; /*pnindex redundant?*/ + int unbalanced, totnodes; + short physical; + float *cost; + Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/ + + s = t = NULL; + + countall(); /*paranoid?*/ + + ese = ((EditSelection*)G.editMesh->selected.last); + if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT){ + physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0"); + + t = (EditVert*)ese->data; + s = (EditVert*)ese->prev->data; + + /*need to find out if t is actually reachable by s....*/ + for(eve=G.editMesh->verts.first; eve; eve=eve->next){ + eve->f1 = 0; + } + + s->f1 = 1; + + unbalanced = 1; + totnodes = 1; + while(unbalanced){ + unbalanced = 0; + for(eed=G.editMesh->edges.first; eed; eed=eed->next){ + if(!eed->h){ + if(eed->v1->f1 && !eed->v2->f1){ + eed->v2->f1 = 1; + totnodes++; + unbalanced = 1; + } + else if(eed->v2->f1 && !eed->v1->f1){ + eed->v1->f1 = 1; + totnodes++; + unbalanced = 1; + } + } + } + } + + + + if(s->f1 && t->f1){ /*t can be reached by s*/ + Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes"); + totnodes = 0; + for(eve=G.editMesh->verts.first; eve; eve=eve->next){ + if(eve->f1){ + Q[totnodes].u = totnodes; + Q[totnodes].edges.first = 0; + Q[totnodes].edges.last = 0; + Q[totnodes].visited = 0; + eve->tmp.p = &(Q[totnodes]); + totnodes++; + } + else eve->tmp.p = NULL; + } + + for(eed=G.editMesh->edges.first; eed; eed=eed->next){ + if(!eed->h){ + if(eed->v1->f1){ + currpn = ((PathNode*)eed->v1->tmp.p); + + newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge"); + newpe->v = ((PathNode*)eed->v2->tmp.p)->u; + if(physical){ + newpe->w = VecLenf(eed->v1->co, eed->v2->co); + } + else newpe->w = 1; + newpe->next = 0; + newpe->prev = 0; + BLI_addtail(&(currpn->edges), newpe); + } + if(eed->v2->f1){ + currpn = ((PathNode*)eed->v2->tmp.p); + newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge"); + newpe->v = ((PathNode*)eed->v1->tmp.p)->u; + if(physical){ + newpe->w = VecLenf(eed->v1->co, eed->v2->co); + } + else newpe->w = 1; + newpe->next = 0; + newpe->prev = 0; + BLI_addtail(&(currpn->edges), newpe); + } + } + } + + heap = BLI_heap_new(); + cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs"); + previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices"); + + for(v=0; v < totnodes; v++){ + cost[v] = 1000000; + previous[v] = -1; /*array of indices*/ + } + + pnindex = ((PathNode*)s->tmp.p)->u; + cost[pnindex] = 0; + BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex)); + + while( !BLI_heap_empty(heap) ){ + + pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap)); + currpn = &(Q[pnindex]); + + if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/ + break; + + for(currpe=currpn->edges.first; currpe; currpe=currpe->next){ + if(!Q[currpe->v].visited){ + if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){ + cost[currpe->v] = cost[currpn->u] + currpe->w; + previous[currpe->v] = currpn->u; + Q[currpe->v].visited = 1; + BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v)); + } + } + } + } + + pathvert = ((PathNode*)t->tmp.p)->u; + while(pathvert != -1){ + for(eve=G.editMesh->verts.first; eve; eve=eve->next){ + if(eve->f1){ + if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT; + } + } + pathvert = previous[pathvert]; + } + + for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges)); + MEM_freeN(Q); + MEM_freeN(cost); + MEM_freeN(previous); + BLI_heap_free(heap, NULL); + EM_select_flush(); + countall(); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + if (EM_texFaceCheck()) + allqueue(REDRAWIMAGE, 0); + } + } + else{ + error("Path Selection requires that exactly two vertices be selected"); + return; + } +} + +void region_to_loop(void) +{ + EditEdge *eed; + EditFace *efa; + + if(G.totfacesel){ + for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0; + + for(efa=G.editMesh->faces.first; efa; efa=efa->next){ + if(efa->f&SELECT){ + efa->e1->f1++; + efa->e2->f1++; + efa->e3->f1++; + if(efa->e4) + efa->e4->f1++; + } + } + + EM_clear_flag_all(SELECT); + + for(eed=G.editMesh->edges.first; eed; eed=eed->next){ + if(eed->f1 == 1) EM_select_edge(eed, 1); + } + + G.scene->selectmode = SCE_SELECT_EDGE; + EM_selectmode_set(); + countall(); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + if (EM_texFaceCheck()) + allqueue(REDRAWIMAGE, 0); + BIF_undo_push("Face Region to Edge Loop"); + + } +} + +static int validate_loop(Collection *edgecollection) +{ + EditEdge *eed; + EditFace *efa; + CollectedEdge *curredge; + + /*1st test*/ + for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ + curredge->eed->v1->f1 = 0; + curredge->eed->v2->f1 = 0; + } + for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ + curredge->eed->v1->f1++; + curredge->eed->v2->f1++; + } + for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ + if(curredge->eed->v1->f1 > 2) return(0); else + if(curredge->eed->v2->f1 > 2) return(0); + } + + /*2nd test*/ + for(eed = G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0; + for(efa=G.editMesh->faces.first; efa; efa=efa->next){ + efa->e1->f1++; + efa->e2->f1++; + efa->e3->f1++; + if(efa->e4) efa->e4->f1++; + } + for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ + if(curredge->eed->f1 > 2) return(0); + } + return(1); +} + +static int loop_bisect(Collection *edgecollection){ + + EditFace *efa, *sf1, *sf2; + EditEdge *eed, *sed; + CollectedEdge *curredge; + int totsf1, totsf2, unbalanced,balancededges; + + for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = eed->f2 = 0; + for(efa=G.editMesh->faces.first; efa; efa=efa->next) efa->f1 = 0; + + for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next) curredge->eed->f1 = 1; + + sf1 = sf2 = NULL; + sed = ((CollectedEdge*)edgecollection->collectionbase.first)->eed; + + for(efa=G.editMesh->faces.first; efa; efa=efa->next){ + if(sf2) break; + else if(sf1){ + if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf2 = efa; + } + else{ + if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf1 = efa; + } + } + + if(sf1==NULL || sf2==NULL) + return(-1); + + if(!(sf1->e1->f1)) sf1->e1->f2 = 1; + if(!(sf1->e2->f1)) sf1->e2->f2 = 1; + if(!(sf1->e3->f1)) sf1->e3->f2 = 1; + if(sf1->e4 && !(sf1->e4->f1)) sf1->e4->f2 = 1; + sf1->f1 = 1; + totsf1 = 1; + + if(!(sf2->e1->f1)) sf2->e1->f2 = 2; + if(!(sf2->e2->f1)) sf2->e2->f2 = 2; + if(!(sf2->e3->f1)) sf2->e3->f2 = 2; + if(sf2->e4 && !(sf2->e4->f1)) sf2->e4->f2 = 2; + sf2->f1 = 2; + totsf2 = 1; + + /*do sf1*/ + unbalanced = 1; + while(unbalanced){ + unbalanced = 0; + for(efa=G.editMesh->faces.first; efa; efa=efa->next){ + balancededges = 0; + if(efa->f1 == 0){ + if(efa->e1->f2 == 1 || efa->e2->f2 == 1 || efa->e3->f2 == 1 || ( (efa->e4) ? efa->e4->f2 == 1 : 0) ){ + balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 1; + balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 1; + balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 1; + if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 1; + if(balancededges){ + unbalanced = 1; + efa->f1 = 1; + totsf1++; + } + } + } + } + } + + /*do sf2*/ + unbalanced = 1; + while(unbalanced){ + unbalanced = 0; + for(efa=G.editMesh->faces.first; efa; efa=efa->next){ + balancededges = 0; + if(efa->f1 == 0){ + if(efa->e1->f2 == 2 || efa->e2->f2 == 2 || efa->e3->f2 == 2 || ( (efa->e4) ? efa->e4->f2 == 2 : 0) ){ + balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 2; + balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 2; + balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 2; + if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 2; + if(balancededges){ + unbalanced = 1; + efa->f1 = 2; + totsf2++; + } + } + } + } + } + + if(totsf1 < totsf2) return(1); + else return(2); +} + +void loop_to_region(void) +{ + EditFace *efa; + ListBase allcollections={NULL,NULL}; + Collection *edgecollection; + int testflag; + + build_edgecollection(&allcollections); + + for(edgecollection = (Collection *)allcollections.first; edgecollection; edgecollection=edgecollection->next){ + if(validate_loop(edgecollection)){ + testflag = loop_bisect(edgecollection); + for(efa=G.editMesh->faces.first; efa; efa=efa->next){ + if(efa->f1 == testflag){ + if(efa->f&SELECT) EM_select_face(efa, 0); + else EM_select_face(efa,1); + } + } + } + } + + for(efa=G.editMesh->faces.first; efa; efa=efa->next){ /*fix this*/ + if(efa->f&SELECT) EM_select_face(efa,1); + } + + countall(); + freecollections(&allcollections); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + if (EM_texFaceCheck()) + allqueue(REDRAWIMAGE, 0); + BIF_undo_push("Edge Loop to Face Region"); +} + + +/* texface and vertex color editmode tools for the face menu */ + +void mesh_rotate_uvs(void) +{ + EditMesh *em = G.editMesh; + EditFace *efa; + short change = 0, ccw; + MTFace *tf; + float u1, v1; + + if (!EM_texFaceCheck()) { + error("mesh has no uv/image layers"); + return; + } + + ccw = (G.qual == LR_SHIFTKEY); + + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + u1= tf->uv[0][0]; + v1= tf->uv[0][1]; + + if (ccw) { + if(efa->v4) { + tf->uv[0][0]= tf->uv[3][0]; + tf->uv[0][1]= tf->uv[3][1]; + + tf->uv[3][0]= tf->uv[2][0]; + tf->uv[3][1]= tf->uv[2][1]; + } else { + tf->uv[0][0]= tf->uv[2][0]; + tf->uv[0][1]= tf->uv[2][1]; + } + + tf->uv[2][0]= tf->uv[1][0]; + tf->uv[2][1]= tf->uv[1][1]; + + tf->uv[1][0]= u1; + tf->uv[1][1]= v1; + } else { + tf->uv[0][0]= tf->uv[1][0]; + tf->uv[0][1]= tf->uv[1][1]; + + tf->uv[1][0]= tf->uv[2][0]; + tf->uv[1][1]= tf->uv[2][1]; + + if(efa->v4) { + tf->uv[2][0]= tf->uv[3][0]; + tf->uv[2][1]= tf->uv[3][1]; + + tf->uv[3][0]= u1; + tf->uv[3][1]= v1; + } + else { + tf->uv[2][0]= u1; + tf->uv[2][1]= v1; + } + } + change = 1; + } + } + + if (change) { + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + BIF_undo_push("Rotate UV face"); + } +} + +void mesh_mirror_uvs(void) +{ + EditMesh *em = G.editMesh; + EditFace *efa; + short change = 0, altaxis; + MTFace *tf; + float u1, v1; + + if (!EM_texFaceCheck()) { + error("mesh has no uv/image layers"); + return; + } + + altaxis = (G.qual == LR_SHIFTKEY); + + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT) { + tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + if (altaxis) { + u1= tf->uv[1][0]; + v1= tf->uv[1][1]; + if(efa->v4) { + + tf->uv[1][0]= tf->uv[2][0]; + tf->uv[1][1]= tf->uv[2][1]; + + tf->uv[2][0]= u1; + tf->uv[2][1]= v1; + + u1= tf->uv[3][0]; + v1= tf->uv[3][1]; + + tf->uv[3][0]= tf->uv[0][0]; + tf->uv[3][1]= tf->uv[0][1]; + + tf->uv[0][0]= u1; + tf->uv[0][1]= v1; + } + else { + tf->uv[1][0]= tf->uv[2][0]; + tf->uv[1][1]= tf->uv[2][1]; + tf->uv[2][0]= u1; + tf->uv[2][1]= v1; + } + + } else { + u1= tf->uv[0][0]; + v1= tf->uv[0][1]; + if(efa->v4) { + + tf->uv[0][0]= tf->uv[1][0]; + tf->uv[0][1]= tf->uv[1][1]; + + tf->uv[1][0]= u1; + tf->uv[1][1]= v1; + + u1= tf->uv[3][0]; + v1= tf->uv[3][1]; + + tf->uv[3][0]= tf->uv[2][0]; + tf->uv[3][1]= tf->uv[2][1]; + + tf->uv[2][0]= u1; + tf->uv[2][1]= v1; + } + else { + tf->uv[0][0]= tf->uv[1][0]; + tf->uv[0][1]= tf->uv[1][1]; + tf->uv[1][0]= u1; + tf->uv[1][1]= v1; + } + } + change = 1; + } + } + + if (change) { + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + BIF_undo_push("Mirror UV face"); + } +} + +void mesh_rotate_colors(void) +{ + EditMesh *em = G.editMesh; + EditFace *efa; + short change = 0, ccw; + MCol tmpcol, *mcol; + if (!EM_vertColorCheck()) { + error("mesh has no color layers"); + return; + } + + ccw = (G.qual == LR_SHIFTKEY); + + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT) { + mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); + tmpcol= mcol[0]; + + if (ccw) { + if(efa->v4) { + mcol[0]= mcol[3]; + mcol[3]= mcol[2]; + } else { + mcol[0]= mcol[2]; + } + mcol[2]= mcol[1]; + mcol[1]= tmpcol; + } else { + mcol[0]= mcol[1]; + mcol[1]= mcol[2]; + + if(efa->v4) { + mcol[2]= mcol[3]; + mcol[3]= tmpcol; + } + else + mcol[2]= tmpcol; + } + change = 1; + } + } + + if (change) { + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + BIF_undo_push("Rotate Color face"); + } +} + +void mesh_mirror_colors(void) +{ + EditMesh *em = G.editMesh; + EditFace *efa; + short change = 0, altaxis; + MCol tmpcol, *mcol; + if (!EM_vertColorCheck()) { + error("mesh has no color layers"); + return; + } + + altaxis = (G.qual == LR_SHIFTKEY); + + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT) { + mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); + if (altaxis) { + tmpcol= mcol[1]; + mcol[1]= mcol[2]; + mcol[2]= tmpcol; + + if(efa->v4) { + tmpcol= mcol[0]; + mcol[0]= mcol[3]; + mcol[3]= tmpcol; + } + } else { + tmpcol= mcol[0]; + mcol[0]= mcol[1]; + mcol[1]= tmpcol; + + if(efa->v4) { + tmpcol= mcol[2]; + mcol[2]= mcol[3]; + mcol[3]= tmpcol; + } + } + change = 1; + } + } + + if (change) { + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + allqueue(REDRAWVIEW3D, 0); + BIF_undo_push("Mirror Color face"); + } +} diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c new file mode 100644 index 00000000000..58025fd33cc --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -0,0 +1,566 @@ +/** + * bmesh_construct.c August 2008 + * + * BM construction functions. + * + * ***** 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. + * 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) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" +#include "BKE_customdata.h" +#include "BKE_utildefines.h" + +#include "DNA_meshdata_types.h" +#include "DNA_mesh_types.h" + +#include "bmesh.h" +#include "bmesh_private.h" + +#include "math.h" +#include "stdio.h" +#include "string.h" + +#define SELECT 1 + +/*prototypes*/ +static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh, + BMLoop *source_loop, BMLoop *target_loop); + +/* + * BM_CONSTRUCT.C + * + * This file contains functions for making and destroying + * individual elements like verts, edges and faces. + * +*/ + +/* + * BMESH MAKE VERT + * + * Creates a new vertex and returns a pointer + * to it. If a pointer to an example vertex is + * passed in, it's custom data and properties + * will be copied to the new vertex. + * +*/ + +BMVert *BM_Make_Vert(BMesh *bm, float co[3], BMVert *example) +{ + BMVert *v = NULL; + v = bmesh_mv(bm, co); + if(example) + CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, example->head.data, &v->head.data); + return v; +} + +/* + * BMESH MAKE EDGE + * + * Creates a new edge betweeen two vertices and returns a + * pointer to it. If 'nodouble' equals 1, then a check is + * is done to make sure that an edge between those two vertices + * does not already exist. If it does, that edge is returned instead + * of creating a new one. + * + * If a new edge is created, and a pointer to an example edge is + * provided, it's custom data and properties will be copied to the + * new edge. + * +*/ + +BMEdge *BM_Make_Edge(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge *example, int nodouble) +{ + BMEdge *e = NULL; + + if(nodouble) /*test if edge already exists.*/ + e = bmesh_disk_existedge(v1, v2); + + if(!e){ + e = bmesh_me(bm, v1, v2); + + if(example) + CustomData_bmesh_copy_data(&bm->edata, &bm->edata, example->head.data, &e->head.data); + } + + return e; + +} + +/* + * BMESH MAKE QUADTRIANGLE + * + * Creates a new quad or triangle from + * a list of 3 or 4 vertices. If nodouble + * equals 1, then a check is done to see + * if a face with these vertices already + * exists and returns it instead. If a pointer + * to an example face is provided, it's custom + * data and properties will be copied to the new + * face. + * + * Note that the winding of the face is determined + * by the order of the vertices in the vertex array + * +*/ + +BMFace *BM_Make_QuadTri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, + BMVert *v4, BMFace *example, int nodouble) +{ + BMEdge *edar[4]; + BMVert *vtar[4]; + + edar[0] = bmesh_disk_existedge(v1, v2); + edar[1] = bmesh_disk_existedge(v2, v3); + edar[2] = bmesh_disk_existedge(v3, v4? v4 : v1); + if (v4) edar[3] = bmesh_disk_existedge(v4, v1); + else edar[3] = NULL; + + if (!edar[0]) edar[0] = BM_Make_Edge(bm, v1, v2, NULL, 0); + if (!edar[1]) edar[1] = BM_Make_Edge(bm, v2, v3, NULL, 0); + if (!edar[2]) edar[2] = BM_Make_Edge(bm, v3, v4?v4:v1, NULL, 0); + if (!edar[0] && v4) edar[0] = BM_Make_Edge(bm, v4, v1, NULL, 0); + + vtar[0] = v1; + vtar[1] = v2; + vtar[2] = v3; + vtar[3] = v4; + + return BM_Make_Quadtriangle(bm, vtar, edar, v4?4:3, example, nodouble); +} + +/*remove the edge array bits from this. Its not really needed?*/ +BMFace *BM_Make_Quadtriangle(BMesh *bm, BMVert **verts, BMEdge **edges, int len, BMFace *example, int nodouble) +{ + BMEdge *edar[4]; + BMFace *f = NULL; + int overlap = 0; + + edar[0] = edar[1] = edar[2] = edar[3] = NULL; + + if(edges){ + edar[0] = edges[0]; + edar[1] = edges[1]; + edar[2] = edges[2]; + if(len == 4) edar[3] = edges[3]; + }else{ + edar[0] = bmesh_disk_existedge(verts[0],verts[1]); + edar[1] = bmesh_disk_existedge(verts[1],verts[2]); + if(len == 4){ + edar[2] = bmesh_disk_existedge(verts[2],verts[3]); + edar[3] = bmesh_disk_existedge(verts[3],verts[0]); + + }else{ + edar[2] = bmesh_disk_existedge(verts[2],verts[0]); + } + } + + if(nodouble){ + /*check if face exists or overlaps*/ + if(len == 4){ + overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f); + }else{ + overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f); + } + } + + /*make new face*/ + if((!f) && (!overlap)){ + if(!edar[0]) edar[0] = bmesh_me(bm, verts[0], verts[1]); + if(!edar[1]) edar[1] = bmesh_me(bm, verts[1], verts[2]); + if(len == 4){ + if(!edar[2]) edar[2] = bmesh_me(bm, verts[2], verts[3]); + if(!edar[3]) edar[3] = bmesh_me(bm, verts[3], verts[0]); + } else { + if(!edar[2]) edar[2] = bmesh_me(bm, verts[2], verts[0]); + } + + if(len == 4) f = bmesh_mf(bm, verts[0], verts[1], edar, 4); + else f = bmesh_mf(bm, verts[0], verts[1], edar, 3); + + if(example) + CustomData_bmesh_copy_data(&bm->pdata, &bm->pdata, example->head.data, &f->head.data); + + } + + return f; +} + + +/*copies face data from shared adjacent faces*/ +void BM_Face_CopyShared(BMesh *bm, BMFace *f) { + BMIter iter; + BMLoop *l, *l2; + + if (!f) return; + + l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); + for (; l; l=BMIter_Step(&iter)) { + l2 = l->radial.next->data; + + if (l2 && l2 != l) { + if (l2->v == l->v) { + bm_copy_loop_attributes(bm, bm, l2, l); + } else { + l2 = (BMLoop*) l2->head.next; + bm_copy_loop_attributes(bm, bm, l2, l); + } + } + } +} + +/* + * BMESH MAKE NGON + * + * Attempts to make a new Ngon from a list of edges. + * If nodouble equals one, a check for overlaps or existing + * + * + * +*/ +#define VERT_BUF_SIZE 100 +BMFace *BM_Make_Ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble) +{ + BMVert *vert_buf[VERT_BUF_SIZE]; + BMVert **verts = vert_buf, *lastv; + BMFace *f = NULL; + int overlap = 0, i, j; + + /*note: need to make sure this is correct*/ + if(bmesh_verts_in_edge(v1,v2,edges[0]) == 0) { + if (v1 == edges[0]->v1) + v2 = edges[0]->v2; + else { + v1 = edges[0]->v2; + v2 = edges[0]->v1; + } + } + + if(nodouble) { + if(len > VERT_BUF_SIZE) + verts = MEM_callocN(sizeof(BMVert *) * len, "bmesh make ngon vertex array"); + + /*if ((edges[i]->v1 == edges[i]->v1) || + (edges[i]->v1 == edges[i]->v2)) + { + lastv = edges[i]->v2; + } else lastv = edges[i]->v1; + verts[0] = lastv; + + for (i=1; i<len; i++) { + if (!BMO_TestFlag + }*/ + + for(i = 0, j=0; i < len; i++){ + if(!BMO_TestFlag(bm, edges[i]->v1, BM_EDGEVERT)){ + BMO_SetFlag(bm, edges[i]->v1, BM_EDGEVERT); + verts[j++] = edges[i]->v1; + } + if(!BMO_TestFlag(bm, edges[i]->v2, BM_EDGEVERT)) { + BMO_SetFlag(bm, edges[i]->v2, BM_EDGEVERT); + verts[j++] = edges[i]->v2; + } + } + + if (j != len) { + /*sanity check*/ + return NULL; + } + + overlap = BM_Face_Exists(bm, verts, len, &f); + + /*clear flags*/ + for(i = 0; i < len; i++){ + BMO_ClearFlag(bm, edges[i]->v1, BM_EDGEVERT); + BMO_ClearFlag(bm, edges[i]->v2, BM_EDGEVERT); + } + + if(len > VERT_BUF_SIZE) + MEM_freeN(verts); + } + + if((!f) && (!overlap)) { + f = bmesh_mf(bm, v1, v2, edges, len); + } + + return f; +} + + +/*bmesh_make_face_from_face(BMesh *bm, BMFace *source, BMFace *target) */ + + +/* + * REMOVE TAGGED XXX + * + * Called by operators to remove elements that they have marked for + * removal. + * +*/ + +void BM_remove_tagged_faces(BMesh *bm, int flag) +{ + BMHeader *current, *next; + + current = bm->polys.first; + while(current){ + next = current->next; + if(BMO_TestFlag(bm, current, flag)) bmesh_kf(bm, (BMFace*)current); + current = next; + } +} +void BM_remove_tagged_edges(BMesh *bm, int flag) +{ + BMHeader *current, *next; + + current = bm->edges.first; + + while(current){ + next = current->next; + if(BMO_TestFlag(bm, current, flag)) bmesh_ke(bm, (BMEdge*)current); + current = next; + } +} + +void BM_remove_tagged_verts(BMesh *bm, int flag) +{ + BMHeader *current, *next; + + current = bm->verts.first; + + while(current){ + next = current->next; + if(BMO_TestFlag(bm, current, flag)) bmesh_kv(bm,(BMVert*)current); + current = next; + } +} + +static void bm_copy_vert_attributes(BMesh *source_mesh, BMesh *target_mesh, BMVert *source_vertex, BMVert *target_vertex) +{ + CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->head.data, &target_vertex->head.data); + target_vertex->bweight = source_vertex->bweight; +} + +static void bm_copy_edge_attributes(BMesh *source_mesh, BMesh *target_mesh, BMEdge *source_edge, BMEdge *target_edge) +{ + CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->head.data, &target_edge->head.data); + target_edge->crease = source_edge->crease; + target_edge->bweight = source_edge->bweight; +} + +static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh, BMLoop *source_loop, BMLoop *target_loop) +{ + CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->head.data, &target_loop->head.data); +} + +static void bm_copy_face_attributes(BMesh *source_mesh, BMesh *target_mesh, BMFace *source_face, BMFace *target_face) +{ + CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->head.data, &target_face->head.data); + target_face->mat_nr = source_face->mat_nr; +} + +/*Todo: Special handling for hide flags?*/ + +void BM_Copy_Attributes(BMesh *source_mesh, BMesh *target_mesh, void *source, void *target) +{ + BMHeader *sheader = source, *theader = target; + + if(sheader->type != theader->type) + return; + + /*First we copy select*/ + if(BM_Is_Selected(source_mesh, source)) BM_Select(target_mesh, target, 1); + + /*Now we copy flags*/ + theader->flag = sheader->flag; + + /*Copy specific attributes*/ + if(theader->type == BM_VERT) + bm_copy_vert_attributes(source_mesh, target_mesh, (BMVert*)source, (BMVert*)target); + else if(theader->type == BM_EDGE) + bm_copy_edge_attributes(source_mesh, target_mesh, (BMEdge*)source, (BMEdge*)target); + else if(theader->type == BM_LOOP) + bm_copy_loop_attributes(source_mesh, target_mesh, (BMLoop*)source, (BMLoop*)target); + else if(theader->type == BM_FACE) + bm_copy_face_attributes(source_mesh, target_mesh, (BMFace*)source, (BMFace*)target); +} + +BMesh *BM_Copy_Mesh(BMesh *bmold) +{ + BMesh *bm; + BMVert *v, *v2, **vtable = NULL; + V_DECLARE(vtable); + BMEdge *e, *e2, **edges = NULL, **etable = NULL; + V_DECLARE(edges); + V_DECLARE(etable); + BMLoop *l, *l2, **loops = NULL; + V_DECLARE(loops); + BMFace *f, *f2; + + BMIter iter, liter; + int allocsize[4] = {512,512,2048,512}, numTex, numCol; + int i; + + /*allocate a bmesh*/ + bm = BM_Make_Mesh(allocsize); + + CustomData_copy(&bmold->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bmold->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bmold->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bmold->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); + + CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]); + CustomData_bmesh_init_pool(&bm->edata, allocsize[1]); + CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]); + CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]); + + /*needed later*/ + numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); + + v = BMIter_New(&iter, bmold, BM_VERTS_OF_MESH, NULL); + for (i=0; v; v=BMIter_Step(&iter), i++) { + v2 = BM_Make_Vert(bm, v->co, NULL); + BM_Copy_Attributes(bmold, bm, v, v2); + V_GROW(vtable); + VECCOPY(v2->no, v->no); + + vtable[V_COUNT(vtable)-1] = v2; + + BMINDEX_SET(v, i); + BMINDEX_SET(v2, i); + } + + e = BMIter_New(&iter, bmold, BM_EDGES_OF_MESH, NULL); + for (i=0; e; e=BMIter_Step(&iter), i++) { + e2 = BM_Make_Edge(bm, vtable[BMINDEX_GET(e->v1)], + vtable[BMINDEX_GET(e->v2)], e, 0); + + BM_Copy_Attributes(bmold, bm, e, e2); + V_GROW(etable); + etable[V_COUNT(etable)-1] = e2; + + BMINDEX_SET(e, i); + BMINDEX_SET(e2, i); + } + + f = BMIter_New(&iter, bmold, BM_FACES_OF_MESH, NULL); + for (; f; f=BMIter_Step(&iter)) { + V_RESET(loops); + V_RESET(edges); + l = BMIter_New(&liter, bmold, BM_LOOPS_OF_FACE, f); + for (i=0; i<f->len; i++, l = BMIter_Step(&liter)) { + V_GROW(loops); + V_GROW(edges); + loops[i] = l; + edges[i] = etable[BMINDEX_GET(l->e)]; + } + + v = vtable[BMINDEX_GET(loops[0]->v)]; + v2 = vtable[BMINDEX_GET(loops[1]->v)]; + + if (!bmesh_verts_in_edge(v, v2, edges[0])) { + v = vtable[BMINDEX_GET(loops[V_COUNT(loops)-1]->v)]; + v2 = vtable[BMINDEX_GET(loops[0]->v)]; + } + + f2 = BM_Make_Ngon(bm, v, v2, edges, f->len, 0); + BM_Copy_Attributes(bmold, bm, f, f2); + VECCOPY(f2->no, f->no); + + l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f2); + for (i=0; i<f->len; i++, l = BMIter_Step(&liter)) { + BM_Copy_Attributes(bmold, bm, loops[i], l); + } + + if (f == bmold->act_face) bm->act_face = f2; + } + + V_FREE(etable); + V_FREE(vtable); + V_FREE(loops); + V_FREE(edges); + + return bm; +} + +/* + BM FLAGS TO ME FLAGS + + Returns the flags stored in element, + which much be either a BMVert, BMEdge, + or BMFace, converted to mesh flags. +*/ +int BMFlags_To_MEFlags(void *element) { + BMHeader *h = element; + int f = 0; + + if (h->flag & BM_HIDDEN) f |= ME_HIDE; + + if (h->type == BM_FACE) { + if (h->flag & BM_SELECT) f |= ME_FACE_SEL; + if (h->flag & BM_SMOOTH) f |= ME_SMOOTH; + } else if (h->type == BM_EDGE) { + if (h->flag & BM_SELECT) f |= BM_SELECT; + if (h->flag & BM_SEAM) f |= ME_SEAM; + if (h->flag & BM_SHARP) f |= ME_SHARP; + if (BM_Wire_Edge(NULL, element)) f |= ME_LOOSEEDGE; + } else if (h->type == BM_VERT) { + if (h->flag & BM_SELECT) f |= BM_SELECT; + if (h->flag & BM_HIDDEN) f |= ME_HIDE; + } + + return f; +} + +/* + BM FLAGS TO ME FLAGS + + Returns the flags stored in element, + which much be either a MVert, MEdge, + or MPoly, converted to mesh flags. + type must be either BM_VERT, BM_EDGE, + or BM_FACE. +*/ +int MEFlags_To_BMFlags(int flag, int type) { + int f = 0; + + if (type == BM_FACE) { + if (flag & ME_FACE_SEL) f |= BM_SELECT; + if (flag & ME_SMOOTH) f |= BM_SMOOTH; + if (flag & ME_HIDE) f |= BM_HIDDEN; + } else if (type == BM_EDGE) { + if (flag & SELECT) f |= BM_SELECT; + if (flag & ME_SEAM) f |= BM_SEAM; + if (flag & ME_SHARP) f |= BM_SHARP; + if (flag & ME_HIDE) f |= BM_HIDDEN; + } else if (type == BM_VERT) { + if (flag & SELECT) f |= BM_SELECT; + if (flag & ME_HIDE) f |= BM_HIDDEN; + } + + return f; +}
\ No newline at end of file diff --git a/source/blender/bmesh/intern/bmesh_eulers.c b/source/blender/bmesh/intern/bmesh_eulers.c new file mode 100644 index 00000000000..6a68989a42a --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_eulers.c @@ -0,0 +1,1186 @@ +/** + * bmesh_eulers.c jan 2007 + * + * BM Euler construction API. + * + * $Id: bmesh_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** 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. + * 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_meshdata_types.h" +#include "DNA_mesh_types.h" + +#include "BKE_customdata.h" +#include "BKE_utildefines.h" + +#include "bmesh.h" +#include "bmesh_private.h" + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" + +/********************************************************* + * "Euler API" * + * * + * * + * Primitive construction operators for mesh tools. * + * * + **********************************************************/ + + +/* + The functions in this file represent the 'primitive' or 'atomic' operators that + mesh tools use to manipulate the topology of the structure.* The purpose of these + functions is to provide a trusted set of operators to manipulate the mesh topology + and which can also be combined together like building blocks to create more + sophisticated tools. It needs to be stressed that NO manipulation of an existing + mesh structure should be done outside of these functions. + + In the BM system, each euler is named by an ancronym which describes what it actually does. + Furthermore each Euler has a logical inverse. An important design criteria of all Eulers is that + through a Euler's logical inverse you can 'undo' an operation. (Special note should + be taken of bmesh_loop_reverse, which is its own inverse). + + bmesh_MF/KF: Make Face and Kill Face + bmesh_ME/KE: Make Edge and Kill Edge + bmesh_MV/KV: Make Vert and Kill Vert + bmesh_SEMV/JEKV: Split Edge, Make Vert and Join Edge, Kill Vert + bmesh_SFME/JFKE: Split Face, Make Edge and Join Face, Kill Edge + bmesh_loop_reverse: Reverse a Polygon's loop cycle. (used for flip normals for one) + + Using a combination of these eleven eulers any non-manifold modelling operation can be achieved. + Each Euler operator has a detailed explanation of what is does in the comments preceding its + code. + + *The term "Euler Operator" is actually a misnomer when referring to a non-manifold + data structure. Its use is in keeping with the convention established by others. + + TODO: + -Make seperate 'debug levels' of validation + -Add in the UnglueFaceRegionMakeVert and GlueFaceRegionKillVert eulers. + + NOTE: + -The functions in this file are notoriously difficult to debug and even understand sometimes. + better code comments would be nice.... + +*/ + + +/*MAKE Eulers*/ + +/** + * bmesh_MV + * + * MAKE VERT EULER: + * + * Makes a single loose vertex. + * + * Returns - + * A BMVert pointer. + */ + +BMVert *bmesh_mv(BMesh *bm, float *vec){ + BMVert *v = bmesh_addvertlist(bm, NULL); + VECCOPY(v->co,vec); + return v; +} + +/** + * bmesh_ME + * + * MAKE EDGE EULER: + * + * Makes a single wire edge between two vertices. + * If the caller does not want there to be duplicate + * edges between the vertices, it is up to them to check + * for this condition beforehand. + * + * Returns - + * A BMEdge pointer. + */ + +BMEdge *bmesh_me(BMesh *bm, BMVert *v1, BMVert *v2){ + BMEdge *e=NULL; + BMNode *d1=NULL, *d2=NULL; + int valance1=0, valance2=0, edok; + + /*edge must be between two distinct vertices...*/ + if(v1 == v2) return NULL; + + #ifndef bmesh_FASTEULER + /*count valance of v1*/ + if(v1->edge){ + d1 = bmesh_disk_getpointer(v1->edge,v1); + if(d1) valance1 = bmesh_cycle_length(d1); + else bmesh_error(); + } + if(v2->edge){ + d2 = bmesh_disk_getpointer(v2->edge,v2); + if(d2) valance2 = bmesh_cycle_length(d2); + else bmesh_error(); + } + #endif + + /*go ahead and add*/ + e = bmesh_addedgelist(bm, v1, v2, NULL); + bmesh_disk_append_edge(e, e->v1); + bmesh_disk_append_edge(e, e->v2); + + #ifndef bmesh_FASTEULER + /*verify disk cycle lengths*/ + d1 = bmesh_disk_getpointer(e, e->v1); + edok = bmesh_cycle_validate(valance1+1, d1); + if(!edok) bmesh_error(); + d2 = bmesh_disk_getpointer(e, e->v2); + edok = bmesh_cycle_validate(valance2+1, d2); + if(!edok) bmesh_error(); + + /*verify that edge actually made it into the cycle*/ + edok = bmesh_disk_hasedge(v1, e); + if(!edok) bmesh_error(); + edok = bmesh_disk_hasedge(v2, e); + if(!edok) bmesh_error(); + #endif + return e; +} + + + +/** + * bmesh_MF + * + * MAKE FACE EULER: + * Takes a list of edge pointers which form a closed loop and makes a face + * from them. The first edge in elist is considered to be the start of the + * polygon, and v1 and v2 are its vertices and determine the winding of the face + * Other than the first edge, no other assumptions are made about the order of edges + * in the elist array. To verify that it is a single closed loop and derive the correct + * order a simple series of verifications is done and all elements are visited. + * + * Returns - + * A BMFace pointer + */ + +#define MF_CANDIDATE 1 +#define MF_VISITED 2 +#define MF_TAKEN 4 + +BMFace *bmesh_mf(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **elist, int len) +{ + BMFace *f = NULL; + BMEdge *curedge; + BMVert *curvert, *tv, **vlist; + int i, j, done, cont, edok; + + if(len < 2) return NULL; + + /*make sure that v1 and v2 are in elist[0]*/ + if(bmesh_verts_in_edge(v1,v2,elist[0]) == 0) + return NULL; + + /*clear euler flags*/ + for(i=0;i<len;i++) elist[i]->head.eflag1=elist[i]->head.eflag2 = 0; + for(i=0;i<len;i++){ + elist[i]->head.eflag1 |= MF_CANDIDATE; + + /*if elist[i] has a loop, count its radial length*/ + if(elist[i]->loop) elist[i]->head.eflag2 = bmesh_cycle_length(&(elist[i]->loop->radial)); + else elist[i]->head.eflag2 = 0; + } + + /* For each vertex in each edge, it must have exactly two MF_CANDIDATE edges attached to it + Note that this does not gauruntee that face is a single closed loop. At best it gauruntees + that elist contains a finite number of seperate closed loops. + */ + for(i=0; i<len; i++){ + edok = bmesh_disk_count_edgeflag(elist[i]->v1, MF_CANDIDATE, 0); + if(edok != 2) return NULL; + edok = bmesh_disk_count_edgeflag(elist[i]->v2, MF_CANDIDATE, 0); + if(edok != 2) return NULL; + } + + /*set start edge, start vert and target vert for our loop traversal*/ + curedge = elist[0]; + tv = v1; + curvert = v2; + + if(bm->vtarlen < len){ + if (bm->vtar) MEM_freeN(bm->vtar); + bm->vtar = MEM_callocN(sizeof(BMVert *)* len, "BM Vert pointer array"); + bm->vtarlen = len; + } + /*insert tv into vlist since its the first vertex in face*/ + + i=0; + vlist=bm->vtar; + vlist[i] = tv; + + /* Basic procedure: Starting with curv we find the edge in it's disk cycle which hasn't + been visited yet. When we do, we put curv in a linked list and find the next MF_CANDIDATE + edge, loop until we find TV. We know TV is reachable because of test we did earlier. + */ + done=0; + while(!done){ + /*add curvert to vlist*/ + /*insert some error cheking here for overflows*/ + i++; + vlist[i] = curvert; + + /*mark curedge as visited*/ + curedge->head.eflag1 |= MF_VISITED; + + /*find next edge and vert*/ + curedge = bmesh_disk_next_edgeflag(curedge, curvert, MF_CANDIDATE, 0); + curvert = bmesh_edge_getothervert(curedge, curvert); + if(curvert == tv){ + curedge->head.eflag1 |= MF_VISITED; + done=1; + } + } + + /* Verify that all edges have been visited It's possible that we did reach tv + from sv, but that several unconnected loops were passed in via elist. + */ + cont=1; + for(i=0; i<len; i++){ + if((elist[i]->head.eflag1 & MF_VISITED) == 0) cont = 0; + } + + /*if we get this far, its ok to allocate the face and add the loops*/ + if(cont){ + BMLoop *l; + BMEdge *e; + f = bmesh_addpolylist(bm, NULL); + f->len = len; + for(i=0;i<len;i++){ + curvert = vlist[i]; + l = bmesh_create_loop(bm,curvert,NULL,f,NULL); + if(!(f->loopbase)) f->loopbase = l; + bmesh_cycle_append(f->loopbase, l); + } + + /*take care of edge pointers and radial cycle*/ + for(i=0, l = f->loopbase; i<len; i++, l=((BMLoop*)(l->head.next))){ + e = NULL; + if(l == f->loopbase) e = elist[0]; /*first edge*/ + + else{/*search elist for others*/ + for(j=1; j<len; j++){ + edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, elist[j]); + if(edok){ + e = elist[j]; + break; + } + } + } + l->e = e; /*set pointer*/ + bmesh_radial_append(e, l); /*append into radial*/ + } + + f->len = len; + + /*Validation Loop cycle*/ + edok = bmesh_cycle_validate(len, f->loopbase); + if(!edok) bmesh_error(); + for(i=0, l = f->loopbase; i<len; i++, l=((BMLoop*)(l->head.next))){ + /*validate loop vert pointers*/ + edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, l->e); + if(!edok) bmesh_error(); + /*validate the radial cycle of each edge*/ + edok = bmesh_cycle_length(&(l->radial)); + if(edok != (l->e->head.eflag2 + 1)) bmesh_error(); + } + } + + for(i=0;i<len;i++) elist[i]->head.eflag1=elist[i]->head.eflag2 = 0; + return f; +} + +/* KILL Eulers */ + +/** + * bmesh_KV + * + * KILL VERT EULER: + * + * Kills a single loose vertex. + * + * Returns - + * 1 for success, 0 for failure. + */ + +int bmesh_kv(BMesh *bm, BMVert *v){ + if(v->edge == NULL){ + if (BM_TestHFlag(v, BM_SELECT)) bm->totvertsel--; + + BLI_remlink(&(bm->verts), &(v->head)); + bmesh_free_vert(bm,v); + return 1; + } + return 0; +} + +/** + * bmesh_KE + * + * KILL EDGE EULER: + * + * Kills a wire edge. + * + * Returns - + * 1 for success, 0 for failure. + */ + +int bmesh_ke(BMesh *bm, BMEdge *e){ + int edok; + + /*Make sure that no faces!*/ + if(e->loop == NULL){ + bmesh_disk_remove_edge(e, e->v1); + bmesh_disk_remove_edge(e, e->v2); + + /*verify that edge out of disk*/ + edok = bmesh_disk_hasedge(e->v1, e); + if(edok) bmesh_error(); + edok = bmesh_disk_hasedge(e->v2, e); + if(edok) bmesh_error(); + + /*remove and deallocate*/ + if (BM_TestHFlag(e, BM_SELECT)) bm->totedgesel--; + BLI_remlink(&(bm->edges), &(e->head)); + bmesh_free_edge(bm, e); + return 1; + } + return 0; +} + +/** + * bmesh_KF + * + * KILL FACE EULER: + * + * The logical inverse of bmesh_MF. + * Kills a face and removes each of its loops from the radial that it belongs to. + * + * Returns - + * 1 for success, 0 for failure. +*/ + +int bmesh_kf(BMesh *bm, BMFace *bply){ + BMLoop *newbase,*oldbase, *curloop; + int i,len=0; + + /*add validation to make sure that radial cycle is cleaned up ok*/ + /*deal with radial cycle first*/ + len = bmesh_cycle_length(bply->loopbase); + for(i=0, curloop=bply->loopbase; i < len; i++, curloop = ((BMLoop*)(curloop->head.next))) + bmesh_radial_remove_loop(curloop, curloop->e); + + /*now deallocate the editloops*/ + for(i=0; i < len; i++){ + newbase = ((BMLoop*)(bply->loopbase->head.next)); + oldbase = bply->loopbase; + bmesh_cycle_remove(oldbase, oldbase); + bmesh_free_loop(bm, oldbase); + bply->loopbase = newbase; + } + + if (BM_TestHFlag(bply, BM_SELECT)) bm->totfacesel--; + BLI_remlink(&(bm->polys), &(bply->head)); + bmesh_free_poly(bm, bply); + return 1; +} + +/*SPLIT Eulers*/ + +/** + * bmesh_SEMV + * + * SPLIT EDGE MAKE VERT: + * Takes a given edge and splits it into two, creating a new vert. + * + * + * Before: OV---------TV + * After: OV----NV---TV + * + * Returns - + * BMVert pointer. + * +*/ + +BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **re){ + BMVert *nv, *ov; + BMNode *diskbase; + BMEdge *ne; + int i, edok, valance1=0, valance2=0; + + if(bmesh_vert_in_edge(e,tv) == 0) return NULL; + ov = bmesh_edge_getothervert(e,tv); + //v2 = tv; + + /*count valance of v1*/ + diskbase = bmesh_disk_getpointer(e, ov); + valance1 = bmesh_cycle_length(diskbase); + /*count valance of v2*/ + diskbase = bmesh_disk_getpointer(e, tv); + valance2 = bmesh_cycle_length(diskbase); + + nv = bmesh_addvertlist(bm, tv); + ne = bmesh_addedgelist(bm, nv, tv, e); + + //e->v2 = nv; + /*remove e from v2's disk cycle*/ + bmesh_disk_remove_edge(e, tv); + /*swap out tv for nv in e*/ + bmesh_edge_swapverts(e, tv, nv); + /*add e to nv's disk cycle*/ + bmesh_disk_append_edge(e, nv); + /*add ne to nv's disk cycle*/ + bmesh_disk_append_edge(ne, nv); + /*add ne to tv's disk cycle*/ + bmesh_disk_append_edge(ne, tv); + /*verify disk cycles*/ + diskbase = bmesh_disk_getpointer(ov->edge,ov); + edok = bmesh_cycle_validate(valance1, diskbase); + if(!edok) bmesh_error(); + diskbase = bmesh_disk_getpointer(tv->edge,tv); + edok = bmesh_cycle_validate(valance2, diskbase); + if(!edok) bmesh_error(); + diskbase = bmesh_disk_getpointer(nv->edge,nv); + edok = bmesh_cycle_validate(2, diskbase); + if(!edok) bmesh_error(); + + /*Split the radial cycle if present*/ + if(e->loop){ + BMLoop *nl,*l; + BMNode *radEBase=NULL, *radNEBase=NULL; + int radlen = bmesh_cycle_length(&(e->loop->radial)); + /*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/ + while(e->loop){ + l=e->loop; + l->f->len++; + bmesh_radial_remove_loop(l,e); + + nl = bmesh_create_loop(bm,NULL,NULL,l->f,l); + nl->head.prev = (BMHeader*)l; + nl->head.next = (BMHeader*)(l->head.next); + nl->head.prev->next = (BMHeader*)nl; + nl->head.next->prev = (BMHeader*)nl; + nl->v = nv; + + /*assign the correct edge to the correct loop*/ + if(bmesh_verts_in_edge(nl->v, ((BMLoop*)(nl->head.next))->v, e)){ + nl->e = e; + l->e = ne; + + /*append l into ne's rad cycle*/ + if(!radNEBase){ + radNEBase = &(l->radial); + radNEBase->next = NULL; + radNEBase->prev = NULL; + } + + if(!radEBase){ + radEBase = &(nl->radial); + radEBase->next = NULL; + radEBase->prev = NULL; + } + + bmesh_cycle_append(radEBase,&(nl->radial)); + bmesh_cycle_append(radNEBase,&(l->radial)); + + } + else if(bmesh_verts_in_edge(nl->v,((BMLoop*)(nl->head.next))->v,ne)){ + nl->e = ne; + l->e = e; + + if(!radNEBase){ + radNEBase = &(nl->radial); + radNEBase->next = NULL; + radNEBase->prev = NULL; + } + if(!radEBase){ + radEBase = &(l->radial); + radEBase->next = NULL; + radEBase->prev = NULL; + } + bmesh_cycle_append(radEBase,&(l->radial)); + bmesh_cycle_append(radNEBase,&(nl->radial)); + } + + } + + e->loop = radEBase->data; + ne->loop = radNEBase->data; + + /*verify length of radial cycle*/ + edok = bmesh_cycle_validate(radlen,&(e->loop->radial)); + if(!edok) bmesh_error(); + edok = bmesh_cycle_validate(radlen,&(ne->loop->radial)); + if(!edok) bmesh_error(); + + /*verify loop->v and loop->next->v pointers for e*/ + for(i=0,l=e->loop; i < radlen; i++, l = l->radial.next->data){ + if(!(l->e == e)) bmesh_error(); + if(!(l->radial.data == l)) bmesh_error(); + if( ((BMLoop*)(l->head.prev))->e != ne && ((BMLoop*)(l->head.next))->e != ne) bmesh_error(); + edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, e); + if(!edok) bmesh_error(); + if(l->v == ((BMLoop*)(l->head.next))->v) bmesh_error(); + if(l->e == ((BMLoop*)(l->head.next))->e) bmesh_error(); + /*verify loop cycle for kloop->f*/ + edok = bmesh_cycle_validate(l->f->len, l->f->loopbase); + if(!edok) bmesh_error(); + } + /*verify loop->v and loop->next->v pointers for ne*/ + for(i=0,l=ne->loop; i < radlen; i++, l = l->radial.next->data){ + if(!(l->e == ne)) bmesh_error(); + if(!(l->radial.data == l)) bmesh_error(); + if( ((BMLoop*)(l->head.prev))->e != e && ((BMLoop*)(l->head.next))->e != e) bmesh_error(); + edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, ne); + if(!edok) bmesh_error(); + if(l->v == ((BMLoop*)(l->head.next))->v) bmesh_error(); + if(l->e == ((BMLoop*)(l->head.next))->e) bmesh_error(); + /*verify loop cycle for kloop->f. Redundant*/ + edok = bmesh_cycle_validate(l->f->len, l->f->loopbase); + if(!edok) bmesh_error(); + } + } + + if(re) *re = ne; + return nv; +} + +/** + * bmesh_SFME + * + * SPLIT FACE MAKE EDGE: + * + * Takes as input two vertices in a single face. An edge is created which divides the original face + * into two distinct regions. One of the regions is assigned to the original face and it is closed off. + * The second region has a new face assigned to it. + * + * Examples: + * + * Before: After: + * ---------- ---------- + * | | | | + * | | | f1 | + * v1 f1 v2 v1======v2 + * | | | f2 | + * | | | | + * ---------- ---------- + * + * Note that the input vertices can be part of the same edge. This will result in a two edged face. + * This is desirable for advanced construction tools and particularly essential for edge bevel. Because + * of this it is up to the caller to decide what to do with the extra edge. + * + * Note that the tesselator abuses eflag2 while using this euler! (don't ever ever do this....) + * + * Returns - + * A BMFace pointer + */ +BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **rl){ + + BMFace *f2; + BMLoop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL; + BMEdge *e; + int i, len, f1len, f2len; + + + /*verify that v1 and v2 are in face.*/ + len = bmesh_cycle_length(f->loopbase); + for(i = 0, curloop = f->loopbase; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){ + if(curloop->v == v1) v1loop = curloop; + else if(curloop->v == v2) v2loop = curloop; + } + + if(!v1loop || !v2loop) return NULL; + + /*allocate new edge between v1 and v2*/ + e = bmesh_addedgelist(bm, v1, v2,NULL); + bmesh_disk_append_edge(e, v1); + bmesh_disk_append_edge(e, v2); + + f2 = bmesh_addpolylist(bm,f); + f1loop = bmesh_create_loop(bm,v2,e,f,v2loop); + f2loop = bmesh_create_loop(bm,v1,e,f2,v1loop); + + f1loop->head.prev = v2loop->head.prev; + f2loop->head.prev = v1loop->head.prev; + v2loop->head.prev->next = (BMHeader*)f1loop; + v1loop->head.prev->next = (BMHeader*)f2loop; + + f1loop->head.next = (BMHeader*)v1loop; + f2loop->head.next = (BMHeader*)v2loop; + v1loop->head.prev = (BMHeader*)f1loop; + v2loop->head.prev = (BMHeader*)f2loop; + + f2->loopbase = f2loop; + f->loopbase = f1loop; + + /*validate both loops*/ + /*I dont know how many loops are supposed to be in each face at this point! FIXME!*/ + + /*go through all of f2's loops and make sure they point to it properly.*/ + f2len = bmesh_cycle_length(f2->loopbase); + for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ) curloop->f = f2; + + /*link up the new loops into the new edges radial*/ + bmesh_radial_append(e, f1loop); + bmesh_radial_append(e, f2loop); + + + f2->len = f2len; + + f1len = bmesh_cycle_length(f->loopbase); + f->len = f1len; + + if(rl) *rl = f2loop; + return f2; +} + + +/** + * bmesh_JEKV + * + * JOIN EDGE KILL VERT: + * Takes a an edge and pointer to one of its vertices and collapses + * the edge on that vertex. + * + * Before: OE KE + * ------- ------- + * | || | + * OV KV TV + * + * + * After: OE + * --------------- + * | | + * OV TV + * + * + * Restrictions: + * KV is a vertex that must have a valance of exactly two. Furthermore + * both edges in KV's disk cycle (OE and KE) must be unique (no double + * edges). + * + * It should also be noted that this euler has the possibility of creating + * faces with just 2 edges. It is up to the caller to decide what to do with + * these faces. + * + * Returns - + * 1 for success, 0 for failure. + */ +int bmesh_jekv(BMesh *bm, BMEdge *ke, BMVert *kv) +{ + BMEdge *oe; + BMVert *ov, *tv; + BMNode *diskbase; + BMLoop *killoop,*nextl; + int len,radlen=0, halt = 0, i, valance1, valance2,edok; + + if(bmesh_vert_in_edge(ke,kv) == 0) return 0; + diskbase = bmesh_disk_getpointer(kv->edge, kv); + len = bmesh_cycle_length(diskbase); + + if(len == 2){ + oe = bmesh_disk_nextedge(ke, kv); + tv = bmesh_edge_getothervert(ke, kv); + ov = bmesh_edge_getothervert(oe, kv); + halt = bmesh_verts_in_edge(kv, tv, oe); //check for double edges + + if(halt) return 0; + else{ + + /*For verification later, count valance of ov and tv*/ + diskbase = bmesh_disk_getpointer(ov->edge, ov); + valance1 = bmesh_cycle_length(diskbase); + diskbase = bmesh_disk_getpointer(tv->edge, tv); + valance2 = bmesh_cycle_length(diskbase); + + /*remove oe from kv's disk cycle*/ + bmesh_disk_remove_edge(oe,kv); + /*relink oe->kv to be oe->tv*/ + bmesh_edge_swapverts(oe, kv, tv); + /*append oe to tv's disk cycle*/ + bmesh_disk_append_edge(oe, tv); + /*remove ke from tv's disk cycle*/ + bmesh_disk_remove_edge(ke, tv); + + + + /*deal with radial cycle of ke*/ + if(ke->loop){ + /*first step, fix the neighboring loops of all loops in ke's radial cycle*/ + radlen = bmesh_cycle_length(&(ke->loop->radial)); + for(i=0,killoop = ke->loop; i<radlen; i++, killoop = bmesh_radial_nextloop(killoop)){ + /*relink loops and fix vertex pointer*/ + killoop->head.next->prev = killoop->head.prev; + killoop->head.prev->next = killoop->head.next; + if( ((BMLoop*)(killoop->head.next))->v == kv) ((BMLoop*)(killoop->head.next))->v = tv; + + /*fix len attribute of face*/ + killoop->f->len--; + if(killoop->f->loopbase == killoop) killoop->f->loopbase = ((BMLoop*)(killoop->head.next)); + } + /*second step, remove all the hanging loops attached to ke*/ + killoop = ke->loop; + radlen = bmesh_cycle_length(&(ke->loop->radial)); + /*make sure we have enough room in bm->lpar*/ + if(bm->lparlen < radlen){ + MEM_freeN(bm->lpar); + bm->lpar = MEM_callocN(sizeof(BMLoop *)* radlen, "BM Loop pointer array"); + bm->lparlen = bm->lparlen * radlen; + } + /*this should be wrapped into a bme_free_radial function to be used by bmesh_KF as well...*/ + i=0; + while(i<radlen){ + bm->lpar[i] = killoop; + killoop = killoop->radial.next->data; + i++; + } + i=0; + while(i<radlen){ + bmesh_free_loop(bm,bm->lpar[i]); + i++; + } + /*Validate radial cycle of oe*/ + edok = bmesh_cycle_validate(radlen,&(oe->loop->radial)); + + } + + + /*Validate disk cycles*/ + diskbase = bmesh_disk_getpointer(ov->edge,ov); + edok = bmesh_cycle_validate(valance1, diskbase); + if(!edok) bmesh_error(); + diskbase = bmesh_disk_getpointer(tv->edge,tv); + edok = bmesh_cycle_validate(valance2, diskbase); + if(!edok) bmesh_error(); + + /*Validate loop cycle of all faces attached to oe*/ + for(i=0,nextl = oe->loop; i<radlen; i++, nextl = bmesh_radial_nextloop(nextl)){ + edok = bmesh_cycle_validate(nextl->f->len,nextl->f->loopbase); + if(!edok) bmesh_error(); + } + /*deallocate edge*/ + BLI_remlink(&(bm->edges), &(ke->head)); + bmesh_free_edge(bm, ke); + /*deallocate vertex*/ + BLI_remlink(&(bm->verts), &(kv->head)); + bmesh_free_vert(bm, kv); + return 1; + } + } + return 0; +} + + +/** + * bmesh_loop_reverse + * + * FLIP FACE EULER + * + * Changes the winding order of a face from CW to CCW or vice versa. + * This euler is a bit peculiar in compairson to others as it is its + * own inverse. + * + * TODO: reinsert validation code. + * + * Returns - + * 1 for success, 0 for failure. + */ + +int bmesh_loop_reverse(BMesh *bm, BMFace *f){ + BMLoop *l = f->loopbase, *curloop, *oldprev, *oldnext; + int i, j, edok, len = 0; + + len = bmesh_cycle_length(l); + if(bm->edarlen < len){ + MEM_freeN(bm->edar); + bm->edar = MEM_callocN(sizeof(BMEdge *)* len, "BM Edge pointer array"); + bm->edarlen = len; + } + + for(i=0, curloop = l; i< len; i++, curloop= ((BMLoop*)(curloop->head.next)) ){ + curloop->e->head.eflag1 = 0; + curloop->e->head.eflag2 = bmesh_cycle_length(&curloop->radial); + bmesh_radial_remove_loop(curloop, curloop->e); + /*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/ + curloop->radial.next = curloop->radial.prev = NULL; + bm->edar[i] = curloop->e; + } + + /*actually reverse the loop. This belongs in bmesh_cycle_reverse!*/ + for(i=0, curloop = l; i < len; i++){ + oldnext = ((BMLoop*)(curloop->head.next)); + oldprev = ((BMLoop*)(curloop->head.prev)); + curloop->head.next = (BMHeader*)oldprev; + curloop->head.prev = (BMHeader*)oldnext; + curloop = oldnext; + } + + if(len == 2){ //two edged face + //do some verification here! + l->e = bm->edar[1]; + ((BMLoop*)(l->head.next))->e = bm->edar[0]; + } + else{ + for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){ + edok = 0; + for(j=0; j < len; j++){ + edok = bmesh_verts_in_edge(curloop->v, ((BMLoop*)(curloop->head.next))->v, bm->edar[j]); + if(edok){ + curloop->e = bm->edar[j]; + break; + } + } + } + } + /*rebuild radial*/ + for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ) bmesh_radial_append(curloop->e, curloop); + + /*validate radial*/ + for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){ + edok = bmesh_cycle_validate(curloop->e->head.eflag2, &(curloop->radial)); + if(!edok){ + bmesh_error(); + } + } + return 1; +} + +/** + * bmesh_JFKE + * + * JOIN FACE KILL EDGE: + * + * Takes two faces joined by a single 2-manifold edge and fuses them togather. + * The edge shared by the faces must not be connected to any other edges which have + * Both faces in its radial cycle + * + * Examples: + * + * A B + * ---------- ---------- + * | | | | + * | f1 | | f1 | + * v1========v2 = Ok! v1==V2==v3 == Wrong! + * | f2 | | f2 | + * | | | | + * ---------- ---------- + * + * In the example A, faces f1 and f2 are joined by a single edge, and the euler can safely be used. + * In example B however, f1 and f2 are joined by multiple edges and will produce an error. The caller + * in this case should call bmesh_JEKV on the extra edges before attempting to fuse f1 and f2. + * + * Also note that the order of arguments decides whether or not certain per-face attributes are present + * in the resultant face. For instance vertex winding, material index, smooth flags, ect are inherited + * from f1, not f2. + * + * Returns - + * A BMFace pointer +*/ + +//disregarding f1loop and f2loop, if a vertex appears in a joined face more than once, we cancel + +BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) +{ + + BMLoop *curloop, *f1loop=NULL, *f2loop=NULL; + int loopok = 0, newlen = 0,i, f1len=0, f2len=0, radlen=0, edok, shared; + + if(f1 == f2) return NULL; //can't join a face to itself + /*verify that e is in both f1 and f2*/ + f1len = bmesh_cycle_length(f1->loopbase); + f2len = bmesh_cycle_length(f2->loopbase); + for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){ + if(curloop->e == e){ + f1loop = curloop; + break; + } + } + for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){ + if(curloop->e==e){ + f2loop = curloop; + break; + } + } + if(!(f1loop && f2loop)) return NULL; + + /*validate that edge is 2-manifold edge*/ + radlen = bmesh_cycle_length(&(f1loop->radial)); + if(radlen != 2) return NULL; + + /*validate direction of f2's loop cycle is compatible.*/ + if(f1loop->v == f2loop->v) return NULL; + + /* + validate that for each face, each vertex has another edge in its disk cycle that is + not e, and not shared. + */ + if(bmesh_radial_find_face( ((BMLoop*)(f1loop->head.next))->e,f2)) return NULL; + if(bmesh_radial_find_face( ((BMLoop*)(f1loop->head.prev))->e,f2)) return NULL; + if(bmesh_radial_find_face( ((BMLoop*)(f2loop->head.next))->e,f1)) return NULL; + if(bmesh_radial_find_face( ((BMLoop*)(f2loop->head.prev))->e,f1)) return NULL; + + /*validate only one shared edge*/ + shared = BM_Face_Sharededges(f1,f2); + if(shared > 1) return NULL; + + /*validate no internal joins*/ + for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->head.next)) ) curloop->v->head.eflag1 = 0; + for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ) curloop->v->head.eflag1 = 0; + + for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){ + if(curloop != f1loop) + curloop->v->head.eflag1++; + } + for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){ + if(curloop != f2loop) + curloop->v->head.eflag1++; + } + + for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){ + if(curloop->v->head.eflag1 > 1) + return NULL; + } + + for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){ + if(curloop->v->head.eflag1 > 1) + return NULL; + } + + /*join the two loops*/ + f1loop->head.prev->next = f2loop->head.next; + f2loop->head.next->prev = f1loop->head.prev; + + f1loop->head.next->prev = f2loop->head.prev; + f2loop->head.prev->next = f1loop->head.next; + + /*if f1loop was baseloop, give f1loop->next the base.*/ + if(f1->loopbase == f1loop) f1->loopbase = ((BMLoop*)(f1loop->head.next)); + + /*validate the new loop*/ + loopok = bmesh_cycle_validate((f1len+f2len)-2, f1->loopbase); + if(!loopok) bmesh_error(); + + /*make sure each loop points to the proper face*/ + newlen = bmesh_cycle_length(f1->loopbase); + for(i = 0, curloop = f1->loopbase; i < newlen; i++, curloop = ((BMLoop*)(curloop->head.next)) ) curloop->f = f1; + + f1->len = newlen; + + edok = bmesh_cycle_validate(f1->len, f1->loopbase); + if(!edok) bmesh_error(); + + /*remove edge from the disk cycle of its two vertices.*/ + bmesh_disk_remove_edge(f1loop->e, f1loop->e->v1); + bmesh_disk_remove_edge(f1loop->e, f1loop->e->v2); + + /*deallocate edge and its two loops as well as f2*/ + BLI_remlink(&(bm->edges), &(f1loop->e->head)); + BLI_remlink(&(bm->polys), &(f2->head)); + bmesh_free_edge(bm, f1loop->e); + bmesh_free_loop(bm, f1loop); + bmesh_free_loop(bm, f2loop); + bmesh_free_poly(bm, f2); + return f1; +} + +/** +* bmesh_URMV +* +* UNGLUE REGION MAKE VERT: +* +* Takes a locally manifold disk of face corners and 'unglues' it +* creating a new vertex +* +**/ + +#define URMV_VISIT 1 +#define URMV_VISIT2 2 + +BMVert *bmesh_urmv(BMesh *bm, BMFace *sf, BMVert *sv) +{ + BMVert *nv = NULL; + BMLoop *l = NULL, *sl = NULL; + BMEdge *curedge = NULL; + int numloops = 0, numedges = 0, i, maxedges, maxloops; + + + /*Todo: Validation*/ + /*validate radial cycle of all collected loops*/ + /*validate the disk cycle of sv, and nv*/ + /*validate the face length of all faces? overkill?*/ + /*validate the l->e pointers of all affected faces, ie: l->v and l->next->v should be equivalent to l->e*/ + + /*verify that sv has edges*/ + if(sv->edge == NULL) + return NULL; + + /*first verify no wire edges on sv*/ + curedge = sv->edge; + do{ + if(curedge->loop == NULL) + return NULL; + curedge = bmesh_disk_nextedge(curedge, sv); + }while(curedge != sv->edge); + + /*next verify that sv is in sf*/ + l = sf->loopbase; + do{ + if(l->v == sv){ + sl = l; + break; + } + l = (BMLoop*)(l->head.next); + }while(l != sf->loopbase); + + if(sl == NULL) + return NULL; + + /*clear euler flags*/ + sv->head.eflag1 = 0; + + curedge = sv->edge; + do{ + curedge->head.eflag1 = 0; + l = curedge->loop; + do{ + l->head.eflag1 = 0; + l->f->head.eflag1 = 0; + l = bmesh_radial_nextloop(l); + }while(l != curedge->loop); + curedge = bmesh_disk_nextedge(curedge, sv); + }while(curedge != sv->edge); + + /*search through face disk and flag elements as we go.*/ + /*Note, test this to make sure that it works correct on + non-manifold faces! + */ + l = sl; + l->e->head.eflag1 |= URMV_VISIT; + l->f->head.eflag1 |= URMV_VISIT; + do{ + if(l->v == sv) + l = bmesh_radial_nextloop((BMLoop*)(l->head.prev)); + else + l = bmesh_radial_nextloop((BMLoop*)(l->head.next)); + l->e->head.eflag1 |= URMV_VISIT; + l->f->head.eflag1 |= URMV_VISIT; + }while(l != sl && (bmesh_cycle_length(&(l->radial)) > 1) ); + + /*Verify that all visited edges are at least 1 or 2 manifold*/ + curedge = sv->edge; + do{ + if(curedge->head.eflag1 && (bmesh_cycle_length(&(curedge->loop->radial)) > 2) ) + return NULL; + curedge = bmesh_disk_nextedge(curedge, sv); + }while(curedge != sv->edge); + + /*allocate temp storage - we overallocate here instead of trying to be clever*/ + maxedges = 0; + maxloops = 0; + curedge = sv->edge; + do{ + if(curedge->loop){ + l = curedge->loop; + do{ + maxloops += l->f->len; + l = bmesh_radial_nextloop(l); + }while(l != curedge->loop); + } + maxedges+= 1; + curedge = bmesh_disk_nextedge(curedge,sv); + }while(curedge != sv->edge); + + if(bm->edarlen < maxedges){ + MEM_freeN(bm->edar); + bm->edar = MEM_callocN(sizeof(BMEdge *) * maxedges, "BM Edge pointer array"); + bm->edarlen = maxedges; + } + if(bm->lparlen < maxloops){ + MEM_freeN(bm->lpar); + bm->lpar = MEM_callocN(sizeof(BMLoop *) * maxloops, "BM Loop pointer array"); + bm->lparlen = maxloops; + } + + /*first get loops by looping around edges and loops around that edges faces*/ + curedge = sv->edge; + do{ + if(curedge->loop){ + l = curedge->loop; + do{ + if( (l->head.eflag1 & URMV_VISIT) && (!(l->head.eflag1 & URMV_VISIT2)) ){ + bm->lpar[numloops] = l; + l->head.eflag1 |= URMV_VISIT2; + numloops++; + } + l = bmesh_radial_nextloop(l); + }while(l != curedge->loop); + } + curedge = bmesh_disk_nextedge(curedge, sv); + }while(curedge != sv->edge); + + /*now collect edges by looping around edges and looking at visited flags*/ + curedge = sv->edge; + do{ + if(curedge->head.eflag1 & URMV_VISIT){ + bm->edar[numedges] = curedge; + numedges++; + } + curedge = bmesh_disk_nextedge(curedge, sv); + }while(curedge != sv->edge); + + /*make new vertex*/ + nv = bmesh_addvertlist(bm, sv); + + /*go through and relink edges*/ + for(i = 0; i < numedges; i++){ + curedge = bm->edar[i]; + /*remove curedge from sv*/ + bmesh_disk_remove_edge(curedge, sv); + /*swap out sv for nv in curedge*/ + bmesh_edge_swapverts(curedge, sv, nv); + /*add curedge to nv's disk cycle*/ + bmesh_disk_append_edge(curedge, nv); + } + + /*go through and relink loops*/ + for(i = 0; i < numloops; i ++){ + l = bm->lpar[i]; + if(l->v == sv) + l->v = nv; + } + return nv; +} diff --git a/source/blender/bmesh/intern/bmesh_filters.c b/source/blender/bmesh/intern/bmesh_filters.c new file mode 100644 index 00000000000..c31139a8f93 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_filters.c @@ -0,0 +1,5 @@ +#include <stdio.h> +#include <string.h> + +#include "bmesh.h" +#include "bmesh_private.h" diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c new file mode 100644 index 00000000000..ae0904a75df --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -0,0 +1,246 @@ +/** + * BME_interp.c August 2008 + * + * BM interpolation functions. + * + * ***** 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. + * 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) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_customdata.h" +#include "BKE_utildefines.h" + +#include "bmesh.h" +#include "bmesh_private.h" + +/* + * BME_INTERP.C + * + * Functions for interpolating data across the surface of a mesh. + * +*/ + +/** + * bmesh_data_interp_from_verts + * + * Interpolates per-vertex data from two sources to a target. + * + * Returns - + * Nothing + */ +void BM_Data_Interp_From_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, float fac) +{ + void *src[2]; + float w[2]; + if (v1->head.data && v2->head.data) { + src[0]= v1->head.data; + src[1]= v2->head.data; + w[0] = 1.0f-fac; + w[1] = fac; + CustomData_bmesh_interp(&bm->vdata, src, w, NULL, 2, v->head.data); + } +} + +/** + * bmesh_data_facevert_edgeinterp + * + * Walks around the faces of an edge and interpolates the per-face-edge + * data between two sources to a target. + * + * Returns - + * Nothing +*/ + +void BM_Data_Facevert_Edgeinterp(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, BMEdge *e1, float fac){ + void *src[2]; + float w[2]; + BMLoop *l=NULL, *v1loop = NULL, *vloop = NULL, *v2loop = NULL; + + w[1] = 1.0f - fac; + w[0] = fac; + + if(!e1->loop) return; + l = e1->loop; + do{ + if(l->v == v1){ + v1loop = l; + vloop = (BMLoop*)(v1loop->head.next); + v2loop = (BMLoop*)(vloop->head.next); + }else if(l->v == v){ + v1loop = (BMLoop*)(l->head.next); + vloop = l; + v2loop = (BMLoop*)(l->head.prev); + + } + + src[0] = v1loop->head.data; + src[1] = v2loop->head.data; + + CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, vloop->head.data); + l = l->radial.next->data; + }while(l!=e1->loop); +} + +void BM_loops_to_corners(BMesh *bm, Mesh *me, int findex, + BMFace *f, int numTex, int numCol) +{ + BMLoop *l; + BMIter iter; + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + int i, j; + + for(i=0; i < numTex; i++){ + texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i); + texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i); + + texface->tpage = texpoly->tpage; + texface->flag = texpoly->flag; + texface->transp = texpoly->transp; + texface->mode = texpoly->mode; + texface->tile = texpoly->tile; + texface->unwrap = texpoly->unwrap; + + j = 0; + BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) { + mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i); + texface->uv[j][0] = mloopuv->uv[0]; + texface->uv[j][1] = mloopuv->uv[1]; + + j++; + } + + } + + for(i=0; i < numCol; i++){ + mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i); + + j = 0; + BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) { + mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i); + mcol[j].r = mloopcol->r; + mcol[j].g = mloopcol->g; + mcol[j].b = mloopcol->b; + mcol[j].a = mloopcol->a; + + j++; + } + } +} + +//static void bmesh_data_interp_from_face(BME_Mesh *bm, BMFace *source, BMFace *target) +//{ +// +//} +/*insert BM_data_interp_from_face here for mean value coordinates...*/ + + +static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data) +{ + BMIter iter; + void *block; + + if (data == &bm->vdata) { + BMVert *eve; + + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + block = NULL; + CustomData_bmesh_set_default(data, &block); + CustomData_bmesh_copy_data(olddata, data, eve->head.data, &block); + CustomData_bmesh_free_block(olddata, &eve->head.data); + eve->head.data= block; + } + } + else if (data == &bm->edata) { + BMEdge *eed; + + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + block = NULL; + CustomData_bmesh_set_default(data, &block); + CustomData_bmesh_copy_data(olddata, data, eed->head.data, &block); + CustomData_bmesh_free_block(olddata, &eed->head.data); + eed->head.data= block; + } + } + else if (data == &bm->pdata || data == &bm->ldata) { + BMIter liter; + BMFace *efa; + BMLoop *l; + + BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL) { + if (data == &bm->pdata) { + block = NULL; + CustomData_bmesh_set_default(data, &block); + CustomData_bmesh_copy_data(olddata, data, efa->head.data, &block); + CustomData_bmesh_free_block(olddata, &efa->head.data); + efa->head.data= block; + } + + if (data == &bm->ldata) { + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) { + block = NULL; + CustomData_bmesh_set_default(data, &block); + CustomData_bmesh_copy_data(olddata, data, l->head.data, &block); + CustomData_bmesh_free_block(olddata, &l->head.data); + l->head.data= block; + } + } + } + } +} + + +void BM_add_data_layer(BMesh *bm, CustomData *data, int type) +{ + CustomData olddata; + + olddata= *data; + olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL; + CustomData_add_layer(data, type, CD_CALLOC, NULL, 0); + + update_data_blocks(bm, &olddata, data); + if (olddata.layers) MEM_freeN(olddata.layers); +} + +void BM_free_data_layer(BMesh *bm, CustomData *data, int type) +{ + CustomData olddata; + + olddata= *data; + olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL; + CustomData_free_layer_active(data, type, 0); + + update_data_blocks(bm, &olddata, data); + if (olddata.layers) MEM_freeN(olddata.layers); +}
\ No newline at end of file diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c new file mode 100644 index 00000000000..73c76817254 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_iterators.c @@ -0,0 +1,393 @@ +#include <string.h> + +#include "bmesh.h" +#include "bmesh_private.h" + + +void *BMIter_AtIndex(struct BMesh *bm, int type, void *data, int index) +{ + BMIter iter; + void *val; + int i; + + /*sanity check*/ + if (index < 0) return NULL; + + val=BMIter_New(&iter, bm, type, data); + + i = 0; + while (i < index) { + val=BMIter_Step(&iter); + i++; + } + + return val; +} + +/* + * BMESH ITERATOR STEP + * + * Calls an iterators step fucntion to return + * the next element. +*/ + +void *BMIter_Step(BMIter *iter) +{ + return iter->step(iter); +} + +/* + * INIT ITERATOR + * + * Clears the internal state of an iterator + * For begin() callbacks. + * +*/ + +static void init_iterator(BMIter *iter) +{ + iter->firstvert = iter->nextvert = NULL; + iter->firstedge = iter->nextedge = NULL; + iter->firstloop = iter->nextloop = NULL; + iter->firstpoly = iter->nextpoly = NULL; + iter->ldata = NULL; +} + +/* + * Notes on iterator implementation: + * + * Iterators keep track of the next element + * in a sequence. When a step() callback is + * invoked the current value of 'next' is stored + * to be returned later and the next variable is + * incremented. + * + * When the end of a sequence is + * reached, next should always equal NULL + * +*/ + +/* + * VERT OF MESH CALLBACKS + * +*/ + +static void vert_of_mesh_begin(BMIter *iter) +{ + init_iterator(iter); + if(iter->bm->verts.first){ + iter->firstvert = iter->bm->verts.first; + iter->nextvert = iter->bm->verts.first; + } +} + +static void *vert_of_mesh_step(BMIter *iter) +{ + BMVert *current = iter->nextvert; + + if(iter->nextvert) + iter->nextvert = (BMVert*)(iter->nextvert->head.next); + + return current; +} + +/* + * EDGE OF MESH CALLBACKS + * +*/ + +static void edge_of_mesh_begin(BMIter *iter) +{ + init_iterator(iter); + if(iter->bm->edges.first){ + iter->firstedge = iter->bm->edges.first; + iter->nextedge = iter->bm->edges.first; + } +} + +static void *edge_of_mesh_step(BMIter *iter) +{ + BMEdge *current = iter->nextedge; + + if(iter->nextedge) + iter->nextedge = (BMEdge*)(iter->nextedge->head.next); + + return current; +} + +/* + * FACE OF MESH CALLBACKS + * +*/ + +static void face_of_mesh_begin(BMIter *iter) +{ + init_iterator(iter); + if(iter->bm->polys.first){ + iter->firstpoly = iter->bm->polys.first; + iter->nextpoly = iter->bm->polys.first; + } +} + +static void *face_of_mesh_step(BMIter *iter) +{ + BMFace *current = iter->nextpoly; + + if(iter->nextpoly) + iter->nextpoly = (BMFace*)(iter->nextpoly->head.next); + return current; +} + +/* + * EDGE OF VERT CALLBACKS + * +*/ + +static void edge_of_vert_begin(BMIter *iter) +{ + init_iterator(iter); + if(iter->vdata->edge){ + iter->firstedge = iter->vdata->edge; + iter->nextedge = iter->vdata->edge; + } +} + +static void *edge_of_vert_step(BMIter *iter) +{ + BMEdge *current = iter->nextedge; + + if(iter->nextedge) + iter->nextedge = bmesh_disk_nextedge(iter->nextedge, iter->vdata); + + if(iter->nextedge == iter->firstedge) iter->nextedge = NULL; + + return current; +} + +/* + * FACE OF VERT CALLBACKS + * +*/ + +static void face_of_vert_begin(BMIter *iter) +{ + init_iterator(iter); + iter->count = 0; + if(iter->vdata->edge) + iter->count = bmesh_disk_count_facevert(iter->vdata); + if(iter->count){ + iter->firstedge = bmesh_disk_find_first_faceedge(iter->vdata->edge, iter->vdata); + iter->nextedge = iter->firstedge; + iter->firstloop = bmesh_radial_find_first_facevert(iter->firstedge->loop, iter->vdata); + iter->nextloop = iter->firstloop; + } +} +static void *face_of_vert_step(BMIter *iter) +{ + BMLoop *current = iter->nextloop; + + if(iter->count){ + iter->count--; + iter->nextloop = bmesh_radial_find_next_facevert(iter->nextloop, iter->vdata); + if(iter->nextloop == iter->firstloop){ + iter->nextedge = bmesh_disk_find_next_faceedge(iter->nextedge, iter->vdata); + iter->firstloop = bmesh_radial_find_first_facevert(iter->nextedge->loop, iter->vdata); + iter->nextloop = iter->firstloop; + } + } + + if(!iter->count) iter->nextloop = NULL; + + + if(current) return current->f; + return NULL; +} + +static void loops_of_loop_begin(BMIter *iter) +{ + BMLoop *l; + + l = iter->ldata; + + /*note sure why this sets ldata. . .*/ + init_iterator(iter); + + iter->firstloop = l; + iter->nextloop = bmesh_radial_nextloop(iter->firstloop); +} + +static void *loops_of_loop_step(BMIter *iter) +{ + BMLoop *current = iter->nextloop; + + if(iter->nextloop) iter->nextloop = bmesh_radial_nextloop(iter->nextloop); + + if(iter->nextloop == iter->firstloop) iter->nextloop = NULL; + if(current) return current; + return NULL; +} + +/* + * FACE OF EDGE CALLBACKS + * +*/ + +static void face_of_edge_begin(BMIter *iter) +{ + init_iterator(iter); + + if(iter->edata->loop){ + iter->firstloop = iter->edata->loop; + iter->nextloop = iter->edata->loop; + } +} + +static void *face_of_edge_step(BMIter *iter) +{ + BMLoop *current = iter->nextloop; + + if(iter->nextloop) iter->nextloop = bmesh_radial_nextloop(iter->nextloop); + + if(iter->nextloop == iter->firstloop) iter->nextloop = NULL; + if(current) return current->f; + return NULL; +} + +/* + * VERT OF FACE CALLBACKS + * +*/ + +static void vert_of_face_begin(BMIter *iter) +{ + init_iterator(iter); + iter->firstloop = iter->nextloop = iter->pdata->loopbase; +} + +static void *vert_of_face_step(BMIter *iter) +{ + BMLoop *current = iter->nextloop; + + if(iter->nextloop) iter->nextloop = ((BMLoop*)(iter->nextloop->head.next)); + if(iter->nextloop == iter->firstloop) iter->nextloop = NULL; + + if(current) return current->v; + return NULL; +} + +/* + * EDGE OF FACE CALLBACKS + * +*/ + +static void edge_of_face_begin(BMIter *iter) +{ + init_iterator(iter); + iter->firstloop = iter->nextloop = iter->pdata->loopbase; +} + +static void *edge_of_face_step(BMIter *iter) +{ + BMLoop *current = iter->nextloop; + + if(iter->nextloop) iter->nextloop = ((BMLoop*)(iter->nextloop->head.next)); + if(iter->nextloop == iter->firstloop) iter->nextloop = NULL; + + if(current) return current->e; + return NULL; +} + +/* + * LOOP OF FACE CALLBACKS + * +*/ + +static void loop_of_face_begin(BMIter *iter) +{ + init_iterator(iter); + iter->firstloop = iter->nextloop = iter->pdata->loopbase; +} + +static void *loop_of_face_step(BMIter *iter) +{ + BMLoop *current = iter->nextloop; + + if(iter->nextloop) iter->nextloop = ((BMLoop*)(iter->nextloop->head.next)); + if(iter->nextloop == iter->firstloop) iter->nextloop = NULL; + + return current; +} + +/* + * BMESH ITERATOR INIT + * + * Takes a bmesh iterator structure and fills + * it with the appropriate function pointers based + * upon its type and then calls BMeshIter_step() + * to return the first element of the iterator. + * +*/ +void *BMIter_New(BMIter *iter, BMesh *bm, int type, void *data) +{ + int argtype; + iter->type = type; + iter->bm = bm; + + switch(type){ + case BM_VERTS_OF_MESH: + iter->begin = vert_of_mesh_begin; + iter->step = vert_of_mesh_step; + iter->bm = bm; + break; + case BM_EDGES_OF_MESH: + iter->begin = edge_of_mesh_begin; + iter->step = edge_of_mesh_step; + iter->bm = bm; + break; + case BM_FACES_OF_MESH: + iter->begin = face_of_mesh_begin; + iter->step = face_of_mesh_step; + iter->bm = bm; + break; + case BM_EDGES_OF_VERT: + iter->begin = edge_of_vert_begin; + iter->step = edge_of_vert_step; + iter->vdata = data; + break; + case BM_FACES_OF_VERT: + iter->begin = face_of_vert_begin; + iter->step = face_of_vert_step; + iter->vdata = data; + break; + case BM_FACES_OF_EDGE: + iter->begin = face_of_edge_begin; + iter->step = face_of_edge_step; + iter->edata = data; + break; + case BM_VERTS_OF_FACE: + iter->begin = vert_of_face_begin; + iter->step = vert_of_face_step; + iter->pdata = data; + break; + case BM_EDGES_OF_FACE: + iter->begin = edge_of_face_begin; + iter->step = edge_of_face_step; + iter->pdata = data; + break; + case BM_LOOPS_OF_FACE: + iter->begin = loop_of_face_begin; + iter->step = loop_of_face_step; + iter->pdata = data; + break; + case BM_LOOPS_OF_LOOP: + iter->begin = loops_of_loop_begin; + iter->step = loops_of_loop_step; + iter->ldata = data; + break; + default: + break; + } + + iter->begin(iter); + return BMIter_Step(iter); +} diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c new file mode 100644 index 00000000000..5923add3025 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -0,0 +1,307 @@ +#include <string.h> +#include "bmesh.h" +#include "bmesh_private.h" + + +/* + * BM_MARK.C + * + * Selection routines for bmesh structures. + * This is actually all old code ripped from + * editmesh_lib.c and slightly modified to work + * for bmesh's. This also means that it has some + * of the same problems.... something that + * that should be addressed eventually. + * +*/ + + +/* + * BMESH SELECTMODE FLUSH + * + * Makes sure to flush selections + * 'upwards' (ie: all verts of an edge + * selects the edge and so on). This + * should only be called by system and not + * tool authors. + * +*/ + +static void recount_totsels(BMesh *bm) +{ + BMIter iter; + BMHeader *ele; + int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH}; + int *tots[3]; + int i; + + /*recount tot*sel variables*/ + bm->totvertsel = bm->totedgesel = bm->totfacesel = 0; + tots[0] = &bm->totvertsel; + tots[1] = &bm->totedgesel; + tots[2] = &bm->totfacesel; + + for (i=0; i<3; i++) { + ele = BMIter_New(&iter, bm, types[i], NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + if (BM_TestHFlag(ele, BM_SELECT)) *tots[i] += 1; + } + } +} + +void BM_SelectMode_Flush(BMesh *bm) +{ + BMEdge *e; + BMLoop *l; + BMFace *f; + + BMIter edges; + BMIter faces; + + int totsel; + + if(bm->selectmode & SCE_SELECT_VERTEX) { + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)) { + if(BM_TestHFlag(e->v1, BM_SELECT) && BM_TestHFlag(e->v2, BM_SELECT)) BM_SetHFlag(e, BM_SELECT); + else BM_ClearHFlag(e, BM_SELECT); + } + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)) { + totsel = 0; + l=f->loopbase; + do{ + if(BM_TestHFlag(l->v, BM_SELECT)) + totsel++; + l = ((BMLoop*)(l->head.next)); + } while(l != f->loopbase); + + if(totsel == f->len) + BM_SetHFlag(f, BM_SELECT); + else + BM_ClearHFlag(f, BM_SELECT); + } + } + else if(bm->selectmode & SCE_SELECT_EDGE) { + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)) { + totsel = 0; + l=f->loopbase; + do{ + if(bmesh_test_sysflag(&(l->e->head), BM_SELECT)) + totsel++; + l = ((BMLoop*)(l->head.next)); + }while(l!=f->loopbase); + + if(totsel == f->len) + BM_SetHFlag(f, BM_SELECT); + else + BM_ClearHFlag(f, BM_SELECT); + } + } + + recount_totsels(bm); +} + +/* + * BMESH SELECT VERT + * + * Changes selection state of a single vertex + * in a mesh + * +*/ + +void BM_Select_Vert(BMesh *bm, BMVert *v, int select) +{ + if(select) { + if (!BM_TestHFlag(v, BM_SELECT)) bm->totvertsel += 1; + BM_SetHFlag(v, BM_SELECT); + } else { + if (BM_TestHFlag(v, BM_SELECT)) bm->totvertsel -= 1; + BM_ClearHFlag(v, BM_SELECT); + } +} + +/* + * BMESH SELECT EDGE + * + * Changes selection state of a single edge + * in a mesh. Note that this is actually not + * 100 percent reliable. Deselecting an edge + * will also deselect both its vertices + * regardless of the selection state of + * other edges incident upon it. Fixing this + * issue breaks multi-select mode though... + * +*/ + +void BM_Select_Edge(BMesh *bm, BMEdge *e, int select) +{ + int candesel; + int testiso = 1; + + /*I might move this logic to bmeshutils_mods.c, where it'd be invoked + by the selection tools. in that case, we'd still retain the checks + for if an edge's verts can be deselected.*/ + + /*ensure vert selections are valid, only if not in a multiselect + mode that shares SCE_SELECT_VERT*/ + if (bm->selectmode & (SCE_SELECT_VERTEX|SCE_SELECT_EDGE)) testiso = 1; + else if (bm->selectmode & (SCE_SELECT_VERTEX|SCE_SELECT_FACE)) testiso = 1; + + if (testiso && !select) { + BMIter eiter; + BMEdge *e2; + int i; + + for (i=0; i<2; i++) { + candesel = 1; + e2 = BMIter_New(&eiter, bm, BM_EDGES_OF_VERT, !i?e->v1:e->v2); + for (; e2; e2=BMIter_Step(&eiter)) { + if (e2 == e) continue; + if (BM_TestHFlag(e2, BM_SELECT)) { + candesel = 0; + break; + } + } + + if (candesel) BM_Select_Vert(bm, !i?e->v1:e->v2, 0); + } + } + + if(select) { + if (!BM_TestHFlag(e, BM_SELECT)) bm->totedgesel += 1; + + BM_SetHFlag(&(e->head), BM_SELECT); + BM_SetHFlag(e->v1, BM_SELECT); + BM_SetHFlag(e->v2, BM_SELECT); + } + else{ + if (BM_TestHFlag(e, BM_SELECT)) bm->totedgesel -= 1; + + BM_ClearHFlag(&(e->head), BM_SELECT); + } +} + +/* + * + * BMESH SELECT FACE + * + * Changes selection state of a single + * face in a mesh. This (might) suffer + * from same problems as edge select + * code... + * +*/ + +void BM_Select_Face(BMesh *bm, BMFace *f, int select) +{ + BMLoop *l; + + if(select){ + if (!BM_TestHFlag(f, BM_SELECT)) bm->totfacesel += 1; + + BM_SetHFlag(&(f->head), BM_SELECT); + l = f->loopbase; + do{ + BM_SetHFlag(&(l->v->head), BM_SELECT); + BM_SetHFlag(&(l->e->head), BM_SELECT); + l = ((BMLoop*)(l->head.next)); + }while(l != f->loopbase); + } + else{ + if (BM_TestHFlag(f, BM_SELECT)) bm->totfacesel -= 1; + + BM_ClearHFlag(&(f->head), BM_SELECT); + l = f->loopbase; + do { + BM_ClearHFlag(&(l->v->head), BM_SELECT); + BM_ClearHFlag(&(l->e->head), BM_SELECT); + l = ((BMLoop*)(l->head.next)); + } while(l != f->loopbase); + } +} + +/* + * BMESH SELECTMODE SET + * + * Sets the selection mode for the bmesh + * +*/ + +void BM_Selectmode_Set(BMesh *bm, int selectmode) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + + bm->selectmode = selectmode; + + if(bm->selectmode & SCE_SELECT_VERTEX) { + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)) + BM_ClearHFlag(e, 0); + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)) + BM_ClearHFlag(f, 0); + BM_SelectMode_Flush(bm); + } + else if(bm->selectmode & SCE_SELECT_EDGE) { + for(v= BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v= BMIter_Step(&verts)) + BM_ClearHFlag(v, 0); + for(e= BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)){ + if(BM_TestHFlag(&(e->head), BM_SELECT)) + BM_Select_Edge(bm, e, 1); + } + BM_SelectMode_Flush(bm); + } + else if(bm->selectmode & SCE_SELECT_FACE) { + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)) + BM_ClearHFlag(e, 0); + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)){ + if(BM_TestHFlag(&(f->head), BM_SELECT)) + BM_Select_Face(bm, f, 1); + } + BM_SelectMode_Flush(bm); + } +} + + +int BM_CountFlag(struct BMesh *bm, int type, int flag) +{ + BMHeader *head; + BMIter iter; + int tot = 0; + + if (type & BM_VERT) { + for (head = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); head; head=BMIter_Step(&iter)) { + if (head->flag & flag) tot++; + } + } + if (type & BM_EDGE) { + for (head = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); head; head=BMIter_Step(&iter)) { + if (head->flag & flag) tot++; + } + } + if (type & BM_FACE) { + for (head = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); head; head=BMIter_Step(&iter)) { + if (head->flag & flag) tot++; + } + } + + return tot; +} + +void BM_Select(struct BMesh *bm, void *element, int select) +{ + BMHeader *head = element; + + if(head->type == BM_VERT) BM_Select_Vert(bm, (BMVert*)element, select); + else if(head->type == BM_EDGE) BM_Select_Edge(bm, (BMEdge*)element, select); + else if(head->type == BM_FACE) BM_Select_Face(bm, (BMFace*)element, select); +} + +int BM_Is_Selected(BMesh *bm, void *element) +{ + BMHeader *head = element; + return BM_TestHFlag(head, BM_SELECT); +}
\ No newline at end of file diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c new file mode 100644 index 00000000000..48b0d117843 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -0,0 +1,277 @@ +/** + * BME_mesh.c jan 2007 + * + * BM mesh level functions. + * + * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** 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. + * 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) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" +#include "DNA_listBase.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BKE_utildefines.h" + +#include "bmesh.h" +#include "bmesh_private.h" + +void BME_error(void); + +/*bmesh_error stub*/ +void bmesh_error(void) +{ + printf("BM modelling error!"); +} + +/* + * BMESH SET SYSFLAG + * + * Sets a bitflag for a given element. + * +*/ + +void bmesh_set_sysflag(BMHeader *head, int flag) +{ + head->flag |= flag; +} + +/* + * BMESH CLEAR SYSFLAG + * + * Clears a bitflag for a given element. + * +*/ + +void bmesh_clear_sysflag(BMHeader *head, int flag) +{ + head->flag &= ~flag; +} + + +/* + * BMESH TEST SYSFLAG + * + * Tests whether a bitflag is set for a given element. + * +*/ + +int bmesh_test_sysflag(BMHeader *head, int flag) +{ + if(head->flag & flag) + return 1; + return 0; +} + +/* + * BMESH MAKE MESH + * + * Allocates a new BMesh structure. + * Returns - + * Pointer to a BM + * +*/ + +BMesh *BM_Make_Mesh(int allocsize[4]) +{ + /*allocate the structure*/ + BMesh *bm = MEM_callocN(sizeof(BMesh),"BM"); + /*allocate the memory pools for the mesh elements*/ + bm->vpool = BLI_mempool_create(sizeof(BMVert), allocsize[0], allocsize[0]); + bm->epool = BLI_mempool_create(sizeof(BMEdge), allocsize[1], allocsize[1]); + bm->lpool = BLI_mempool_create(sizeof(BMLoop), allocsize[2], allocsize[2]); + bm->ppool = BLI_mempool_create(sizeof(BMFace), allocsize[3], allocsize[3]); + + /*allocate one flag pool that we dont get rid of.*/ + bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer), 512, 512); + bm->totflags = 1; + + return bm; +} +/* + * BMESH FREE MESH + * + * Frees a BMesh structure. +*/ + +void BM_Free_Mesh_Data(BMesh *bm) +{ + BMVert *v; + BMEdge *e; + BMLoop *l; + BMFace *f; + + + BMIter verts; + BMIter edges; + BMIter faces; + BMIter loops; + + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v = BMIter_Step(&verts)) CustomData_bmesh_free_block( &(bm->vdata), &(v->head.data) ); + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e = BMIter_Step(&edges)) CustomData_bmesh_free_block( &(bm->edata), &(e->head.data) ); + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f = BMIter_Step(&faces)){ + CustomData_bmesh_free_block( &(bm->pdata), &(f->head.data) ); + for(l = BMIter_New(&loops, bm, BM_LOOPS_OF_FACE, f ); l; l = BMIter_Step(&loops)) CustomData_bmesh_free_block( &(bm->ldata), &(l->head.data) ); + } + + /*Free custom data pools, This should probably go in CustomData_free?*/ + if(bm->vdata.totlayer) BLI_mempool_destroy(bm->vdata.pool); + if(bm->edata.totlayer) BLI_mempool_destroy(bm->edata.pool); + if(bm->ldata.totlayer) BLI_mempool_destroy(bm->ldata.pool); + if(bm->pdata.totlayer) BLI_mempool_destroy(bm->pdata.pool); + + /*free custom data*/ + CustomData_free(&bm->vdata,0); + CustomData_free(&bm->edata,0); + CustomData_free(&bm->ldata,0); + CustomData_free(&bm->pdata,0); + + /*destroy element pools*/ + BLI_mempool_destroy(bm->vpool); + BLI_mempool_destroy(bm->epool); + BLI_mempool_destroy(bm->ppool); + BLI_mempool_destroy(bm->lpool); + + /*destroy flag pool*/ + BLI_mempool_destroy(bm->flagpool); + + BMO_ClearStack(bm); +} + +void BM_Free_Mesh(BMesh *bm) +{ + BM_Free_Mesh_Data(bm); + MEM_freeN(bm); +} + +/* + * BMESH COMPUTE NORMALS + * + * Updates the normals of a mesh. + * Note that this can only be called + * +*/ + +void BM_Compute_Normals(BMesh *bm) +{ + BMVert *v; + BMFace *f; + BMLoop *l; + + BMIter verts; + BMIter faces; + BMIter loops; + + unsigned int maxlength = 0; + float (*projectverts)[3]; + + /*first, find out the largest face in mesh*/ + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f = BMIter_Step(&faces)){ + if(f->len > maxlength) maxlength = f->len; + } + + /*make sure we actually have something to do*/ + if(maxlength < 3) return; + + /*allocate projectverts array*/ + projectverts = MEM_callocN(sizeof(float) * maxlength * 3, "BM normal computation array"); + + /*calculate all face normals*/ + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f = BMIter_Step(&faces)){ + if (f->head.flag & BM_NONORMCALC) continue; + bmesh_update_face_normal(bm, f, projectverts); + } + + /*Zero out vertex normals*/ + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v = BMIter_Step(&verts)) v->no[0] = v->no[1] = v->no[2] = 0.0; + + /*add face normals to vertices*/ + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f = BMIter_Step(&faces)){ + for(l = BMIter_New(&loops, bm, BM_LOOPS_OF_FACE, f ); l; l = BMIter_Step(&loops)) VecAddf(l->v->no, l->v->no, f->no); + } + + /*average the vertex normals*/ + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v= BMIter_Step(&verts)){ + if (Normalize(v->no)==0.0) { + VECCOPY(v->no, v->co); + Normalize(v->no); + } + } + + MEM_freeN(projectverts); +} + +/* + * BMESH BEGIN/END EDIT + * + * Functions for setting up a mesh for editing and cleaning up after + * the editing operations are done. These are called by the tools/operator + * API for each time a tool is executed. + * + * Returns - + * Nothing + * +*/ + +void bmesh_begin_edit(BMesh *bm){ + + /*Initialize some scratch pointer arrays used by eulers*/ + bm->vtar = MEM_callocN(sizeof(BMVert *) * 1024, "BM scratch vert array"); + bm->edar = MEM_callocN(sizeof(BMEdge *) * 1024, "BM scratch edge array"); + bm->lpar = MEM_callocN(sizeof(BMLoop *) * 1024, "BM scratch loop array"); + bm->plar = MEM_callocN(sizeof(BMFace *) * 1024, "BM scratch poly array"); + + bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 1024; +} + +void bmesh_end_edit(BMesh *bm, int flag){ + int totvert, totedge, totface; + /*verify element counts*/ + totvert = BLI_countlist(&(bm->verts)); + totedge = BLI_countlist(&(bm->edges)); + totface = BLI_countlist(&(bm->polys)); + + if(bm->totvert!=totvert || bm->totedge!=totedge || bm->totface!=totface) BME_error(); + + /*free temp storage*/ + if(bm->vtar) MEM_freeN(bm->vtar); + if(bm->edar) MEM_freeN(bm->edar); + if(bm->lpar) MEM_freeN(bm->lpar); + if(bm->plar) MEM_freeN(bm->plar); + + /*zero out pointers*/ + bm->vtar = NULL; + bm->edar = NULL; + bm->lpar = NULL; + bm->plar = NULL; + bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 0; + + /*compute normals, clear temp flags and flush selections*/ + BM_Compute_Normals(bm); + BM_SelectMode_Flush(bm); +} diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c new file mode 100644 index 00000000000..433b8a74387 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -0,0 +1,417 @@ +#include <limits.h> +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "BKE_utildefines.h" +#include "BLI_blenlib.h" +#include "BLI_linklist.h" +#include "BLI_ghash.h" +#include "BLI_arithb.h" + +#include "bmesh.h" +#include "bmesh_private.h" + +#include <stdlib.h> +#include <string.h> + +/* + * BME_MODS.C + * + * This file contains functions for locally modifying + * the topology of existing mesh data. (split, join, flip ect). + * +*/ + +/** + * bmesh_dissolve_disk + * + * Turns the face region surrounding a manifold vertex into + * A single polygon. + * + * + * Example: + * + * |=========| |=========| + * | \ / | | | + * Before: | V | After: | | + * | / \ | | | + * |=========| |=========| + * + * + */ +#if 1 +int BM_Dissolve_Vert(BMesh *bm, BMVert *v) { + BMIter iter; + BMEdge *e; + int len=0; + + if (!v) return 0; + + e = BMIter_New(&iter, bm, BM_EDGES_OF_VERT, v); + for (; e; e=BMIter_Step(&iter)) { + len++; + } + + if (len == 1) { + bmesh_ke(bm, v->edge); + bmesh_kv(bm, v); + return 1; + } + + if(BM_Nonmanifold_Vert(bm, v)) { + if (!v->edge) bmesh_kv(bm, v); + else if (!v->edge->loop) { + bmesh_ke(bm, v->edge); + bmesh_kv(bm, v); + } else return 0; + + return 1; + } + + return BM_Dissolve_Disk(bm, v); +} + +int BM_Dissolve_Disk(BMesh *bm, BMVert *v) { + BMFace *f, *f2; + BMEdge *e, *keepedge=NULL, *baseedge=NULL; + BMLoop *loop; + int done, len; + + if(BM_Nonmanifold_Vert(bm, v)) { + return 0; + } + + if(v->edge){ + /*v->edge we keep, what else?*/ + e = v->edge; + len = 0; + do{ + e = bmesh_disk_nextedge(e,v); + if(!(BM_Edge_Share_Faces(e, v->edge))){ + keepedge = e; + baseedge = v->edge; + break; + } + len++; + }while(e != v->edge); + } + + /*this code for handling 2 and 3-valence verts + may be totally bad.*/ + if (keepedge == NULL && len == 3) { + /*handle specific case for three-valence. solve it by + increasing valence to four. this may be hackish. . .*/ + loop = e->loop; + if (loop->v == v) loop = (BMLoop*) loop->head.next; + if (!BM_Split_Face(bm, loop->f, v, loop->v, NULL, NULL)) + return 0; + + BM_Dissolve_Disk(bm, v); + return 1; + } else if (keepedge == NULL && len == 2) { + /*handle two-valence*/ + f = v->edge->loop->f; + f2 = ((BMLoop*)v->edge->loop->radial.next->data)->f; + /*collapse the vertex*/ + BM_Collapse_Vert(bm, v->edge, v, 1.0); + BM_Join_Faces(bm, f, f2, NULL); + + return 1; + } + + if(keepedge){ + done = 0; + while(!done){ + done = 1; + e = v->edge; + do{ + f = NULL; + len = bmesh_cycle_length(&(e->loop->radial)); + if(len == 2 && (e!=baseedge) && (e!=keepedge)) { + f = BM_Join_Faces(bm, e->loop->f, ((BMLoop*)(e->loop->radial.next->data))->f, e); + /*return if couldn't join faces in manifold + conditions.*/ + //!disabled for testing why bad things happen + if (!f) return 0; + } + + if(f){ + done = 0; + break; + } + e = bmesh_disk_nextedge(e, v); + }while(e != v->edge); + } + + /*get remaining two faces*/ + f = v->edge->loop->f; + f2 = ((BMLoop*)v->edge->loop->radial.next->data)->f; + + /*collapse the vertex*/ + BM_Collapse_Vert(bm, baseedge, v, 1.0); + + if (f != f2) { + /*join two remaining faces*/ + if (!BM_Join_Faces(bm, f, f2, NULL)) return 0; + } + } + + return 1; +} +#else +void BM_Dissolve_Disk(BMesh *bm, BMVert *v){ + BMFace *f; + BMEdge *e; + BMIter iter; + int done, len; + + if(v->edge){ + done = 0; + while(!done){ + done = 1; + + /*loop the edges looking for an edge to dissolve*/ + for (e=BMIter_New(&iter, bm, BM_EDGES_OF_VERT, v); e; + e = BMIter_Step(&iter)) { + f = NULL; + len = bmesh_cycle_length(&(e->loop->radial)); + if(len == 2){ + f = BM_Join_Faces(bm,e->loop->f,((BMLoop*) + (e->loop->radial.next->data))->f, + e); + } + if(f){ + done = 0; + break; + } + }; + } + BM_Collapse_Vert(bm, v->edge, v, 1.0); + } +} +#endif + +/** + * bmesh_join_faces + * + * joins two adjacenct faces togather. + * + * Returns - + * BMFace pointer + */ + +BMFace *BM_Join_Faces(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) { + + BMLoop *l1, *l2; + BMEdge *jed=NULL; + + jed = e; + if(!jed){ + /*search for an edge that has both these faces in its radial cycle*/ + l1 = f1->loopbase; + do{ + if( ((BMLoop*)l1->radial.next->data)->f == f2 ){ + jed = l1->e; + break; + } + l1 = ((BMLoop*)(l1->head.next)); + }while(l1!=f1->loopbase); + } + + l1 = jed->loop; + l2 = l1->radial.next->data; + if (l1->v == l2->v) { + bmesh_loop_reverse(bm, f2); + } + + f1 = bmesh_jfke(bm, f1, f2, jed); + + return f1; +} + +/*connects two verts together, automatically (if very naively) finding the + face they both share (if there is one) and splittling it. use this at your + own risk, as it doesn't handle the many complex cases it should (like zero-area faces, + multiple faces, etc). + + this is really only meant for cases where you don't know before hand the face + the two verts belong to for splitting (e.g. the subdivision operator). +*/ + +BMEdge *BM_Connect_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf) { + BMIter iter, iter2; + BMVert *v; + BMLoop *nl; + BMFace *face; + + /*this isn't the best thing in the world. it doesn't handle cases where there's + multiple faces yet. that might require a convexity test to figure out which + face is "best," and who knows what for non-manifold conditions.*/ + for (face = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v1); face; face=BMIter_Step(&iter)) { + for (v=BMIter_New(&iter2, bm, BM_VERTS_OF_FACE, face); v; v=BMIter_Step(&iter2)) { + if (v == v2) { + face = BM_Split_Face(bm, face, v1, v2, &nl, NULL); + + if (nf) *nf = face; + return nl->e; + } + } + } + + return NULL; +} + +/** + * BM_split_face + * + * Splits a single face into two. + * + * Returns - + * BMFace pointer + */ + +BMFace *BM_Split_Face(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **nl, BMEdge *example) +{ + BMFace *nf; + nf = bmesh_sfme(bm,f,v1,v2,nl); + + if (nf) { + BM_Copy_Attributes(bm, bm, f, nf); + VECCOPY(nf->no, f->no); + } + + return nf; +} + +/** + * bmesh_collapse_vert + * + * Collapses a vertex that has only two manifold edges + * onto a vertex it shares an edge with. Fac defines + * the amount of interpolation for Custom Data. + * + * Note that this is not a general edge collapse function. For + * that see BM_manifold_edge_collapse + * + * TODO: + * Insert error checking for KV valance. + * + * Returns - + * Nothing + */ + +void BM_Collapse_Vert(BMesh *bm, BMEdge *ke, BMVert *kv, float fac){ + void *src[2]; + float w[2]; + BMLoop *l=NULL, *kvloop=NULL, *tvloop=NULL; + BMVert *tv = bmesh_edge_getothervert(ke,kv); + + w[0] = 1.0f - fac; + w[1] = fac; + + if(ke->loop){ + l = ke->loop; + do{ + if(l->v == tv && ((BMLoop*)(l->head.next))->v == kv){ + tvloop = l; + kvloop = ((BMLoop*)(l->head.next)); + + src[0] = kvloop->head.data; + src[1] = tvloop->head.data; + CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, kvloop->head.data); + } + l=l->radial.next->data; + }while(l!=ke->loop); + } + BM_Data_Interp_From_Verts(bm, kv, tv, kv, fac); + bmesh_jekv(bm,ke,kv); +} + +/** + * BM_split_edge + * + * Splits an edge. v should be one of the vertices in e and + * defines the direction of the splitting operation for interpolation + * purposes. + * + * Returns - + * the new vert + */ + +BMVert *BM_Split_Edge(BMesh *bm, BMVert *v, BMEdge *e, BMEdge **ne, float percent) { + BMVert *nv, *v2; + + v2 = bmesh_edge_getothervert(e,v); + nv = bmesh_semv(bm,v,e,ne); + if (nv == NULL) return NULL; + VECSUB(nv->co,v2->co,v->co); + VECADDFAC(nv->co,v->co,nv->co,percent); + if (ne) { + if(bmesh_test_sysflag(&(e->head), BM_SELECT)) { + bmesh_set_sysflag((BMHeader*)*ne, BM_SELECT); + bmesh_set_sysflag((BMHeader*)nv, BM_SELECT); + } + if(bmesh_test_sysflag(&(e->head), BM_HIDDEN)) { + bmesh_set_sysflag((BMHeader*)*ne, BM_HIDDEN); + bmesh_set_sysflag((BMHeader*)nv, BM_HIDDEN); + } + } + /*v->nv->v2*/ + BM_Data_Facevert_Edgeinterp(bm,v2, v, nv, e, percent); + BM_Data_Interp_From_Verts(bm, v2, v, nv, percent); + return nv; +} + +BMVert *BM_Split_Edge_Multi(BMesh *bm, BMEdge *e, int numcuts) +{ + int i; + float percent; + BMVert *nv = NULL; + + for(i=0; i < numcuts; i++){ + percent = 1.0f / (float)(numcuts + 1 - i); + nv = BM_Split_Edge(bm, e->v2, e, NULL, percent); + } + return nv; +} + +int BM_Validate_Face(BMesh *bm, BMFace *face, FILE *err) +{ + BMIter iter; + V_DECLARE(verts); + BMVert **verts = NULL; + BMLoop *l; + int ret = 1, i, j; + + if (face->len == 2) { + fprintf(err, "warning: found two-edged face. face ptr: %p\n", face); + fflush(err); + } + + for (l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, face);l;l=BMIter_Step(&iter)) { + V_GROW(verts); + verts[V_COUNT(verts)-1] = l->v; + + if (l->e->v1 == l->e->v2) { + fprintf(err, "Found bmesh edge with identical verts!\n"); + fprintf(err, " edge ptr: %p, vert: %p\n", l->e, l->e->v1); + fflush(err); + ret = 0; + } + } + + for (i=0; i<V_COUNT(verts); i++) { + for (j=0; j<V_COUNT(verts); j++) { + if (j == i) continue; + if (verts[i] == verts[j]) { + fprintf(err, "Found duplicate verts in bmesh face!\n"); + fprintf(err, " face ptr: %p, vert: %p\n", face, verts[i]); + fflush(err); + ret = 0; + } + } + } + + V_FREE(verts); + return ret; +} diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c new file mode 100644 index 00000000000..07f1144b37e --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -0,0 +1,324 @@ +#include "bmesh.h" +#include "bmesh_private.h" + +#include <stdio.h> + +/*do not rename any operator or slot names! otherwise you must go + through the code and find all references to them!*/ + +BMOpDefine def_finddoubles = { + "finddoubles", + /*maps welded vertices to verts they should weld to.*/ + {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, + //list of verts to keep + {BMOP_OPSLOT_ELEMENT_BUF, "keepverts"}, + {BMOP_OPSLOT_FLT, "dist"}, + {BMOP_OPSLOT_MAPPING, "targetmapout"}, + {0, /*null-terminating sentinel*/}}, + bmesh_finddoubles_exec, + 0, +}; + +BMOpDefine def_removedoubles = { + "removedoubles", + /*maps welded vertices to verts they should weld to.*/ + {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, + {BMOP_OPSLOT_FLT, "dist"}, + {0, /*null-terminating sentinel*/}}, + bmesh_removedoubles_exec, + 0, +}; + +BMOpDefine def_weldverts = { + "weldverts", + /*maps welded vertices to verts they should weld to.*/ + {{BMOP_OPSLOT_MAPPING, "targetmap"}, + {0, /*null-terminating sentinel*/}}, + bmesh_weldverts_exec, + 0, +}; + +BMOpDefine def_makevert = { + "makevert", + {{BMOP_OPSLOT_VEC, "co"}, + {BMOP_OPSLOT_ELEMENT_BUF, "newvertout"}, + {0, /*null-terminating sentinel*/}}, + bmesh_makevert_exec, + 0, +}; + +/*contextual_create is fkey, it creates + new faces, makes stuff from edge nets, + makes wire edges, etc. it also dissolves + faces.*/ +BMOpDefine def_contextual_create= { + "contextual_create", + {{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, + {BMOP_OPSLOT_ELEMENT_BUF, "faceout"}, + {0, /*null-terminating sentinel*/}}, + bmesh_contextual_create_exec, + 0, +}; + +BMOpDefine def_edgenet_fill= { + "edgenet_fill", + {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, + {BMOP_OPSLOT_ELEMENT_BUF, "faceout"}, + {0, /*null-terminating sentinel*/}}, + bmesh_edgenet_fill_exec, + 0, +}; + +BMOpDefine def_rotate = { + "rotate", + {{BMOP_OPSLOT_VEC, "cent"}, + {BMOP_OPSLOT_MAT, "mat"}, + {BMOP_OPSLOT_ELEMENT_BUF, "verts"}, + {0, /*null-terminating sentinel*/}}, + bmesh_rotate_exec, + 0, +}; + +BMOpDefine def_translate= { + "translate", + {{BMOP_OPSLOT_VEC, "vec"}, + {BMOP_OPSLOT_ELEMENT_BUF, "verts"}, + {0, /*null-terminating sentinel*/}}, + bmesh_translate_exec, + 0, +}; + + +/*applies a transform to vertices*/ +BMOpDefine def_transform = { + "transform", + {{BMOP_OPSLOT_MAT, "mat"}, + {BMOP_OPSLOT_ELEMENT_BUF, "verts"}, + {0, /*null-terminating sentinel*/}}, + bmesh_transform_exec, + 0, +}; + +/*loads a bmesh into an object*/ +BMOpDefine def_object_load_bmesh = { + "object_load_bmesh", + {{BMOP_OPSLOT_PNT, "scene"}, + {BMOP_OPSLOT_PNT, "object"}, + {0, /*null-terminating sentinel*/}}, + bmesh_to_mesh_exec, + 0, +}; + + +BMOpDefine def_mesh_to_bmesh = { + "mesh_to_bmesh", + {{BMOP_OPSLOT_PNT, "mesh"}, + {0, /*null-terminating sentinel*/}}, + mesh_to_bmesh_exec, + 0 +}; + +BMOpDefine def_extrudeverts_indiv = { + "extrude_vert_indiv", + {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, + {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"}, + {BMOP_OPSLOT_ELEMENT_BUF, "vertout"}, + {0} /*null-terminating sentinel*/}, + extrude_vert_indiv_exec, + 0 +}; + +#if 0 +BMOpDefine def_makeprim = { + "makeprim", + {{BMOP_OPSLOT_INT, "type"}, + {BMOP_OPSLOT_INT, "tot", /*rows/cols also applies to spheres*/ + {BMOP_OPSLOT_INT, "seg", + {BMOP_OPSLOT_INT, "subdiv"}, + {BMOP_OPSLOT_INT, "ext"}, + {BMOP_OPSLOT_INT, "fill"}, + {BMOP_OPSLOT_FLT, "dia"}, + {BMOP_OPSLOT_FLT, "depth"}, + {BMOP_OPSLOT_PNT, "mat"}, + {BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, //won't be implemented right away + {0}} + makeprim_exec, + 0 +}; +#endif + +BMOpDefine def_connectverts = { + "connectverts", + {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, + {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"}, + {0} /*null-terminating sentinel*/}, + connectverts_exec, + 0 +}; + +BMOpDefine def_extrudefaceregion = { + "extrudefaceregion", + {{BMOP_OPSLOT_ELEMENT_BUF, "edgefacein"}, + {BMOP_OPSLOT_MAPPING, "exclude"}, + {BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, + {0} /*null-terminating sentinel*/}, + extrude_edge_context_exec, + 0 +}; + +BMOpDefine def_makefgonsop = { + "makefgon", + {{BMOP_OPSLOT_INT, "trifan"}, /*use triangle fans instead of + real interpolation*/ + {0} /*null-terminating sentinel*/}, + bmesh_make_fgons_exec, + 0 +}; + +BMOpDefine def_dissolvevertsop = { + "dissolveverts", + {{BMOP_OPSLOT_ELEMENT_BUF, "verts"}, + {0} /*null-terminating sentinel*/}, + dissolveverts_exec, + 0 +}; + +BMOpDefine def_dissolveedgessop = { + "dissolveedges", + {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, + {BMOP_OPSLOT_ELEMENT_BUF, "regionout"}, + {0} /*null-terminating sentinel*/}, + dissolveedges_exec, + 0 +}; + +BMOpDefine def_dissolveedgeloopsop = { + "dissolveedgeloop", + {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, + {BMOP_OPSLOT_ELEMENT_BUF, "regionout"}, + {0} /*null-terminating sentinel*/}, + dissolve_edgeloop_exec, + 0 +}; + +BMOpDefine def_dissolvefacesop = { + "dissolvefaces", + {{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, + {BMOP_OPSLOT_ELEMENT_BUF, "regionout"}, + {0} /*null-terminating sentinel*/}, + dissolvefaces_exec, + 0 +}; + + +BMOpDefine def_triangop = { + "triangulate", + {{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, + {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"}, + {BMOP_OPSLOT_ELEMENT_BUF, "faceout"}, + {BMOP_OPSLOT_MAPPING, "facemap"}, + {0} /*null-terminating sentinel*/}, + triangulate_exec, + 0 +}; + +BMOpDefine def_subdop = { + "esubd", + {{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, + {BMOP_OPSLOT_INT, "numcuts"}, + {BMOP_OPSLOT_FLT, "smooth"}, + {BMOP_OPSLOT_FLT, "fractal"}, + {BMOP_OPSLOT_INT, "beauty"}, + {BMOP_OPSLOT_MAPPING, "custompatterns"}, + {BMOP_OPSLOT_MAPPING, "edgepercents"}, + + /*these next two can have multiple types of elements in them.*/ + {BMOP_OPSLOT_ELEMENT_BUF, "outinner"}, + {BMOP_OPSLOT_ELEMENT_BUF, "outsplit"}, + {0} /*null-terminating sentinel*/, + }, + esubdivide_exec, + 0 +}; + +BMOpDefine def_edit2bmesh = { + "editmesh_to_bmesh", + {{BMOP_OPSLOT_PNT, "em"}, {BMOP_OPSLOT_MAPPING, "map"}, + {0} /*null-terminating sentinel*/}, + edit2bmesh_exec, + 0 +}; + +BMOpDefine def_bmesh2edit = { + "bmesh_to_editmesh", + {{BMOP_OPSLOT_PNT, "emout"}, + {0} /*null-terminating sentinel*/}, + bmesh2edit_exec, + 0 +}; + +BMOpDefine def_delop = { + "del", + {{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, {BMOP_OPSLOT_INT, "context"}, + {0} /*null-terminating sentinel*/}, + delop_exec, + 0 +}; + +BMOpDefine def_dupeop = { + "dupe", + {{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, + {BMOP_OPSLOT_ELEMENT_BUF, "origout"}, + {BMOP_OPSLOT_ELEMENT_BUF, "newout"}, + /*facemap maps from source faces to dupe + faces, and from dupe faces to source faces.*/ + {BMOP_OPSLOT_MAPPING, "facemap"}, + {BMOP_OPSLOT_MAPPING, "boundarymap"}, + {BMOP_OPSLOT_MAPPING, "isovertmap"}, + {0} /*null-terminating sentinel*/}, + dupeop_exec, + 0 +}; + +BMOpDefine def_splitop = { + "split", + {{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, + {BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, + {BMOP_OPSLOT_MAPPING, "boundarymap"}, + {BMOP_OPSLOT_MAPPING, "isovertmap"}, + {0} /*null-terminating sentinel*/}, + splitop_exec, + 0 +}; + +BMOpDefine *opdefines[] = { + &def_splitop, + &def_dupeop, + &def_delop, + &def_edit2bmesh, + &def_bmesh2edit, + &def_subdop, + &def_triangop, + &def_dissolvefacesop, + &def_dissolveedgessop, + &def_dissolveedgeloopsop, + &def_dissolvevertsop, + &def_makefgonsop, + &def_extrudefaceregion, + &def_connectverts, + //&def_makeprim, + &def_extrudeverts_indiv, + &def_mesh_to_bmesh, + &def_object_load_bmesh, + &def_transform, + &def_translate, + &def_rotate, + &def_edgenet_fill, + &def_contextual_create, + &def_makevert, + &def_weldverts, + &def_removedoubles, + &def_finddoubles, +}; + +int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*)); diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c new file mode 100644 index 00000000000..d168d85b025 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -0,0 +1,1305 @@ +#include "MEM_guardedalloc.h" + +#include "BLI_arithb.h" +#include "BLI_memarena.h" +#include "BLI_mempool.h" +#include "BLI_blenlib.h" + +#include "BKE_utildefines.h" + +#include "bmesh.h" +#include "bmesh_private.h" +#include "stdarg.h" + +#include <string.h> + +/*forward declarations*/ +static void alloc_flag_layer(BMesh *bm); +static void free_flag_layer(BMesh *bm); +static void clear_flag_layer(BMesh *bm); +static int bmesh_name_to_slotcode(BMOpDefine *def, char *name); +static int bmesh_opname_to_opcode(char *opname); + +typedef void (*opexec)(struct BMesh *bm, struct BMOperator *op); + +/*mappings map elements to data, which + follows the mapping struct in memory.*/ +typedef struct element_mapping { + BMHeader *element; + int len; +} element_mapping; + + +/*operator slot type information - size of one element of the type given.*/ +const int BMOP_OPSLOT_TYPEINFO[] = { + 0, + sizeof(int), + sizeof(float), + sizeof(void*), + 0, /* unused */ + 0, /* unused */ + 0, /* unused */ + sizeof(void*), /* pointer buffer */ + sizeof(element_mapping) +}; + +/* + * BMESH OPSTACK PUSH + * + * Pushes the opstack down one level + * and allocates a new flag layer if + * appropriate. + * +*/ + +void BMO_push(BMesh *bm, BMOperator *op) +{ + bm->stackdepth++; + + /*add flag layer, if appropriate*/ + if (bm->stackdepth > 1) + alloc_flag_layer(bm); + else + clear_flag_layer(bm); +} + +/* + * BMESH OPSTACK POP + * + * Pops the opstack one level + * and frees a flag layer if appropriate + * TODO: investigate NOT freeing flag + * layers. + * +*/ +void BMO_pop(BMesh *bm) +{ + if(bm->stackdepth > 1) + free_flag_layer(bm); + + bm->stackdepth--; +} + +/* + * BMESH OPSTACK INIT OP + * + * Initializes an operator structure + * to a certain type + * +*/ + +void BMO_Init_Op(BMOperator *op, char *opname) +{ + int i, opcode = bmesh_opname_to_opcode(opname); + + memset(op, 0, sizeof(BMOperator)); + op->type = opcode; + + /*initialize the operator slot types*/ + for(i = 0; opdefines[opcode]->slottypes[i].type; i++) { + op->slots[i].slottype = opdefines[opcode]->slottypes[i].type; + op->slots[i].index = i; + } + + /*callback*/ + op->exec = opdefines[opcode]->exec; + + /*memarena, used for operator's slot buffers*/ + op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + BLI_memarena_use_calloc (op->arena); +} + +/* + * BMESH OPSTACK EXEC OP + * + * Executes a passed in operator. This handles + * the allocation and freeing of temporary flag + * layers and starting/stopping the modelling + * loop. Can be called from other operators + * exec callbacks as well. + * +*/ + +void BMO_Exec_Op(BMesh *bm, BMOperator *op) +{ + + BMO_push(bm, op); + + if(bm->stackdepth == 1) + bmesh_begin_edit(bm); + op->exec(bm, op); + + if(bm->stackdepth == 1) + bmesh_end_edit(bm,0); + + BMO_pop(bm); +} + +/* + * BMESH OPSTACK FINISH OP + * + * Does housekeeping chores related to finishing + * up an operator. + * +*/ + +void BMO_Finish_Op(BMesh *bm, BMOperator *op) +{ + BMOpSlot *slot; + int i; + + for (i=0; opdefines[op->type]->slottypes[i].type; i++) { + slot = &op->slots[i]; + if (slot->slottype == BMOP_OPSLOT_MAPPING) { + if (slot->data.ghash) + BLI_ghash_free(slot->data.ghash, NULL, NULL); + } + } + + BLI_memarena_free(op->arena); +} + +/* + * BMESH OPSTACK GET SLOT + * + * Returns a pointer to the slot of + * type 'slotcode' + * +*/ + +BMOpSlot *BMO_GetSlot(BMOperator *op, char *slotname) +{ + int slotcode = bmesh_name_to_slotcode(opdefines[op->type], slotname); + + return &(op->slots[slotcode]); +} + +/* + * BMESH OPSTACK COPY SLOT + * + * Copies data from one slot to another + * +*/ + +void BMO_CopySlot(BMOperator *source_op, BMOperator *dest_op, char *src, char *dst) +{ + BMOpSlot *source_slot = BMO_GetSlot(source_op, src); + BMOpSlot *dest_slot = BMO_GetSlot(dest_op, dst); + + if(source_slot == dest_slot) + return; + + if(source_slot->slottype != dest_slot->slottype) + return; + + if (dest_slot->slottype > BMOP_OPSLOT_VEC) { + if (dest_slot->slottype != BMOP_OPSLOT_MAPPING) { + /*do buffer copy*/ + dest_slot->data.buf = NULL; + dest_slot->len = source_slot->len; + if(dest_slot->len){ + dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len); + memcpy(dest_slot->data.buf, source_slot->data.buf, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len); + } + } else { + GHashIterator it; + element_mapping *srcmap, *dstmap; + + /*sanity check*/ + if (!source_slot->data.ghash) return; + + if (!dest_slot->data.ghash) { + dest_slot->data.ghash = + BLI_ghash_new(BLI_ghashutil_ptrhash, + BLI_ghashutil_ptrcmp); + } + + BLI_ghashIterator_init(&it, source_slot->data.ghash); + for (;srcmap=BLI_ghashIterator_getValue(&it); + BLI_ghashIterator_step(&it)) + { + dstmap = BLI_memarena_alloc(dest_op->arena, + sizeof(*dstmap) + srcmap->len); + + dstmap->element = srcmap->element; + dstmap->len = srcmap->len; + memcpy(dstmap+1, srcmap+1, srcmap->len); + + BLI_ghash_insert(dest_slot->data.ghash, + dstmap->element, dstmap); + } + } + } else { + dest_slot->data = source_slot->data; + } +} + +/* + * BMESH OPSTACK SET XXX + * + * Sets the value of a slot depending on it's type + * +*/ + + +void BMO_Set_Float(BMOperator *op, char *slotname, float f) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_FLT) ) + return; + + slot->data.f = f; +} + +void BMO_Set_Int(BMOperator *op, char *slotname, int i) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_INT) ) + return; + + slot->data.i = i; +} + +/*only supports square mats*/ +void BMO_Set_Mat(struct BMOperator *op, char *slotname, float *mat, int size) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_MAT) ) + return; + + slot->len = 4; + slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float)*4*4); + + if (size == 4) { + memcpy(slot->data.p, mat, sizeof(float)*4*4); + } else if (size == 3) { + Mat4CpyMat3(slot->data.p, mat); + } else { + printf("yeek! invalid size in BMO_Set_Mat!\n"); + + memset(slot->data.p, 0, sizeof(float)*4*4); + return; + } +} + +void BMO_Get_Mat4(struct BMOperator *op, char *slotname, float mat[4][4]) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_MAT) ) + return; + + memcpy(mat, slot->data.p, sizeof(float)*4*4); +} + +void BMO_Get_Mat3(struct BMOperator *op, char *slotname, float mat[3][3]) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_MAT) ) + return; + + Mat3CpyMat4(mat, slot->data.p); +} + +void BMO_Set_Pnt(BMOperator *op, char *slotname, void *p) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_PNT) ) + return; + + slot->data.p = p; +} + +void BMO_Set_Vec(BMOperator *op, char *slotname, float *vec) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_VEC) ) + return; + + VECCOPY(slot->data.vec, vec); +} + + +float BMO_Get_Float(BMOperator *op, char *slotname) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_FLT) ) + return 0.0f; + + return slot->data.f; +} + +int BMO_Get_Int(BMOperator *op, char *slotname) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_INT) ) + return 0; + + return slot->data.i; +} + + +void *BMO_Get_Pnt(BMOperator *op, char *slotname) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_PNT) ) + return NULL; + + return slot->data.p; +} + +void BMO_Get_Vec(BMOperator *op, char *slotname, float *vec_out) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + if( !(slot->slottype == BMOP_OPSLOT_VEC) ) + return; + + VECCOPY(vec_out, slot->data.vec); +} + +/* + * BMO_SETFLAG + * + * Sets a flag for a certain element + * +*/ +void BMO_SetFlag(BMesh *bm, void *element, int flag) +{ + BMHeader *head = element; + head->flags[bm->stackdepth-1].mask |= flag; +} + +/* + * BMO_CLEARFLAG + * + * Clears a specific flag from a given element + * +*/ + +void BMO_ClearFlag(BMesh *bm, void *element, int flag) +{ + BMHeader *head = element; + head->flags[bm->stackdepth-1].mask &= ~flag; +} + +/* + * BMO_TESTFLAG + * + * Tests whether or not a flag is set for a specific element + * + * +*/ + +int BMO_TestFlag(BMesh *bm, void *element, int flag) +{ + BMHeader *head = element; + if(head->flags[bm->stackdepth-1].mask & flag) + return 1; + return 0; +} + +/* + * BMO_COUNTFLAG + * + * Counts the number of elements of a certain type that + * have a specific flag set. + * +*/ + +int BMO_CountFlag(BMesh *bm, int flag, int type) +{ + BMIter elements; + BMHeader *e; + int count = 0; + + if(type & BM_VERT){ + for(e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)){ + if(BMO_TestFlag(bm, e, flag)) + count++; + } + } + if(type & BM_EDGE){ + for(e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)){ + if(BMO_TestFlag(bm, e, flag)) + count++; + } + } + if(type & BM_FACE){ + for(e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)){ + if(BMO_TestFlag(bm, e, flag)) + count++; + } + } + + return count; +} + +int BMO_CountSlotBuf(struct BMesh *bm, struct BMOperator *op, char *slotname) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + /*check if its actually a buffer*/ + if( !(slot->slottype > BMOP_OPSLOT_VEC) ) + return 0; + + return slot->len; +} + +#if 0 +void *BMO_Grow_Array(BMesh *bm, BMOperator *op, int slotcode, int totadd) { + BMOpSlot *slot = &op->slots[slotcode]; + void *tmp; + + /*check if its actually a buffer*/ + if( !(slot->slottype > BMOP_OPSLOT_VEC) ) + return NULL; + + if (slot->flag & BMOS_DYNAMIC_ARRAY) { + if (slot->len >= slot->size) { + slot->size = (slot->size+1+totadd)*2; + + tmp = slot->data.buf; + slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size, "opslot dynamic array"); + memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size); + MEM_freeN(tmp); + } + + slot->len += totadd; + } else { + slot->flag |= BMOS_DYNAMIC_ARRAY; + slot->len += totadd; + slot->size = slot->len+2; + tmp = slot->data.buf; + slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len, "opslot dynamic array"); + memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len); + } + + return slot->data.buf; +} +#endif + +void BMO_Insert_Mapping(BMesh *bm, BMOperator *op, char *slotname, + void *element, void *data, int len) { + element_mapping *mapping; + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + /*sanity check*/ + if (slot->slottype != BMOP_OPSLOT_MAPPING) return; + + mapping = BLI_memarena_alloc(op->arena, sizeof(*mapping) + len); + + mapping->element = element; + mapping->len = len; + memcpy(mapping+1, data, len); + + if (!slot->data.ghash) { + slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, + BLI_ghashutil_ptrcmp); + } + + BLI_ghash_insert(slot->data.ghash, element, mapping); +} + +void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op, + char *slotname, int flag) +{ + GHashIterator it; + BMOpSlot *slot = BMO_GetSlot(op, slotname); + BMHeader *ele; + + /*sanity check*/ + if (slot->slottype != BMOP_OPSLOT_MAPPING) return; + if (!slot->data.ghash) return; + + BLI_ghashIterator_init(&it, slot->data.ghash); + for (;ele=BLI_ghashIterator_getKey(&it);BLI_ghashIterator_step(&it)) { + BMO_SetFlag(bm, ele, flag); + } +} + +void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, char *slotname, + void *element, float val) +{ + BMO_Insert_Mapping(bm, op, slotname, element, &val, sizeof(float)); +} + +void BMO_Insert_MapPointer(BMesh *bm, BMOperator *op, char *slotname, + void *element, void *val) +{ + BMO_Insert_Mapping(bm, op, slotname, element, &val, sizeof(void*)); +} + +int BMO_InMap(BMesh *bm, BMOperator *op, char *slotname, void *element) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + /*sanity check*/ + if (slot->slottype != BMOP_OPSLOT_MAPPING) return 0; + if (!slot->data.ghash) return 0; + + return BLI_ghash_haskey(slot->data.ghash, element); +} + +void *BMO_Get_MapData(BMesh *bm, BMOperator *op, char *slotname, + void *element) +{ + element_mapping *mapping; + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + /*sanity check*/ + if (slot->slottype != BMOP_OPSLOT_MAPPING) return NULL; + if (!slot->data.ghash) return NULL; + + mapping = BLI_ghash_lookup(slot->data.ghash, element); + + if (!mapping) return NULL; + + return mapping + 1; +} + +float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, char *slotname, + void *element) +{ + float *val = BMO_Get_MapData(bm, op, slotname, element); + if (val) return *val; + + return 0.0f; +} + +void *BMO_Get_MapPointer(BMesh *bm, BMOperator *op, char *slotname, + void *element) +{ + void **val = BMO_Get_MapData(bm, op, slotname, element); + if (val) return *val; + + return NULL; +} + +static void *alloc_slot_buffer(BMOperator *op, char *slotname, int len){ + int slotcode = bmesh_name_to_slotcode(opdefines[op->type], slotname); + + /*check if its actually a buffer*/ + if( !(op->slots[slotcode].slottype > BMOP_OPSLOT_VEC) ) + return NULL; + + op->slots[slotcode].len = len; + if(len) + op->slots[slotcode].data.buf = BLI_memarena_alloc(op->arena, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * len); + return op->slots[slotcode].data.buf; +} + + +/* + * + * BMO_ALL_TO_SLOT + * + * Copies all elements of a certain type into an operator slot. + * +*/ + +void BMO_All_To_Slot(BMesh *bm, BMOperator *op, char *slotname, int type) +{ + BMIter elements; + BMHeader *e; + BMOpSlot *output = BMO_GetSlot(op, slotname); + int totelement=0, i=0; + + if (type & BM_VERT) totelement += bm->totvert; + if (type & BM_EDGE) totelement += bm->totedge; + if (type & BM_FACE) totelement += bm->totface; + + if(totelement){ + alloc_slot_buffer(op, slotname, totelement); + + if (type & BM_VERT) { + for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + + if (type & BM_EDGE) { + for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + + if (type & BM_FACE) { + for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } +} + +/* + * + * BMO_HEADERFLAG_TO_SLOT + * + * Copies elements of a certain type, which have a certain header flag set + * into a slot for an operator. + * +*/ + +void BMO_HeaderFlag_To_Slot(BMesh *bm, BMOperator *op, char *slotname, int flag, int type) +{ + BMIter elements; + BMHeader *e; + BMOpSlot *output = BMO_GetSlot(op, slotname); + int totelement=0, i=0; + + totelement = BM_CountFlag(bm, type, flag); + + if(totelement){ + alloc_slot_buffer(op, slotname, totelement); + + if (type & BM_VERT) { + for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(e->flag & flag) { + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } + + if (type & BM_EDGE) { + for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(e->flag & flag){ + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } + + if (type & BM_FACE) { + for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(e->flag & flag){ + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } + } +} + +/* + * + * BMO_FLAG_TO_SLOT + * + * Copies elements of a certain type, which have a certain flag set + * into an output slot for an operator. + * +*/ +void BMO_Flag_To_Slot(BMesh *bm, BMOperator *op, char *slotname, int flag, int type) +{ + BMIter elements; + BMHeader *e; + BMOpSlot *output = BMO_GetSlot(op, slotname); + int totelement = BMO_CountFlag(bm, flag, type), i=0; + + if(totelement){ + alloc_slot_buffer(op, slotname, totelement); + + if (type & BM_VERT) { + for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(BMO_TestFlag(bm, e, flag)){ + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } + + if (type & BM_EDGE) { + for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(BMO_TestFlag(bm, e, flag)){ + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } + + if (type & BM_FACE) { + for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) { + if(BMO_TestFlag(bm, e, flag)){ + ((BMHeader**)output->data.p)[i] = e; + i++; + } + } + } + } +} + +/* + * + * BMO_FLAG_BUFFER + * + * Header Flags elements in a slots buffer, automatically + * using the selection API where appropriate. + * +*/ + +void BMO_HeaderFlag_Buffer(BMesh *bm, BMOperator *op, char *slotname, int flag) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + BMHeader **data = slot->data.p; + int i; + + for(i = 0; i < slot->len; i++) { + BM_SetHFlag(data[i], flag); + if (flag & BM_SELECT) + BM_Select(bm, data[i], 1); + } +} + +/* + * + * BMO_FLAG_BUFFER + * + * Removes flags from elements in a slots buffer, automatically + * using the selection API where appropriate. + * +*/ + +void BMO_UnHeaderFlag_Buffer(BMesh *bm, BMOperator *op, char *slotname, int flag) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + BMHeader **data = slot->data.p; + int i; + + for(i = 0; i < slot->len; i++) { + BM_ClearHFlag(data[i], flag); + if (flag & BM_SELECT) + BM_Select(bm, data[i], 0); + } +} + + +/* + * + * BMO_FLAG_BUFFER + * + * Flags elements in a slots buffer + * +*/ + +void BMO_Flag_Buffer(BMesh *bm, BMOperator *op, char *slotname, int flag) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + BMHeader **data = slot->data.p; + int i; + + for(i = 0; i < slot->len; i++) + BMO_SetFlag(bm, data[i], flag); +} + +/* + * + * BMO_FLAG_BUFFER + * + * Removes flags from elements in a slots buffer + * +*/ + +void BMO_Unflag_Buffer(BMesh *bm, BMOperator *op, char *slotname, int flag) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + BMHeader **data = slot->data.p; + int i; + + for(i = 0; i < slot->len; i++) + BMO_ClearFlag(bm, data[i], flag); +} + + +/* + * + * ALLOC/FREE FLAG LAYER + * + * Used by operator stack to free/allocate + * private flag data. This is allocated + * using a mempool so the allocation/frees + * should be quite fast. + * + * TODO: + * Investigate not freeing flag layers until + * all operators have been executed. This would + * save a lot of realloc potentially. + * +*/ + +static void alloc_flag_layer(BMesh *bm) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + BLI_mempool *oldpool = bm->flagpool; /*old flag pool*/ + void *oldflags; + + /*allocate new flag pool*/ + bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer)*(bm->totflags+1), 512, 512 ); + + /*now go through and memcpy all the flags. Loops don't get a flag layer at this time...*/ + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){ + oldflags = v->head.flags; + v->head.flags = BLI_mempool_calloc(bm->flagpool); + memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); /*dont know if this memcpy usage is correct*/ + } + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){ + oldflags = e->head.flags; + e->head.flags = BLI_mempool_calloc(bm->flagpool); + memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); + } + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){ + oldflags = f->head.flags; + f->head.flags = BLI_mempool_calloc(bm->flagpool); + memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); + } + bm->totflags++; + BLI_mempool_destroy(oldpool); +} + +static void free_flag_layer(BMesh *bm) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + BLI_mempool *oldpool = bm->flagpool; + void *oldflags; + + /*de-increment the totflags first...*/ + bm->totflags--; + /*allocate new flag pool*/ + bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512); + + /*now go through and memcpy all the flags*/ + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){ + oldflags = v->head.flags; + v->head.flags = BLI_mempool_calloc(bm->flagpool); + memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); /*correct?*/ + } + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){ + oldflags = e->head.flags; + e->head.flags = BLI_mempool_calloc(bm->flagpool); + memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); + } + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){ + oldflags = f->head.flags; + f->head.flags = BLI_mempool_calloc(bm->flagpool); + memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); + } + + BLI_mempool_destroy(oldpool); +} + +static void clear_flag_layer(BMesh *bm) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + + /*now go through and memcpy all the flags*/ + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){ + memset(v->head.flags+bm->totflags-1, 0, sizeof(BMFlagLayer)); + } + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){ + memset(e->head.flags+bm->totflags-1, 0, sizeof(BMFlagLayer)); + } + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){ + memset(f->head.flags+bm->totflags-1, 0, sizeof(BMFlagLayer)); + } +} + +void *BMO_IterNew(BMOIter *iter, BMesh *bm, BMOperator *op, + char *slotname, int restrict) +{ + BMOpSlot *slot = BMO_GetSlot(op, slotname); + + memset(iter, 0, sizeof(BMOIter)); + + iter->slot = slot; + iter->cur = 0; + iter->restrict = restrict; + + if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) { + if (iter->slot->data.ghash) + BLI_ghashIterator_init(&iter->giter, slot->data.ghash); + else return NULL; + } + + return BMO_IterStep(iter); +} + +void *BMO_IterStep(BMOIter *iter) +{ + if (iter->slot->slottype == BMOP_OPSLOT_ELEMENT_BUF) { + BMHeader *h; + + if (iter->cur >= iter->slot->len) return NULL; + + h = ((void**)iter->slot->data.buf)[iter->cur++]; + while (!(iter->restrict & h->type)) { + if (iter->cur >= iter->slot->len) return NULL; + h = ((void**)iter->slot->data.buf)[iter->cur++]; + } + + return h; + } else if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) { + struct element_mapping *map; + void *ret = BLI_ghashIterator_getKey(&iter->giter); + map = BLI_ghashIterator_getValue(&iter->giter); + + iter->val = map + 1; + + BLI_ghashIterator_step(&iter->giter); + + return ret; + } + + return NULL; +} + +/*used for iterating over mappings*/ +void *BMO_IterMapVal(BMOIter *iter) +{ + return iter->val; +} + +void *BMO_IterMapValp(BMOIter *iter) +{ + return *((void**)iter->val); +} + +float BMO_IterMapValf(BMOIter *iter) +{ + return *((float*)iter->val); +} + +/*error system*/ +typedef struct bmop_error { + struct bmop_error *next, *prev; + int errorcode; + BMOperator *op; + char *msg; +} bmop_error; + +void BMO_ClearStack(BMesh *bm) +{ + while (BMO_PopError(bm, NULL, NULL)); +} + +void BMO_RaiseError(BMesh *bm, BMOperator *owner, int errcode, char *msg) +{ + bmop_error *err = MEM_callocN(sizeof(bmop_error), "bmop_error"); + + err->errorcode = errcode; + if (!msg) msg = bmop_error_messages[errcode]; + err->msg = msg; + err->op = owner; + + BLI_addhead(&bm->errorstack, err); +} + +int BMO_HasError(BMesh *bm) +{ + return bm->errorstack.first != NULL; +} + +/*returns error code or 0 if no error*/ +int BMO_GetError(BMesh *bm, char **msg, BMOperator **op) +{ + bmop_error *err = bm->errorstack.first; + if (!err) return 0; + + if (msg) *msg = err->msg; + if (op) *op = err->op; + + return err->errorcode; +} + +int BMO_PopError(BMesh *bm, char **msg, BMOperator **op) +{ + int errorcode = BMO_GetError(bm, msg, op); + + if (errorcode) { + bmop_error *err = bm->errorstack.first; + + BLI_remlink(&bm->errorstack, bm->errorstack.first); + MEM_freeN(err); + } + + return errorcode; +} + +/* +typedef struct bflag { + char *str; + int flag; +} bflag; + +#define b(f) {#f, f}, +static char *bmesh_flags = { + b(BM_SELECT); + b(BM_SEAM); + b(BM_FGON); + b(BM_HIDDEN); + b(BM_SHARP); + b(BM_SMOOTH); + {NULL, 0}; +}; + +int bmesh_str_to_flag(char *str) +{ + int i; + + while (bmesh_flags[i]->name) { + if (!strcmp(bmesh_flags[i]->name, str)) + return bmesh_flags[i]->flag; + } + + return -1; +} +*/ + +//example: +//BMO_CallOp(bm, "del %d %hv", DEL_ONLYFACES, BM_SELECT); +/* + d - int + i - int + f - float + hv - header flagged verts + he - header flagged edges + hf - header flagged faces + fv - flagged verts + fe - flagged edges + ff - flagged faces + +*/ + +#define nextc(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0) + +static int bmesh_name_to_slotcode(BMOpDefine *def, char *name) +{ + int i; + + for (i=0; def->slottypes[i].type; i++) { + if (!strcmp(name, def->slottypes[i].name)) return i; + } + + printf("yeek! could not find bmesh slot for name %s!\n", name); + return 0; +} + +static int bmesh_opname_to_opcode(char *opname) { + int i; + + for (i=0; i<bmesh_total_ops; i++) { + if (!strcmp(opname, opdefines[i]->name)) break; + } + + if (i == bmesh_total_ops) { + printf("yeek!! invalid op name %s!\n", opname); + return 0; + } + + return i; +} + +int BMO_VInitOpf(BMesh *bm, BMOperator *op, char *fmt, va_list vlist) +{ + BMOpDefine *def; + char *opname, *ofmt; + char slotname[64] = {0}; + int i, n=strlen(fmt), stop, slotcode = -1, ret, type, state, c; + int noslot=0; + + /*we muck around in here, so dup it*/ + fmt = ofmt = strdup(fmt); + + /*find operator name*/ + i = strcspn(fmt, " \t"); + + opname = fmt; + if (!opname[i]) noslot = 1; + opname[i] = 0; + + fmt += i + (noslot ? 0 : 1); + + for (i=0; i<bmesh_total_ops; i++) { + if (!strcmp(opname, opdefines[i]->name)) break; + } + + if (i == bmesh_total_ops) return 0; + + BMO_Init_Op(op, opname); + def = opdefines[i]; + + i = 0; + state = 1; //0: not inside slotcode name, 1: inside slotcode name + c = 0; + + while (*fmt) { + if (state) { + /*jump past leading whitespace*/ + i = strspn(fmt, " \t"); + fmt += i; + + /*ignore trailing whitespace*/ + if (!fmt[i]) + break; + + /*find end of slot name. currently this is + a little flexible, allowing "slot=%f", + "slot %f", "slot%f", and "slot\t%f". */ + i = strcspn(fmt, "= \t%"); + if (!fmt[i]) goto error; + + fmt[i] = 0; + + if (bmesh_name_to_slotcode(def, fmt) < 0) goto error; + + strcpy(slotname, fmt); + + state = 0; + fmt += i; + } else { + switch (*fmt) { + case ' ': + case '\t': + case '=': + case '%': + break; + case 'm': { + int size, c; + + c = nextc(fmt); + fmt++; + + if (c == '3') size = 3; + else if (c == '4') size = 4; + else goto error; + + BMO_Set_Mat(op, slotname, va_arg(vlist, void*), size); + state = 1; + break; + } + case 'v': { + BMO_Set_Vec(op, slotname, va_arg(vlist, float*)); + state = 1; + break; + } + case 's': { + BMOperator *op2 = va_arg(vlist, void*); + char *slotname2 = va_arg(vlist, char*); + + BMO_CopySlot(op2, op, slotname2, slotname); + state = 1; + break; + } + case 'i': + case 'd': + BMO_Set_Int(op, slotname, va_arg(vlist, int)); + state = 1; + break; + case 'p': + BMO_Set_Pnt(op, slotname, va_arg(vlist, void*)); + state = 1; + break; + case 'f': + case 'h': + case 'a': + type = *fmt; + + if (nextc(fmt) == ' ' || nextc(fmt) == '\t' || + nextc(fmt)==0) + { + BMO_Set_Float(op,slotname,va_arg(vlist,double)); + } else { + ret = 0; + stop = 0; + while (1) { + switch (nextc(fmt)) { + case 'f': ret |= BM_FACE;break; + case 'e': ret |= BM_EDGE;break; + case 'v': ret |= BM_VERT;break; + default: + stop = 1; + break; + } + if (stop) break; + fmt++; + } + + if (type == 'h') + BMO_HeaderFlag_To_Slot(bm, op, + slotname, va_arg(vlist, int), ret); + else if (type == 'a') + BMO_All_To_Slot(bm, op, slotname, ret); + else + BMO_Flag_To_Slot(bm, op, slotname, + va_arg(vlist, int), ret); + } + + state = 1; + break; + default: + printf("unrecognized bmop format char: %c\n", *fmt); + break; + } + } + fmt++; + } + + free(ofmt); + return 1; +error: + BMO_Finish_Op(bm, op); + free(fmt); + return 0; +} + + +int BMO_InitOpf(BMesh *bm, BMOperator *op, char *fmt, ...) { + va_list list; + + va_start(list, fmt); + if (!BMO_VInitOpf(bm, op, fmt, list)) { + printf("BMO_InitOpf failed\n"); + va_end(list); + return 0; + } + va_end(list); + + return 1; +} + +int BMO_CallOpf(BMesh *bm, char *fmt, ...) { + va_list list; + BMOperator op; + + va_start(list, fmt); + if (!BMO_VInitOpf(bm, &op, fmt, list)) { + printf("BMO_CallOpf failed\n"); + va_end(list); + return 0; + } + + BMO_Exec_Op(bm, &op); + BMO_Finish_Op(bm, &op); + + va_end(list); + return 1; +} + diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h new file mode 100644 index 00000000000..3eaaf4e8913 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_operators_private.h @@ -0,0 +1,38 @@ +#ifndef BM_OPERATORS_PRIVATE_H +#define BM_OPERATORS_PRIVATE_H + +struct BMesh; +struct BMOperator; + +void BMO_push(BMesh *bm, BMOperator *op); +void BMO_pop(BMesh *bm); + +void splitop_exec(BMesh *bm, BMOperator *op); +void dupeop_exec(BMesh *bm, BMOperator *op); +void delop_exec(BMesh *bm, BMOperator *op); +void esubdivide_exec(BMesh *bmesh, BMOperator *op); +void edit2bmesh_exec(BMesh *bmesh, BMOperator *op); +void bmesh2edit_exec(BMesh *bmesh, BMOperator *op); +void triangulate_exec(BMesh *bmesh, BMOperator *op); +void dissolvefaces_exec(BMesh *bmesh, BMOperator *op); +void dissolveverts_exec(BMesh *bmesh, BMOperator *op); +void bmesh_make_fgons_exec(BMesh *bmesh, BMOperator *op); +void extrude_edge_context_exec(BMesh *bm, BMOperator *op); +void connectverts_exec(BMesh *bm, BMOperator *op); +void makeprim_exec(BMesh *bm, BMOperator *op); +void extrude_vert_indiv_exec(BMesh *bm, BMOperator *op); +void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op); +void bmesh_to_mesh_exec(BMesh *bm, BMOperator *op); +void bmesh_translate_exec(BMesh *bm, BMOperator *op); +void bmesh_transform_exec(BMesh *bm, BMOperator *op); +void bmesh_contextual_create_exec(BMesh *bm, BMOperator *op); +void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op); +void bmesh_rotate_exec(BMesh *bm, BMOperator *op); +void bmesh_makevert_exec(BMesh *bm, BMOperator *op); +void dissolveedges_exec(BMesh *bm, BMOperator *op); +void dissolve_edgeloop_exec(BMesh *bm, BMOperator *op); +void bmesh_weldverts_exec(BMesh *bm, BMOperator *op); +void bmesh_removedoubles_exec(BMesh *bm, BMOperator *op); +void bmesh_finddoubles_exec(BMesh *bm, BMOperator *op); + +#endif diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c new file mode 100644 index 00000000000..c013952a622 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -0,0 +1,838 @@ +#include <string.h> +#include <math.h> +#include <stdlib.h> + +#include "BKE_utildefines.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "MEM_guardedalloc.h" + +#include "bmesh.h" +#include "bmesh_private.h" + +/* + * + * BME POLYGON.C + * + * This file contains code for dealing + * with polygons (normal/area calculation, + * tesselation, ect) + * + * TODO: + * -Add in Tesselator frontend that creates + * BMTriangles from copied faces + * -Add in Function that checks for and flags + * degenerate faces. + * +*/ + +/* + * TEST EDGE SIDE and POINT IN TRIANGLE + * + * Point in triangle tests stolen from scanfill.c. + * Used for tesselator + * +*/ + +static short testedgeside(double *v1, double *v2, double *v3) +/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */ +{ + double inp; + + //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]); + inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]); + + if(inp<0.0) return 0; + else if(inp==0) { + if(v1[0]==v3[0] && v1[1]==v3[1]) return 0; + if(v2[0]==v3[0] && v2[1]==v3[1]) return 0; + } + return 1; +} + +static short testedgesidef(float *v1, float *v2, float *v3) +/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */ +{ + double inp; + + //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]); + inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]); + + if(inp<0.0) return 0; + else if(inp==0) { + if(v1[0]==v3[0] && v1[1]==v3[1]) return 0; + if(v2[0]==v3[0] && v2[1]==v3[1]) return 0; + } + return 1; +} + +static int point_in_triangle(double *v1, double *v2, double *v3, double *pt) +{ + if(testedgeside(v1,v2,pt) && testedgeside(v2,v3,pt) && testedgeside(v3,v1,pt)) + return 1; + return 0; +} + +/* + * COMPUTE POLY NORMAL + * + * Computes the normal of a planar + * polygon See Graphics Gems for + * computing newell normal. + * +*/ +static void compute_poly_normal(float normal[3], float (*verts)[3], int nverts) +{ + + float *u, *v;/*, *w, v1[3], v2[3];*/ + double n[3] = {0.0, 0.0, 0.0}, l; + int i; + + /*this fixes some weird numerical error*/ + verts[0][0] += 0.0001f; + verts[0][1] += 0.0001f; + verts[0][2] += 0.0001f; + + for(i = 0; i < nverts; i++){ + u = verts[i]; + v = verts[(i+1) % nverts]; + + /* newell's method + + so thats?: + (a[1] - b[1]) * (a[2] + b[2]); + a[1]*b[2] - b[1]*a[2] - b[1]*b[2] + a[1]*a[2] + + odd. half of that is the cross product. . .what's the + other half? + + also could be like a[1]*(b[2] + a[2]) - b[1]*(a[2] - b[2]) + */ + + n[0] += (u[1] - v[1]) * (u[2] + v[2]); + n[1] += (u[2] - v[2]) * (u[0] + v[0]); + n[2] += (u[0] - v[0]) * (u[1] + v[1]); + } + + l = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]); + + if (l == 0.0) { + normal[0] = 0.0f; + normal[1] = 0.0f; + normal[2] = 1.0f; + + return; + } + + n[0] /= l; + n[1] /= l; + n[2] /= l; + + normal[0] = (float) n[0]; + normal[1] = (float) n[1]; + normal[2] = (float) n[2]; +} + +/* + * COMPUTE POLY CENTER + * + * Computes the centroid and + * area of a polygon in the X/Y + * plane. + * +*/ + +static int compute_poly_center(float center[3], float *area, float (*verts)[3], int nverts) +{ + int i, j; + float atmp = 0.0, xtmp = 0.0, ytmp = 0.0, ai; + + center[0] = center[1] = center[2] = 0.0; + + if(nverts < 3) + return 0; + + i = nverts-1; + j = 0; + + while(j < nverts){ + ai = verts[i][0] * verts[j][1] - verts[j][0] * verts[i][1]; + atmp += ai; + xtmp += (verts[j][0] + verts[i][0]) * ai; + ytmp += (verts[j][1] + verts[i][1]) * ai; + i = j; + j += 1; + } + + if(area) + *area = atmp / 2.0f; + + if (atmp != 0){ + center[0] = xtmp / (3.0f * atmp); + center[1] = xtmp / (3.0f * atmp); + return 1; + } + return 0; +} + +/* +computes center of face in 3d. uses center of bounding box. +*/ + +int BM_Compute_Face_Center(BMesh *bm, BMFace *f, float center[3]) +{ + BMIter iter; + BMLoop *l; + float min[3], max[3]; + int i; + + INIT_MINMAX(min, max); + l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); + for (i=0; l; l=BMIter_Step(&iter), i++) { + DO_MINMAX(l->v->co, min, max); + } + + VECADD(center, min, max); + VECMUL(center, 0.5f); +} + +/* + * COMPUTE POLY PLANE + * + * Projects a set polygon's vertices to + * a plane defined by the average + * of its edges cross products + * +*/ + +void compute_poly_plane(float (*verts)[3], int nverts) +{ + + float avgc[3], norm[3], temp[3], mag, avgn[3]; + float *v1, *v2, *v3; + int i; + + if(nverts < 3) + return; + + avgn[0] = avgn[1] = avgn[2] = 0.0; + avgc[0] = avgc[1] = avgc[2] = 0.0; + + for(i = 0; i < nverts; i++){ + v1 = verts[i]; + v2 = verts[(i+1) % nverts]; + v3 = verts[(i+2) % nverts]; + CalcNormFloat(v1, v2, v3, norm); + + avgn[0] += norm[0]; + avgn[1] += norm[1]; + avgn[2] += norm[2]; + } + + /*what was this bit for?*/ + if(avgn[0] == 0.0 && avgn[1] == 0.0 && avgn[2] == 0.0){ + avgn[0] = 0.0; + avgn[1] = 0.0; + avgn[2] = 1.0; + } else { + avgn[0] /= nverts; + avgn[1] /= nverts; + avgn[2] /= nverts; + Normalize(avgn); + } + + for(i = 0; i < nverts; i++){ + v1 = verts[i]; + VECCOPY(temp, v1); + mag = 0.0; + mag += (temp[0] * avgn[0]); + mag += (temp[1] * avgn[1]); + mag += (temp[2] * avgn[2]); + + temp[0] = (avgn[0] * mag); + temp[1] = (avgn[1] * mag); + temp[2] = (avgn[2] * mag); + + VecSubf(v1, v1, temp); + } +} + +/* + BM LEGAL EDGES + + takes in a face and a list of edges, and sets to NULL any edge in + the list that bridges a concave region of the face or intersects + any of the faces's edges. +*/ +static void shrink_edged(double *v1, double *v2, double fac) +{ + double mid[3]; + + VECADD(mid, v1, v2); + VECMUL(mid, 0.5); + + VECSUB(v1, v1, mid); + VECSUB(v2, v2, mid); + + VECMUL(v1, fac); + VECMUL(v2, fac); + + VECADD(v1, v1, mid); + VECADD(v2, v2, mid); +} + +static void shrink_edgef(float *v1, float *v2, float fac) +{ + float mid[3]; + + VECADD(mid, v1, v2); + VECMUL(mid, 0.5); + + VECSUB(v1, v1, mid); + VECSUB(v2, v2, mid); + + VECMUL(v1, fac); + VECMUL(v2, fac); + + VECADD(v1, v1, mid); + VECADD(v2, v2, mid); +} + +/* + * POLY ROTATE PLANE + * + * Rotates a polygon so that it's + * normal is pointing towards the mesh Z axis + * +*/ + +void poly_rotate_plane(float normal[3], float (*verts)[3], int nverts) +{ + + float up[3] = {0.0f,0.0f,1.0f}, axis[3], q[4]; + float mat[3][3]; + double angle; + int i; + + Crossf(axis, up, normal); + axis[0] *= -1; + axis[1] *= -1; + axis[2] *= -1; + + angle = saacos(normal[0]*up[0]+normal[1]*up[1] + normal[2]*up[2]); + + if (angle == 0.0f) return; + + AxisAngleToQuatd(q, axis, angle); + QuatToMat3(q, mat); + + for(i = 0; i < nverts; i++) + Mat3MulVecfl(mat, verts[i]); +} + +/* + * BMESH UPDATE FACE NORMAL + * + * Updates the stored normal for the + * given face. Requires that a buffer + * of sufficient length to store projected + * coordinates for all of the face's vertices + * is passed in as well. + * +*/ + +void BM_Face_UpdateNormal(BMesh *bm, BMFace *f) +{ + float projverts[12][3]; + float (*proj)[3] = f->len < 12 ? projverts : MEM_mallocN(sizeof(float)*f->len*3, "projvertsn"); + BMLoop *l = f->loopbase; + int i=0; + + if (f->len < 3) return; + + do { + VECCOPY(proj[i], l->v->co); + i += 1; + } while (l != f->loopbase); + + bmesh_update_face_normal(bm, f, proj); + + if (projverts != proj) MEM_freeN(proj); +} + +void BM_Edge_UpdateNormals(BMesh *bm, BMEdge *e) +{ + BMIter iter; + BMFace *f; + + f = BMIter_New(&iter, bm, BM_FACES_OF_EDGE, e); + for (; f; f=BMIter_Step(&iter)) { + BM_Face_UpdateNormal(bm, f); + } + + BM_Vert_UpdateNormal(bm, e->v1); + BM_Vert_UpdateNormal(bm, e->v2); +} + +void BM_Vert_UpdateNormal(BMesh *bm, BMVert *v) +{ + BMIter iter; + BMFace *f; + int len=0; + + v->no[0] = v->no[1] = v->no[2] = 0.0f; + + f = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v); + for (; f; f=BMIter_Step(&iter), len++) { + VecAddf(v->no, f->no, v->no); + } + + if (!len) return; + + VecMulf(v->no, 1.0f/(int)len); +} + +void bmesh_update_face_normal(BMesh *bm, BMFace *f, float (*projectverts)[3]) +{ + BMLoop *l; + int i; + + if(f->len > 4){ + i = 0; + l = f->loopbase; + do{ + VECCOPY(projectverts[i], l->v->co); + l = (BMLoop*)(l->head.next); + i += 1; + }while(l!=f->loopbase); + + compute_poly_plane(projectverts, f->len); + compute_poly_normal(f->no, projectverts, f->len); + } + else if(f->len == 3){ + BMVert *v1, *v2, *v3; + v1 = f->loopbase->v; + v2 = ((BMLoop*)(f->loopbase->head.next))->v; + v3 = ((BMLoop*)(f->loopbase->head.next->next))->v; + CalcNormFloat(v1->co, v2->co, v3->co, f->no); + } + else if(f->len == 4){ + BMVert *v1, *v2, *v3, *v4; + v1 = f->loopbase->v; + v2 = ((BMLoop*)(f->loopbase->head.next))->v; + v3 = ((BMLoop*)(f->loopbase->head.next->next))->v; + v4 = ((BMLoop*)(f->loopbase->head.prev))->v; + CalcNormFloat4(v1->co, v2->co, v3->co, v4->co, f->no); + } + else{ /*horrible, two sided face!*/ + f->no[0] = 0.0; + f->no[1] = 0.0; + f->no[2] = 1.0; + } + +} + + +/* + * BMESH FLIP NORMAL + * + * Reverses the winding of a faces + * Note that this does *not* update the calculated + * Normal +*/ +void BM_flip_normal(BMesh *bm, BMFace *f) +{ + bmesh_loop_reverse(bm, f); +} + +/* detects if two line segments cross each other (intersects). + note, there could be more winding cases then there needs to be. */ +int linecrosses(double *v1, double *v2, double *v3, double *v4) +{ + int w1, w2, w3, w4, w5; + + /*w1 = winding(v1, v3, v4); + w2 = winding(v2, v3, v4); + w3 = winding(v3, v1, v2); + w4 = winding(v4, v1, v2); + + return (w1 == w2) && (w3 == w4);*/ + + w1 = testedgeside(v1, v3, v2); + w2 = testedgeside(v2, v4, v1); + w3 = !testedgeside(v1, v2, v3); + w4 = testedgeside(v3, v2, v4); + w5 = !testedgeside(v3, v1, v4); + return w1 == w2 && w2 == w3 && w3 == w4 && w4==w5; +} + +/* detects if two line segments cross each other (intersects). + note, there could be more winding cases then there needs to be. */ +int linecrossesf(float *v1, float *v2, float *v3, float *v4) +{ + int w1, w2, w3, w4, w5; + +/* int test1_a, test1_a, test2_a, test2_a; + + test1_a = check_tri_clock_dir(l1p1, l1p2, l2p1); + test1_b = check_tri_clock_dir(l1p1, l1p2, l2p2); + if (test1_a != test1_b) + { + test2_a = check_tri_clock_dir(l2p1, l2p2, l1p1); + test2_b = check_tri_clock_dir(l2p1, l2p2, l1p2); + if (test2_a != test2_b) + { + return 1; + } + }*/ + /*w1 = testedgesidef(v1, v2, v3); + w2 = testedgesidef(v1, v2, v4); + if(w1 != w2) { + w3 = testedgesidef(v3, v4, v1); + w4 = testedgesidef(v3, v4, v2); + if (w3 != w4) return 1; + } + + return 0;*/ + + /*w1 = testedgesidef(v1, v3, v4); + w2 = testedgesidef(v2, v3, v4); + w3 = testedgesidef(v3, v1, v2); + w4 = testedgesidef(v4, v1, v2); + + return (w1 == w2) && (w2 == w3) && (w3 == w4);*/ + + w1 = testedgesidef(v1, v3, v2); + w2 = testedgesidef(v2, v4, v1); + w3 = !testedgesidef(v1, v2, v3); + w4 = testedgesidef(v3, v2, v4); + w5 = !testedgesidef(v3, v1, v4); + return w1 == w2 && w2 == w3 && w3 == w4 && w4==w5; +} + +int goodline(float (*projectverts)[3], BMFace *f, int v1i, + int v2i, int v3i, int nvert) { + BMLoop *l = f->loopbase; + double v1[3], v2[3], v3[3], pv1[3], pv2[3]; + int i; + + VECCOPY(v1, projectverts[v1i]); + VECCOPY(v2, projectverts[v2i]); + VECCOPY(v3, projectverts[v3i]); + + if (testedgeside(v1, v2, v3)) return 0; + + //for (i=0; i<nvert; i++) { + do { + i = l->v->head.eflag2; + if (i == v1i || i == v2i || i == v3i) { + l = (BMLoop*)l->head.next; + continue; + } + + VECCOPY(pv1, projectverts[l->v->head.eflag2]); + VECCOPY(pv2, projectverts[((BMLoop*)l->head.next)->v->head.eflag2]); + + //if (linecrosses(pv1, pv2, v1, v3)) return 0; + if (point_in_triangle(v1, v2, v3, pv1)) return 0; + if (point_in_triangle(v3, v2, v1, pv1)) return 0; + + l = (BMLoop*)l->head.next; + } while (l != f->loopbase); + return 1; +} +/* + * FIND EAR + * + * Used by tesselator to find + * the next triangle to 'clip off' + * of a polygon while tesselating. + * +*/ + +static BMLoop *find_ear(BMesh *bm, BMFace *f, float (*verts)[3], + int nvert) +{ + BMVert *v1, *v2, *v3; + BMLoop *bestear = NULL, *l; + float angle, bestangle = 180.0f; + int isear, i=0; + + l = f->loopbase; + do { + isear = 1; + + v1 = ((BMLoop*)(l->head.prev))->v; + v2 = l->v; + v3 = ((BMLoop*)(l->head.next))->v; + + if (BM_Edge_Exist(v1, v3)) isear = 0; + + if (isear && !goodline(verts, f, v1->head.eflag2, v2->head.eflag2, + v3->head.eflag2, nvert)) + isear = 0; + + if(isear) { + /*angle = VecAngle3(verts[v1->head.eflag2], verts[v2->head.eflag2], verts[v3->head.eflag2]); + if(!bestear || ABS(angle-45.0f) < bestangle) { + bestear = l; + bestangle = ABS(45.0f-angle); + } + + if (angle > 20 && angle < 90) break; + if (angle < 100 && i > 5) break; + i += 1;*/ + bestear = l; + break; + } + l = (BMLoop*)(l->head.next); + } + while(l != f->loopbase); + + return bestear; +} + +/* + * BMESH TRIANGULATE FACE + * + * Triangulates a face using a + * simple 'ear clipping' algorithm + * that tries to favor non-skinny + * triangles (angles less than + * 90 degrees). If the triangulator + * has bits left over (or cannot + * triangulate at all) it uses a + * simple fan triangulation + * + * newfaces, if non-null, must be an array of BMFace pointers, + * with a length equal to f->len. it will be filled with the new + * triangles, and will be NULL-terminated. +*/ +void BM_Triangulate_Face(BMesh *bm, BMFace *f, float (*projectverts)[3], + int newedgeflag, int newfaceflag, BMFace **newfaces) +{ + int i, done, nvert, nf_i = 0; + BMLoop *l, *newl, *nextloop; + BMVert *v; + + /*copy vertex coordinates to vertspace array*/ + i = 0; + l = f->loopbase; + do{ + VECCOPY(projectverts[i], l->v->co); + l->v->head.eflag2 = i; /*warning, abuse! never duplicate in tools code! never you hear?*/ /*actually, get rid of this completely, use a new structure for this....*/ + i++; + l = (BMLoop*)(l->head.next); + }while(l != f->loopbase); + + ///bmesh_update_face_normal(bm, f, projectverts); + + compute_poly_normal(f->no, projectverts, f->len); + poly_rotate_plane(f->no, projectverts, i); + + nvert = f->len; + + //compute_poly_plane(projectverts, i); + for (i=0; i<nvert; i++) { + projectverts[i][2] = 0.0f; + } + + done = 0; + while(!done && f->len > 3){ + done = 1; + l = find_ear(bm, f, projectverts, nvert); + if(l) { + done = 0; + v = l->v; + f = BM_Split_Face(bm, l->f, ((BMLoop*)(l->head.prev))->v, + ((BMLoop*)(l->head.next))->v, + &newl, NULL); + VECCOPY(f->no, l->f->no); + + if (!f) { + printf("yeek! triangulator failed to split face!\n"); + break; + } + + BMO_SetFlag(bm, newl->e, newedgeflag); + BMO_SetFlag(bm, f, newfaceflag); + + if (newfaces) newfaces[nf_i++] = f; + + /*l = f->loopbase; + do { + if (l->v == v) { + f->loopbase = l; + break; + } + l = l->head.next; + } while (l != f->loopbase);*/ + } + } + + if (f->len > 3){ + l = f->loopbase; + while (l->f->len > 3){ + nextloop = ((BMLoop*)(l->head.next->next)); + f = BM_Split_Face(bm, l->f, l->v, nextloop->v, + &newl, NULL); + if (!f) { + printf("triangle fan step of triangulator failed.\n"); + + /*NULL-terminate*/ + if (newfaces) newfaces[nf_i] = NULL; + return; + } + + if (newfaces) newfaces[nf_i++] = f; + + BMO_SetFlag(bm, newl->e, newedgeflag); + BMO_SetFlag(bm, f, newfaceflag); + l = nextloop; + } + } + + /*NULL-terminate*/ + if (newfaces) newfaces[nf_i] = NULL; +} + +/*each pair of loops defines a new edge, a split. this function goes + through and sets pairs that are geometrically invalid to null. a + split is invalid, if it forms a concave angle or it intersects other + edges in the face, or it intersects another split. in the case of + intersecting splits, only the first of the set of intersecting + splits survives.*/ +void BM_LegalSplits(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len) +{ + BMIter iter; + BMLoop *l; + float v1[3], v2[3], v3[3], v4[3], no[3], mid[3], *p1, *p2, *p3, *p4; + float out[3] = {-234324.0f, -234324.0f, 0.0f}; + float projectverts[100][3]; + float edgevertsstack[200][3]; + float (*projverts)[3] = projectverts; + float (*edgeverts)[3] = edgevertsstack; + float fac1 = 1.0000001f, fac2 = 0.9f; //9999f; //0.999f; + int i, j, a=0, clen; + + if (f->len > 100) projverts = MEM_mallocN(sizeof(float)*3*f->len, "projvertsb"); + if (len > 100) edgeverts = MEM_mallocN(sizeof(float)*3*2*len, "edgevertsb"); + + i = 0; + l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); + for (; l; l=BMIter_Step(&iter)) { + l->head.eflag2 = i; + VECCOPY(projverts[i], l->v->co); + i++; + } + + for (i=0; i<len; i++) { + VECCOPY(v1, loops[i][0]->v->co); + VECCOPY(v2, loops[i][1]->v->co); + + shrink_edgef(v1, v2, fac2); + + VECCOPY(edgeverts[a], v1); + a++; + VECCOPY(edgeverts[a], v2); + a++; + } + + compute_poly_normal(no, projverts, f->len); + poly_rotate_plane(no, projverts, f->len); + poly_rotate_plane(no, edgeverts, len*2); + + l = f->loopbase; + for (i=0; i<f->len; i++) { + p1 = projverts[i]; + out[0] = MAX2(out[0], p1[0]) + 0.01f; + out[1] = MAX2(out[1], p1[1]) + 0.01f; + out[2] = 0.0f; + p1[2] = 0.0f; + + //VECCOPY(l->v->co, p1); + + l = (BMLoop*) l->head.next; + } + + for (i=0; i<len; i++) { + edgeverts[i*2][2] = 0.0f; + edgeverts[i*2+1][2] = 0.0f; + } + + /*do convexity test*/ + for (i=0; i<len; i++) { + VECCOPY(v2, edgeverts[i*2]); + VECCOPY(v3, edgeverts[i*2+1]); + + VecAddf(mid, v2, v3); + VecMulf(mid, 0.5f); + + clen = 0; + for (j=0; j<f->len; j++) { + p1 = projverts[j]; + p2 = projverts[(j+1)%f->len]; + + VECCOPY(v1, p1); + VECCOPY(v2, p2); + + shrink_edgef(v1, v2, fac1); + + if (linecrossesf(p1, p2, mid, out)) clen++; + } + + if (clen%2 == 0) { + loops[i][0] = NULL; + } + } + + /*do line crossing tests*/ + for (i=0; i<f->len; i++) { + p1 = projverts[i]; + p2 = projverts[(i+1)%f->len]; + + VECCOPY(v1, p1); + VECCOPY(v2, p2); + + shrink_edgef(v1, v2, fac1); + + for (j=0; j<len; j++) { + if (!loops[j][0]) continue; + + p3 = edgeverts[j*2]; + p4 = edgeverts[j*2+1]; + + if (linecrossesf(v1, v2, p3, p4)) + { + loops[j][0] = NULL; + } + } + } + + for (i=0; i<len; i++) { + for (j=0; j<len; j++) { + if (j == i) continue; + if (!loops[i][0]) continue; + if (!loops[j][0]) continue; + + p1 = edgeverts[i*2]; + p2 = edgeverts[i*2+1]; + p3 = edgeverts[j*2]; + p4 = edgeverts[j*2+1]; + + VECCOPY(v1, p1); + VECCOPY(v2, p2); + + shrink_edgef(v1, v2, fac1); + + if (linecrossesf(v1, v2, p3, p4)) { + loops[i][0]=NULL; + } + } + } + + if (projverts != projectverts) MEM_freeN(projverts); + if (edgeverts != edgevertsstack) MEM_freeN(edgeverts); +} diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h new file mode 100644 index 00000000000..999285a6d12 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_private.h @@ -0,0 +1,84 @@ +/** + * bmesh_private.h jan 2007 + * + * Private function prototypes for bmesh public API. + * This file is a grab-bag of functions from various + * parts of the bmesh internals. + * + * + * $Id: BKE_bmesh.h,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BMESH_PRIVATE_H +#define BMESH_PRIVATE_H + +#include "bmesh.h" + +/*start/stop edit*/ +void bmesh_begin_edit(struct BMesh *bm); +void bmesh_end_edit(struct BMesh *bm, int flag); + +/*internal selection flushing*/ +void bmesh_selectmode_flush(struct BMesh *bm); + +/*internal filter API*/ +void *bmesh_get_filter_callback(int type); +int bmesh_get_filter_argtype(int type); + +/*system flag access*/ +void bmesh_set_sysflag(struct BMHeader *element, int flag); +void bmesh_clear_sysflag(struct BMHeader *element, int flag); +int bmesh_test_sysflag(struct BMHeader *element, int flag); + +/*NOTE: ensure different parts of the API do not conflict + on using this! sets and gets the API index member + of the current flag layer.*/ +#define bmesh_api_seti(bm, head, i) ((head)->flags[bm->stackdepth-1].pflag = i) +#define bmesh_api_geti(bm, head) ((head)->flags[bm->stackdepth-1].pflag) + +/*Polygon Utilities ? FIXME... where do these each go?*/ +/*newedgeflag sets a flag layer flag, obviously not the header flag.*/ +void BM_Triangulate_Face(BMesh *bm, BMFace *f, float (*projectverts)[3], + int newedgeflag, int newfaceflag, BMFace **newfaces); +void bmesh_update_face_normal(struct BMesh *bm, struct BMFace *f, + float (*projectverts)[3]); +void compute_poly_plane(float (*verts)[3], int nverts); +void poly_rotate_plane(float normal[3], float (*verts)[3], int nverts); +void bmesh_flip_normal(struct BMesh *bm, struct BMFace *f); + +/*Error reporting. Shouldnt be called by tools ever.*/ +void BME_error(void); + +/*include the rest of our private declarations*/ +#include "bmesh_structure.h" +#include "bmesh_operators_private.h" + +#endif diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c new file mode 100644 index 00000000000..c5a9916ae24 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -0,0 +1,548 @@ +#include <string.h> + +#include "bmesh.h" +#include "bmesh_private.h" + +#include "BLI_arithb.h" +#include "MTC_vectorops.h" + +/* + * BM_QUERIES.C + * + * This file contains functions for answering common + * Topological and geometric queries about a mesh, such + * as, "What is the angle between these two faces?" or, + * "How many faces are incident upon this vertex?" Tool + * authors should use the functions in this file instead + * of inspecting the mesh structure directly. + * +*/ + +/* + * BMESH COUNT ELEMENT + * + * Return the amount of element of + * type 'type' in a given bmesh. + * + * +*/ + +int BM_Count_Element(BMesh *bm, int type) +{ + if(type == BM_VERT) return bm->totvert; + else if(type == BM_EDGE) return bm->totedge; + else if(type == BM_FACE) return bm->totface; + + return 0; +} + + +/* + * BMESH VERT IN EDGE + * + * Returns whether or not a given vertex is + * is part of a given edge. + * +*/ + +int BM_Vert_In_Edge(BMEdge *e, BMVert *v) +{ + return bmesh_vert_in_edge(e, v); +} + +/* + * BMESH OTHER EDGE IN FACE SHARING A VERTEX + * + * Returns an opposing loop that shares the same face. + * +*/ + +BMLoop *BM_OtherFaceLoop(BMEdge *e, BMFace *f, BMVert *v) +{ + BMLoop *l = f->loopbase, *l2, *l3; + int found = 0; + + do { + if (l->e == e) break; + found = 1; + l = l->head.next; + } while (l != f->loopbase); + + return l->v == v ? l->head.prev : l->head.next; +} + +/* + * BMESH VERT IN FACE + * + * Returns whether or not a given vertex is + * is part of a given face. + * +*/ + +int BM_Vert_In_Face(BMFace *f, BMVert *v) +{ + BMLoop *l; + + l = f->loopbase; + do{ + if(l->v == v) return 1; + l = ((BMLoop*)(l->head.next)); + }while(l != f->loopbase); + return 0; +} + +/* + * BMESH VERTS IN FACE + * + * Compares the number of vertices in an array + * that appear in a given face + * +*/ +int BM_Verts_In_Face(BMesh *bm, BMFace *f, BMVert **varr, int len) +{ + BMLoop *curloop = NULL; + int i, count = 0; + + for(i=0; i < len; i++) BMO_SetFlag(bm, varr[i], BM_OVERLAP); + + curloop = f->loopbase; + do{ + if(BMO_TestFlag(bm, curloop->v, BM_OVERLAP)) count++; + curloop = (BMLoop*)(curloop->head.next); + } while(curloop != f->loopbase); + + for(i=0; i < len; i++) BMO_ClearFlag(bm, varr[i], BM_OVERLAP); + + return count; +} + +/* + * BMESH EDGE IN FACE + * + * Returns whether or not a given edge is + * is part of a given face. + * +*/ + +int BM_Edge_In_Face(BMFace *f, BMEdge *e) +{ + BMLoop *l; + + l = f->loopbase; + do{ + + if(l->e == e) return 1; + l = ((BMLoop*)(l->head.next)); + }while(l != f->loopbase); + + return 0; +} + +/* + * BMESH VERTS IN EDGE + * + * Returns whether or not two vertices are in + * a given edge + * +*/ + +int BM_Verts_In_Edge(BMVert *v1, BMVert *v2, BMEdge *e) +{ + return bmesh_verts_in_edge(v1,v2,e); +} + +/* + * BMESH GET OTHER EDGEVERT + * + * Given a edge and one of its vertices, returns + * the other vertex. + * +*/ + +BMVert *BM_OtherEdgeVert(BMEdge *e, BMVert *v) +{ + return bmesh_edge_getothervert(e,v); +} + +/** + * BMESH EDGE EXIST + * + * Finds out if two vertices already have an edge + * connecting them. Note that multiple edges may + * exist between any two vertices, and therefore + * This function only returns the first one found. + * + * Returns - + * BMEdge pointer + */ + +BMEdge *BM_Edge_Exist(BMVert *v1, BMVert *v2) +{ + BMNode *diskbase; + BMEdge *curedge; + int i, len=0; + + if(v1->edge){ + diskbase = bmesh_disk_getpointer(v1->edge,v1); + len = bmesh_cycle_length(diskbase); + + for(i=0,curedge=v1->edge;i<len;i++,curedge = bmesh_disk_nextedge(curedge,v1)){ + if(bmesh_verts_in_edge(v1,v2,curedge)) return curedge; + } + } + + return NULL; +} + +/* + * BMESH VERT EDGECOUNT + * + * Returns the number of edges around this vertex. + */ + +int BM_Vert_EdgeCount(BMVert *v) +{ + if (v == v->edge->v1) return bmesh_cycle_length(&v->edge->d1); + else return bmesh_cycle_length(&v->edge->d2); +} + +/** + * BMESH EDGE FACECOUNT + * + * Returns the number of faces around this edge +*/ + +int BM_Edge_FaceCount(BMEdge *e) +{ + int count = 0; + BMLoop *curloop = NULL; + + if(e->loop){ + curloop = e->loop; + do{ + count++; + curloop = bmesh_radial_nextloop(curloop); + }while(curloop != e->loop); + } + + return count; +} + +/** + * BMESH VERT FACECOUNT + * + * Returns the number of faces around this vert +*/ + +int BM_Vert_FaceCount(BMVert *v){ + int count = 0; + BMEdge *curedge = NULL; + + if(v->edge){ + curedge = v->edge; + do{ + if(curedge->loop) count += BM_Edge_FaceCount(curedge); + curedge = bmesh_disk_nextedge(curedge,v); + }while(curedge != v->edge); + } + return count; +} + +/** + * BMESH WIRE VERT + * + * Tests whether or not the vertex is part of a wire edge. + * (ie: has no faces attached to it) + * + * Returns - + * 1 for true, 0 for false. + */ + +int BM_Wire_Vert(BMesh *bm, BMVert *v) +{ + BMEdge *curedge; + + if(!(v->edge)) return 0; + + curedge = v->edge; + do{ + if(curedge->loop) return 0; + curedge = bmesh_disk_nextedge(curedge, v); + }while(curedge != v->edge); + + return 1; +} + +/** + * BMESH WIRE EDGE + * + * Tests whether or not the edge is part of a wire. + * (ie: has no faces attached to it) + * + * Returns - + * 1 for true, 0 for false. + */ + +int BM_Wire_Edge(BMesh *bm, BMEdge *e) +{ + if(e->loop) return 0; + return 1; +} + +/** + * BMESH NONMANIFOLD VERT + * + * A vertex is non-manifold if it meets the following conditions: + * 1: Loose - (has no edges/faces incident upon it) + * 2: Joins two distinct regions - (two pyramids joined at the tip) + * 3: Is part of a non-manifold edge (edge with more than 2 faces) + * 4: Is part of a wire edge + * + * Returns - + * 1 for true, 0 for false. + */ + +int BM_Nonmanifold_Vert(BMesh *bm, BMVert *v) { + BMEdge *e, *oe; + BMLoop *l; + int len, count, flag; + + if (v->edge == NULL) { + /* loose vert */ + return 1; + } + + /* count edges while looking for non-manifold edges */ + oe = v->edge; + for (len=0,e=v->edge; e != oe || (e == oe && len == 0); len++,e=bmesh_disk_nextedge(e,v)) { + if (e->loop == NULL) { + /* loose edge */ + return 1; + } + + if (bmesh_cycle_length(&(e->loop->radial)) > 2) { + /* edge shared by more than two faces */ + return 1; + } + } + + count = 1; + flag = 1; + e = NULL; + oe = v->edge; + l = oe->loop; + while(e != oe) { + if (l->v == v) l = ((BMLoop*)(l->head.prev)); + else l = ((BMLoop*)(l->head.next)); + e = l->e; + count++; /* count the edges */ + + if (flag && l->radial.next->data == l) { + /* we've hit the edge of an open mesh, reset once */ + flag = 0; + count = 1; + oe = e; + e = NULL; + l = oe->loop; + } + else if (l->radial.next->data == l) { + /* break the loop */ + e = oe; + } + else { + l = l->radial.next->data; + } + } + + if (count < len) { + /* vert shared by multiple regions */ + return 1; + } + + return 0; +} + +/** + * BMESH NONMANIFOLD EDGE + * + * Tests whether or not this edge is manifold. + * A manifold edge either has 1 or 2 faces attached + * to it. + * + * Returns - + * 1 for true, 0 for false. + */ + +int BM_Nonmanifold_Edge(BMesh *bm, BMEdge *e) +{ + int count = BM_Edge_FaceCount(e); + if(count != 2 && count != 1) return 1; + return 0; +} + +/** + * BMESH BOUNDARY EDGE + * + * Tests whether or not an edge is on the boundary + * of a shell (has one face associated with it) + * + * Returns - + * 1 for true, 0 for false. + */ + +int BM_Boundary_Edge(BMEdge *e) +{ + int count = BM_Edge_FaceCount(e); + if(count == 1) return 1; + return 0; +} + +/** + * BMESH FACE SHAREDEDGES + * + * Counts the number of edges two faces share (if any) + * + * TODO: + * Move this to structure, and wrap. + * + * Returns - + * Integer + */ + +int BM_Face_Sharededges(BMFace *f1, BMFace *f2){ + BMLoop *l; + int count = 0; + + l = f1->loopbase; + do{ + if(bmesh_radial_find_face(l->e,f2)) count++; + l = ((BMLoop*)(l->head.next)); + }while(l != f1->loopbase); + + return count; +} + +/** + * + * BMESH EDGE SHARE FACES + * + * Tests to see if e1 shares any faces with e2 + * +*/ + +int BM_Edge_Share_Faces(BMEdge *e1, BMEdge *e2) +{ + BMLoop *l; + BMFace *f; + + if(e1->loop && e2->loop){ + l = e1->loop; + do{ + f = l->f; + if(bmesh_radial_find_face(e2,f)){ + return 1; + } + l = (BMLoop*)(l->radial.next->data); + }while(l != e1->loop); + } + return 0; +} + + + +/** + * BMESH FACE ANGLE + * + * Calculates the angle between two faces. Assumes + * That face normals are correct. + * + * Returns - + * Float. + */ + +float BM_Face_Angle(BMesh *bm, BMEdge *e) +{ + BMLoop *l1, *l2; + int radlen; + float edge_angle_cos = 0.0; + + radlen = BM_Edge_FaceCount(e); + if(radlen == 2){ + l1 = e->loop; + l2 = e->loop->radial.next->data; + edge_angle_cos = MTC_dot3Float(l1->f->no, l2->f->no); + } + return edge_angle_cos; + +} + +/* + * BMESH EXIST FACE OVERLAPS + * + * Given a set of vertices (varr), find out if + * all those vertices overlap an existing face. + * + * Returns: + * 0 for no overlap + * 1 for overlap + * + * +*/ + +int BM_Exist_Face_Overlaps(BMesh *bm, BMVert **varr, int len, BMFace **overlapface) +{ + BMIter vertfaces; + BMFace *f; + int i, amount; + + if (overlapface) *overlapface = NULL; + + for(i=0; i < len; i++){ + f = BMIter_New(&vertfaces, bm, BM_FACES_OF_VERT, varr[i] ); + while(f){ + amount = BM_Verts_In_Face(bm, f, varr, len); + if(amount >= len){ + if (overlapface) *overlapface = f; + return 1; + } + f = BMIter_Step(&vertfaces); + } + } + return 0; +} + +/* + * BMESH FACE EXISTS + * + * Given a set of vertices (varr), find out if + * there is a face with exactly those vertices + * (and only those vertices). + * + * Returns: + * 0 for no face found + * 1 for face found + * + * +*/ + +int BM_Face_Exists(BMesh *bm, BMVert **varr, int len, BMFace **existface) +{ + BMIter vertfaces; + BMFace *f; + int i, amount; + + if (existface) *existface = NULL; + + for(i=0; i < len; i++){ + f = BMIter_New(&vertfaces, bm, BM_FACES_OF_VERT, varr[i] ); + while(f){ + amount = BM_Verts_In_Face(bm, f, varr, len); + if(amount == len && amount == f->len){ + if (existface) *existface = f; + return 1; + } + f = BMIter_Step(&vertfaces); + } + } + return 0; +} diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c new file mode 100644 index 00000000000..a14f1d662ae --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_structure.c @@ -0,0 +1,775 @@ +/** + * bmesh_structure.c jan 2007 + * + * Low level routines for manipulating the BM structure. + * + * $Id: bmesh_structure.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** 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. + * 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) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <limits.h> +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "BKE_utildefines.h" +#include "bmesh.h" +#include "bmesh_private.h" +#include "BLI_blenlib.h" +#include "BLI_linklist.h" +#include "BLI_ghash.h" +/** + * MISC utility functions. + * + */ + +int bmesh_vert_in_edge(BMEdge *e, BMVert *v){ + if(e->v1 == v || e->v2 == v) return 1; + return 0; +} +int bmesh_verts_in_edge(BMVert *v1, BMVert *v2, BMEdge *e){ + if(e->v1 == v1 && e->v2 == v2) return 1; + else if(e->v1 == v2 && e->v2 == v1) return 1; + return 0; +} + +BMVert *bmesh_edge_getothervert(BMEdge *e, BMVert *v){ + if(e->v1 == v) return e->v2; + else if(e->v2 == v) return e->v1; + return NULL; +} + +int bmesh_edge_swapverts(BMEdge *e, BMVert *orig, BMVert *new){ + if(e->v1 == orig){ + e->v1 = new; + e->d1.next = NULL; + e->d1.prev = NULL; + return 1; + } + else if(e->v2 == orig){ + e->v2 = new; + e->d2.next = NULL; + e->d2.prev = NULL; + return 1; + } + return 0; +} + +/** + * ALLOCATION/DEALLOCATION FUNCTIONS + */ + +BMVert *bmesh_addvertlist(BMesh *bm, BMVert *example){ + BMVert *v=NULL; + v = BLI_mempool_calloc(bm->vpool); + v->head.next = v->head.prev = NULL; + v->head.flag = 0; + v->head.EID = bm->nextv; + v->head.type = BM_VERT; + v->co[0] = v->co[1] = v->co[2] = 0.0f; + v->no[0] = v->no[1] = v->no[2] = 0.0f; + v->edge = NULL; + v->head.data = NULL; + v->bweight = 0.0f; + BLI_addtail(&(bm->verts), &(v->head)); + bm->nextv++; + bm->totvert++; + + if(example){ + VECCOPY(v->co,example->co); + CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, example->head.data, &v->head.data); + } + else + CustomData_bmesh_set_default(&bm->vdata, &v->head.data); + + /*allocate flags*/ + v->head.flags = BLI_mempool_calloc(bm->flagpool); + + return v; +} +BMEdge *bmesh_addedgelist(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge *example){ + BMEdge *e=NULL; + e = BLI_mempool_calloc(bm->epool); + e->head.next = e->head.prev = NULL; + e->head.EID = bm->nexte; + e->head.type = BM_EDGE; + e->head.flag = 0; + e->v1 = v1; + e->v2 = v2; + e->d1.next = e->d1.prev = e->d2.next = e->d2.prev = NULL; + e->d1.data = e; + e->d2.data = e; + e->loop = NULL; + e->head.data = NULL; + e->crease = e->bweight = 0.0f; + bm->nexte++; + bm->totedge++; + BLI_addtail(&(bm->edges), &(e->head)); + + if(example) + CustomData_bmesh_copy_data(&bm->edata, &bm->edata, example->head.data, &e->head.data); + else + CustomData_bmesh_set_default(&bm->edata, &e->head.data); + + /*allocate flags*/ + e->head.flags = BLI_mempool_calloc(bm->flagpool); + + return e; +} +BMLoop *bmesh_create_loop(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f, BMLoop *example){ + BMLoop *l=NULL; + l = BLI_mempool_calloc(bm->lpool); + l->head.next = l->head.prev = NULL; + l->head.EID = bm->nextl; + l->head.type = BM_LOOP; + l->head.flag = 0; + l->radial.next = l->radial.prev = NULL; + l->radial.data = l; + l->v = v; + l->e = e; + l->f = f; + l->head.data = NULL; + bm->nextl++; + bm->totloop++; + + if(example) + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, example->head.data, &l->head.data); + else + CustomData_bmesh_set_default(&bm->ldata, &l->head.data); + + return l; +} + +BMFace *bmesh_addpolylist(BMesh *bm, BMFace *example){ + BMFace *f = NULL; + f = BLI_mempool_calloc(bm->ppool); + f->head.flag = 0; + f->head.next = f->head.prev = NULL; + f->head.EID = bm->nextp; + f->head.type = BM_FACE; + f->loopbase = NULL; + f->len = 0; + f->head.data = NULL; + f->mat_nr = 0; + BLI_addtail(&(bm->polys),&(f->head)); + bm->nextp++; + bm->totface++; + + if(example) + CustomData_bmesh_copy_data(&bm->pdata, &bm->pdata, example->head.data, &f->head.data); + else + CustomData_bmesh_set_default(&bm->pdata, &f->head.data); + + /*allocate flags*/ + f->head.flags = BLI_mempool_calloc(bm->flagpool); + + return f; +} + +/* free functions dont do much *yet*. When per-vertex, per-edge and per-face/faceloop + data is added though these will be needed. +*/ +void bmesh_free_vert(BMesh *bm, BMVert *v){ + bm->totvert--; + CustomData_bmesh_free_block(&bm->vdata, &v->head.data); + BLI_mempool_free(bm->flagpool, v->head.flags); + BLI_mempool_free(bm->vpool, v); +} +void bmesh_free_edge(BMesh *bm, BMEdge *e){ + bm->totedge--; + CustomData_bmesh_free_block(&bm->edata, &e->head.data); + BLI_mempool_free(bm->flagpool, e->head.flags); + BLI_mempool_free(bm->epool, e); +} +void bmesh_free_poly(BMesh *bm, BMFace *f){ + if (f == bm->act_face) + bm->act_face = NULL; + + bm->totface--; + CustomData_bmesh_free_block(&bm->pdata, &f->head.data); + BLI_mempool_free(bm->flagpool, f->head.flags); + BLI_mempool_free(bm->ppool, f); +} +void bmesh_free_loop(BMesh *bm, BMLoop *l){ + bm->totloop--; + CustomData_bmesh_free_block(&bm->ldata, &l->head.data); + BLI_mempool_free(bm->lpool, l); +} +/** + * BMESH CYCLES + * + * Cycles are circular doubly linked lists that form the basis of adjacency + * information in the BME modeller. Full adjacency relations can be derived + * from examining these cycles very quickly. Although each cycle is a double + * circular linked list, each one is considered to have a 'base' or 'head', + * and care must be taken by Euler code when modifying the contents of a cycle. + * + * The contents of this file are split into two parts. First there are the + * bmesh_cycle family of functions which are generic circular double linked list + * procedures. The second part contains higher level procedures for supporting + * modification of specific cycle types. + * + * The three cycles explicitly stored in the BM data structure are as follows: + * + * 1: The Disk Cycle - A circle of edges around a vertex + * Base: vertex->edge pointer. + * + * This cycle is the most complicated in terms of its structure. Each bmesh_Edge contains + * two bmesh_CycleNode structures to keep track of that edge's membership in the disk cycle + * of each of its vertices. However for any given vertex it may be the first in some edges + * in its disk cycle and the second for others. The bmesh_disk_XXX family of functions contain + * some nice utilities for navigating disk cycles in a way that hides this detail from the + * tool writer. + * + * Note that the disk cycle is completley independant from face data. One advantage of this + * is that wire edges are fully integrated into the topology database. Another is that the + * the disk cycle has no problems dealing with non-manifold conditions involving faces. + * + * Functions relating to this cycle: + * + * bmesh_disk_append_edge + * bmesh_disk_remove_edge + * bmesh_disk_nextedge + * bmesh_disk_getpointer + * + * 2: The Radial Cycle - A circle of face edges (bmesh_Loop) around an edge + * Base: edge->loop->radial structure. + * + * The radial cycle is similar to the radial cycle in the radial edge data structure.* + * Unlike the radial edge however, the radial cycle does not require a large amount of memory + * to store non-manifold conditions since BM does not keep track of region/shell + * information. + * + * Functions relating to this cycle: + * + * bmesh_radial_append + * bmesh_radial_remove_loop + * bmesh_radial_nextloop + * bmesh_radial_find_face + * + * + * 3: The Loop Cycle - A circle of face edges around a polygon. + * Base: polygon->loopbase. + * + * The loop cycle keeps track of a faces vertices and edges. It should be noted that the + * direction of a loop cycle is either CW or CCW depending on the face normal, and is + * not oriented to the faces editedges. + * + * Functions relating to this cycle: + * + * bmesh_cycle_XXX family of functions. + * + * + * Note that the order of elements in all cycles except the loop cycle is undefined. This + * leads to slightly increased seek time for deriving some adjacency relations, however the + * advantage is that no intrinsic properties of the data structures are dependant upon the + * cycle order and all non-manifold conditions are represented trivially. + * +*/ + + +void bmesh_cycle_append(void *h, void *nt) +{ + BMNode *oldtail, *head, *newtail; + + head = (BMNode*)h; + newtail = (BMNode*)nt; + + if(head->next == NULL){ + head->next = newtail; + head->prev = newtail; + newtail->next = head; + newtail->prev = head; + } + else{ + oldtail = head->prev; + oldtail->next = newtail; + newtail->next = head; + newtail->prev = oldtail; + head->prev = newtail; + + } +} + +/** + * bmesh_cycle_length + * + * Count the nodes in a cycle. + * + * Returns - + * Integer + */ + +int bmesh_cycle_length(void *h){ + + int len = 0; + BMNode *head, *curnode; + head = (BMNode*)h; + + if(head){ + len = 1; + for(curnode = head->next; curnode != head; curnode=curnode->next){ + if(len == INT_MAX){ //check for infinite loop/corrupted cycle + return -1; + } + len++; + } + } + return len; +} + + +/** + * bmesh_cycle_remove + * + * Removes a node from a cycle. + * + * Returns - + * 1 for success, 0 for failure. + */ + +int bmesh_cycle_remove(void *h, void *remn) +{ + int i, len; + BMNode *head, *remnode, *curnode; + + head = (BMNode*)h; + remnode = (BMNode*)remn; + len = bmesh_cycle_length(h); + + if(len == 1 && head == remnode){ + head->next = NULL; + head->prev = NULL; + return 1; + } + else{ + for(i=0, curnode = head; i < len; curnode = curnode->next){ + if(curnode == remnode){ + remnode->prev->next = remnode->next; + remnode->next->prev = remnode->prev; + /*zero out remnode pointers, important!*/ + //remnode->next = NULL; + //remnode->prev = NULL; + return 1; + + } + } + } + return 0; +} + +/** + * bmesh_cycle_validate + * + * Validates a cycle. Takes as an argument the expected length of the cycle and + * a pointer to the cycle head or base. + * + * + * Returns - + * 1 for success, 0 for failure. + */ + +int bmesh_cycle_validate(int len, void *h){ + int i; + BMNode *curnode, *head; + head = (BMNode*)h; + + /*forward validation*/ + for(i = 0, curnode = head; i < len; i++, curnode = curnode->next); + if(curnode != head) return 0; + + /*reverse validation*/ + for(i = 0, curnode = head; i < len; i++, curnode = curnode->prev); + if(curnode != head) return 0; + + return 1; +} + +/*Begin Disk Cycle routines*/ + +/** + * bmesh_disk_nextedge + * + * Find the next edge in a disk cycle + * + * Returns - + * Pointer to the next edge in the disk cycle for the vertex v. + */ + +BMEdge *bmesh_disk_nextedge(BMEdge *e, BMVert *v) +{ + if(bmesh_vert_in_edge(e, v)){ + if(e->v1 == v) return e->d1.next->data; + else if(e->v2 == v) return e->d2.next->data; + } + return NULL; +} + +/** + * bmesh_disk_getpointer + * + * Given an edge and one of its vertices, find the apporpriate CycleNode + * + * Returns - + * Pointer to bmesh_CycleNode. + */ +BMNode *bmesh_disk_getpointer(BMEdge *e, BMVert *v){ + /*returns pointer to the cycle node for the appropriate vertex in this disk*/ + if(e->v1 == v) return &(e->d1); + else if (e->v2 == v) return &(e->d2); + return NULL; +} + +/** + * bmesh_disk_append_edge + * + * Appends edge to the end of a vertex disk cycle. + * + * Returns - + * 1 for success, 0 for failure + */ + +int bmesh_disk_append_edge(BMEdge *e, BMVert *v) +{ + + BMNode *base, *tail; + + if(bmesh_vert_in_edge(e, v) == 0) return 0; /*check to make sure v is in e*/ + + /*check for loose vert first*/ + if(v->edge == NULL){ + v->edge = e; + base = tail = bmesh_disk_getpointer(e, v); + bmesh_cycle_append(base, tail); /*circular reference is ok!*/ + return 1; + } + + /*insert e at the end of disk cycle and make it the new v->edge*/ + base = bmesh_disk_getpointer(v->edge, v); + tail = bmesh_disk_getpointer(e, v); + bmesh_cycle_append(base, tail); + return 1; +} + +/** + * bmesh_disk_remove_edge + * + * Removes an edge from a disk cycle. If the edge to be removed is + * at the base of the cycle, the next edge becomes the new base. + * + * + * Returns - + * Nothing + */ + +void bmesh_disk_remove_edge(BMEdge *e, BMVert *v) +{ + BMNode *base, *remnode; + BMEdge *newbase; + int len; + + base = bmesh_disk_getpointer(v->edge, v); + remnode = bmesh_disk_getpointer(e, v); + + /*first deal with v->edge pointer...*/ + len = bmesh_cycle_length(base); + if(len == 1) newbase = NULL; + else if(v->edge == e) newbase = base->next-> data; + else newbase = v->edge; + + /*remove and rebase*/ + bmesh_cycle_remove(base, remnode); + v->edge = newbase; +} + +/** + * bmesh_disk_next_edgeflag + * + * Searches the disk cycle of v, starting with e, for the + * next edge that has either eflag or tflag. + * + * bmesh_Edge pointer. + */ + +BMEdge *bmesh_disk_next_edgeflag(BMEdge *e, BMVert *v, int eflag, int tflag) +{ + + BMNode *diskbase; + BMEdge *curedge; + int len, ok; + + if(eflag && tflag) return NULL; + + ok = bmesh_vert_in_edge(e,v); + if(ok){ + diskbase = bmesh_disk_getpointer(e, v); + len = bmesh_cycle_length(diskbase); + curedge = bmesh_disk_nextedge(e,v); + while(curedge != e){ + if(eflag){ + if(curedge->head.eflag1 == eflag) return curedge; + } + curedge = bmesh_disk_nextedge(curedge, v); + } + } + return NULL; +} + +/** + * bmesh_disk_count_edgeflag + * + * Counts number of edges in this verts disk cycle which have + * either eflag or tflag (but not both!) + * + * Returns - + * Integer. + */ + +int bmesh_disk_count_edgeflag(BMVert *v, int eflag, int tflag) +{ + BMNode *diskbase; + BMEdge *curedge; + int i, len=0, count=0; + + if(v->edge){ + if(eflag && tflag) return 0; /*tflag and eflag are reserved for different functions!*/ + diskbase = bmesh_disk_getpointer(v->edge, v); + len = bmesh_cycle_length(diskbase); + + for(i = 0, curedge=v->edge; i<len; i++){ + if(eflag){ + if(curedge->head.eflag1 == eflag) count++; + } + curedge = bmesh_disk_nextedge(curedge, v); + } + } + return count; +} + + +int bmesh_disk_hasedge(BMVert *v, BMEdge *e){ + BMNode *diskbase; + BMEdge *curedge; + int i, len=0; + + if(v->edge){ + diskbase = bmesh_disk_getpointer(v->edge,v); + len = bmesh_cycle_length(diskbase); + + for(i = 0, curedge=v->edge; i<len; i++){ + if(curedge == e) return 1; + else curedge=bmesh_disk_nextedge(curedge, v); + } + } + return 0; +} + +BMEdge *bmesh_disk_existedge(BMVert *v1, BMVert *v2){ + BMNode *diskbase; + BMEdge *curedge; + int i, len=0; + + if(v1->edge){ + diskbase = bmesh_disk_getpointer(v1->edge,v1); + len = bmesh_cycle_length(diskbase); + + for(i=0,curedge=v1->edge;i<len;i++,curedge = bmesh_disk_nextedge(curedge,v1)){ + if(bmesh_verts_in_edge(v1,v2,curedge)) return curedge; + } + } + + return NULL; +} + +/*end disk cycle routines*/ + +BMLoop *bmesh_radial_nextloop(BMLoop *l){ + return (BMLoop*)(l->radial.next->data); +} + +void bmesh_radial_append(BMEdge *e, BMLoop *l){ + if(e->loop == NULL) e->loop = l; + bmesh_cycle_append(&(e->loop->radial), &(l->radial)); +} + +void bmesh_radial_remove_loop(BMLoop *l, BMEdge *e) +{ + BMLoop *newbase; + int len; + + /*deal with edge->loop pointer*/ + len = bmesh_cycle_length(&(e->loop->radial)); + if(len == 1) newbase = NULL; + else if(e->loop == l) newbase = e->loop->radial.next->data; + else newbase = e->loop; + + /*remove and rebase*/ + bmesh_cycle_remove(&(e->loop->radial), &(l->radial)); + e->loop = newbase; +} + +int bmesh_radial_find_face(BMEdge *e,BMFace *f) +{ + + BMLoop *curloop; + int i, len; + + len = bmesh_cycle_length(&(e->loop->radial)); + for(i = 0, curloop = e->loop; i < len; i++, curloop = curloop->radial.next->data){ + if(curloop->f == f) return 1; + } + return 0; +} + + +/* + * BME RADIAL COUNT FACE VERT + * + * Returns the number of times a vertex appears + * in a radial cycle + * +*/ + +int bmesh_radial_count_facevert(BMLoop *l, BMVert *v) +{ + BMLoop *curloop; + int count = 0; + curloop = l; + do{ + if(curloop->v == v) count++; + curloop = bmesh_radial_nextloop(curloop); + }while(curloop != l); + return count; +} + +/* + * BME DISK COUNT FACE VERT + * + * Counts the number of loop users + * for this vertex. Note that this is + * equivalent to counting the number of + * faces incident upon this vertex + * +*/ + +int bmesh_disk_count_facevert(BMVert *v) +{ + BMEdge *curedge; + int count = 0; + + /*is there an edge on this vert at all?*/ + if(!v->edge) + return count; + + /*first, loop around edges*/ + curedge = v->edge; + do{ + if(curedge->loop) count += bmesh_radial_count_facevert(curedge->loop, v); + curedge = bmesh_disk_nextedge(curedge, v); + }while(curedge != v->edge); + + return count; +} + +/* + * BME RADIAL FIND FIRST FACE VERT + * + * Finds the first loop of v around radial + * cycle + * +*/ +BMLoop *bmesh_radial_find_first_facevert(BMLoop *l, BMVert *v) +{ + BMLoop *curloop; + curloop = l; + do{ + if(curloop->v == v) return curloop; + curloop = bmesh_radial_nextloop(curloop); + }while(curloop != l); + return NULL; +} + +BMLoop *bmesh_radial_find_next_facevert(BMLoop *l, BMVert *v) +{ + BMLoop *curloop; + curloop = bmesh_radial_nextloop(l); + do{ + if(curloop->v == v) return curloop; + curloop = bmesh_radial_nextloop(curloop); + }while(curloop !=l); + return l; +} + + +/* + * BME FIND FIRST FACE EDGE + * + * Finds the first edge in a vertices + * Disk cycle that has one of this + * vert's loops attached + * to it. + * + * +*/ + +BMEdge *bmesh_disk_find_first_faceedge(BMEdge *e, BMVert *v) +{ + BMEdge *searchedge = NULL; + searchedge = e; + do{ + if(searchedge->loop && bmesh_radial_count_facevert(searchedge->loop,v)) return searchedge; + searchedge = bmesh_disk_nextedge(searchedge,v); + }while(searchedge != e); + + return NULL; +} + +BMEdge *bmesh_disk_find_next_faceedge(BMEdge *e, BMVert *v) +{ + BMEdge *searchedge = NULL; + searchedge = bmesh_disk_nextedge(e,v); + do{ + if(searchedge->loop && bmesh_radial_count_facevert(searchedge->loop,v)) return searchedge; + searchedge = bmesh_disk_nextedge(searchedge,v); + }while(searchedge !=e); + return e; +} + + + + + +struct BMLoop *bmesh_loop_find_loop(struct BMFace *f, struct BMVert *v) { + BMLoop *l; + int i, len; + + len = bmesh_cycle_length(f->loopbase); + for (i = 0, l=f->loopbase; i < len; i++, l=((BMLoop*)(l->head.next)) ) { + if (l->v == v) return l; + } + return NULL; +} diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h new file mode 100644 index 00000000000..ba63bb8f65f --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_structure.h @@ -0,0 +1,100 @@ +/** + * bmesh_structure.h jan 2007 + * + * The lowest level of functionality for manipulating bmesh structures. + * None of these functions should ever be exported to the rest of Blender. + * + * ***** 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef BM_STRUCTURE_H +#define BM_STRUCTURE_H + +/*ALLOCATION/DEALLOCATION*/ +struct BMVert *bmesh_addvertlist(struct BMesh *bm, struct BMVert *example); +struct BMEdge *bmesh_addedgelist(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMEdge *example); +struct BMFace *bmesh_addpolylist(struct BMesh *bm, struct BMFace *example); +struct BMLoop *bmesh_create_loop(struct BMesh *bm, struct BMVert *v, struct BMEdge *e, struct BMFace *f, struct BMLoop *example); + +void bmesh_free_vert(struct BMesh *bm, struct BMVert *v); +void bmesh_free_edge(struct BMesh *bm, struct BMEdge *e); +void bmesh_free_poly(struct BMesh *bm, struct BMFace *f); +void bmesh_free_loop(struct BMesh *bm, struct BMLoop *l); + +/*DOUBLE CIRCULAR LINKED LIST FUNCTIONS*/ +void bmesh_cycle_append(void *h, void *nt); +int bmesh_cycle_remove(void *h, void *remn); +int bmesh_cycle_validate(int len, void *h); +int bmesh_cycle_length(void *h); + +/*DISK CYCLE MANAGMENT*/ +int bmesh_disk_append_edge(struct BMEdge *e, struct BMVert *v); +void bmesh_disk_remove_edge(struct BMEdge *e, struct BMVert *v); +struct BMEdge *bmesh_disk_nextedge(struct BMEdge *e, struct BMVert *v); +struct BMNode *bmesh_disk_getpointer(struct BMEdge *e, struct BMVert *v); +int bmesh_disk_count_facevert(struct BMVert *v); +struct BMEdge *bmesh_disk_find_first_faceedge(struct BMEdge *e, struct BMVert *v); +struct BMEdge *bmesh_disk_find_next_faceedge(struct BMEdge *e, struct BMVert *v); + +/*RADIAL CYCLE MANAGMENT*/ +void bmesh_radial_append(struct BMEdge *e, struct BMLoop *l); +void bmesh_radial_remove_loop(struct BMLoop *l, struct BMEdge *e); +int bmesh_radial_find_face(struct BMEdge *e, struct BMFace *f); +struct BMLoop *bmesh_radial_nextloop(struct BMLoop *l); +int bmesh_radial_count_facevert(struct BMLoop *l, struct BMVert *v); +struct BMLoop *bmesh_radial_find_first_facevert(struct BMLoop *l, struct BMVert *v); +struct BMLoop *bmesh_radial_find_next_facevert(struct BMLoop *l, struct BMVert *v); + +/*EDGE UTILITIES*/ +int bmesh_vert_in_edge(struct BMEdge *e, struct BMVert *v); +int bmesh_verts_in_edge(struct BMVert *v1, struct BMVert *v2, struct BMEdge *e); +int bmesh_edge_swapverts(struct BMEdge *e, struct BMVert *orig, struct BMVert *new); /*relink edge*/ +struct BMVert *bmesh_edge_getothervert(struct BMEdge *e, struct BMVert *v); +int bmesh_disk_hasedge(struct BMVert *v, struct BMEdge *e); +struct BMEdge *bmesh_disk_existedge(BMVert *v1, BMVert *v2); +struct BMEdge *bmesh_disk_next_edgeflag(struct BMEdge *e, struct BMVert *v, int eflag, int tflag); +int bmesh_disk_count_edgeflag(struct BMVert *v, int eflag, int tflag); + +/*EULER API - For modifying structure*/ +struct BMVert *bmesh_mv(struct BMesh *bm, float *vec); +struct BMEdge *bmesh_me(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2); +struct BMFace *bmesh_mf(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMEdge **elist, int len); +int bmesh_kv(struct BMesh *bm, struct BMVert *v); +int bmesh_ke(struct BMesh *bm, struct BMEdge *e); +int bmesh_kf(struct BMesh *bm, struct BMFace *bply); +struct BMVert *bmesh_semv(struct BMesh *bm, struct BMVert *tv, struct BMEdge *e, struct BMEdge **re); +struct BMFace *bmesh_sfme(struct BMesh *bm, struct BMFace *f, struct BMVert *v1, struct BMVert *v2, struct BMLoop **rl); +int bmesh_jekv(struct BMesh *bm, struct BMEdge *ke, struct BMVert *kv); +int bmesh_loop_reverse(struct BMesh *bm, struct BMFace *f); +struct BMFace *bmesh_jfke(struct BMesh *bm, struct BMFace *f1, BMFace *f2, BMEdge *e); + +struct BMVert *bmesh_urmv(struct BMesh *bm, struct BMFace *sf, struct BMVert *sv); +//int *bmesh_grkv(struct BMesh *bm, struct BMFace *sf, struct BMVert *kv); + +#endif diff --git a/source/blender/bmesh/intern/bmesh_to_editmesh.c b/source/blender/bmesh/intern/bmesh_to_editmesh.c new file mode 100644 index 00000000000..4654d353255 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_to_editmesh.c @@ -0,0 +1,312 @@ +#include "MEM_guardedalloc.h" +#include "BKE_customdata.h" +#include "DNA_listBase.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include <string.h> +#include "BKE_utildefines.h" +#include "BKE_mesh.h" +#include "BKE_global.h" +#include "BKE_DerivedMesh.h" +#include "BKE_cdderivedmesh.h" + +#include "BLI_editVert.h" +#include "mesh_intern.h" +#include "ED_mesh.h" + +#include "BLI_blenlib.h" +#include "BLI_edgehash.h" + +#include "bmesh.h" + +/* + * BMESH TO EDITMESH + * + * This file contains functions for converting + * from a bmesh to an editmesh + * +*/ + +/* + * LOOPS TO EDITMESH CORNERS + * + * Converts N-Gon loop (face-edge) + * data (UVs, Verts Colors, ect) to + * face corner data. + * +*/ + +static void loops_to_editmesh_corners(BMesh *bm, CustomData *facedata, void *face_block, BMFace *f,int numCol, int numTex){ + int i, j; + BMLoop *l; + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + + for(i=0; i < numTex; i++){ + texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i); + texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i); + + texface->tpage = texpoly->tpage; + texface->flag = texpoly->flag; + texface->transp = texpoly->transp; + texface->mode = texpoly->mode; + texface->tile = texpoly->tile; + texface->unwrap = texpoly->unwrap; + + j = 0; + l = f->loopbase; + do { + mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i); + texface->uv[j][0] = mloopuv->uv[0]; + texface->uv[j][1] = mloopuv->uv[1]; + j++; + l = ((BMLoop*)(l->head.next)); + } while(l!=f->loopbase); + + } + + for(i=0; i < numCol; i++){ + mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i); + j = 0; + l = f->loopbase; + do { + mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i); + mcol[j].r = mloopcol->r; + mcol[j].g = mloopcol->g; + mcol[j].b = mloopcol->b; + mcol[j].a = mloopcol->a; + j++; + l = ((BMLoop*)(l->head.next)); + } while(l!=f->loopbase); + } +} + +static EditVert *bmeshvert_to_editvert(BMesh *bm, EditMesh *em, BMVert *v, int index, EditVert **evlist) +{ + EditVert *eve = NULL; + + v->head.eflag1 = index; /*abuse!*/ + eve = addvertlist(em, v->co, NULL); + eve->keyindex = index; + evlist[index]= eve; + + /*copy flags*/ + if(v->head.flag & BM_HIDDEN) eve->h = 1; + if (v->head.flag & BM_SELECT) eve->f |= SELECT; + + eve->bweight = v->bweight; + CustomData_em_copy_data(&bm->vdata, &em->vdata, v->head.data, &eve->data); + /*copy normal*/ + eve->no[0] = v->no[0]; + eve->no[1] = v->no[1]; + eve->no[2] = v->no[2]; + + return eve; +} + +static void bmeshedge_to_editedge_internal(BMesh *bm, EditMesh *em, BMEdge *e, EditEdge *eed) +{ + eed->crease = e->crease; + eed->bweight = e->bweight; + + //copy relavent flags + if (e->head.flag & BM_SELECT) eed->f |= SELECT; + if (e->head.flag & BM_SEAM) eed->seam = 1; + if (e->head.flag & BM_SHARP) eed->sharp = 1; + if (e->head.flag & BM_HIDDEN) eed->h = 1; + if (e->head.flag & BM_FGON) eed->h |= EM_FGON; + + CustomData_em_copy_data(&bm->edata, &em->edata, e->head.data, &eed->data); +} + +static EditEdge *bmeshedge_to_editedge(BMesh *bm, EditMesh *em, BMEdge *e, EditVert **evlist) +{ + EditEdge *eed = NULL; + + if(!(findedgelist(em, evlist[e->v1->head.eflag1], evlist[e->v2->head.eflag1]))){ + eed= addedgelist(em, evlist[e->v1->head.eflag1], evlist[e->v2->head.eflag1], NULL); + bmeshedge_to_editedge_internal(bm, em, e, eed); + } + + return eed; +} + +static EditFace *bmeshface_to_editface(BMesh *bm, EditMesh *em, BMFace *f, EditVert **evlist, int numCol, int numTex) +{ + EditVert *eve1, *eve2, *eve3, *eve4; + EditFace *efa = NULL; + int len; + + len = f->len; + + eve1= evlist[f->loopbase->v->head.eflag1]; + eve2= evlist[((BMLoop*)(f->loopbase->head.next))->v->head.eflag1]; + eve3= evlist[((BMLoop*)(f->loopbase->head.next->next))->v->head.eflag1]; + if (len == 4) { + eve4= evlist[ ((BMLoop*)(f->loopbase->head.prev))->v->head.eflag1]; + } + else { + eve4= NULL; + } + + if (eve1==eve2 || eve1==eve3 || eve1==eve4 || eve2==eve3 || eve3==eve4 + || eve2==eve4) return NULL; + + efa = addfacelist(em, eve1, eve2, eve3, eve4, NULL, NULL); + if (!efa) return NULL; + + bmeshedge_to_editedge_internal(bm, em, f->loopbase->e, efa->e1); + bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->loopbase->head.next))->e, efa->e2); + bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->loopbase->head.next->next))->e, efa->e3); + if(eve4) + bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->loopbase->head.prev))->e, efa->e4); + + efa->mat_nr = (unsigned char)f->mat_nr; + + /*Copy normal*/ + efa->n[0] = f->no[0]; + efa->n[1] = f->no[1]; + efa->n[2] = f->no[2]; + + //copy relavent original flags + if (f->head.flag & BM_SELECT) efa->f |= SELECT; + if (f->head.flag & BM_HIDDEN) efa->h = 1; + if (f->head.flag & BM_SMOOTH) efa->flag |= ME_SMOOTH; + if (f->head.flag & BM_ACTIVE) EM_set_actFace(em, efa); + + CustomData_em_copy_data(&bm->pdata, &em->fdata, f->head.data, &efa->data); + loops_to_editmesh_corners(bm, &em->fdata, efa->data, f, numCol,numTex); + + return efa; +} + +EditMesh *bmesh_to_editmesh_intern(BMesh *bm) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + + EditMesh *em; + EditVert *eve, **evlist; + + int totvert, i, numTex, numCol; + + em = MEM_callocN(sizeof(EditMesh), "EditMesh from bmesh"); + + em->selectmode = bm->selectmode; + + CustomData_copy(&bm->vdata, &em->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->edata, &em->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->pdata, &em->fdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_from_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata,0); + numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); + + totvert = BM_Count_Element(bm, BM_VERT); + evlist= MEM_mallocN(totvert*sizeof(EditVert *),"evlist"); + + /* make vertices */ + for(i=0, v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts), i++) + eve = bmeshvert_to_editvert(bm, em, v, i, evlist); + + /* make edges */ + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)) + bmeshedge_to_editedge(bm, em, e, evlist); + + /* make faces */ + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)) + bmeshface_to_editface(bm, em, f, evlist, numCol, numTex); + + MEM_freeN(evlist); + + EM_fgon_flags(em); + + EM_nvertices_selected(em); + EM_nedges_selected(em); + EM_nfaces_selected(em); + + return em; +} + +void bmesh2edit_exec(BMesh *bmesh, BMOperator *op) +{ + BMO_Set_Pnt(op, "emout", bmesh_to_editmesh_intern(bmesh)); +} + +#define FACE_NGON 1 + +void bmesh_make_fgons_exec(BMesh *bmesh, BMOperator *op) +{ + BMOperator triop; + BMFace *face; + BMIter iter, liter; + BMEdge *edge; + BMLoop *l, *nl; + BMOpSlot *eout; + int i, trifan = BMO_Get_Int(op, "trifan"); + + if (!trifan) BMO_Init_Op(&triop, "triangulate"); + + /*instead of properly tesselate, just make a triangle fan, this + should make bmesh -> editmesh -> bmesh conversions always properly + work.*/ + for (face = BMIter_New(&iter, bmesh, BM_FACES_OF_MESH, NULL); face; face=BMIter_Step(&iter)) { + if (face->len > 4) { + BMO_SetFlag(bmesh, face, FACE_NGON); + if (trifan) { + while (face->len > 4) { + BM_Split_Face(bmesh, face, + face->loopbase->v, + ((BMLoop*)face->loopbase->head.next->next)->v, + &nl, NULL); + BM_SetHFlag(nl->e, BM_FGON); + } + } + } + } + + if (!trifan) { + BMO_Flag_To_Slot(bmesh, &triop, "faces", FACE_NGON, BM_FACE); + BMO_Exec_Op(bmesh, &triop); + + eout = BMO_GetSlot(&triop, "edgeout"); + for (i=0; i<eout->len; i++) { + edge = ((BMEdge**)eout->data.buf)[i]; + edge->head.flag |= BM_FGON; + face = BMIter_New(&iter, bmesh, BM_FACES_OF_EDGE, edge); + + for (; face; face=BMIter_Step(&iter)) { + face->head.flag |= BM_NONORMCALC; + } + } + + BMO_Finish_Op(bmesh, &triop); + } +} + +EditMesh *bmesh_to_editmesh(BMesh *bmesh) +{ + BMOperator conv, makefgon; + EditMesh *em; + + /*first fgon-afy the mesh*/ + BMO_Init_Op(&makefgon, "makefgon"); + BMO_Set_Int(&makefgon, "trifan", 1); + BMO_Exec_Op(bmesh, &makefgon); + BMO_Finish_Op(bmesh, &makefgon); + + BMO_Init_Op(&conv, "bmesh_to_editmesh"); + BMO_Exec_Op(bmesh, &conv); + em = BMO_Get_Pnt(&conv, "emout"); + BMO_Finish_Op(bmesh, &conv); + + return em; +}
\ No newline at end of file diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c new file mode 100644 index 00000000000..40f787bf6c2 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_walkers.c @@ -0,0 +1,667 @@ +#include <stdio.h> +#include <string.h> +#include "BLI_mempool.h" + +#include "bmesh_private.h" +#include "bmesh_walkers.h" + +#include "bmesh.h" + +/* + - joeedh - + design notes: + + original desing: walkers directly emulation recursive functions. + functions save their state onto a stack, and also push new states + to implement recursive or looping behaviour. generally only one + state push per call with a specific state is desired. + + basic design pattern: the walker step function goes through it's + list of possible choices for recursion, and recurses (by pushing a new state) + using the first non-visited one. this choise is the flagged as visited using + the ghash. each time this happens, only one state is pushed. + + * walkers use tool flags, not header flags + * walkers now use ghash for storing visited elements, + rather then stealing flags. ghash can be rewritten + to be faster if necassary, in the far future :) . + * tools should ALWAYS have necassary error handling + for if walkers fail. +*/ + +typedef struct shellWalker{ + struct shellWalker *prev; + BMVert *base; + BMEdge *curedge, *current; +} shellWalker; + +typedef struct islandboundWalker { + struct islandboundWalker *prev; + BMLoop *base; + BMVert *lastv; + BMLoop *curloop; +} islandboundWalker; + +typedef struct islandWalker { + struct islandWalker * prev; + BMFace *cur; +} islandWalker; + +typedef struct loopWalker { + struct loopWalker * prev; + BMEdge *cur, *start; + BMVert *lastv, *startv; + int startrad, stage2; +} loopWalker; + +typedef struct faceloopWalker { + struct faceloopWalker * prev; + BMLoop *l; +} faceloopWalker; + +/* NOTE: this comment is out of date, update it - joeedh + * BMWalker - change this to use the filters functions. + * + * A generic structure for maintaing the state and callbacks nessecary for walking over + * the surface of a mesh. An example of usage: + * + * BMEdge *edge; + * BMWalker *walker = BMW_create(BM_SHELLWALKER, BM_SELECT); + * walker->begin(walker, vert); + * for(edge = BMW_walk(walker); edge; edge = bmeshWwalker_walk(walker)){ + * bmesh_select_edge(edge); + * } + * BMW_free(walker); + * + * The above example creates a walker that walks over the surface a mesh by starting at + * a vertex and traveling across its edges to other vertices, and repeating the process + * over and over again until it has visited each vertex in the shell. An additional restriction + * is passed into the BMW_create function stating that we are only interested + * in walking over edges that have been flagged with the bitmask 'BM_SELECT'. + * + * +*/ + +/*Forward declerations*/ +static void *BMW_walk(struct BMWalker *walker); +static void BMW_popstate(struct BMWalker *walker); +static void BMW_pushstate(struct BMWalker *walker); + +static void shellWalker_begin(struct BMWalker *walker, void *data); +static void *shellWalker_yield(struct BMWalker *walker); +static void *shellWalker_step(struct BMWalker *walker); + +static void islandboundWalker_begin(BMWalker *walker, void *data); +static void *islandboundWalker_yield(BMWalker *walker); +static void *islandboundWalker_step(BMWalker *walker); + +static void islandWalker_begin(BMWalker *walker, void *data); +static void *islandWalker_yield(BMWalker *walker); +static void *islandWalker_step(BMWalker *walker); + +static void loopWalker_begin(BMWalker *walker, void *data); +static void *loopWalker_yield(BMWalker *walker); +static void *loopWalker_step(BMWalker *walker); + +static void faceloopWalker_begin(BMWalker *walker, void *data); +static void *faceloopWalker_yield(BMWalker *walker); +static void *faceloopWalker_step(BMWalker *walker); + +/* Pointer hiding*/ +typedef struct bmesh_walkerGeneric{ + struct bmesh_walkerGeneric *prev; +} bmesh_walkerGeneric; + + +void *BMW_Begin(BMWalker *walker, void *start) { + walker->begin(walker, start); + + return walker->step(walker); +} + +/* + * BMW_CREATE + * + * Allocates and returns a new mesh walker of + * a given type. The elements visited are filtered + * by the bitmask 'searchmask'. + * +*/ + +void BMW_Init(BMWalker *walker, BMesh *bm, int type, int searchmask) +{ + int size = 0; + + memset(walker, 0, sizeof(BMWalker)); + walker->bm = bm; + walker->restrictflag = searchmask; + walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + switch(type){ + case BMW_SHELL: + walker->begin = shellWalker_begin; + walker->step = shellWalker_step; + walker->yield = shellWalker_yield; + size = sizeof(shellWalker); + break; + case BMW_ISLANDBOUND: + walker->begin = islandboundWalker_begin; + walker->step = islandboundWalker_step; + walker->yield = islandboundWalker_yield; + size = sizeof(islandboundWalker); + break; + case BMW_ISLAND: + walker->begin = islandWalker_begin; + walker->step = islandWalker_step; + walker->yield = islandWalker_yield; + size = sizeof(islandWalker); + break; + case BMW_LOOP: + walker->begin = loopWalker_begin; + walker->step = loopWalker_step; + walker->yield = loopWalker_yield; + size = sizeof(loopWalker); + break; + case BMW_FACELOOP: + walker->begin = faceloopWalker_begin; + walker->step = faceloopWalker_step; + walker->yield = faceloopWalker_yield; + size = sizeof(faceloopWalker); + break; + default: + break; + } + walker->stack = BLI_mempool_create(size, 100, 100); + walker->currentstate = NULL; +} + +/* + * BMW_End + * + * Frees a walker's stack. + * +*/ + +void BMW_End(BMWalker *walker) +{ + BLI_mempool_destroy(walker->stack); + BLI_ghash_free(walker->visithash, NULL, NULL); +} + + +/* + * BMW_Step + * +*/ + +void *BMW_Step(BMWalker *walker) +{ + BMHeader *head; + + head = BMW_walk(walker); + + return head; +} + +/* + * BMW_WALK + * + * Steps a mesh walker forward by one element + * + * TODO: + * -add searchmask filtering + * +*/ + +static void *BMW_walk(BMWalker *walker) +{ + void *current = NULL; + + while(walker->currentstate){ + current = walker->step(walker); + if(current) return current; + } + return NULL; +} + +/* + * BMW_popstate + * + * Pops the current walker state off the stack + * and makes the previous state current + * +*/ + +static void BMW_popstate(BMWalker *walker) +{ + void *oldstate; + oldstate = walker->currentstate; + walker->currentstate + = ((bmesh_walkerGeneric*)walker->currentstate)->prev; + BLI_mempool_free(walker->stack, oldstate); +} + +/* + * BMW_pushstate + * + * Pushes the current state down the stack and allocates + * a new one. + * +*/ + +static void BMW_pushstate(BMWalker *walker) +{ + bmesh_walkerGeneric *newstate; + newstate = BLI_mempool_alloc(walker->stack); + newstate->prev = walker->currentstate; + walker->currentstate = newstate; +} + +void BMW_reset(BMWalker *walker) { + while (walker->currentstate) { + BMW_popstate(walker); + } +} + +/* Shell Walker: + * + * Starts at a vertex on the mesh and walks over the 'shell' it belongs + * to via visiting connected edges. + * + * TODO: + * + * Add restriction flag/callback for wire edges. + * +*/ + +static void shellWalker_begin(BMWalker *walker, void *data){ + BMVert *v = data; + shellWalker *shellWalk = NULL; + + BMW_pushstate(walker); + + shellWalk = walker->currentstate; + shellWalk->base = NULL; + shellWalk->curedge = NULL; + + if(v->edge){ + shellWalk->base = v; + shellWalk->curedge = v->edge; + } +} +static void *shellWalker_yield(BMWalker *walker) +{ + shellWalker *shellWalk = walker->currentstate; + return shellWalk->curedge; +} + +static void *shellWalker_step(BMWalker *walker) +{ + BMEdge *curedge, *next = NULL; + BMVert *ov = NULL; + int restrictpass = 1; + shellWalker *shellWalk = walker->currentstate; + + if (!BLI_ghash_lookup(walker->visithash, shellWalk->base)) + BLI_ghash_insert(walker->visithash, shellWalk->base, NULL); + + /*find the next edge whose other vertex has not been visited*/ + curedge = shellWalk->curedge; + do{ + if (!BLI_ghash_lookup(walker->visithash, curedge)) { + BLI_ghash_insert(walker->visithash, curedge, NULL); + if(walker->restrictflag && + (!BMO_TestFlag(walker->bm, curedge, walker->restrictflag))) + { + restrictpass = 0; + } + if(restrictpass) { + ov = BM_OtherEdgeVert(curedge, shellWalk->base); + + /*save current state*/ + shellWalk->curedge = curedge; + + /*push a new state onto the stack*/ + BMW_pushstate(walker); + + /*populate the new state*/ + ((shellWalker*)walker->currentstate)->base = ov; + ((shellWalker*)walker->currentstate)->curedge = curedge; + /*break out of loop*/ + + next = curedge; + break; + } + } + curedge = bmesh_disk_nextedge(curedge, shellWalk->base); + }while(curedge != shellWalk->curedge); + + shellWalk->current = next; + return next; +} + +/* Island Boundary Walker: + * + * Starts at a edge on the mesh and walks over the boundary of an + * island it belongs to. + * + * TODO: + * + * Add restriction flag/callback for wire edges. + * +*/ + +static void islandboundWalker_begin(BMWalker *walker, void *data){ + BMLoop *l = data; + islandboundWalker *iwalk = NULL; + + BMW_pushstate(walker); + + iwalk = walker->currentstate; + + iwalk->base = iwalk->curloop = l; + iwalk->lastv = l->v; + + BLI_ghash_insert(walker->visithash, data, NULL); + +} + +static void *islandboundWalker_yield(BMWalker *walker) +{ + islandboundWalker *iwalk = walker->currentstate; + + return iwalk->curloop; +} + +static void *islandboundWalker_step(BMWalker *walker) +{ + islandboundWalker *iwalk = walker->currentstate, owalk; + BMVert *v; + BMEdge *e = iwalk->curloop->e; + BMFace *f; + BMLoop *l = iwalk->curloop; + int found=0; + + owalk = *iwalk; + + if (iwalk->lastv == e->v1) v = e->v2; + else v = e->v1; + + if (BM_Nonmanifold_Vert(walker->bm, v)) { + BMW_reset(walker); + BMO_RaiseError(walker->bm, NULL,BMERR_WALKER_FAILED, + "Non-manifold vert" + " while searching region boundary"); + return NULL; + } + + /*pop off current state*/ + BMW_popstate(walker); + + f = l->f; + + while (1) { + l = BM_OtherFaceLoop(e, f, v); + if (bmesh_radial_nextloop(l) != l) { + l = bmesh_radial_nextloop(l); + f = l->f; + e = l->e; + if(!BMO_TestFlag(walker->bm, f, walker->restrictflag)){ + l = l->radial.next->data; + break; + } + } else { + f = l->f; + e = l->e; + break; + } + } + + if (l == owalk.curloop) return NULL; + if (BLI_ghash_haskey(walker->visithash, l)) return owalk.curloop; + + BLI_ghash_insert(walker->visithash, l, NULL); + BMW_pushstate(walker); + iwalk = walker->currentstate; + iwalk->base = owalk.base; + + //if (!BMO_TestFlag(walker->bm, l->f, walker->restrictflag)) + // iwalk->curloop = l->radial.next->data; + iwalk->curloop = l; //else iwalk->curloop = l; + iwalk->lastv = v; + + return owalk.curloop; +} + + +/* Island Walker: + * + * Starts at a tool flagged-face and walks over the face region + * + * TODO: + * + * Add restriction flag/callback for wire edges. + * +*/ + +static void islandWalker_begin(BMWalker *walker, void *data){ + islandWalker *iwalk = NULL; + + BMW_pushstate(walker); + + iwalk = walker->currentstate; + BLI_ghash_insert(walker->visithash, data, NULL); + + iwalk->cur = data; +} + +static void *islandWalker_yield(BMWalker *walker) +{ + islandWalker *iwalk = walker->currentstate; + + return iwalk->cur; +} + +static void *islandWalker_step(BMWalker *walker) +{ + islandWalker *iwalk = walker->currentstate, *owalk; + BMIter iter, liter; + BMFace *f, *curf = iwalk->cur; + BMLoop *l; + owalk = iwalk; + + BMW_popstate(walker); + + l = BMIter_New(&liter, walker->bm, BM_LOOPS_OF_FACE, iwalk->cur); + for (; l; l=BMIter_Step(&liter)) { + f = BMIter_New(&iter, walker->bm, BM_FACES_OF_EDGE, l->e); + for (; f; f=BMIter_Step(&iter)) { + if (!BMO_TestFlag(walker->bm, f, walker->restrictflag)) + continue; + if (BLI_ghash_haskey(walker->visithash, f)) continue; + + BMW_pushstate(walker); + iwalk = walker->currentstate; + iwalk->cur = f; + BLI_ghash_insert(walker->visithash, f, NULL); + break; + + } + } + + return curf; +} + + +/* Island Walker: + * + * Starts at a tool flagged-face and walks over the face region + * + * TODO: + * + * Add restriction flag/callback for wire edges. + * +*/ + +static void loopWalker_begin(BMWalker *walker, void *data){ + loopWalker *lwalk = NULL, owalk; + BMEdge *e = data; + BMVert *v; + int found=1, val; + + v = e->v1; + + val = BM_Vert_EdgeCount(v); + + BMW_pushstate(walker); + + lwalk = walker->currentstate; + BLI_ghash_insert(walker->visithash, e, NULL); + + lwalk->cur = lwalk->start = e; + lwalk->lastv = lwalk->startv = v; + lwalk->stage2 = 0; + lwalk->startrad = BM_Edge_FaceCount(e); + + /*rewind*/ + while (walker->currentstate) { + owalk = *((loopWalker*)walker->currentstate); + BMW_walk(walker); + } + + BMW_pushstate(walker); + lwalk = walker->currentstate; + *lwalk = owalk; + + if (lwalk->lastv == owalk.cur->v1) lwalk->lastv = owalk.cur->v2; + else lwalk->lastv = owalk.cur->v1; + + lwalk->startv = lwalk->lastv; + + BLI_ghash_free(walker->visithash, NULL, NULL); + walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + BLI_ghash_insert(walker->visithash, owalk.cur, NULL); +} + +static void *loopWalker_yield(BMWalker *walker) +{ + loopWalker *lwalk = walker->currentstate; + + return lwalk->cur; +} + +static void *loopWalker_step(BMWalker *walker) +{ + loopWalker *lwalk = walker->currentstate, owalk; + BMEdge *e = lwalk->cur, *nexte = NULL; + BMLoop *l, *l2; + BMVert *v; + int val, rlen, found=0, i=0, stopi; + + owalk = *lwalk; + + if (e->v1 == lwalk->lastv) v = e->v2; + else v = e->v1; + + val = BM_Vert_EdgeCount(v); + + BMW_popstate(walker); + + rlen = owalk.startrad; + l = e->loop; + + if (val == 4 || val == 2 || rlen == 1) { + i = 0; + stopi = val / 2; + while (1) { + if (rlen != 1 && i == stopi) break; + + l = BM_OtherFaceLoop(l->e, l->f, v); + l2 = bmesh_radial_nextloop(l); + + if (l2 == l) { + break; + } + + l = l2; + + i += 1; + } + } + + if (l != e->loop && !BLI_ghash_haskey(walker->visithash, l->e)) { + if (!(rlen != 1 && i != stopi)) { + BMW_pushstate(walker); + lwalk = walker->currentstate; + *lwalk = owalk; + lwalk->cur = l->e; + lwalk->lastv = v; + BLI_ghash_insert(walker->visithash, l->e, NULL); + } + } + + return owalk.cur; +} + +static void faceloopWalker_begin(BMWalker *walker, void *data) +{ + faceloopWalker *lwalk, owalk; + BMEdge *e = data; + + BMW_pushstate(walker); + + if (!e->loop) return; + + lwalk = walker->currentstate; + lwalk->l = e->loop; + BLI_ghash_insert(walker->visithash, lwalk->l->f, NULL); + + /*rewind*/ + while (walker->currentstate) { + owalk = *((faceloopWalker*)walker->currentstate); + BMW_walk(walker); + } + + BMW_pushstate(walker); + lwalk = walker->currentstate; + *lwalk = owalk; + + BLI_ghash_free(walker->visithash, NULL, NULL); + walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + BLI_ghash_insert(walker->visithash, lwalk->l->f, NULL); +} + +static void *faceloopWalker_yield(BMWalker *walker) +{ + faceloopWalker *lwalk = walker->currentstate; + + if (!lwalk) return NULL; + + return lwalk->l->f; +} + +static void *faceloopWalker_step(BMWalker *walker) +{ + faceloopWalker *lwalk = walker->currentstate; + BMFace *f = lwalk->l->f; + BMLoop *l = lwalk->l; + + BMW_popstate(walker); + + l = l->head.next->next; + if (l == l->radial.next->data) { + l = l->head.prev->prev; + } + l = l->radial.next->data; + + if (l->f->len == 4 && !BLI_ghash_haskey(walker->visithash, l->f)) { + BMW_pushstate(walker); + lwalk = walker->currentstate; + lwalk->l = l; + + BLI_ghash_insert(walker->visithash, l->f, NULL); + } + + return f; +} + diff --git a/source/blender/bmesh/intern/editmesh_to_bmesh.c b/source/blender/bmesh/intern/editmesh_to_bmesh.c new file mode 100644 index 00000000000..81e3572dec6 --- /dev/null +++ b/source/blender/bmesh/intern/editmesh_to_bmesh.c @@ -0,0 +1,473 @@ + +#include "MEM_guardedalloc.h" +#include "BKE_customdata.h" +#include "DNA_listBase.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include <string.h> +#include "BKE_utildefines.h" +#include "BKE_mesh.h" +#include "BKE_global.h" +#include "BKE_DerivedMesh.h" +#include "BKE_cdderivedmesh.h" + +#include "BLI_editVert.h" +#include "mesh_intern.h" +#include "ED_mesh.h" + +#include "BLI_blenlib.h" +#include "BLI_edgehash.h" + +#include "bmesh.h" + +/* + * EDITMESH TO BMESH.C + * + * This file contains functions + * for converting an editmesh + * into a Bmesh + * +*/ + +/* + * EDITMESH CORNERS TO LOOPS + * + * Converts editmesh face corner data + * (UVs, Vert colors, ect) to N-Gon + * face-edge ('loop') data. + * +*/ + +static void editmesh_corners_to_loops(BMesh *bm, CustomData *facedata, void *face_block, BMFace *f,int numCol, int numTex){ + int i, j; + BMLoop *l; + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + BMIter iter; + + for(i=0; i < numTex; i++){ + texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i); + texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i); + + texpoly->tpage = texface->tpage; + texpoly->flag = texface->flag; + texpoly->transp = texface->transp; + texpoly->mode = texface->mode; + texpoly->tile = texface->tile; + texpoly->unwrap = texface->unwrap; + + for (j=0, l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); l; j++, l=BMIter_Step(&iter)) { + mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i); + mloopuv->uv[0] = texface->uv[j][0]; + mloopuv->uv[1] = texface->uv[j][1]; + } + + } + for(i=0; i < numCol; i++){ + mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i); + for (j=0, l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); l; j++, l=BMIter_Step(&iter)) { + mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i); + mloopcol->r = mcol[j].r; + mloopcol->g = mcol[j].g; + mloopcol->b = mcol[j].b; + mloopcol->a = mcol[j].a; + } + } +} + +/* + * EDITVERT TO BMVert + * + * Converts an editvert to + * a BMVert. + * +*/ + +static BMVert *editvert_to_BMVert(BMesh *bm, BMOperator *op, EditMesh *em, EditVert *eve) +{ + BMVert *v = NULL; + + v = BM_Make_Vert(bm, eve->co, NULL); + VECCOPY(v->no, eve->no); + + /*transfer flags*/ + v->head.flag = eve->h ? BM_HIDDEN : 0; + if(eve->f & SELECT) BM_Select_Vert(bm, v, 1); + v->bweight = eve->bweight; + + BMO_Insert_MapPointer(bm, op, "map", eve, v); + + /*Copy Custom Data*/ + CustomData_bmesh_copy_data(&em->vdata, &bm->vdata, eve->data, &v->head.data); + + return v; +} + +/* + * EDITEDGE TO BMEdge + * + * Converts an editedge to + * a BMEdge + * +*/ + +static void editedge_to_BMEdge_internal(BMesh *bm, BMOperator *op, EditMesh *em, BMEdge *e, EditEdge *eed) +{ + e->crease = eed->crease; + e->bweight = eed->bweight; + + BM_Select(bm, e, eed->f & SELECT); + e->head.flag |= eed->seam ? BM_SEAM : 0; + e->head.flag |= eed->h & 1 ? BM_HIDDEN : 0; + e->head.flag |= eed->h & EM_FGON ? BM_FGON : 0; + e->head.flag |= eed->sharp ? BM_SHARP : 0; + + CustomData_bmesh_copy_data(&em->edata, &bm->edata, eed->data, &e->head.data); + + BMO_Insert_MapPointer(bm, op, "map", eed, e); +} + +static BMEdge *editedge_to_BMEdge(BMesh *bm, BMOperator *op, EditMesh *em, EditEdge *eed) +{ + BMVert *v1 = NULL, *v2 = NULL; + BMEdge *e = NULL; + + v1 = eed->v1->tmp.p; + v2 = eed->v2->tmp.p; + + e = BM_Make_Edge(bm, v1, v2,NULL, 0); + + editedge_to_BMEdge_internal(bm, op, em, e, eed); + + return e; +} +/* + * EDITFACE TO BMFace + * + * Converts an editface to a BMFace. + * Note that this also convert per-face + * corner data as well. + * +*/ + +static BMFace *editface_to_BMFace(BMesh *bm, BMOperator *op, EditMesh *em, EditFace *efa, int numCol, int numTex) +{ + BMVert *v1 = NULL, *v2 = NULL; + BMFace *f = NULL; + BMEdge *edar[4]; + int len; + + edar[0] = BM_Make_Edge(bm, efa->v1->tmp.p, efa->v2->tmp.p, NULL, 1); + edar[1] = BM_Make_Edge(bm, efa->v2->tmp.p, efa->v3->tmp.p, NULL, 1); + if(efa->v4){ + edar[2] = BM_Make_Edge(bm, efa->v3->tmp.p, efa->v4->tmp.p, NULL, 1); + edar[3] = BM_Make_Edge(bm, efa->v4->tmp.p, efa->v1->tmp.p, NULL, 1); + }else{ + edar[2] = BM_Make_Edge(bm, efa->v3->tmp.p, efa->v1->tmp.p, NULL, 1); + } + + editedge_to_BMEdge_internal(bm, op, em, edar[0], efa->e1); + editedge_to_BMEdge_internal(bm, op, em, edar[1], efa->e2); + editedge_to_BMEdge_internal(bm, op, em, edar[2], efa->e3); + if(efa->v4) + editedge_to_BMEdge_internal(bm, op, em, edar[3], efa->e4); + + + if(efa->e1->fgoni) edar[0]->head.flag |= BM_FGON; + if(efa->e2->fgoni) edar[1]->head.flag |= BM_FGON; + if(efa->e3->fgoni) edar[2]->head.flag |= BM_FGON; + if(efa->v4 && efa->e4->fgoni) edar[3]->head.flag |= BM_FGON; + + if(efa->v4) len = 4; + else len = 3; + + /*find v1 and v2*/ + v1 = efa->v1->tmp.p; + v2 = efa->v2->tmp.p; + + f = BM_Make_Ngon(bm, v1, v2, edar, len, 0); + + VECCOPY(f->no, efa->n); + + BMO_Insert_MapPointer(bm, op, "map", efa, f); + + f->head.flag = 0; + f->mat_nr = efa->mat_nr; + if(efa->f & SELECT) BM_Select_Face(bm, f, 1); + if (efa->flag & ME_SMOOTH) f->head.flag |= BM_SMOOTH; + if(efa->h) f->head.flag |= BM_HIDDEN; + + if (efa == em->act_face) f->head.flag |= BM_ACTIVE; + + CustomData_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->head.data); + editmesh_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex); + + return f; +} + +/* + * BMESH FGONCONVERT + * + * This function and its associated structures + * /helpers (fgonsort, sortfgon, fuse_fgon) are + * used to convert f-gons to bmesh n-gons. This + * is accomplished by sorting a list of fgon faces + * such that faces that are part of the same fgon + * are next to each other. These faces are then + * converted as is into bmesh faces and + * fused togather. + * + * Note that currently, there is no support for + * holes in faces in the bmesh structure, so + * f-gons with holes will only partially convert. + * +*/ + +typedef struct fgonsort { + unsigned long x; + struct EditFace *efa; + struct BMFace *f; + int done; +}fgonsort; + +static int sortfgon(const void *v1, const void *v2) +{ + const struct fgonsort *x1=v1, *x2=v2; + + if( x1->x > x2->x ) return 1; + else if( x1->x < x2->x) return -1; + return 0; +} + +static void fuse_fgon(BMesh *bm, BMFace *f) +{ + BMFace *sf; + BMLoop *l; + int done, act=0; + + sf = f; + done = 0; + while(!done){ + done = 1; + l = sf->loopbase; + do{ + if(l->e->head.flag & BM_FGON) { + if (l->f->head.flag & BM_ACTIVE) act = BM_ACTIVE; + if (((BMLoop*)l->radial.next->data)->f->head.flag & BM_ACTIVE) act = BM_ACTIVE; + + sf = BM_Join_Faces(bm,l->f, ((BMLoop*)l->radial.next->data)->f, l->e); + if (!sf) { + //tesselation error + break; + } + + sf->head.flag |= act; + if(sf){ + done = 0; + break; + } else { /*we have to get out of here...*/ + return; + } + } + l = ((BMLoop*)(l->head.next)); + }while(l != sf->loopbase); + } +} + +static BM_fgonconvert(BMesh *bm, BMOperator *op, EditMesh *em, int numCol, int numTex) +{ + EditFace *efa; + BMFace *f; + BMIter iter; + struct fgonsort *sortblock, *sb, *sb1; + int a, b, amount=0; + + /* + for (efa=em->faces.first; efa; efa=efa->next) { + f = editface_to_BMFace(bm, em, efa, numCol, numTex); + } + + for (f=bm->polys.first; f; f=f->head.next) { + fuse_fgon(bm, f); + } + + return;*/ + + EM_fgon_flags(em); + + /*zero out efa->tmp, we store fgon index here*/ + for(efa = em->faces.first; efa; efa = efa->next){ + efa->tmp.l = 0; + amount++; + } + /*go through and give each editface an fgon index*/ + for(efa = em->faces.first; efa; efa = efa->next){ + if(efa->e1->fgoni) efa->tmp.l = efa->e1->fgoni; + else if(efa->e2->fgoni) efa->tmp.l = efa->e2->fgoni; + else if(efa->e3->fgoni) efa->tmp.l = efa->e3->fgoni; + else if(efa->e4 && efa->e4->fgoni) efa->tmp.l = efa->e4->fgoni; + } + + sb= sortblock= MEM_mallocN(sizeof(fgonsort)* amount,"fgon sort block"); + + for(efa = em->faces.first; efa; efa=efa->next){ + sb->x = efa->tmp.l; + sb->efa = efa; + sb->done = 0; + sb++; + } + + qsort(sortblock, amount, sizeof(fgonsort), sortfgon); + + sb = sortblock; + for(a=0; a<amount; a++, sb++) { + if(sb->x && sb->done == 0){ + /*first pass: add in faces for this fgon*/ + for(b=a, sb1 = sb; b<amount && sb1->x == sb->x; b++, sb1++){ + efa = sb1->efa; + sb1->f = editface_to_BMFace(bm, op, em, efa, numCol, numTex); + sb1->done = 1; + } + /*fuse fgon*/ + fuse_fgon(bm, sb->f); + } + } + MEM_freeN(sortblock); +} + +/* + * TAG WIRE EDGES + * + * Flags editedges 'f1' member + * if the edge has no faces. + * +*/ + +static void tag_wire_edges(EditMesh *em){ + EditFace *efa; + EditEdge *eed; + for(eed = em->edges.first; eed; eed = eed->next) eed->f1 = 1; + for(efa = em->faces.first; efa; efa = efa->next){ + efa->e1->f1 = 0; + efa->e2->f1 = 0; + efa->e3->f1 = 0; + if(efa->e4) efa->e4->f1 = 0; + } +} + +/* + * EDITMESH TO BMESH + * + * Function to convert an editmesh to a bmesh + * Currently all custom data as well as + * f-gons should be converted correctly. + * +*/ + +BMesh *editmesh_to_bmesh_intern(EditMesh *em, BMesh *bm, BMOperator *op) { + BMVert *v; + EditVert *eve; + EditEdge *eed; + EditFace *efa; + BMEdge *e; + BMIter iter; + int allocsize[4] = {512,512,2048,512}, numTex, numCol; + + /*make sure to update FGon flags*/ + EM_fgon_flags(em); + + /*copy custom data layout*/ + CustomData_copy(&em->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&em->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); + + /*copy face corner data*/ + CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata, 0, 0); + + CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]); + CustomData_bmesh_init_pool(&bm->edata, allocsize[1]); + CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]); + CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]); + + /*needed later*/ + numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); + + /*copy over selection mode*/ + bm->selectmode = 0; + if(em->selectmode & SCE_SELECT_VERTEX) bm->selectmode |= SCE_SELECT_VERTEX; + if(em->selectmode & SCE_SELECT_EDGE) bm->selectmode |= SCE_SELECT_EDGE; + if(em->selectmode & SCE_SELECT_FACE) bm->selectmode |= SCE_SELECT_FACE; + + + /*begin editloop*/ + //BM_Begin_Edit(bm); + + /*tag wire edges*/ + tag_wire_edges(em); + + /*add verts*/ + for(eve = em->verts.first; eve; eve = eve->next){ + v = editvert_to_BMVert(bm, op, em, eve); + eve->tmp.p = v; + } + /*convert f-gons*/ + BM_fgonconvert(bm, op, em, numCol, numTex); + + /*clean up any dangling fgon flags*/ + for (e=BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); e; e=BMIter_Step(&iter)){ + e->head.flag &= ~BM_FGON; + } + + /*do quads + triangles*/ + for(efa = em->faces.first; efa; efa = efa->next){ + if(!efa->tmp.l) editface_to_BMFace(bm, op, em, efa, numCol, numTex); + } + + /*add wire edges*/ + for(eed = em->edges.first; eed; eed = eed->next){ + if(eed->f1) editedge_to_BMEdge(bm, op, em, eed); + } + //BM_end_edit(bm, BM_CALC_NORM); + return bm; +} + +void edit2bmesh_exec(BMesh *bmesh, BMOperator *op) +{ + editmesh_to_bmesh_intern(BMO_Get_Pnt(op, "em"), bmesh, op); +} + +BMesh *editmesh_to_bmesh(EditMesh *em) +{ + BMOperator conv; + BMesh *bm; + int allocsize[4] = {512,512,2048,512}; + + /*allocate a bmesh*/ + bm = BM_Make_Mesh(allocsize); + + BMO_Init_Op(&conv, "editmesh_to_bmesh"); + BMO_Set_Pnt(&conv, "em", em); + BMO_Exec_Op(bm, &conv); + BMO_Finish_Op(bm, &conv); + + return bm; +} + +BMesh *init_editmesh_to_bmesh(EditMesh *em, BMOperator *op) +{ + BMesh *bm; + int allocsize[4] = {512,512,2048,512}, numTex, numCol; + + /*allocate a bmesh*/ + bm = BM_Make_Mesh(allocsize); + + BMO_Init_Op(op, "editmesh_to_bmesh"); + BMO_Set_Pnt(op, "em", em); + + return bm; +}
\ No newline at end of file diff --git a/source/blender/bmesh/intern/in-progress/BME_conversions.c b/source/blender/bmesh/intern/in-progress/BME_conversions.c new file mode 100644 index 00000000000..d39bf689e76 --- /dev/null +++ b/source/blender/bmesh/intern/in-progress/BME_conversions.c @@ -0,0 +1,478 @@ +/** + * BME_conversions.c August 2008 + * + * BM to Derived Mesh conversion functions. + * + * ***** 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. + * 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) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle, Levi Schooley. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" +#include "BKE_customdata.h" + +#include "DNA_listBase.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_utildefines.h" +#include "BKE_mesh.h" +#include "bmesh.h" +#include "BKE_global.h" +#include "BKE_DerivedMesh.h" +#include "BKE_cdderivedmesh.h" + +#include "BLI_blenlib.h" +#include "BLI_editVert.h" +#include "BLI_edgehash.h" +#include "bmesh_private.h" + + + +/* + * BMESH DERIVED MESH CONVERSION FUNCTIONS + * + * The functions in this file provides + * methods for converting to and from + * a bmesh. + * +*/ + + +/* + * DMCORNERS TO LOOPS + * + * Function to convert derived mesh per-face + * corner data (uvs, vertex colors), to n-gon + * per-loop data. + * +*/ + +static void DMcorners_to_loops(BMMesh *bm, CustomData *facedata, int index, BMFace *f, int numCol, int numTex){ + int i, j; + BMLoop *l; + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + + for(i=0; i< numTex; i++){ + texface = CustomData_get_layer_n(facedata, CD_MTFACE, i); + texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i); + + texpoly->tpage = texface[index].tpage; + texpoly->flag = texface[index].flag; + texpoly->transp = texface[index].transp; + texpoly->mode = texface[index].mode; + texpoly->tile = texface[index].tile; + texpoly->unwrap = texface[index].unwrap; + + j = 0; + l = f->loopbase; + do{ + mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i); + mloopuv->uv[0] = texface[index].uv[j][0]; + mloopuv->uv[1] = texface[index].uv[j][1]; + j++; + l = l->next; + }while(l!=f->loopbase); + } + + for(i=0; i < numCol; i++){ + mcol = CustomData_get_layer_n(facedata, CD_MCOL, i); + j = 0; + l = f->loopbase; + do{ + mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i); + mloopcol->r = mcol[(index*4)+j].r; + mloopcol->g = mcol[(index*4)+j].g; + mloopcol->b = mcol[(index*4)+j].b; + mloopcol->a = mcol[(index*4)+j].a; + j++; + l = l->next; + }while(l!=f->loopbase); + } +} + +/* + * LOOPS TO DMCORNERS + * + * Function to convert n-gon per-loop data + * (uvs, vertex colors, ect)to derived mesh + * face corner data. + * +*/ + +static void loops_to_DMcorners(BMMesh *bm, CustomData *facedata, int index, BMFace *f,int numCol, int numTex){ + int i, j; + BMLoop *l; + MTFace *texface; + MTexPoly *texpoly; + MCol *mcol; + MLoopCol *mloopcol; + MLoopUV *mloopuv; + + for(i=0; i < numTex; i++){ + texface = CustomData_get_layer_n(facedata, CD_MTFACE, i); + texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i); + + texface[index].tpage = texpoly->tpage; + texface[index].flag = texpoly->flag; + texface[index].transp = texpoly->transp; + texface[index].mode = texpoly->mode; + texface[index].tile = texpoly->tile; + texface[index].unwrap = texpoly->unwrap; + + j = 0; + l = f->loopbase; + do{ + mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i); + texface[index].uv[j][0] = mloopuv->uv[0]; + texface[index].uv[j][1] = mloopuv->uv[1]; + j++; + l = l->next; + }while(l!=f->loopbase); + + } + for(i=0; i < numCol; i++){ + mcol = CustomData_get_layer_n(facedata,CD_MCOL, i); + j = 0; + l = f->loopbase; + do{ + mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i); + mcol[(index*4) + j].r = mloopcol->r; + mcol[(index*4) + j].g = mloopcol->g; + mcol[(index*4) + j].b = mloopcol->b; + mcol[(index*4) + j].a = mloopcol->a; + j++; + l = l->next; + }while(l!=f->loopbase); + } +} + +/* + * MVERT TO BMESHVERT + * + * Converts a MVert to a BMVert + * +*/ +static BMVert *mvert_to_bmeshvert(BMMesh *bm, BMVert **vert_array, int index, MVert *mv, CustomData *data) +{ + BMVert *v = NULL; + + v = bmesh_make_vert(bm, mv->co, NULL); + vert_array[index] = v; + if(mv->flag & SELECT) bmesh_set_flag(v, BMESH_SELECT); + v->bweight = mv->bweight/255.0f; + CustomData_to_bmesh_block(data, &bm->vdata, index, &v->data); + + return v; +} + +/* + * MEDGE TO BMESHEDGE + * + * Converts a MEdge to a BMEdge + * +*/ + +static BMEdge *medge_to_bmeshedge(BMMesh *bm, BMVert **vert_array, int index, MEdge *me, CustomData *data, Edge_Hash *edge_hash) +{ + BMVert *v1, *v2; + BMEdge *e = NULL; + + v1 = vert_array[me->v1]; + v2 = vert_array[me->v2]; + e = bmesh_make_edge(bm, v1, v2, NULL, 0); + e->crease = me->crease/255.0f; + e->bweight = me->bweight/255.0f; + if(me->flag & 1) bmesh_set_flag(e, BMESH_SELECT); + if(me->flag & ME_SEAM) bmesh_set_flag(e, BMESH_SEAM); + BLI_edgehash_insert(edge_hash,me->v1,me->v2,e); + CustomData_to_bmesh_block(data, &bm->edata, index, &e->data); + + return e; +} + +/* + * MFACE TO BMESHFACE + * + * Converts a MFace to a BMFace. + * Note that this will fail on eekadoodle + * faces. + * +*/ + +static BMFace *mface_to_bmeshface(BMMesh *bm, BMVert **vert_array, int index, MFace *mf, CustomData *data, Edge_Hash *edge_hash) +{ + BMVert *v1, *v2; + BMEdge *edar[4]; + BMFace *f = NULL; + int len; + + if(mf->v4) len = 4; + else len = 3; + + edar[0] = BLI_edgehash_lookup(edge_hash,mf->v1,mf->v2); + edar[1] = BLI_edgehash_lookup(edge_hash,mf->v2,mf->v3); + if(len == 4){ + edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v4); + edar[3] = BLI_edgehash_lookup(edge_hash,mf->v4,mf->v1); + } + else + edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v1); + + /*find v1 and v2*/ + v1 = vert_array[mf->v1]; + v2 = vert_array[mf->v2]; + + f = bmesh_make_ngon(bm, v1, v2, edar, len, 0); + f->mat_nr = mf->mat_nr; + if(mf->flag & 1) bmesh_set_flag(f, BMESH_SELECT); + if(mf->flag & ME_HIDE) bmesh_set_flag(f, BMESH_HIDDEN); + CustomData_to_bmesh_block(data, &bm->pdata, index, &f->data); + + return f; +} + +/* + * DERIVEDMESH TO BMESH + * + * Converts a derived mesh to a bmesh. + * +*/ + +BMMesh *derivedmesh_to_bmesh(DerivedMesh *dm) +{ + + BMMesh *bm; + BMVert **vert_array; + BMFace *f=NULL; + + MVert *mvert, *mv; + MEdge *medge, *me; + MFace *mface, *mf; + + int totface,totedge,totvert,i,len, numTex, numCol; + int allocsize[4] = {512,512,2048,512}; + + EdgeHash *edge_hash = BLI_edgehash_new(); + + /*allocate a new bmesh*/ + bm = bmesh_make_mesh(allocsize); + + /*copy custom data layout*/ + CustomData_copy(&dm->vertData, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&dm->edgeData, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0); + + /*copy face corner data*/ + CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata); + /*initialize memory pools*/ + CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]); + CustomData_bmesh_init_pool(&bm->edata, allocsize[1]); + CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]); + CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]); + + /*needed later*/ + numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); + + totvert = dm->getNumVerts(dm); + totedge = dm->getNumEdges(dm); + totface = dm->getNumFaces(dm); + mvert = dm->getVertArray(dm); + medge = dm->getEdgeArray(dm); + mface = dm->getFaceArray(dm); + + vert_array = MEM_mallocN(sizeof(BMVert *)* totvert,"derivedmesh to bmesh vertex pointer array"); + + bmesh_begin_edit(bm); + /*add verts*/ + for(i=0, mv = mvert; i < totvert; i++, mv++) + mvert_to_bmeshvert(bm, vert_array, i, mv, &dm->vertData); + + /*add edges*/ + for(i=0, me = medge; i < totedge; i++, me++) + medge_to_bmeshedge(bm, vert_array, i, me, &dm->edgeData, edge_hash); + + /*add faces.*/ + for(i=0, mf = mface; i < totface; i++, mf++){ + f = mface_to_bmeshface(bm, vert_array, mf, &dm->faceData, edge_hash); + if(f) DMcorners_to_loops(bm, &dm->faceData, i, f, numCol, numTex); + } + + bmesh_end__edit(bm); + BLI_edgehash_free(edge_hash, NULL); + MEM_freeN(vert_array); + return bm; +} + +static void bmeshvert_to_mvert(BMMesh *bm, BMVert *v, MVert *mv, int index, CustomData *data) +{ + VECCOPY(mv->co,v->co); + if(bmesh_test_flag(v, BMESH_SELECT)) mv->flag |= 1; + if(bmesh_test_flag(v, BMESH_HIDDEN)) mv->flag |= ME_HIDE; + mv->bweight = (char)(255.0*v1->bweight); + CustomData_from_bmesh_block(&bm->vdata, data, &v1->data, index); +} + +static int bmeshedge_to_medge(BMMesh *bm, BMEdge *e, MEdge *me, int index, CustomData *data) +{ + if(e->head.eflag2){ + if(e->v1->head.eflag1 < e->v2->head.eflag1){ + me->v1 = e->v1->head.eflag1; + me->v2 = e->v2->head.eflag1; + } + else{ + me->v1 = e->v2->head.eflag1; + me->v2 = e->v1->eflag1; + } + + me->crease = (char)(255.0*e->crease); + me->bweight = (char)(255.0*e->bweight); + if(bmesh_test_flag(e, BMESH_SELECT)) me->flag |= 1; + if(bmesh_test_flag(e, BMESH_HIDDEN)) me->flag |= ME_HIDE; + CustomData_from_bmesh_block(&bm->edata, data, &e->data, index); + return 1; + } + return 0; +} + +static int bmeshface_to_mface(BMMesh *bm, BMFace *f, MFace *mf, int index, CustomData *data) +{ + if(f->len==3 || f->len==4){ + mf->v1 = f->loopbase->v->head.eflag1; + mf->v2 = f->loopbase->next->v->head.eflag1; + mf->v3 = f->loopbase->next->next->v->head.eflag1; + if(len == 4){ + mf->v4 = f->loopbase->prev->v->head.eflag1; + } + /* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */ + if(mf->v3 == 0 || (f->len == 4 && mf->v4 == 0)){ + test_index_face(mf, NULL, index, f->len); + } + mf->mat_nr = (unsigned char)f->mat_nr; + if(bmesh_test_flag(f, BMESH_SELECT)) mf->flag |= 1; + if(bmesh_test_flag(f, BMESH_HIDDEN)) mf->flag |= ME_HIDE; + CustomData_from_bmesh_block(&bm->pdata, data, &f->data, index); + return 1; + } + return 0; +} + +/* + * BMESH TO DERIVEDMESH + * + * Converts a bmesh to a derived mesh. + * +*/ + +DerivedMesh *bmesh_to_derivedmesh(BMMesh *bm, DerivedMesh *dm) +{ + MFace *mface = NULL, *mf = NULL; + MEdge *medge = NULL, *me = NULL; + MVert *mvert = NULL, *mv = NULL; + DerivedMesh *result = NULL; + + BMVert *v=NULL; + BMEdge *e=NULL, *oe=NULL; + BMFace *f=NULL; + + BMIter verts; + BMIter edges; + BMIter faces; + + int totface = 0,totedge = 0,totvert = 0,i = 0, numTex, numCol; + + EdgeHash *edge_hash = BLI_edgehash_new(); + + /*get element counts*/ + totvert = bmesh_count_element(bm, BMESH_VERT); + + /*store element indices. Note that the abuse of eflag here should NOT be duplicated!*/ + for(i=0, v = bmeshIterator_init(verts, BM_VERTS, bm, 0); v; v = bmeshIterator_step(verts), i++) + v->head.eflag1 = i; + + /*we cannot have double edges in a derived mesh!*/ + for(e = bmeshIterator_init(edges, BM_EDGES, bm, 0); e; e = bmeshIterator_step(edges)){ + oe = BLI_edgehash_lookup(edge_hash,e->v1->head.eflag1, e->v2->head.eflag1); + if(!oe){ + totedge++; + BLI_edgehash_insert(edge_hash,e->v1->head.eflag1,e->v2->head.eflag1,e); + e->head.eflag2 = 1; + } + else{ + e->head.eflag2 = 0; + } + } + + /*count quads and tris*/ + for(f = bmeshIterator_init(faces, BM_FACES, bm, 0); f; f = bmeshIterator_step(faces)){ + if(f->len == 3 || f->len == 4) totface++; + } + + /*Allocate derivedmesh and copy custom data*/ + result = CDDM_from_template(dm,totvert,totedge,totface); + CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert); + CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge); + CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface); + CustomData_from_bmeshpoly(&result->faceData, &bm->pdata, &bm->ldata,totface); + numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); + numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL); + + /*Make Verts*/ + mvert = CDDM_get_verts(result); + for(i = 0, v = bmeshIterator_init(verts, BM_VERTS, bm, 0); v; v = bmeshIterator_step(verts), i++, mv++){ + bmeshvert_to_mvert(bm,v,mv,i,&result->vertData); + } + + /*Make Edges*/ + medge = CDDM_get_edges(result); + i=0; + for(e = bmeshIterator_init(edges, BM_EDGES, bm, 0); e; e = bmeshIterator_step(edges)){ + me = &medge[i]; + if(bmeshedge_to_medge(bm, e, me, i, &result->edgeData){ + me++; + i++; + } + } + /*Make Faces*/ + if(totface){ + mface = CDDM_get_faces(result); + i=0; + for(f = bmeshIterator_init(faces, BM_FACES, bm, 0); f; f = bmeshIterator_step(faces)){ + mf = &mface[i]; + if(bmeshface_to_mface(bm, f, mf, i, &result->faceData)){ + loops_to_DMcorners(bm, &result->faceData, i, f, numCol, numTex); + i++; + } + } + } + BLI_edgehash_free(edge_hash, NULL); + return result; +} diff --git a/source/blender/bmesh/operators/bmesh_dupeops.c b/source/blender/bmesh/operators/bmesh_dupeops.c new file mode 100644 index 00000000000..b5c327bc24c --- /dev/null +++ b/source/blender/bmesh/operators/bmesh_dupeops.c @@ -0,0 +1,570 @@ +#include "MEM_guardedalloc.h" + +#include "BKE_utildefines.h" + +#include "BLI_ghash.h" +#include "BLI_memarena.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "bmesh.h" +#include "bmesh_operators_private.h" + +/*local flag defines*/ +#define DUPE_INPUT 1 /*input from operator*/ +#define DUPE_NEW 2 +#define DUPE_DONE 4 +#define DUPE_MAPPED 8 + +/* + * COPY VERTEX + * + * Copy an existing vertex from one bmesh to another. + * +*/ +static BMVert *copy_vertex(BMesh *source_mesh, BMVert *source_vertex, BMesh *target_mesh, GHash *vhash) +{ + BMVert *target_vertex = NULL; + + /*Create a new vertex*/ + target_vertex = BM_Make_Vert(target_mesh, source_vertex->co, NULL); + + /*Insert new vertex into the vert hash*/ + BLI_ghash_insert(vhash, source_vertex, target_vertex); + + /*Copy attributes*/ + BM_Copy_Attributes(source_mesh, target_mesh, source_vertex, target_vertex); + + /*Set internal op flags*/ + BMO_SetFlag(target_mesh, (BMHeader*)target_vertex, DUPE_NEW); + + return target_vertex; +} + +/* + * COPY EDGE + * + * Copy an existing edge from one bmesh to another. + * +*/ +static BMEdge *copy_edge(BMOperator *op, BMesh *source_mesh, + BMEdge *source_edge, BMesh *target_mesh, + GHash *vhash, GHash *ehash) +{ + BMEdge *target_edge = NULL; + BMVert *target_vert1, *target_vert2; + BMFace *face; + BMIter fiter; + int rlen; + + /*see if any of the neighboring faces are + not being duplicated. in that case, + add it to the new/old map.*/ + rlen = 0; + for (face=BMIter_New(&fiter,source_mesh, BM_FACES_OF_EDGE,source_edge); + face; face=BMIter_Step(&fiter)) { + if (BMO_TestFlag(source_mesh, face, DUPE_INPUT)) { + rlen++; + } + } + + /*Lookup v1 and v2*/ + target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1); + target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2); + + /*Create a new edge*/ + target_edge = BM_Make_Edge(target_mesh, target_vert1, target_vert2, NULL, 0); + + /*add to new/old edge map if necassary*/ + if (rlen < 2) { + /*not sure what non-manifold cases of greater then three + radial should do.*/ + BMO_Insert_MapPointer(source_mesh,op, "boundarymap", + source_edge, target_edge); + } + + /*Insert new edge into the edge hash*/ + BLI_ghash_insert(ehash, source_edge, target_edge); + + /*Copy attributes*/ + BM_Copy_Attributes(source_mesh, target_mesh, source_edge, target_edge); + + /*Set internal op flags*/ + BMO_SetFlag(target_mesh, (BMHeader*)target_edge, DUPE_NEW); + + return target_edge; +} + +/* + * COPY FACE + * + * Copy an existing face from one bmesh to another. + * +*/ +static BMFace *copy_face(BMOperator *op, BMesh *source_mesh, + BMFace *source_face, BMesh *target_mesh, + BMEdge **edar, GHash *vhash, GHash *ehash) +{ + BMVert *target_vert1, *target_vert2; + BMLoop *source_loop, *target_loop; + BMFace *target_face = NULL; + BMIter iter, iter2; + int i; + + /*lookup the first and second verts*/ + target_vert1 = BLI_ghash_lookup(vhash, BMIter_New(&iter, source_mesh, BM_VERTS_OF_FACE, source_face)); + target_vert2 = BLI_ghash_lookup(vhash, BMIter_Step(&iter)); + + /*lookup edges*/ + for (i=0,source_loop=BMIter_New(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face); + source_loop; source_loop=BMIter_Step(&iter), i++) { + edar[i] = BLI_ghash_lookup(ehash, source_loop->e); + } + + /*create new face*/ + target_face = BM_Make_Ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0); + BMO_Insert_MapPointer(source_mesh, op, + "facemap", source_face, target_face); + BMO_Insert_MapPointer(source_mesh, op, + "facemap", target_face, source_face); + + BM_Copy_Attributes(source_mesh, target_mesh, source_face, target_face); + + /*mark the face for output*/ + BMO_SetFlag(target_mesh, (BMHeader*)target_face, DUPE_NEW); + + /*copy per-loop custom data*/ + for (i=0,source_loop=BMIter_New(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face), + target_loop=BMIter_New(&iter2, target_mesh, BM_LOOPS_OF_FACE, target_face); + source_loop && target_loop; source_loop=BMIter_Step(&iter), target_loop=BMIter_Step(&iter2), + i++) { + BM_Copy_Attributes(source_mesh, target_mesh, source_loop, target_loop); + } + + + return target_face; +} + /* + * COPY MESH + * + * Internal Copy function. +*/ + +static void copy_mesh(BMOperator *op, BMesh *source, BMesh *target) +{ + + BMVert *v = NULL, *v2; + BMEdge *e = NULL, **edar = NULL; + BMLoop *l = NULL; + BMFace *f = NULL; + + BMIter verts; + BMIter edges; + BMIter faces; + + GHash *vhash; + GHash *ehash; + + int maxlength = 0; + + /*initialize pointer hashes*/ + vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + /*initialize edge pointer array*/ + for(f = BMIter_New(&faces, source, BM_FACES_OF_MESH, source); f; f = BMIter_Step(&faces)){ + if(f->len > maxlength) maxlength = f->len; + } + edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array"); + + for(v = BMIter_New(&verts, source, BM_VERTS_OF_MESH, source); v; v = BMIter_Step(&verts)){ + if(BMO_TestFlag(source, (BMHeader*)v, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE))){ + BMIter iter; + int iso = 1; + + v2 = copy_vertex(source, v, target, vhash); + + BM_ITER(f, &iter, source, BM_FACES_OF_VERT, v) { + if (BMO_TestFlag(source, f, DUPE_INPUT)) { + iso = 0; + break; + } + } + + if (iso) { + BM_ITER(e, &iter, source, BM_EDGES_OF_VERT, v) { + if (BMO_TestFlag(source, e, DUPE_INPUT)) { + iso = 0; + break; + } + } + } + + if (iso) + BMO_Insert_MapPointer(source, op, "isovertmap", v, v2); + + BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE); + } + } + + /*now we dupe all the edges*/ + for(e = BMIter_New(&edges, source, BM_EDGES_OF_MESH, source); e; e = BMIter_Step(&edges)){ + if(BMO_TestFlag(source, (BMHeader*)e, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE))){ + /*make sure that verts are copied*/ + if(!BMO_TestFlag(source, (BMHeader*)e->v1, DUPE_DONE)) { + copy_vertex(source, e->v1, target, vhash); + BMO_SetFlag(source, (BMHeader*)e->v1, DUPE_DONE); + } + if(!BMO_TestFlag(source, (BMHeader*)e->v2, DUPE_DONE)) { + copy_vertex(source, e->v2, target, vhash); + BMO_SetFlag(source, (BMHeader*)e->v2, DUPE_DONE); + } + /*now copy the actual edge*/ + copy_edge(op, source, e, target, vhash, ehash); + BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE); + } + } + + /*first we dupe all flagged faces and their elements from source*/ + for(f = BMIter_New(&faces, source, BM_FACES_OF_MESH, source); f; f= BMIter_Step(&faces)){ + if(BMO_TestFlag(source, (BMHeader*)f, DUPE_INPUT)){ + /*vertex pass*/ + for(v = BMIter_New(&verts, source, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts)){ + if(!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE)){ + copy_vertex(source,v, target, vhash); + BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE); + } + } + + /*edge pass*/ + for(e = BMIter_New(&edges, source, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges)){ + if(!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE)){ + copy_edge(op, source, e, target, vhash, ehash); + BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE); + } + } + copy_face(op, source, f, target, edar, vhash, ehash); + BMO_SetFlag(source, (BMHeader*)f, DUPE_DONE); + } + } + + /*free pointer hashes*/ + BLI_ghash_free(vhash, NULL, NULL); + BLI_ghash_free(ehash, NULL, NULL); + + /*free edge pointer array*/ + if(edar) + MEM_freeN(edar); +} + +/* +BMesh *bmesh_make_mesh_from_mesh(BMesh *bm, int allocsize[4]) +{ + BMesh *target = NULL; + target = bmesh_make_mesh(allocsize); + + + CustomData_copy(&bm->vdata, &target->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->edata, &target->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->ldata, &target->ldata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->pdata, &target->pdata, CD_MASK_BMESH, CD_CALLOC, 0); + + + CustomData_bmesh_init_pool(&target->vdata, allocsize[0]); + CustomData_bmesh_init_pool(&target->edata, allocsize[1]); + CustomData_bmesh_init_pool(&target->ldata, allocsize[2]); + CustomData_bmesh_init_pool(&target->pdata, allocsize[3]); + + bmesh_begin_edit(bm); + bmesh_begin_edit(target); + + bmesh_copy_mesh(bm, target, 0); + + bmesh_end_edit(bm); + bmesh_end_edit(target); + + return target; + +} +*/ + +/* + * Duplicate Operator + * + * Duplicates verts, edges and faces of a mesh. + * + * INPUT SLOTS: + * + * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be duplicated + * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be duplicated + * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be duplicated + * + * OUTPUT SLOTS: + * + * BMOP_DUPE_VORIGINAL: Buffer containing pointers to the original mesh vertices + * BMOP_DUPE_EORIGINAL: Buffer containing pointers to the original mesh edges + * BMOP_DUPE_FORIGINAL: Buffer containing pointers to the original mesh faces + * BMOP_DUPE_VNEW: Buffer containing pointers to the new mesh vertices + * BMOP_DUPE_ENEW: Buffer containing pointers to the new mesh edges + * BMOP_DUPE_FNEW: Buffer containing pointers to the new mesh faces + * +*/ + +void dupeop_exec(BMesh *bm, BMOperator *op) +{ + BMOperator *dupeop = op; + + /*flag input*/ + BMO_Flag_Buffer(bm, dupeop, "geom", DUPE_INPUT); + /*use the internal copy function*/ + copy_mesh(dupeop, bm, bm); + + /*Output*/ + /*First copy the input buffers to output buffers - original data*/ + BMO_CopySlot(dupeop, dupeop, "geom", "origout"); + + /*Now alloc the new output buffers*/ + BMO_Flag_To_Slot(bm, dupeop, "newout", DUPE_NEW, BM_ALL); +} + +/*executes the duplicate operation, feeding elements of + type flag etypeflag and header flag flag to it. note, + to get more useful information (such as the mapping from + original to new elements) you should run the dupe op manually.*/ +void BMOP_DupeFromFlag(BMesh *bm, int etypeflag, int flag) +{ + BMOperator dupeop; + + BMO_Init_Op(&dupeop, "dupe"); + BMO_HeaderFlag_To_Slot(bm, &dupeop, "geom", flag, etypeflag); + + BMO_Exec_Op(bm, &dupeop); + BMO_Finish_Op(bm, &dupeop); +} + +/* + * Split Operator + * + * Duplicates verts, edges and faces of a mesh but also deletes the originals. + * + * INPUT SLOTS: + * + * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be split + * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be split + * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be split + * + * OUTPUT SLOTS: + * + * BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices + * BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges + * BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces + * +*/ + +#define SPLIT_INPUT 1 +void splitop_exec(BMesh *bm, BMOperator *op) +{ + BMOperator *splitop = op; + BMOperator dupeop; + BMOperator delop; + BMVert *v; + BMEdge *e; + BMFace *f; + BMIter iter, iter2; + int found; + + /*initialize our sub-operators*/ + BMO_Init_Op(&dupeop, "dupe"); + BMO_Init_Op(&delop, "del"); + + BMO_CopySlot(splitop, &dupeop, "geom", "geom"); + BMO_Exec_Op(bm, &dupeop); + + BMO_Flag_Buffer(bm, splitop, "geom", SPLIT_INPUT); + + /*make sure to remove edges and verts we don't need.*/ + for (e= BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);e;e=BMIter_Step(&iter)) { + found = 0; + f = BMIter_New(&iter2, bm, BM_FACES_OF_EDGE, e); + for (; f; f=BMIter_Step(&iter2)) { + if (!BMO_TestFlag(bm, f, SPLIT_INPUT)) { + found = 1; + break; + } + } + if (!found) BMO_SetFlag(bm, e, SPLIT_INPUT); + } + + for (v= BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);v;v=BMIter_Step(&iter)) { + found = 0; + e = BMIter_New(&iter2, bm, BM_EDGES_OF_VERT, v); + for (; e; e=BMIter_Step(&iter2)) { + if (!BMO_TestFlag(bm, e, SPLIT_INPUT)) { + found = 1; + break; + } + } + if (!found) BMO_SetFlag(bm, v, SPLIT_INPUT); + + } + + /*connect outputs of dupe to delete, exluding keep geometry*/ + BMO_Set_Int(&delop, "context", DEL_FACES); + BMO_Flag_To_Slot(bm, &delop, "geom", SPLIT_INPUT, BM_ALL); + + BMO_Exec_Op(bm, &delop); + + /*now we make our outputs by copying the dupe outputs*/ + BMO_CopySlot(&dupeop, splitop, "newout", "geom"); + BMO_CopySlot(&dupeop, splitop, "boundarymap", + "boundarymap"); + BMO_CopySlot(&dupeop, splitop, "isovertmap", + "isovertmap"); + + /*cleanup*/ + BMO_Finish_Op(bm, &delop); + BMO_Finish_Op(bm, &dupeop); +} + +#define DEL_INPUT 1 +#define DEL_WIREVERT 2 + +static void delete_verts(BMesh *bm); +static void delete_context(BMesh *bm, int type); + +void delop_exec(BMesh *bm, BMOperator *op) +{ + BMOperator *delop = op; + + /*Mark Buffers*/ + BMO_Flag_Buffer(bm, delop, "geom", DEL_INPUT); + + delete_context(bm, BMO_Get_Int(op, "context")); +} + +static void delete_verts(BMesh *bm) +{ + BMVert *v; + BMEdge *e; + BMLoop *f; + + BMIter verts; + BMIter edges; + BMIter faces; + + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){ + if(BMO_TestFlag(bm, (BMHeader*)v, DEL_INPUT)) { + /*Visit edges*/ + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_VERT, v); e; e = BMIter_Step(&edges)) + BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT); + /*Visit faces*/ + for(f = BMIter_New(&faces, bm, BM_FACES_OF_VERT, v); f; f = BMIter_Step(&faces)) + BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT); + } + } + + BM_remove_tagged_faces(bm, DEL_INPUT); + BM_remove_tagged_edges(bm, DEL_INPUT); + BM_remove_tagged_verts(bm, DEL_INPUT); +} + +static void delete_edges(BMesh *bm){ + BMEdge *e; + BMFace *f; + + BMIter edges; + BMIter faces; + + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){ + if(BMO_TestFlag(bm, (BMHeader*)e, DEL_INPUT)) { + for(f = BMIter_New(&faces, bm, BM_FACES_OF_EDGE, e); f; f = BMIter_Step(&faces)){ + BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT); + } + } + } + BM_remove_tagged_faces(bm, DEL_INPUT); + BM_remove_tagged_edges(bm, DEL_INPUT); +} + +/*you need to make remove tagged verts/edges/faces + api functions that take a filter callback..... + and this new filter type will be for opstack flags. + This is because the BM_remove_taggedXXX functions bypass iterator API. + -Ops dont care about 'UI' considerations like selection state, hide state, ect. If you want to work on unhidden selections for instance, + copy output from a 'select context' operator to another operator.... +*/ + +/*Break this into smaller functions*/ + +static void delete_context(BMesh *bm, int type){ + BMVert *v; + BMEdge *e; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + + if(type == DEL_VERTS) delete_verts(bm); + else if(type == DEL_EDGES){ + /*flush down to verts*/ + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){ + if(BMO_TestFlag(bm, (BMHeader*)e, DEL_INPUT)){ + BMO_SetFlag(bm, (BMHeader*)(e->v1), DEL_INPUT); + BMO_SetFlag(bm, (BMHeader*)(e->v2), DEL_INPUT); + } + } + delete_edges(bm); + /*remove loose vertices*/ + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){ + if(BMO_TestFlag(bm, (BMHeader*)v, DEL_INPUT) && (!(v->edge))) + BMO_SetFlag(bm, (BMHeader*)v, DEL_WIREVERT); + } + BM_remove_tagged_verts(bm, DEL_WIREVERT); + } + else if(type == DEL_EDGESFACES) delete_edges(bm); + else if(type == DEL_ONLYFACES) BM_remove_tagged_faces(bm, DEL_INPUT); + else if (type == DEL_ONLYTAGGED) { + BM_remove_tagged_faces(bm, DEL_INPUT); + BM_remove_tagged_edges(bm, DEL_INPUT); + BM_remove_tagged_verts(bm, DEL_INPUT); + } else if(type == DEL_FACES){ + /*go through and mark all edges and all verts of all faces for delete*/ + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){ + if(BMO_TestFlag(bm, (BMHeader*)f, DEL_INPUT)){ + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges)) + BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT); + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts)) + BMO_SetFlag(bm, (BMHeader*)v, DEL_INPUT); + } + } + /*now go through and mark all remaining faces all edges for keeping.*/ + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){ + if(!BMO_TestFlag(bm, (BMHeader*)f, DEL_INPUT)){ + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e= BMIter_Step(&edges)) + BMO_ClearFlag(bm, (BMHeader*)e, DEL_INPUT); + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v= BMIter_Step(&verts)) + BMO_ClearFlag(bm, (BMHeader*)v, DEL_INPUT); + } + } + /*now delete marked faces*/ + BM_remove_tagged_faces(bm, DEL_INPUT); + /*delete marked edges*/ + BM_remove_tagged_edges(bm, DEL_INPUT); + /*remove loose vertices*/ + BM_remove_tagged_verts(bm, DEL_INPUT); + } + /*does this option even belong in here?*/ + else if(type == DEL_ALL){ + for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)) + BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT); + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)) + BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT); + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)) + BMO_SetFlag(bm, (BMHeader*)v, DEL_INPUT); + + BM_remove_tagged_faces(bm, DEL_INPUT); + BM_remove_tagged_edges(bm, DEL_INPUT); + BM_remove_tagged_verts(bm, DEL_INPUT); + } +}
\ No newline at end of file diff --git a/source/blender/bmesh/operators/connectops.c b/source/blender/bmesh/operators/connectops.c new file mode 100644 index 00000000000..a8f5899fd65 --- /dev/null +++ b/source/blender/bmesh/operators/connectops.c @@ -0,0 +1,126 @@ +#include "MEM_guardedalloc.h" + +#include "BKE_utildefines.h" + +#include "bmesh.h" +#include "mesh_intern.h" +#include "bmesh_private.h" +#include "BLI_arithb.h" + +#include <stdio.h> +#include <string.h> + +#define VERT_INPUT 1 +#define EDGE_OUT 1 +#define FACE_NEW 2 + +void connectverts_exec(BMesh *bm, BMOperator *op) +{ + BMIter iter, liter; + BMFace *f, *nf; + BMLoop **loops = NULL, *lastl = NULL; + V_DECLARE(loops); + BMLoop *l, *nl; + BMVert *v1, *v2, **verts = NULL; + V_DECLARE(verts); + int i; + + BMO_Flag_Buffer(bm, op, "verts", VERT_INPUT); + + for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)){ + V_RESET(loops); + V_RESET(verts); + + if (BMO_TestFlag(bm, f, FACE_NEW)) continue; + + l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f); + v1 = v2 = NULL; + lastl = NULL; + for (; l; l=BMIter_Step(&liter)) { + if (BMO_TestFlag(bm, l->v, VERT_INPUT)) { + if (!lastl) { + lastl = l; + continue; + } + + if (lastl != l->head.prev && lastl != + l->head.next) + { + V_GROW(loops); + loops[V_COUNT(loops)-1] = lastl; + + V_GROW(loops); + loops[V_COUNT(loops)-1] = l; + + } + lastl = l; + } + } + + if (V_COUNT(loops) == 0) continue; + + if (V_COUNT(loops) > 2) { + V_GROW(loops); + loops[V_COUNT(loops)-1] = loops[V_COUNT(loops)-2]; + + V_GROW(loops); + loops[V_COUNT(loops)-1] = loops[0]; + } + + BM_LegalSplits(bm, f, loops, V_COUNT(loops)/2); + + for (i=0; i<V_COUNT(loops)/2; i++) { + if (loops[i*2]==NULL) continue; + + V_GROW(verts); + verts[V_COUNT(verts)-1] = loops[i*2]->v; + + V_GROW(verts); + verts[V_COUNT(verts)-1] = loops[i*2+1]->v; + } + + for (i=0; i<V_COUNT(verts)/2; i++) { + nf = BM_Split_Face(bm, f, verts[i*2], + verts[i*2+1], &nl, NULL); + f = nf; + + if (!nl || !nf) { + BMO_RaiseError(bm, op, + BMERR_CONNECTVERT_FAILED, NULL); + V_FREE(loops); + return;;; + } + BMO_SetFlag(bm, nf, FACE_NEW); + BMO_SetFlag(bm, nl->e, EDGE_OUT); + } + } + + BMO_Flag_To_Slot(bm, op, "edgeout", EDGE_OUT, BM_EDGE); + + V_FREE(loops); + V_FREE(verts); +} + +int BM_ConnectVerts(EditMesh *em, int flag) +{ + EditMesh *em2; + BMesh *bm = editmesh_to_bmesh(em); + BMOperator op; + + BMO_Init_Op(&op, "connectverts"); + BMO_HeaderFlag_To_Slot(bm, &op, "verts", flag, BM_VERT); + BMO_Exec_Op(bm, &op); + BMO_Finish_Op(bm, &op); + + if (BMO_GetSlot(&op, "edgeout")->len > 0 && + BMO_GetError(bm, NULL, NULL)==0) + { + em2 = bmesh_to_editmesh(bm); + set_editMesh(em, em2); + MEM_freeN(em2); + + return 1; + } + + return 0; +}
\ No newline at end of file diff --git a/source/blender/bmesh/operators/createops.c b/source/blender/bmesh/operators/createops.c new file mode 100644 index 00000000000..29ec08868ec --- /dev/null +++ b/source/blender/bmesh/operators/createops.c @@ -0,0 +1,156 @@ +#include "MEM_guardedalloc.h" + +#include "BKE_utildefines.h" + +#include "BLI_ghash.h" +#include "BLI_memarena.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "bmesh.h" +#include "bmesh_operators_private.h" + +#define ELE_NEW 1 +#define ELE_OUT 2 + +void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op) +{ + /*unimplemented, need to think on how to do this. probably are graph + theory stuff that could help with this problem.*/ +} + +/* evaluate if entire quad is a proper convex quad */ +static int convex(float *v1, float *v2, float *v3, float *v4) +{ + float nor[3], nor1[3], nor2[3], vec[4][2]; + + /* define projection, do both trias apart, quad is undefined! */ + CalcNormFloat(v1, v2, v3, nor1); + CalcNormFloat(v1, v3, v4, nor2); + nor[0]= ABS(nor1[0]) + ABS(nor2[0]); + nor[1]= ABS(nor1[1]) + ABS(nor2[1]); + nor[2]= ABS(nor1[2]) + ABS(nor2[2]); + + if(nor[2] >= nor[0] && nor[2] >= nor[1]) { + vec[0][0]= v1[0]; vec[0][1]= v1[1]; + vec[1][0]= v2[0]; vec[1][1]= v2[1]; + vec[2][0]= v3[0]; vec[2][1]= v3[1]; + vec[3][0]= v4[0]; vec[3][1]= v4[1]; + } + else if(nor[1] >= nor[0] && nor[1]>= nor[2]) { + vec[0][0]= v1[0]; vec[0][1]= v1[2]; + vec[1][0]= v2[0]; vec[1][1]= v2[2]; + vec[2][0]= v3[0]; vec[2][1]= v3[2]; + vec[3][0]= v4[0]; vec[3][1]= v4[2]; + } + else { + vec[0][0]= v1[1]; vec[0][1]= v1[2]; + vec[1][0]= v2[1]; vec[1][1]= v2[2]; + vec[2][0]= v3[1]; vec[2][1]= v3[2]; + vec[3][0]= v4[1]; vec[3][1]= v4[2]; + } + + /* linetests, the 2 diagonals have to instersect to be convex */ + if( IsectLL2Df(vec[0], vec[2], vec[1], vec[3]) > 0 ) return 1; + return 0; +} + +/*this is essentially new fkey*/ +void bmesh_contextual_create_exec(BMesh *bm, BMOperator *op) +{ + BMOperator op2; + BMOIter oiter; + BMIter iter, liter; + BMHeader *h; + BMVert *v, *verts[4]; + BMEdge *e; + BMLoop *l; + BMFace *f; + int totv=0, tote=0, totf=0, amount; + + /*count number of each element type we were passed*/ + BMO_ITER(h, &oiter, bm, op, "geom", BM_VERT|BM_EDGE|BM_FACE) { + switch (h->type) { + case BM_VERT: totv++; break; + case BM_EDGE: tote++; break; + case BM_FACE: totf++; break; + } + + BMO_SetFlag(bm, h, ELE_NEW); + } + + /*first call dissolve faces*/ + BMO_InitOpf(bm, &op2, "dissolvefaces faces=%ff", ELE_NEW); + BMO_Exec_Op(bm, &op2); + BMO_ITER(f, &oiter, bm, &op2, "regionout", BM_FACE) { + BMO_SetFlag(bm, f, ELE_OUT); + + /*unflag verts associated with dissolved faces*/ + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) { + BMO_ClearFlag(bm, l->v, ELE_NEW); + } + } + BMO_Finish_Op(bm, &op2); + + /*then call edgenet create, which may still be unimplemented, heh*/ + BMO_InitOpf(bm, &op2, "edgenet_fill edges=%fe", ELE_NEW); + BMO_Exec_Op(bm, &op2); + BMO_ITER(f, &oiter, bm, &op2, "faceout", BM_FACE) { + BMO_SetFlag(bm, f, ELE_OUT); + + /*unflag verts associated with the output faces*/ + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) { + BMO_ClearFlag(bm, l->v, ELE_NEW); + } + } + BMO_Finish_Op(bm, &op2); + + /*now, count how many verts we have*/ + amount = 0; + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if (BMO_TestFlag(bm, v, ELE_NEW)) { + verts[amount] = v; + amount++; + + if (amount > 4) break; + } + } + + if (amount == 2) { + /*create edge*/ + e = BM_Make_Edge(bm, verts[0], verts[1], NULL, 1); + BMO_SetFlag(bm, e, ELE_OUT); + } else if (amount == 3) { + /*create triangle*/ + BM_Make_QuadTri(bm, verts[0], verts[1], verts[2], NULL, NULL, 1); + } else if (amount == 4) { + f = NULL; + + /* the order of vertices can be anything, 6 cases to check */ + if( convex(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co) ) { + f= BM_Make_QuadTri(bm, verts[0], verts[1], verts[2], verts[3], NULL, 1); + } + else if( convex(verts[0]->co, verts[2]->co, verts[3]->co, verts[1]->co) ) { + f= BM_Make_QuadTri(bm, verts[0], verts[2], verts[3], verts[1], NULL, 1); + } + else if( convex(verts[0]->co, verts[2]->co, verts[1]->co, verts[3]->co) ) { + f= BM_Make_QuadTri(bm, verts[0], verts[2], verts[1], verts[3], NULL, 1); + } + else if( convex(verts[0]->co, verts[1]->co, verts[3]->co, verts[2]->co) ) { + f= BM_Make_QuadTri(bm, verts[0], verts[1], verts[3], verts[2], NULL, 1); + } + else if( convex(verts[0]->co, verts[3]->co, verts[2]->co, verts[1]->co) ) { + f= BM_Make_QuadTri(bm, verts[0], verts[3], verts[2], verts[1], NULL, 1); + } + else if( convex(verts[0]->co, verts[3]->co, verts[1]->co, verts[2]->co) ) { + f= BM_Make_QuadTri(bm, verts[0], verts[3], verts[1], verts[2], NULL, 1); + } + else { + printf("cannot find nice quad from concave set of vertices\n"); + } + + if (f) BMO_SetFlag(bm, f, ELE_OUT); + } + + BMO_Flag_To_Slot(bm, op, "faceout", ELE_OUT, BM_FACE); +} diff --git a/source/blender/bmesh/operators/dissolveops.c b/source/blender/bmesh/operators/dissolveops.c new file mode 100644 index 00000000000..997a24d0507 --- /dev/null +++ b/source/blender/bmesh/operators/dissolveops.c @@ -0,0 +1,430 @@ +#include "MEM_guardedalloc.h" + +#include "BKE_utildefines.h" + +#include "bmesh.h" +#include "mesh_intern.h" +#include "bmesh_private.h" +#include "BLI_arithb.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define FACE_MARK 1 +#define FACE_ORIG 2 +#define FACE_NEW 4 +#define EDGE_MARK 1 + +#define VERT_MARK 1 + +static int check_hole_in_region(BMesh *bm, BMFace *f) { + BMWalker regwalker; + BMIter liter2; + BMLoop *l2, *l3; + BMFace *f2; + + /*checks if there are any unmarked boundary edges in the face region*/ + + BMW_Init(®walker, bm, BMW_ISLAND, FACE_MARK); + f2 = BMW_Begin(®walker, f); + for (; f2; f2=BMW_Step(®walker)) { + l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2); + for (; l2; l2=BMIter_Step(&liter2)) { + l3 = bmesh_radial_nextloop(l2); + if (BMO_TestFlag(bm, l3->f, FACE_MARK) + != BMO_TestFlag(bm, l2->f, FACE_MARK)) + { + if (!BMO_TestFlag(bm, l2->e, EDGE_MARK)) { + return 0; + } + } + } + } + BMW_End(®walker); + + return 1; +} + +void dissolvefaces_exec(BMesh *bm, BMOperator *op) +{ + BMOIter oiter; + BMIter liter, liter2, liter3; + BMLoop *l, *l2, *l3; + BMFace *f, *f2, *nf = NULL; + V_DECLARE(region); + V_DECLARE(regions); + BMLoop ***regions = NULL; + BMLoop **region = NULL; + BMWalker regwalker; + int i, j, fcopied; + + BMO_Flag_Buffer(bm, op, "faces", FACE_MARK); + + /*collect regions*/ + f = BMO_IterNew(&oiter, bm, op, "faces", BM_FACE); + for (; f; f=BMO_IterStep(&oiter)) { + if (!BMO_TestFlag(bm, f, FACE_MARK)) continue; + + V_RESET(region); + region = NULL; /*forces different allocation*/ + + /*yay, walk!*/ + BMW_Init(®walker, bm, BMW_ISLAND, FACE_MARK); + f2 = BMW_Begin(®walker, f); + for (; f2; f2=BMW_Step(®walker)) { + l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2); + for (; l2; l2=BMIter_Step(&liter2)) { + l3 = BMIter_New(&liter3, bm, BM_LOOPS_OF_LOOP, l2); + for (; l3; l3=BMIter_Step(&liter3)) { + if (!BMO_TestFlag(bm, l3->f, FACE_MARK)) { + V_GROW(region); + region[V_COUNT(region)-1] = l2; + break; + } + } + if (bmesh_radial_nextloop(l2) == l2) { + V_GROW(region); + region[V_COUNT(region)-1] = l2; + } + } + } + BMW_End(®walker); + + BMW_Init(®walker, bm, BMW_ISLAND, FACE_MARK); + f2 = BMW_Begin(®walker, f); + for (; f2; f2=BMW_Step(®walker)) { + BMO_ClearFlag(bm, f2, FACE_MARK); + BMO_SetFlag(bm, f2, FACE_ORIG); + } + + BMW_End(®walker); + + if (BMO_HasError(bm)) { + BMO_ClearStack(bm); + BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL); + goto cleanup; + } + + V_GROW(region); + V_GROW(regions); + regions[V_COUNT(regions)-1] = region; + region[V_COUNT(region)-1] = NULL; + } + + for (i=0; i<V_COUNT(regions); i++) { + BMEdge **edges = NULL; + V_DECLARE(edges); + + region = regions[i]; + for (j=0; region[j]; j++) { + V_GROW(edges); + edges[V_COUNT(edges)-1] = region[j]->e; + } + + if (!region[0]) { + BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, + "Could not find boundary of dissolve region"); + goto cleanup; + } + + if (region[0]->e->v1 == region[0]->v) + f= BM_Make_Ngon(bm, region[0]->e->v1, region[0]->e->v2, edges, j, 1); + else + f= BM_Make_Ngon(bm, region[0]->e->v2, region[0]->e->v1, edges, j, 1); + + V_FREE(edges); + + if (!f) { + BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, + "Could not create merged face"); + goto cleanup; + } + + /*if making the new face failed (e.g. overlapping test) + unmark the original faces for deletion.*/ + BMO_ClearFlag(bm, f, FACE_ORIG); + BMO_SetFlag(bm, f, FACE_NEW); + + fcopied = 0; + l=BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f); + for (; l; l=BMIter_Step(&liter)) { + /*ensure winding is identical*/ + l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_LOOP, l); + for (; l2; l2=BMIter_Step(&liter2)) { + if (BMO_TestFlag(bm, l2->f, FACE_ORIG)) { + if (l2->v != l->v) + bmesh_loop_reverse(bm, l2->f); + break; + } + } + + /*copy over attributes*/ + l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_LOOP, l); + for (; l2; l2=BMIter_Step(&liter2)) { + if (BMO_TestFlag(bm, l2->f, FACE_ORIG)) { + if (!fcopied) { + BM_Copy_Attributes(bm, bm, l2->f, f); + fcopied = 1; + } + BM_Copy_Attributes(bm, bm, l2, l); + break; + } + } + } + } + + BMO_CallOpf(bm, "del geom=%ff context=%d", FACE_ORIG, DEL_FACES); + if (BMO_HasError(bm)) goto cleanup; + + BMO_Flag_To_Slot(bm, op, "regionout", FACE_NEW, BM_FACE); + +cleanup: + /*free/cleanup*/ + for (i=0; i<V_COUNT(regions); i++) { + if (regions[i]) V_FREE(regions[i]); + } + + V_FREE(regions); +} + +/*almost identical to dissolve edge, except it cleans up vertices*/ +void dissolve_edgeloop_exec(BMesh *bm, BMOperator *op) +{ + BMOperator fop; + BMOIter oiter; + BMIter iter; + BMVert *v, **verts = NULL; + V_DECLARE(verts); + BMEdge *e; + BMFace *f; + int i; + + BMO_ITER(e, &oiter, bm, op, "edges", BM_EDGE) { + if (BM_Edge_FaceCount(e) == 2) { + BMO_SetFlag(bm, e->v1, VERT_MARK); + BMO_SetFlag(bm, e->v2, VERT_MARK); + + BM_Join_Faces(bm, e->loop->f, + ((BMLoop*)e->loop->radial.next->data)->f, + e); + } + } + + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if (BMO_TestFlag(bm, v, VERT_MARK) && + BM_Vert_EdgeCount(v) == 2) + { + V_GROW(verts); + verts[V_COUNT(verts)-1] = v; + } + } + + /*clean up extreneous 2-valence vertices*/ + for (i=0; i<V_COUNT(verts); i++) { + BM_Collapse_Vert(bm, verts[i]->edge, verts[i], 1.0); + } + + V_FREE(verts); + + //BMO_InitOpf(bm, &fop, "dissolvefaces faces=%ff", FACE_MARK); + //BMO_Exec_Op(bm, &fop); + + //BMO_CopySlot(op, &fop, "regionout", "regionout"); + + //BMO_Finish_Op(bm, &fop); +} + + +void dissolveedges_exec(BMesh *bm, BMOperator *op) +{ + BMOperator fop; + BMOIter oiter; + BMIter iter; + BMVert *v; + BMEdge *e; + BMFace *f; + int i; + + BMO_ITER(e, &oiter, bm, op, "edges", BM_EDGE) { + if (BM_Edge_FaceCount(e) == 2) { + BMO_SetFlag(bm, e->v1, VERT_MARK); + BMO_SetFlag(bm, e->v2, VERT_MARK); + + BM_Join_Faces(bm, e->loop->f, + ((BMLoop*)e->loop->radial.next->data)->f, + e); + } + } + + //BMO_InitOpf(bm, &fop, "dissolvefaces faces=%ff", FACE_MARK); + //BMO_Exec_Op(bm, &fop); + + //BMO_CopySlot(op, &fop, "regionout", "regionout"); + + //BMO_Finish_Op(bm, &fop); +} + +static int test_extra_verts(BMesh *bm, BMVert *v) +{ + BMIter iter, liter, iter2, iter3; + BMFace *f, *f2; + BMLoop *l; + BMEdge *e; + int found; + + /*test faces around verts for verts that would be wronly killed + by dissolve faces.*/ + f = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v); + for (; f; f=BMIter_Step(&iter)) { + l=BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f); + for (; l; l=BMIter_Step(&liter)) { + if (!BMO_TestFlag(bm, l->v, VERT_MARK)) { + /*if an edge around a vert is a boundary edge, + then dissolve faces won't destroy it. + also if it forms a boundary with one + of the face regions*/ + found = 0; + e = BMIter_New(&iter2, bm, BM_EDGES_OF_VERT, l->v); + for (; e; e=BMIter_Step(&iter2)) { + if (BM_Edge_FaceCount(e)==1) found = 1; + f2 = BMIter_New(&iter3, bm, BM_FACES_OF_EDGE, e); + for (; f2; f2=BMIter_Step(&iter3)) { + if (!BMO_TestFlag(bm, f2, FACE_MARK)) { + found = 1; + break; + } + } + if (found) break; + } + if (!found) return 0; + } + } + } + + return 1; +} +void dissolveverts_exec(BMesh *bm, BMOperator *op) +{ + BMOpSlot *vinput; + BMIter iter, fiter; + BMVert *v; + BMFace *f; + int i; + + vinput = BMO_GetSlot(op, "verts"); + BMO_Flag_Buffer(bm, op, "verts", VERT_MARK); + + for (v=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v=BMIter_Step(&iter)) { + if (BMO_TestFlag(bm, v, VERT_MARK)) { + f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v); + for (; f; f=BMIter_Step(&fiter)) { + BMO_SetFlag(bm, f, FACE_ORIG); + BMO_SetFlag(bm, f, FACE_MARK); + } + + /*check if our additions to the input to face dissolve + will destroy nonmarked vertices.*/ + if (!test_extra_verts(bm, v)) { + f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v); + for (; f; f=BMIter_Step(&fiter)) { + if (BMO_TestFlag(bm, f, FACE_ORIG)) { + BMO_ClearFlag(bm, f, FACE_MARK); + BMO_ClearFlag(bm, f, FACE_ORIG); + } + } + } else { + f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v); + for (; f; f=BMIter_Step(&fiter)) { + BMO_ClearFlag(bm, f, FACE_ORIG); + } + } + } + } + + BMO_CallOpf(bm, "dissolvefaces faces=%ff", FACE_MARK); + if (BMO_HasError(bm)) { + char *msg; + + BMO_GetError(bm, &msg, NULL); + BMO_ClearStack(bm); + BMO_RaiseError(bm, op, BMERR_DISSOLVEVERTS_FAILED,msg); + } + + /*clean up any remaining*/ + for (v=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v=BMIter_Step(&iter)) { + if (BMO_TestFlag(bm, v, VERT_MARK)) { + if (!BM_Dissolve_Vert(bm, v)) { + BMO_RaiseError(bm, op, + BMERR_DISSOLVEVERTS_FAILED, NULL); + return; + } + } + } + +} + +/*this code is for cleaning up two-edged faces, it shall become + it's own function one day.*/ +#if 0 + /*clean up two-edged faces*/ + /*basic idea is to keep joining 2-edged faces until their + gone. this however relies on joining two 2-edged faces + together to work, which doesn't.*/ + found3 = 1; + while (found3) { + found3 = 0; + for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)){ + if (!BM_Validate_Face(bm, f, stderr)) { + printf("error.\n"); + } + + if (f->len == 2) { + //this design relies on join faces working + //with two-edged faces properly. + //commenting this line disables the + //outermost loop. + //found3 = 1; + found2 = 0; + l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f); + fe = l->e; + for (; l; l=BMIter_Step(&liter)) { + f2 = BMIter_New(&fiter, bm, + BM_FACES_OF_EDGE, l->e); + for (; f2; f2=BMIter_Step(&fiter)) { + if (f2 != f) { + BM_Join_Faces(bm, f, f2, l->e); + found2 = 1; + break; + } + } + if (found2) break; + } + + if (!found2) { + bmesh_kf(bm, f); + bmesh_ke(bm, fe); + } + } /*else if (f->len == 3) { + BMEdge *ed[3]; + BMVert *vt[3]; + BMLoop *lp[3]; + int i=0; + + //check for duplicate edges + l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f); + for (; l; l=BMIter_Step(&liter)) { + ed[i] = l->e; + lp[i] = l; + vt[i++] = l->v; + } + if (vt[0] == vt[1] || vt[0] == vt[2]) { + i += 1; + } + }*/ + } + } + if (oldlen == len) break; + oldlen = len; + +#endif diff --git a/source/blender/bmesh/operators/extrudeops.c b/source/blender/bmesh/operators/extrudeops.c new file mode 100644 index 00000000000..5417d232205 --- /dev/null +++ b/source/blender/bmesh/operators/extrudeops.c @@ -0,0 +1,190 @@ +#include "MEM_guardedalloc.h" + +#include "BKE_utildefines.h" + +#include "BLI_ghash.h" +#include "BLI_memarena.h" +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "bmesh.h" +#include "bmesh_operators_private.h" + +#define EXT_INPUT 1 +#define EXT_KEEP 2 +#define EXT_DEL 4 + +void extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) +{ + BMOIter siter; + BMVert *v, *dupev; + BMEdge *e; + + v = BMO_IterNew(&siter, bm, op, "verts", BM_VERT); + for (; v; v=BMO_IterStep(&siter)) { + dupev = BM_Make_Vert(bm, v->co, NULL); + VECCOPY(dupev->no, v->no); + BM_Copy_Attributes(bm, bm, v, dupev); + + e = BM_Make_Edge(bm, v, dupev, NULL, 0); + + BMO_SetFlag(bm, e, EXT_KEEP); + BMO_SetFlag(bm, dupev, EXT_KEEP); + } + + BMO_Flag_To_Slot(bm, op, "vertout", EXT_KEEP, BM_VERT); + BMO_Flag_To_Slot(bm, op, "edgeout", EXT_KEEP, BM_EDGE); +} + +void extrude_edge_context_exec(BMesh *bm, BMOperator *op) +{ + BMOperator dupeop, delop; + BMOIter siter; + BMIter iter, fiter, viter; + BMEdge *e, *newedge, *e2, *ce; + BMLoop *l, *l2; + BMVert *verts[4], *v, *v2; + BMFace *f; + int rlen, found, delorig=0, i, reverse; + + /*initialize our sub-operators*/ + BMO_Init_Op(&dupeop, "dupe"); + + BMO_Flag_Buffer(bm, op, "edgefacein", EXT_INPUT); + + /*if one flagged face is bordered by an unflagged face, then we delete + original geometry.*/ + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (!BMO_TestFlag(bm, e, EXT_INPUT)) continue; + + found = 0; + f = BMIter_New(&fiter, bm, BM_FACES_OF_EDGE, e); + for (rlen=0; f; f=BMIter_Step(&fiter), rlen++) { + if (!BMO_TestFlag(bm, f, EXT_INPUT)) { + found = 1; + delorig = 1; + break; + } + } + + if (!found && (rlen > 1)) BMO_SetFlag(bm, e, EXT_DEL); + } + + /*calculate verts to delete*/ + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + found = 0; + + BM_ITER(e, &viter, bm, BM_EDGES_OF_VERT, v) { + if (!BMO_TestFlag(bm, e, EXT_INPUT)) { + found = 1; + break; + } + } + + BM_ITER(f, &viter, bm, BM_FACES_OF_VERT, v) { + if (!BMO_TestFlag(bm, f, EXT_INPUT)) { + found = 1; + break; + } + } + + if (!found) { + BMO_SetFlag(bm, v, EXT_DEL); + } + } + + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + if (BMO_TestFlag(bm, f, EXT_INPUT)) + BMO_SetFlag(bm, f, EXT_DEL); + } + if (delorig) BMO_InitOpf(bm, &delop, "del geom=%fvef context=%d", + EXT_DEL, DEL_ONLYTAGGED); + + BMO_CopySlot(op, &dupeop, "edgefacein", "geom"); + BMO_Exec_Op(bm, &dupeop); + + if (bm->act_face && BMO_TestFlag(bm, bm->act_face, EXT_INPUT)) + bm->act_face = BMO_Get_MapPointer(bm, &dupeop, "facemap", bm->act_face); + + if (delorig) BMO_Exec_Op(bm, &delop); + + /*if not delorig, reverse loops of original faces*/ + if (!delorig) { + for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)) { + if (BMO_TestFlag(bm, f, EXT_INPUT)) { + BM_flip_normal(bm, f); + } + } + } + + BMO_CopySlot(&dupeop, op, "newout", "geomout"); + e = BMO_IterNew(&siter, bm, &dupeop, "boundarymap", 0); + for (; e; e=BMO_IterStep(&siter)) { + if (BMO_InMap(bm, op, "exclude", e)) continue; + + newedge = BMO_IterMapVal(&siter); + newedge = *(BMEdge**)newedge; + if (!newedge) continue; + if (!newedge->loop) ce = e; + else ce = newedge; + + if (ce->loop && (ce->loop->v == ce->v1)) { + verts[0] = e->v1; + verts[1] = e->v2; + verts[2] = newedge->v2; + verts[3] = newedge->v1; + } else { + verts[3] = e->v1; + verts[2] = e->v2; + verts[1] = newedge->v2; + verts[0] = newedge->v1; + } + + /*not sure what to do about example face, pass NULL for now.*/ + f = BM_Make_Quadtriangle(bm, verts, NULL, 4, NULL, 0); + + /*copy attributes*/ + l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); + for (; l; l=BMIter_Step(&iter)) { + if (l->e != e && l->e != newedge) continue; + l2 = l->radial.next->data; + + if (l2 == l) { + l2 = newedge->loop; + BM_Copy_Attributes(bm, bm, l2->f, l->f); + + BM_Copy_Attributes(bm, bm, l2, l); + l2 = (BMLoop*) l2->head.next; + l = (BMLoop*) l->head.next; + BM_Copy_Attributes(bm, bm, l2, l); + } else { + BM_Copy_Attributes(bm, bm, l2->f, l->f); + + /*copy data*/ + if (l2->v == l->v) { + BM_Copy_Attributes(bm, bm, l2, l); + l2 = (BMLoop*) l2->head.next; + l = (BMLoop*) l->head.next; + BM_Copy_Attributes(bm, bm, l2, l); + } else { + l2 = (BMLoop*) l2->head.next; + BM_Copy_Attributes(bm, bm, l2, l); + l2 = (BMLoop*) l2->head.prev; + l = (BMLoop*) l->head.next; + BM_Copy_Attributes(bm, bm, l2, l); + } + } + } + } + + /*link isolated verts*/ + v = BMO_IterNew(&siter, bm, &dupeop, "isovertmap", 0); + for (; v; v=BMO_IterStep(&siter)) { + v2 = *((void**)BMO_IterMapVal(&siter)); + BM_Make_Edge(bm, v, v2, v->edge, 1); + } + + /*cleanup*/ + if (delorig) BMO_Finish_Op(bm, &delop); + BMO_Finish_Op(bm, &dupeop); +} diff --git a/source/blender/bmesh/operators/mesh_conv.c b/source/blender/bmesh/operators/mesh_conv.c new file mode 100644 index 00000000000..3ca95ea1e32 --- /dev/null +++ b/source/blender/bmesh/operators/mesh_conv.c @@ -0,0 +1,308 @@ + +#include "MEM_guardedalloc.h" +#include "BKE_customdata.h" +#include "DNA_listBase.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 <string.h> +#include "BKE_utildefines.h" +#include "BKE_mesh.h" +#include "BKE_global.h" +#include "BKE_DerivedMesh.h" +#include "BKE_cdderivedmesh.h" + +#include "BLI_editVert.h" +#include "mesh_intern.h" +#include "ED_mesh.h" + +#include "BLI_blenlib.h" +#include "BLI_edgehash.h" + +#include "bmesh.h" + +/* + * MESH CONV.C + * + * This file contains functions + * for converting a Mesh + * into a Bmesh. will not support non-ngon + * meshes at first, use the editmesh functions + * until it's implemented, and remove this + * comment if it already is. -joeedh + * +*/ + +void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op) { + Mesh *me = BMO_Get_Pnt(op, "mesh"); + MVert *mvert; + MEdge *medge; + MLoop *ml; + MPoly *mpoly; + BMVert *v, **vt=NULL; + BMEdge *e, **fedges=NULL, **et; + V_DECLARE(fedges); + BMFace *f; + int i, j, allocsize[4] = {512, 512, 2048, 512}; + + if (!me || !me->totvert) return; /*sanity check*/ + + mvert = me->mvert; + + vt = MEM_mallocN(sizeof(void**)*me->totvert, "mesh to bmesh vtable"); + + CustomData_copy(&bm->vdata, &me->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->edata, &me->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->ldata, &me->ldata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->pdata, &me->pdata, CD_MASK_BMESH, CD_CALLOC, 0); + + CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]); + CustomData_bmesh_init_pool(&bm->edata, allocsize[1]); + CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]); + CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]); + + for (i=0; i<me->totvert; i++, mvert++) { + v = BM_Make_Vert(bm, mvert->co, NULL); + VECCOPY(v->no, mvert->no); + + vt[i] = v; + BMINDEX_SET(v, i); + + /*transfer flags*/ + v->head.flag = (mvert->flag & ME_HIDE) ? BM_HIDDEN : 0; + if(mvert->flag & SELECT) BM_Select_Vert(bm, v, 1); + v->bweight = (float)mvert->bweight / 255.0f; + + /*Copy Custom Data*/ + CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data); + + v->head.flag = MEFlags_To_BMFlags(mvert->flag, BM_VERT); + } + + if (!me->totedge) return; + + et = MEM_mallocN(sizeof(void**)*me->totedge, "mesh to bmesh etable"); + + medge = me->medge; + for (i=0; i<me->totedge; i++, medge++) { + e = BM_Make_Edge(bm, vt[medge->v1], vt[medge->v2], NULL, 0); + et[i] = e; + + /*Copy Custom Data*/ + CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data); + + e->crease = (float)medge->crease / 255.0f; + e->bweight = (float)medge->bweight / 255.0f; + + e->head.flag = MEFlags_To_BMFlags(medge->flag, BM_EDGE); + } + + if (!me->totpoly) return; + + mpoly = me->mpoly; + for (i=0; i<me->totpoly; i++, mpoly++) { + BMVert *v1, *v2; + + V_RESET(fedges); + for (j=0; j<mpoly->totloop; j++) { + ml = &me->mloop[mpoly->loopstart+j]; + v = vt[ml->v]; + e = et[ml->e]; + + V_GROW(fedges); + + fedges[j] = e; + } + + v1 = vt[me->mloop[mpoly->loopstart].v]; + v2 = vt[me->mloop[mpoly->loopstart+1].v]; + + if (v1 == fedges[0]->v1) v2 = fedges[0]->v2; + else { + v1 = fedges[0]->v2; + v2 = fedges[0]->v1; + } + + f = BM_Make_Ngon(bm, v1, v2, fedges, mpoly->totloop, 0); + + f->head.flag = MEFlags_To_BMFlags(mpoly->flag, BM_FACE); + if (i == me->act_face) bm->act_face = f; + + /*Copy Custom Data*/ + CustomData_to_bmesh_block(&me->fdata, &bm->pdata, i, &f->head.data); + } +} + +void bmesh_to_mesh_exec(BMesh *bm, BMOperator *op) { + BMesh *bmtess; + Object *ob = BMO_Get_Pnt(op, "object"); + Scene *scene = BMO_Get_Pnt(op, "scene"); + Mesh *me = ob->data; + MLoop *mloop; + MPoly *mpoly; + MVert *mvert, *oldverts; + MEdge *medge; + MFace *mface; + BMVert *v; + BMEdge *e; + BMLoop *l; + BMFace *f; + BMIter iter, liter; + int i, j, ototvert, totloop, numTex, numCol; + + numTex = CustomData_number_of_layers(&me->pdata, CD_MLOOPUV); + numCol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); + + bmtess = BM_Copy_Mesh(bm); + BMO_CallOpf(bmtess, "makefgon trifan=%i", 0); + + /* new Vertex block */ + if(bm->totvert==0) mvert= NULL; + else mvert= MEM_callocN(bm->totvert*sizeof(MVert), "loadeditbMesh vert"); + + /* new Edge block */ + if(bm->totedge==0) medge= NULL; + else medge= MEM_callocN(bm->totedge*sizeof(MEdge), "loadeditbMesh edge"); + + /* new Face block */ + if(bmtess->totface==0) mface= NULL; + else mface= MEM_callocN(bmtess->totface*sizeof(MFace), "loadeditbMesh face"); + + /*build ngon data*/ + /* new Ngon Face block */ + if(bm->totface==0) mpoly = NULL; + else mpoly= MEM_callocN(bm->totface*sizeof(MPoly), "loadeditbMesh poly"); + + /*find number of loops to allocate*/ + totloop = 0; + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + totloop += f->len; + } + + if (totloop==0) mloop = NULL; + else mloop = MEM_callocN(totloop*sizeof(MLoop), "loadeditbMesh loop"); + + /* lets save the old verts just in case we are actually working on + * a key ... we now do processing of the keys at the end */ + oldverts= me->mvert; + + /* don't free this yet */ + CustomData_set_layer(&me->vdata, CD_MVERT, NULL); + + /* free custom data */ + CustomData_free(&me->vdata, me->totvert); + CustomData_free(&me->edata, me->totedge); + CustomData_free(&me->fdata, me->totface); + CustomData_free(&me->ldata, me->totloop); + CustomData_free(&me->pdata, me->totpoly); + + /* add new custom data */ + me->totvert= bm->totvert; + me->totedge= bm->totedge; + me->totface= bmtess->totface; + me->totloop= totloop; + me->totpoly= bm->totface; + + CustomData_copy(&bm->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert); + CustomData_copy(&bm->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge); + CustomData_copy(&bm->ldata, &me->ldata, CD_MASK_MESH, CD_CALLOC, me->totloop); + CustomData_copy(&bm->pdata, &me->pdata, CD_MASK_MESH, CD_CALLOC, me->totpoly); + + CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert); + CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge); + CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, mface, me->totface); + CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop); + CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly); + + CustomData_from_bmeshpoly(&me->fdata, &bmtess->pdata, &bmtess->ldata, bmtess->totface); + + mesh_update_customdata_pointers(me); + + /*set indices*/ + i = 0; + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + VECCOPY(mvert->co, v->co); + + mvert->no[0] = (unsigned char) (v->no[0]*255.0f); + mvert->no[1] = (unsigned char) (v->no[1]*255.0f); + mvert->no[2] = (unsigned char) (v->no[2]*255.0f); + + mvert->flag = BMFlags_To_MEFlags(v); + + BMINDEX_SET(v, i); + i++; + mvert++; + } + + i = 0; + BM_ITER(v, &iter, bmtess, BM_VERTS_OF_MESH, NULL) { + BMINDEX_SET(v, i); + i++; + } + + i = 0; + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + medge->v1 = BMINDEX_GET(e->v1); + medge->v2 = BMINDEX_GET(e->v2); + + medge->flag = BMFlags_To_MEFlags(e); + + BMINDEX_SET(e, i); + i++; + medge++; + } + + i = 0; + BM_ITER(f, &iter, bmtess, BM_FACES_OF_MESH, NULL) { + mface->mat_nr = f->mat_nr; + mface->flag = BMFlags_To_MEFlags(f); + + mface->v1 = BMINDEX_GET(f->loopbase->v); + mface->v2 = BMINDEX_GET(((BMLoop*)f->loopbase->head.next)->v); + if (f->len < 3) { + mface++; + i++; + continue; + } + + mface->v3 = BMINDEX_GET(((BMLoop*)f->loopbase->head.next->next)->v); + if (f->len < 4) { + mface->v4 = 0; + mface++; + i++; + continue; + } + + mface->v4 = BMINDEX_GET(((BMLoop*)f->loopbase->head.next->next->next)->v); + test_index_face(mface, &me->fdata, i, 1); + + BM_loops_to_corners(bmtess, me, i, f, numTex, numCol); + + mface++; + i++; + } + + i = 0; + j = 0; + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + mpoly->loopstart = j; + mpoly->totloop = f->len; + mpoly->mat_nr = f->mat_nr; + mpoly->flag = BMFlags_To_MEFlags(f); + + l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f); + for ( ; l; l=BMIter_Step(&liter), j++, mloop++) { + mloop->e = BMINDEX_GET(l->e); + mloop->v = BMINDEX_GET(l->v); + } + + if (f == bm->act_face) me->act_face = i; + + i++; + mpoly++; + } + + BM_Free_Mesh(bmtess); +}
\ No newline at end of file diff --git a/source/blender/bmesh/operators/removedoubles.c b/source/blender/bmesh/operators/removedoubles.c new file mode 100644 index 00000000000..605626d15e0 --- /dev/null +++ b/source/blender/bmesh/operators/removedoubles.c @@ -0,0 +1,309 @@ +#include "MEM_guardedalloc.h" + +#include "BKE_utildefines.h" + +#include "bmesh.h" +#include "mesh_intern.h" +#include "bmesh_private.h" +#include "BLI_arithb.h" +#include "BLI_ghash.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define BL(ptr) ((BMLoop*)(ptr)) + +void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op) +{ + BMIter liter; + BMLoop *l; + BMVert *v2, *doub; + int split=0; + + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) { + v2 = BMO_Get_MapPointer(bm, op, "targetmap", l->v); + /*ok: if v2 is NULL (e.g. not in the map) then it's + a target vert, otherwise it's a double*/ + if (v2 && BM_Vert_In_Face(f, v2) && v2 != BL(l->head.prev)->v + && v2 != BL(l->head.next)->v) + { + doub = l->v; + split = 1; + break; + } + } + + if (split && doub != v2) { + BMLoop *nl; + BMFace *f2 = BM_Split_Face(bm, f, doub, v2, &nl, NULL); + + remdoubles_splitface(f, bm, op); + remdoubles_splitface(f2, bm, op); + } +} + +#define ELE_DEL 1 +#define EDGE_COL 2 +#define FACE_MARK 2 + +#if 0 +int remdoubles_face_overlaps(BMesh *bm, BMVert **varr, + int len, BMFace *exclude, + BMFace **overlapface) +{ + BMIter vertfaces; + BMFace *f; + int i, amount; + + if (overlapface) *overlapface = NULL; + + for(i=0; i < len; i++){ + f = BMIter_New(&vertfaces, bm, BM_FACES_OF_VERT, varr[i] ); + while(f){ + amount = BM_Verts_In_Face(bm, f, varr, len); + if(amount >= len){ + if (overlapface) *overlapface = f; + return 1; + } + f = BMIter_Step(&vertfaces); + } + } + return 0; +} +#endif + +void bmesh_weldverts_exec(BMesh *bm, BMOperator *op) +{ + BMIter iter, liter; + BMVert *v, *v2; + BMEdge *e, *e2, **edges = NULL; + V_DECLARE(edges); + BMLoop *l, *l2, **loops = NULL; + V_DECLARE(loops); + BMFace *f, *f2; + int a; + + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if (BMO_Get_MapPointer(bm, op, "targetmap", v)) + BMO_SetFlag(bm, v, ELE_DEL); + } + + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + remdoubles_splitface(f, bm, op); + } + + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + v = BMO_Get_MapPointer(bm, op, "targetmap", e->v1); + v2 = BMO_Get_MapPointer(bm, op, "targetmap", e->v2); + + if (!v) v = e->v1; + if (!v2) v2 = e->v2; + + if ((e->v1 != v) || (e->v2 != v2)) { + if (v == v2) BMO_SetFlag(bm, e, EDGE_COL); + else BM_Make_Edge(bm, v, v2, e, 1); + + BMO_SetFlag(bm, e, ELE_DEL); + } + } + + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + BMINDEX_SET(f, 0); + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) { + if (BMO_TestFlag(bm, l->v, ELE_DEL)) + BMO_SetFlag(bm, f, FACE_MARK); + if (BMO_TestFlag(bm, l->e, EDGE_COL)) + BMINDEX_SET(f, BMINDEX_GET(f)+1); + } + } + + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + if (!BMO_TestFlag(bm, f, FACE_MARK)) continue; + if (f->len - BMINDEX_GET(f) < 3) { + BMO_SetFlag(bm, f, ELE_DEL); + continue; + } + + V_RESET(edges); + V_RESET(loops); + a = 0; + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) { + v = l->v; + v2 = BL(l->head.next)->v; + if (BMO_TestFlag(bm, v, ELE_DEL)) + v = BMO_Get_MapPointer(bm, op, "targetmap", v); + if (BMO_TestFlag(bm, v2, ELE_DEL)) + v2 = BMO_Get_MapPointer(bm, op, "targetmap", v2); + + e2 = v != v2 ? BM_Edge_Exist(v, v2) : NULL; + if (e2) { + V_GROW(edges); + V_GROW(loops); + + edges[a] = e2; + loops[a] = l; + + a++; + } + } + + v = loops[0]->v; + v2 = loops[1]->v; + + if (BMO_TestFlag(bm, v, ELE_DEL)) + v = BMO_Get_MapPointer(bm, op, "targetmap", v); + if (BMO_TestFlag(bm, v2, ELE_DEL)) + v2 = BMO_Get_MapPointer(bm, op, "targetmap", v2); + + + f2 = BM_Make_Ngon(bm, v, v2, edges, a, 0); + if (f2) { + BM_Copy_Attributes(bm, bm, f, f2); + BMO_SetFlag(bm, f, ELE_DEL); + + a = 0; + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f2) { + l2 = loops[a]; + BM_Copy_Attributes(bm, bm, l2, l); + + a++; + } + } + + /*need to still copy customdata stuff here, will do later*/ + } + + BMO_CallOpf(bm, "del geom=%fvef context=%i", ELE_DEL, DEL_ONLYTAGGED); + + V_FREE(edges); +} + +static int vergaverco(const void *e1, const void *e2) +{ + const BMVert *v1 = *(void**)e1, *v2 = *(void**)e2; + float x1 = v1->co[0] + v1->co[1] + v1->co[2]; + float x2 = v2->co[0] + v2->co[1] + v2->co[2]; + + if (x1 > x2) return 1; + else if (x1 < x2) return -1; + else return 0; +} + +#define VERT_TESTED 1 +#define VERT_DOUBLE 2 +#define VERT_TARGET 4 +#define VERT_KEEP 8 + +void bmesh_removedoubles_exec(BMesh *bm, BMOperator *op) +{ + BMOperator weldop; + BMOIter oiter; + BMVert *v, *v2; + BMVert **verts=NULL; + V_DECLARE(verts); + float dist, distsqr; + int i, j, len; + + dist = BMO_Get_Float(op, "dist"); + distsqr = dist*dist; + + BMO_Init_Op(&weldop, "weldverts"); + + i = 0; + BMO_ITER(v, &oiter, bm, op, "verts", BM_VERT) { + V_GROW(verts); + verts[i++] = v; + } + + /*sort by vertex coordinates added together*/ + qsort(verts, V_COUNT(verts), sizeof(void*), vergaverco); + + len = V_COUNT(verts); + for (i=0; i<len; i++) { + v = verts[i]; + if (BMO_TestFlag(bm, v, VERT_TESTED)) continue; + + BMO_SetFlag(bm, v, VERT_TESTED); + for (j=i+1; j<len; j++) { + float vec[3]; + + v2 = verts[j]; + if ((v2->co[0]+v2->co[1]+v2->co[2]) - (v->co[0]+v->co[1]+v->co[2]) + > distsqr) break; + + vec[0] = v->co[0] - v2->co[0]; + vec[1] = v->co[1] - v2->co[1]; + vec[2] = v->co[2] - v2->co[2]; + + if (INPR(vec, vec) < distsqr) { + BMO_SetFlag(bm, v2, VERT_TESTED); + BMO_SetFlag(bm, v2, VERT_DOUBLE); + BMO_SetFlag(bm, v, VERT_TARGET); + + BMO_Insert_MapPointer(bm, &weldop, "targetmap", v2, v); + } + } + } + + V_FREE(verts); + + BMO_Exec_Op(bm, &weldop); + BMO_Finish_Op(bm, &weldop); +} + + +void bmesh_finddoubles_exec(BMesh *bm, BMOperator *op) +{ + BMOIter oiter; + BMVert *v, *v2; + BMVert **verts=NULL; + V_DECLARE(verts); + float dist, distsqr; + int i, j, len; + + dist = BMO_Get_Float(op, "dist"); + distsqr = dist*dist; + + i = 0; + BMO_ITER(v, &oiter, bm, op, "verts", BM_VERT) { + V_GROW(verts); + verts[i++] = v; + } + + /*sort by vertex coordinates added together*/ + //qsort(verts, V_COUNT(verts), sizeof(void*), vergaverco); + + BMO_Flag_Buffer(bm, op, "keepverts", VERT_KEEP); + + len = V_COUNT(verts); + for (i=0; i<len; i++) { + v = verts[i]; + if (BMO_TestFlag(bm, v, VERT_DOUBLE)) continue; + + //BMO_SetFlag(bm, v, VERT_TESTED); + for (j=0; j<len; j++) { + if (j == i) continue; + + //float vec[3]; + if (BMO_TestFlag(bm, v, VERT_KEEP)) continue; + + v2 = verts[j]; + //if ((v2->co[0]+v2->co[1]+v2->co[2]) - (v->co[0]+v->co[1]+v->co[2]) + // > distsqr) break; + + //vec[0] = v->co[0] - v2->co[0]; + //vec[1] = v->co[1] - v2->co[1]; + //vec[2] = v->co[2] - v2->co[2]; + + if (VecLenCompare(v->co, v2->co, dist)) { + BMO_SetFlag(bm, v2, VERT_DOUBLE); + BMO_SetFlag(bm, v, VERT_TARGET); + + BMO_Insert_MapPointer(bm, op, "targetmapout", v2, v); + } + } + } + + V_FREE(verts); +} diff --git a/source/blender/bmesh/operators/subdivideop.c b/source/blender/bmesh/operators/subdivideop.c new file mode 100644 index 00000000000..8482fecb7bb --- /dev/null +++ b/source/blender/bmesh/operators/subdivideop.c @@ -0,0 +1,825 @@ +#include "MEM_guardedalloc.h" + +#include "BKE_utildefines.h" + +#include "BLI_arithb.h" +#include "BLI_rand.h" +#include "BLI_ghash.h" + +#include "DNA_object_types.h" + +#include "ED_mesh.h" + +#include "bmesh.h" +#include "mesh_intern.h" +#include "subdivideop.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +/*flags for all elements share a common bitfield space*/ +#define SUBD_SPLIT 1 + +#define EDGE_PERCENT 2 + +/*I don't think new faces are flagged, currently, but + better safe than sorry.*/ +#define FACE_NEW 4 +#define FACE_CUSTOMFILL 8 +#define ELE_INNER 16 +#define ELE_SPLIT 32 +#define ELE_CONNECT 64 + +/*stuff for the flag paramter. note that + what used to live in "beauty" and + in "seltype" live here. still have to + convert the beauty flags over, which + is why it starts at 128 (to avoid + collision).*/ +#define SELTYPE_INNER 128 + +/* +NOTE: beauty has been renamed to flag! +*/ + +/*generic subdivision rules: + + * two selected edges in a face should make a link + between them. + + * one edge should do, what? make pretty topology, or just + split the edge only? +*/ + +/*connects face with smallest len, which I think should always be correct for + edge subdivision*/ +BMEdge *connect_smallest_face(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf) { + BMIter iter, iter2; + BMVert *v; + BMLoop *nl; + BMFace *face, *curf = NULL; + + /*this isn't the best thing in the world. it doesn't handle cases where there's + multiple faces yet. that might require a convexity test to figure out which + face is "best," and who knows what for non-manifold conditions.*/ + for (face = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v1); face; face=BMIter_Step(&iter)) { + for (v=BMIter_New(&iter2, bm, BM_VERTS_OF_FACE, face); v; v=BMIter_Step(&iter2)) { + if (v == v2) { + if (!curf || face->len < curf->len) curf = face; + } + } + } + + if (curf) { + face = BM_Split_Face(bm, curf, v1, v2, &nl, NULL); + + if (nf) *nf = face; + return nl ? nl->e : NULL; + } + + return NULL; +} +/* calculates offset for co, based on fractal, sphere or smooth settings */ +static void alter_co(float *co, BMEdge *edge, subdparams *params, float perc, + BMVert *vsta, BMVert *vend) +{ + float vec1[3], fac; + + if(params->beauty & B_SMOOTH) { + /* we calculate an offset vector vec1[], to be added to *co */ + float len, fac, nor[3], nor1[3], nor2[3], smooth=params->smooth; + + VecSubf(nor, vsta->co, vend->co); + len= 0.5f*Normalize(nor); + + VECCOPY(nor1, vsta->no); + VECCOPY(nor2, vend->no); + + /* cosine angle */ + fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ; + + vec1[0]= fac*nor1[0]; + vec1[1]= fac*nor1[1]; + vec1[2]= fac*nor1[2]; + + /* cosine angle */ + fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ; + + vec1[0]+= fac*nor2[0]; + vec1[1]+= fac*nor2[1]; + vec1[2]+= fac*nor2[2]; + + /* falloff for multi subdivide */ + smooth *= sqrt(fabs(1.0f - 2.0f*fabs(perc))); + + vec1[0]*= smooth*len; + vec1[1]*= smooth*len; + vec1[2]*= smooth*len; + + co[0] += vec1[0]; + co[1] += vec1[1]; + co[2] += vec1[2]; + } + else if(params->beauty & B_SPHERE) { /* subdivide sphere */ + Normalize(co); + co[0]*= params->smooth; + co[1]*= params->smooth; + co[2]*= params->smooth; + } + + if(params->beauty & B_FRACTAL) { + fac= params->fractal*VecLenf(vsta->co, vend->co); + vec1[0]= fac*(float)(0.5-BLI_drand()); + vec1[1]= fac*(float)(0.5-BLI_drand()); + vec1[2]= fac*(float)(0.5-BLI_drand()); + VecAddf(co, co, vec1); + } +} + +/* assumes in the edge is the correct interpolated vertices already */ +/* percent defines the interpolation, rad and flag are for special options */ +/* results in new vertex with correct coordinate, vertex normal and weight group info */ +static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge,BMEdge *oedge, + subdparams *params, float percent, + float percent2, + BMEdge **out,BMVert *vsta,BMVert *vend) +{ + BMVert *ev; +// float co[3]; + + ev = BM_Split_Edge(bm, edge->v1, edge, out, percent); + BM_Vert_UpdateNormal(bm, ev); + + BMO_SetFlag(bm, ev, ELE_INNER); + + /* offset for smooth or sphere or fractal */ + alter_co(ev->co, oedge, params, percent2, vsta, vend); + +#if 0 //TODO + /* clip if needed by mirror modifier */ + if (edge->v1->f2) { + if ( edge->v1->f2 & edge->v2->f2 & 1) { + co[0]= 0.0f; + } + if ( edge->v1->f2 & edge->v2->f2 & 2) { + co[1]= 0.0f; + } + if ( edge->v1->f2 & edge->v2->f2 & 4) { + co[2]= 0.0f; + } + } +#endif + + return ev; +} + +static BMVert *subdivideedgenum(BMesh *bm, BMEdge *edge, BMEdge *oedge, + int curpoint, int totpoint, subdparams *params, + BMEdge **newe, BMVert *vsta, BMVert *vend) +{ + BMVert *ev; + float percent, percent2 = 0.0f; + + if (BMO_TestFlag(bm, edge, EDGE_PERCENT) && totpoint == 1) + percent = BMO_Get_MapFloat(bm, params->op, + "edgepercents", edge); + else { + percent= 1.0f/(float)(totpoint+1-curpoint); + percent2 = (float)curpoint / (float)(totpoint + 1); + + } + + ev= bm_subdivide_edge_addvert(bm, edge, oedge, params, percent, + percent2, newe, vsta, vend); + return ev; +} + +static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, subdparams *params, + BMVert *vsta, BMVert *vend) { + BMEdge *eed = edge, *newe, temp = *edge; + BMVert *v; + int i, numcuts = params->numcuts; + + for(i=0;i<numcuts;i++) { + v = subdivideedgenum(bm, eed, &temp, i, params->numcuts, params, + &newe, vsta, vend); + BMO_SetFlag(bm, v, SUBD_SPLIT); + BMO_SetFlag(bm, eed, SUBD_SPLIT); + + BMO_SetFlag(bm, v, ELE_SPLIT); + BMO_SetFlag(bm, eed, ELE_SPLIT); + } +} + +/*note: the patterns are rotated as necassary to + match the input geometry. they're based on the + pre-split state of the face*/ + +/* + +v3---------v2 +| | +| | +| | +| | +v4---v0---v1 + +*/ +static void q_1edge_split(BMesh *bm, BMFace *face, + BMVert **verts, subdparams *params) { + BMFace *nf; + int i, add, numcuts = params->numcuts; + + /*if it's odd, the middle face is a quad, otherwise it's a triangle*/ + if (numcuts % 2==0) { + add = 2; + for (i=0; i<numcuts; i++) { + if (i == numcuts/2) add -= 1; + connect_smallest_face(bm, verts[i], verts[numcuts+add], + &nf); + } + } else { + add = 2; + for (i=0; i<numcuts; i++) { + connect_smallest_face(bm, verts[i], verts[numcuts+add], + &nf); + if (i == numcuts/2) { + add -= 1; + connect_smallest_face(bm, verts[i], + verts[numcuts+add], + &nf); + } + } + + } +} + +subdpattern q_1edge = { + {1, 0, 0, 0}, + q_1edge_split, + 4, +}; + + +/* + +v4---v3---v2 +| s | +| | +| | +| s | +v5---v0---v1 + +*/ + +static void q_2edge_op_split(BMesh *bm, BMFace *face, BMVert **verts, + subdparams *params) +{ + BMFace *nf; + int i, numcuts = params->numcuts; + + for (i=0; i<numcuts; i++) { + connect_smallest_face(bm, verts[i],verts[(numcuts-i-1)+numcuts+2], + &nf); + } +} + +subdpattern q_2edge_op = { + {1, 0, 1, 0}, + q_2edge_op_split, + 4, +}; + +/* +v6--------v5 +| | +| |v4s +| |v3s +| s s | +v7-v0--v1-v2 + +*/ +static void q_2edge_split(BMesh *bm, BMFace *face, BMVert **verts, + subdparams *params) +{ + BMFace *nf; + int i, numcuts = params->numcuts; + + for (i=0; i<numcuts; i++) { + connect_smallest_face(bm, verts[i], verts[numcuts+(numcuts-i)], + &nf); + } + connect_smallest_face(bm, verts[numcuts*2+3], verts[numcuts*2+1], &nf); +} + +subdpattern q_2edge = { + {1, 1, 0, 0}, + q_2edge_split, + 4, +}; + +/* s s +v8--v7--v6-v5 +| | +| v4 s +| | +| v3 s +| s s | +v9-v0--v1-v2 + +*/ +static void q_3edge_split(BMesh *bm, BMFace *face, BMVert **verts, + subdparams *params) +{ + BMFace *nf; + int i, add=0, numcuts = params->numcuts; + + for (i=0; i<numcuts; i++) { + if (i == numcuts/2) { + if (numcuts % 2 != 0) { + connect_smallest_face(bm, verts[numcuts-i-1+add], + verts[i+numcuts+1], &nf); + } + add = numcuts*2+2; + } + connect_smallest_face(bm, verts[numcuts-i-1+add], + verts[i+numcuts+1], &nf); + } + + for (i=0; i<numcuts/2+1; i++) { + connect_smallest_face(bm, verts[i],verts[(numcuts-i)+numcuts*2+1], + &nf); + } +} + +subdpattern q_3edge = { + {1, 1, 1, 0}, + q_3edge_split, + 4, +}; + +/* + + v8--v7-v6--v5 + | s | + |v9 s s|v4 +first line | | last line + |v10s s s|v3 + v11-v0--v1-v2 + + it goes from bottom up +*/ +static void q_4edge_split(BMesh *bm, BMFace *face, BMVert **verts, + subdparams *params) +{ + BMFace *nf; + BMVert *v, *v1, *v2; + BMEdge *e, *ne, temp; + BMVert **lines; + int numcuts = params->numcuts; + int i, j, a, b, s=numcuts+2, totv=numcuts*4+4; + + lines = MEM_callocN(sizeof(BMVert*)*(numcuts+2)*(numcuts+2), + "q_4edge_split"); + /*build a 2-dimensional array of verts, + containing every vert (and all new ones) + in the face.*/ + + /*first line*/ + for (i=0; i<numcuts+2; i++) { + lines[i] = verts[numcuts*3+2+(numcuts-i+1)]; + } + + /*last line*/ + for (i=0; i<numcuts+2; i++) { + lines[(s-1)*s+i] = verts[numcuts+i]; + } + + /*first and last members of middle lines*/ + for (i=0; i<numcuts; i++) { + a = i; + b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1); + + e = connect_smallest_face(bm, verts[a], verts[b], &nf); + if (!e) continue; + + BMO_SetFlag(bm, e, ELE_INNER); + BMO_SetFlag(bm, nf, ELE_INNER); + + + v1 = lines[(i+1)*s] = verts[a]; + v2 = lines[(i+1)*s + s-1] = verts[b]; + + temp = *e; + for (a=0; a<numcuts; a++) { + v = subdivideedgenum(bm, e, &temp, a, numcuts, params, &ne, + v1, v2); + BMO_SetFlag(bm, ne, ELE_INNER); + lines[(i+1)*s+a+1] = v; + } + } + + for (i=1; i<numcuts+2; i++) { + for (j=1; j<numcuts+1; j++) { + a = i*s + j; + b = (i-1)*s + j; + e = connect_smallest_face(bm, lines[a], lines[b], &nf); + if (!e) continue; + + BMO_SetFlag(bm, e, ELE_INNER); + BMO_SetFlag(bm, nf, ELE_INNER); + } + } + + MEM_freeN(lines); +} + +/* v3 + / \ + / \ + / \ + / \ + / \ +v4--v0--v1--v2 + s s +*/ +static void t_1edge_split(BMesh *bm, BMFace *face, BMVert **verts, + subdparams *params) +{ + BMFace *nf; + int i, numcuts = params->numcuts; + + for (i=0; i<numcuts; i++) { + connect_smallest_face(bm, verts[i], verts[numcuts+1], &nf); + } +} + +subdpattern t_1edge = { + {1, 0, 0}, + t_1edge_split, + 3, +}; + +/* v5 + / \ + / \ v4 s + / \ + / \ v3 s + / \ +v6--v0--v1--v2 + s s +*/ +static void t_2edge_split(BMesh *bm, BMFace *face, BMVert **verts, + subdparams *params) +{ + BMFace *nf; + int i, numcuts = params->numcuts; + + for (i=0; i<numcuts; i++) { + connect_smallest_face(bm, verts[i], verts[numcuts+numcuts-i], &nf); + } +} + +subdpattern t_2edge = { + {1, 1, 0}, + t_2edge_split, + 3, +}; + + +/* v5 + / \ + s v6/---\ v4 s + / \ / \ +sv7/---v---\ v3 s + / \/ \/ \ + v8--v0--v1--v2 + s s +*/ +static void t_3edge_split(BMesh *bm, BMFace *face, BMVert **verts, + subdparams *params) +{ + BMFace *nf; + BMEdge *e, *ne, temp; + BMVert ***lines, *v; + void *stackarr[1]; + int i, j, a, b, numcuts = params->numcuts; + + /*number of verts in each line*/ + lines = MEM_callocN(sizeof(void*)*(numcuts+2), "triangle vert table"); + + lines[0] = (BMVert**) stackarr; + lines[0][0] = verts[numcuts*2+1]; + + lines[1+numcuts] = MEM_callocN(sizeof(void*)*(numcuts+2), + "triangle vert table 2"); + for (i=0; i<numcuts; i++) { + lines[1+numcuts][1+i] = verts[i]; + } + lines[1+numcuts][0] = verts[numcuts*3+2]; + lines[1+numcuts][1+numcuts] = verts[numcuts]; + + for (i=0; i<numcuts; i++) { + lines[i+1] = MEM_callocN(sizeof(void*)*(2+i), + "triangle vert table row"); + a = numcuts*2 + 2 + i; + b = numcuts + numcuts - i; + e = connect_smallest_face(bm, verts[a], verts[b], &nf); + if (!e) goto cleanup; + + BMO_SetFlag(bm, e, ELE_INNER); + BMO_SetFlag(bm, nf, ELE_INNER); + + lines[i+1][0] = verts[a]; + lines[i+1][1+i] = verts[b]; + + temp = *e; + for (j=0; j<i; j++) { + v = subdivideedgenum(bm, e, &temp, j, i, params, &ne, + verts[a], verts[b]); + lines[i+1][j+1] = v; + + BMO_SetFlag(bm, ne, ELE_INNER); + } + } + + +/* v5 + / \ + s v6/---\ v4 s + / \ / \ +sv7/---v---\ v3 s + / \/ \/ \ + v8--v0--v1--v2 + s s +*/ + for (i=1; i<numcuts+1; i++) { + for (j=0; j<i; j++) { + e= connect_smallest_face(bm, lines[i][j], lines[i+1][j+1], + &nf); + + BMO_SetFlag(bm, e, ELE_INNER); + BMO_SetFlag(bm, nf, ELE_INNER); + + e= connect_smallest_face(bm,lines[i][j+1],lines[i+1][j+1], + &nf); + + BMO_SetFlag(bm, e, ELE_INNER); + BMO_SetFlag(bm, nf, ELE_INNER); + } + } + +cleanup: + for (i=1; i<numcuts+2; i++) { + if (lines[i]) MEM_freeN(lines[i]); + } + + MEM_freeN(lines); +} + +subdpattern t_3edge = { + {1, 1, 1}, + t_3edge_split, + 3, +}; + + +subdpattern q_4edge = { + {1, 1, 1, 1}, + q_4edge_split, + 4, +}; + +subdpattern *patterns[] = { + &q_1edge, + &q_2edge_op, + &q_4edge, + &q_3edge, + &q_2edge, + &t_1edge, + &t_2edge, + &t_3edge, +}; + +#define PLEN (sizeof(patterns) / sizeof(void*)) + +typedef struct subd_facedata { + BMVert *start; subdpattern *pat; +} subd_facedata; + +void esubdivide_exec(BMesh *bmesh, BMOperator *op) +{ + BMOpSlot *einput; + BMEdge *edge, **edges = NULL; + V_DECLARE(edges); + BMFace *face; + BMLoop *nl; + BMVert **verts = NULL; + V_DECLARE(verts); + BMIter fiter, liter; + subdpattern *pat; + subdparams params; + subd_facedata *facedata = NULL; + V_DECLARE(facedata); + float smooth, fractal; + int beauty; + int i, j, matched, a, b, numcuts; + + BMO_Flag_Buffer(bmesh, op, "edges", SUBD_SPLIT); + + numcuts = BMO_GetSlot(op, "numcuts")->data.i; + smooth = BMO_GetSlot(op, "smooth")->data.f; + fractal = BMO_GetSlot(op, "fractal")->data.f; + beauty = BMO_GetSlot(op, "beauty")->data.i; + + einput = BMO_GetSlot(op, "edges"); + + /*first go through and tag edges*/ + BMO_Flag_To_Slot(bmesh, op, "edges", + SUBD_SPLIT, BM_EDGE); + + params.numcuts = numcuts; + params.op = op; + params.smooth = smooth; + params.fractal = fractal; + params.beauty = beauty; + + BMO_Mapping_To_Flag(bmesh, op, "custompatterns", + FACE_CUSTOMFILL); + + BMO_Mapping_To_Flag(bmesh, op, "edgepercents", + EDGE_PERCENT); + + for (face=BMIter_New(&fiter, bmesh, BM_FACES_OF_MESH, NULL); + face; face=BMIter_Step(&fiter)) { + /*figure out which pattern to use*/ + + V_RESET(edges); + V_RESET(verts); + i = 0; + for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face); + nl; nl=BMIter_Step(&liter)) { + V_GROW(edges); + V_GROW(verts); + edges[i] = nl->e; + verts[i] = nl->v; + i++; + } + + if (BMO_TestFlag(bmesh, face, FACE_CUSTOMFILL)) { + pat = BMO_Get_MapData(bmesh, op, + "custompatterns", face); + for (i=0; i<pat->len; i++) { + matched = 1; + for (j=0; j<pat->len; j++) { + a = (j + i) % pat->len; + if ((!!BMO_TestFlag(bmesh, edges[a], SUBD_SPLIT)) + != (!!pat->seledges[j])) { + matched = 0; + break; + } + } + if (matched) { + V_GROW(facedata); + b = V_COUNT(facedata)-1; + facedata[b].pat = pat; + facedata[b].start = verts[i]; + BMO_SetFlag(bmesh, face, SUBD_SPLIT); + break; + } + } + if (!matched) { + /*if no match, append null element to array.*/ + V_GROW(facedata); + } + + /*obvously don't test for other patterns matching*/ + continue; + } + + for (i=0; i<PLEN; i++) { + pat = patterns[i]; + if (pat->len == face->len) { + for (a=0; a<pat->len; a++) { + matched = 1; + for (b=0; b<pat->len; b++) { + j = (b + a) % pat->len; + if ((!!BMO_TestFlag(bmesh, edges[j], SUBD_SPLIT)) + != (!!pat->seledges[b])) { + matched = 0; + break; + } + } + if (matched) break; + } + if (matched) { + V_GROW(facedata); + BMO_SetFlag(bmesh, face, SUBD_SPLIT); + j = V_COUNT(facedata) - 1; + facedata[j].pat = pat; + facedata[j].start = verts[a]; + break; + } + } + } + } + + einput = BMO_GetSlot(op, "edges"); + + /*go through and split edges*/ + for (i=0; i<einput->len; i++) { + edge = ((BMEdge**)einput->data.p)[i]; + bm_subdivide_multicut(bmesh, edge,¶ms, edge->v1, edge->v2); + //BM_Split_Edge_Multi(bmesh, edge, numcuts); + } + + //if (facedata) V_FREE(facedata); + //return; + + i = 0; + for (face=BMIter_New(&fiter, bmesh, BM_FACES_OF_MESH, NULL); + face; face=BMIter_Step(&fiter)) { + /*figure out which pattern to use*/ + V_RESET(verts); + if (BMO_TestFlag(bmesh, face, SUBD_SPLIT) == 0) continue; + + pat = facedata[i].pat; + if (!pat) continue; + + j = a = 0; + for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face); + nl; nl=BMIter_Step(&liter)) { + if (nl->v == facedata[i].start) { + a = j+1; + break; + } + j++; + } + + for (j=0; j<face->len; j++) { + V_GROW(verts); + } + + j = 0; + for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face); + nl; nl=BMIter_Step(&liter)) { + b = (j-a+face->len) % face->len; + verts[b] = nl->v; + j += 1; + } + + pat->connectexec(bmesh, face, verts, ¶ms); + i++; + } + + if (facedata) V_FREE(facedata); + if (edges) V_FREE(edges); + if (verts) V_FREE(verts); + + BMO_Flag_To_Slot(bmesh, op, "outinner", + ELE_INNER, BM_ALL); + BMO_Flag_To_Slot(bmesh, op, "outsplit", + ELE_SPLIT, BM_ALL); +} + +/*editmesh-emulating function*/ +void BM_esubdivideflag(Object *obedit, BMesh *bm, int flag, float smooth, + float fractal, int beauty, int numcuts, int seltype) { + BMOperator op; + + BMO_InitOpf(bm, &op, "esubd edges=%he smooth=%f fractal=%f " + "beauty=%d numcuts=%d", flag, smooth, fractal, + beauty, numcuts); + + BMO_Exec_Op(bm, &op); + + if (seltype == SUBDIV_SELECT_INNER) { + BMOIter iter; + BMHeader *ele; + int i; + + ele = BMO_IterNew(&iter,bm,&op, "outinner", BM_EDGE|BM_VERT); + for (; ele; ele=BMO_IterStep(&iter)) { + BM_Select(bm, ele, 1); + } + } + BMO_Finish_Op(bm, &op); +} + +#if 0 +void BM_esubdivideflag_conv(Object *obedit,EditMesh *em,int selflag, float rad, + int flag, int numcuts, int seltype) { + BMesh *bm = editmesh_to_bmesh(em); + EditMesh *em2; + + BM_esubdivideflag(obedit, bm, selflag, rad, flag, numcuts, seltype); + em2 = bmesh_to_editmesh(bm); + + free_editMesh(em); + *em = *em2; + MEM_freeN(em2); + BM_Free_Mesh(bm); +} +#endif
\ No newline at end of file diff --git a/source/blender/bmesh/operators/subdivideop.h b/source/blender/bmesh/operators/subdivideop.h new file mode 100644 index 00000000000..7bb471117d8 --- /dev/null +++ b/source/blender/bmesh/operators/subdivideop.h @@ -0,0 +1,38 @@ +#ifndef _SUBDIVIDEOP_H +#define _SUBDIVIDEOP_H + +typedef struct subdparams { + int numcuts; + float smooth; + float fractal; + int beauty; + BMOperator *op; +} subdparams; + +typedef void (*subd_pattern_fill_fp)(BMesh *bm, BMFace *face, BMVert **verts, + subdparams *params); + +/* +note: this is a pattern-based edge subdivider. +it tries to match a pattern to edge selections on faces, +then executes functions to cut them. +*/ +typedef struct subdpattern { + int seledges[20]; //selected edges mask, for splitting + + /*verts starts at the first new vert cut, not the first vert in the + face*/ + subd_pattern_fill_fp connectexec; + int len; /*total number of verts, before any subdivision*/ +} subdpattern; + +/*generic subdivision rules: + + * two selected edges in a face should make a link + between them. + + * one edge should do, what? make pretty topology, or just + split the edge only? +*/ + +#endif /* _SUBDIVIDEOP_H */
\ No newline at end of file diff --git a/source/blender/bmesh/operators/triangulateop.c b/source/blender/bmesh/operators/triangulateop.c new file mode 100644 index 00000000000..732a3a85860 --- /dev/null +++ b/source/blender/bmesh/operators/triangulateop.c @@ -0,0 +1,55 @@ +#include "MEM_guardedalloc.h" + +#include "BKE_utildefines.h" + +#include "bmesh.h" +#include "bmesh_private.h" +#include "BLI_arithb.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define EDGE_NEW 1 +#define FACE_NEW 1 + +void triangulate_exec(BMesh *bm, BMOperator *op) +{ + BMOIter siter; + BMFace *face, **newfaces = NULL; + V_DECLARE(newfaces); + float (*projectverts)[3] = NULL; + V_DECLARE(projectverts); + int i, lastlen=0, count = 0; + + face = BMO_IterNew(&siter, bm, op, "faces", BM_FACE); + for (; face; face=BMO_IterStep(&siter)) { + if (lastlen < face->len) { + V_RESET(projectverts); + V_RESET(newfaces); + for (lastlen=0; lastlen<face->len; lastlen++) { + V_GROW(projectverts); + V_GROW(projectverts); + V_GROW(projectverts); + V_GROW(newfaces); + } + } + + BM_Triangulate_Face(bm, face, projectverts, EDGE_NEW, + FACE_NEW, newfaces); + + BMO_Insert_MapPointer(bm, op, "facemap", + face, face); + for (i=0; newfaces[i]; i++) { + BMO_Insert_MapPointer(bm, op, "facemap", + newfaces[i], face); + + } + } + + BMO_Flag_To_Slot(bm, op, "edgeout", EDGE_NEW, BM_EDGE); + BMO_Flag_To_Slot(bm, op, "faceout", FACE_NEW, BM_FACE); + + V_FREE(projectverts); + V_FREE(newfaces); +}
\ No newline at end of file diff --git a/source/blender/bmesh/operators/utils.c b/source/blender/bmesh/operators/utils.c new file mode 100644 index 00000000000..77e0b7083e2 --- /dev/null +++ b/source/blender/bmesh/operators/utils.c @@ -0,0 +1,91 @@ + +#include "MEM_guardedalloc.h" +#include "BKE_customdata.h" +#include "DNA_listBase.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 <string.h> +#include "BKE_utildefines.h" +#include "BKE_mesh.h" +#include "BKE_global.h" +#include "BKE_DerivedMesh.h" +#include "BKE_cdderivedmesh.h" + +#include "BLI_editVert.h" +#include "mesh_intern.h" +#include "ED_mesh.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_edgehash.h" + +#include "bmesh.h" + +/* + * UTILS.C + * + * utility bmesh operators, e.g. transform, + * translate, rotate, scale, etc. + * +*/ + +void bmesh_makevert_exec(BMesh *bm, BMOperator *op) { + float vec[3]; + + BMO_Get_Vec(op, "co", vec); + + BMO_SetFlag(bm, BM_Make_Vert(bm, vec, NULL), 1); + BMO_Flag_To_Slot(bm, op, "newvertout", 1, BM_VERT); +} + +void bmesh_transform_exec(BMesh *bm, BMOperator *op) { + BMOIter iter; + BMVert *v; + float mat[4][4]; + + BMO_Get_Mat4(op, "mat", mat); + + BMO_ITER(v, &iter, bm, op, "verts", BM_VERT) { + Mat4MulVecfl(mat, v->co); + } +} + +/*this operator calls the transform operator, which + is a little complex, but makes it easier to make + sure the transform op is working, since initially + only this one will be used.*/ +void bmesh_translate_exec(BMesh *bm, BMOperator *op) { + BMOIter iter; + BMVert *v; + float mat[4][4], vec[3]; + + BMO_Get_Vec(op, "vec", vec); + + Mat4One(mat); + VECCOPY(mat[3], vec); + + BMO_CallOpf(bm, "transform mat=%m4 verts=%s", mat, op, "verts"); +} + +void bmesh_rotate_exec(BMesh *bm, BMOperator *op) { + BMOIter iter; + BMVert *v; + float mat[4][4], vec[3]; + + BMO_Get_Vec(op, "cent", vec); + + /*there has to be a proper matrix way to do this, but + this is how editmesh did it and I'm too tired to think + through the math right now.*/ + VecMulf(vec, -1); + BMO_CallOpf(bm, "translate verts=%s vec=%v", op, "verts", vec); + + BMO_CallOpf(bm, "transform mat=%s verts=%s", op, "mat", op, "verts"); + + VecMulf(vec, -1); + BMO_CallOpf(bm, "translate verts=%s vec=%v", op, "verts", vec); +} + diff --git a/source/blender/bmesh/tools/BME_bevel.c b/source/blender/bmesh/tools/BME_bevel.c new file mode 100644 index 00000000000..543d64b6131 --- /dev/null +++ b/source/blender/bmesh/tools/BME_bevel.c @@ -0,0 +1,918 @@ +/** + * BME_tools.c jan 2007 + * + * Functions for changing the topology of a mesh. + * + * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $ + * + * ***** 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) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Geoffrey Bantle and Levi Schooley. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_meshdata_types.h" +#include "DNA_mesh_types.h" + +#include "BKE_utildefines.h" +#include "BKE_bmesh.h" +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "MTC_matrixops.h" +#include "MTC_vectorops.h" + +#include "blendef.h" + +/* ------- Bevel code starts here -------- */ + +BME_TransData_Head *BME_init_transdata(int bufsize) { + BME_TransData_Head *td; + + td = MEM_callocN(sizeof(BME_TransData_Head), "BM transdata header"); + td->gh = BLI_ghash_new(BLI_ghashutil_ptrhash,BLI_ghashutil_ptrcmp); + td->ma = BLI_memarena_new(bufsize); + BLI_memarena_use_calloc(td->ma); + + return td; +} + +void BME_free_transdata(BME_TransData_Head *td) { + BLI_ghash_free(td->gh,NULL,NULL); + BLI_memarena_free(td->ma); + MEM_freeN(td); +} + +BME_TransData *BME_assign_transdata(BME_TransData_Head *td, BMesh *bm, BMVert *v, + float *co, float *org, float *vec, float *loc, + float factor, float weight, float maxfactor, float *max) { + BME_TransData *vtd; + int is_new = 0; + + if (v == NULL) return NULL; + + if ((vtd = BLI_ghash_lookup(td->gh, v)) == NULL && bm != NULL) { + vtd = BLI_memarena_alloc(td->ma, sizeof(*vtd)); + BLI_ghash_insert(td->gh, v, vtd); + td->len++; + is_new = 1; + } + + vtd->bm = bm; + vtd->v = v; + if (co != NULL) VECCOPY(vtd->co,co); + if (org == NULL && is_new) { VECCOPY(vtd->org,v->co); } /* default */ + else if (org != NULL) VECCOPY(vtd->org,org); + if (vec != NULL) { + VECCOPY(vtd->vec,vec); + Normalize(vtd->vec); + } + vtd->loc = loc; + + vtd->factor = factor; + vtd->weight = weight; + vtd->maxfactor = maxfactor; + vtd->max = max; + + return vtd; +} + +BME_TransData *BME_get_transdata(BME_TransData_Head *td, BMVert *v) { + BME_TransData *vtd; + vtd = BLI_ghash_lookup(td->gh, v); + return vtd; +} + +/* a hack (?) to use the transdata memarena to allocate floats for use with the max limits */ +float *BME_new_transdata_float(BME_TransData_Head *td) { + return BLI_memarena_alloc(td->ma, sizeof(float)); +} + +static int BME_bevel_is_split_vert(BMLoop *l) { + /* look for verts that have already been added to the edge when + * beveling other polys; this can be determined by testing the + * vert and the edges around it for originality + */ + if ((l->v->tflag1 & BME_BEVEL_ORIG)==0 + && (l->e->tflag1 & BME_BEVEL_ORIG) + && (l->prev->e->tflag1 & BME_BEVEL_ORIG)) + { + return 1; + } + return 0; +} + +/* get a vector, vec, that points from v1->co to wherever makes sense to + * the bevel operation as a whole based on the relationship between v1 and v2 + * (won't necessarily be a vec from v1->co to v2->co, though it probably will be); + * the return value is -1 for failure, 0 if we used vert co's, and 1 if we used transform origins */ +static int BME_bevel_get_vec(float *vec, BMVert *v1, BMVert *v2, BME_TransData_Head *td) { + BME_TransData *vtd1, *vtd2; + + vtd1 = BME_get_transdata(td,v1); + vtd2 = BME_get_transdata(td,v2); + if (!vtd1 || !vtd2) { + //printf("BME_bevel_get_vec() got called without proper BME_TransData\n"); + return -1; + } + + /* compare the transform origins to see if we can use the vert co's; + * if they belong to different origins, then we will use the origins to determine + * the vector */ + if (VecCompare(vtd1->org,vtd2->org,0.000001f)) { + VECSUB(vec,v2->co,v1->co); + if (VecLength(vec) < 0.000001f) { + VecMulf(vec,0); + } + return 0; + } + else { + VECSUB(vec,vtd2->org,vtd1->org); + if (VecLength(vec) < 0.000001f) { + VecMulf(vec,0); + } + return 1; + } +} + +/* "Projects" a vector perpendicular to vec2 against vec1, such that + * the projected vec1 + vec2 has a min distance of 1 from the "edge" defined by vec2. + * note: the direction, is_forward, is used in conjunction with up_vec to determine + * whether this is a convex or concave corner. If it is a concave corner, it will + * be projected "backwards." If vec1 is before vec2, is_forward should be 0 (we are projecting backwards). + * vec1 is the vector to project onto (expected to be normalized) + * vec2 is the direction of projection (pointing away from vec1) + * up_vec is used for orientation (expected to be normalized) + * returns the length of the projected vector that lies along vec1 */ +static float BME_bevel_project_vec(float *vec1, float *vec2, float *up_vec, int is_forward, BME_TransData_Head *td) { + float factor, vec3[3], tmp[3],c1,c2; + + Crossf(tmp,vec1,vec2); + Normalize(tmp); + factor = Inpf(up_vec,tmp); + if ((factor > 0 && is_forward) || (factor < 0 && !is_forward)) { + Crossf(vec3,vec2,tmp); /* hmm, maybe up_vec should be used instead of tmp */ + } + else { + Crossf(vec3,tmp,vec2); /* hmm, maybe up_vec should be used instead of tmp */ + } + Normalize(vec3); + c1 = Inpf(vec3,vec1); + c2 = Inpf(vec1,vec1); + if (fabs(c1) < 0.000001f || fabs(c2) < 0.000001f) { + factor = 0.0f; + } + else { + factor = c2/c1; + } + + return factor; +} + +/* BME_bevel_split_edge() is the main math work-house; its responsibilities are: + * using the vert and the loop passed, get or make the split vert, set its coordinates + * and transform properties, and set the max limits. + * Finally, return the split vert. */ +static BMVert *BME_bevel_split_edge(BMesh *bm, BMVert *v, BMVert *v1, BMLoop *l, float *up_vec, float value, BME_TransData_Head *td) { + BME_TransData *vtd, *vtd1, *vtd2; + BMVert *sv, *v2, *v3, *ov; + BMLoop *lv1, *lv2; + BMEdge *ne, *e1, *e2; + float maxfactor, scale, len, dis, vec1[3], vec2[3], t_up_vec[3]; + int is_edge, forward, is_split_vert; + + if (l == NULL) { + /* what you call operator overloading in C :) + * I wanted to use the same function for both wire edges and poly loops + * so... here we walk around edges to find the needed verts */ + forward = 1; + is_split_vert = 0; + if (v->edge == NULL) { + //printf("We can't split a loose vert's edge!\n"); + return NULL; + } + e1 = v->edge; /* we just use the first two edges */ + e2 = bmesh_disk_nextedge(v->edge, v); + if (e1 == e2) { + //printf("You need at least two edges to use BME_bevel_split_edge()\n"); + return NULL; + } + v2 = BM_OtherEdgeVert(e1, v); + v3 = BM_OtherEdgeVert(e2, v); + if (v1 != v2 && v1 != v3) { + //printf("Error: more than 2 edges in v's disk cycle, or v1 does not share an edge with v\n"); + return NULL; + } + if (v1 == v2) { + v2 = v3; + } + else { + e1 = e2; + } + ov = BM_OtherEdgeVert(e1,v); + sv = BM_Split_Edge(bm,v,e1,&ne,0); + //BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/ + //BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25); + //BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25); + BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */ + sv->tflag1 |= BME_BEVEL_BEVEL; + ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */ + BME_bevel_get_vec(vec1,v1,v,td); + BME_bevel_get_vec(vec2,v2,v,td); + Crossf(t_up_vec,vec1,vec2); + Normalize(t_up_vec); + up_vec = t_up_vec; + } + else { + /* establish loop direction */ + if (l->v == v) { + forward = 1; + lv1 = l->next; + lv2 = l->prev; + v1 = l->next->v; + v2 = l->prev->v; + } + else if (l->next->v == v) { + forward = 0; + lv1 = l; + lv2 = l->next->next; + v1 = l->v; + v2 = l->next->next->v; + } + else { + //printf("ERROR: BME_bevel_split_edge() - v must be adjacent to l\n"); + return NULL; + } + + if (BME_bevel_is_split_vert(lv1)) { + is_split_vert = 1; + sv = v1; + if (forward) v1 = l->next->next->v; + else v1 = l->prev->v; + } + else { + is_split_vert = 0; + ov = BM_OtherEdgeVert(l->e,v); + sv = BM_Split_Edge(bm,v,l->e,&ne,0); + //BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/ + //BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25); + //BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25); + BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */ + sv->tflag1 |= BME_BEVEL_BEVEL; + ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */ + } + + if (BME_bevel_is_split_vert(lv2)) { + if (forward) v2 = lv2->prev->v; + else v2 = lv2->next->v; + } + } + + is_edge = BME_bevel_get_vec(vec1,v,v1,td); /* get the vector we will be projecting onto */ + BME_bevel_get_vec(vec2,v,v2,td); /* get the vector we will be projecting parallel to */ + len = VecLength(vec1); + Normalize(vec1); + + vtd = BME_get_transdata(td, sv); + vtd1 = BME_get_transdata(td, v); + vtd2 = BME_get_transdata(td,v1); + + if (vtd1->loc == NULL) { + /* this is a vert with data only for calculating initial weights */ + if (vtd1->weight < 0) { + vtd1->weight = 0; + } + scale = vtd1->weight/vtd1->factor; + if (!vtd1->max) { + vtd1->max = BME_new_transdata_float(td); + *vtd1->max = -1; + } + } + else { + scale = vtd1->weight; + } + vtd->max = vtd1->max; + + if (is_edge && vtd1->loc != NULL) { + maxfactor = vtd1->maxfactor; + } + else { + maxfactor = scale*BME_bevel_project_vec(vec1,vec2,up_vec,forward,td); + if (vtd->maxfactor > 0 && vtd->maxfactor < maxfactor) { + maxfactor = vtd->maxfactor; + } + } + + dis = (v1->tflag1 & BME_BEVEL_ORIG)? len/3 : len/2; + if (is_edge || dis > maxfactor*value) { + dis = maxfactor*value; + } + VECADDFAC(sv->co,v->co,vec1,dis); + VECSUB(vec1,sv->co,vtd1->org); + dis = VecLength(vec1); + Normalize(vec1); + BME_assign_transdata(td, bm, sv, vtd1->org, vtd1->org, vec1, sv->co, dis, scale, maxfactor, vtd->max); + + return sv; +} + +static float BME_bevel_set_max(BMVert *v1, BMVert *v2, float value, BME_TransData_Head *td) { + BME_TransData *vtd1, *vtd2; + float max, fac1, fac2, vec1[3], vec2[3], vec3[3]; + + BME_bevel_get_vec(vec1,v1,v2,td); + vtd1 = BME_get_transdata(td,v1); + vtd2 = BME_get_transdata(td,v2); + + if (vtd1->loc == NULL) { + fac1 = 0; + } + else { + VECCOPY(vec2,vtd1->vec); + VecMulf(vec2,vtd1->factor); + if (Inpf(vec1, vec1)) { + Projf(vec2,vec2,vec1); + fac1 = VecLength(vec2)/value; + } + else { + fac1 = 0; + } + } + + if (vtd2->loc == NULL) { + fac2 = 0; + } + else { + VECCOPY(vec3,vtd2->vec); + VecMulf(vec3,vtd2->factor); + if (Inpf(vec1, vec1)) { + Projf(vec2,vec3,vec1); + fac2 = VecLength(vec2)/value; + } + else { + fac2 = 0; + } + } + + if (fac1 || fac2) { + max = VecLength(vec1)/(fac1 + fac2); + if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) { + *vtd1->max = max; + } + if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) { + *vtd2->max = max; + } + } + else { + max = -1; + } + + return max; +} + +static BMVert *BME_bevel_wire(BMesh *bm, BMVert *v, float value, int res, int options, BME_TransData_Head *td) { + BMVert *ov1, *ov2, *v1, *v2; + + ov1 = BM_OtherEdgeVert(v->edge, v); + ov2 = BM_OtherEdgeVert(bmesh_disk_nextedge(v->edge, v), v); + + /* split the edges */ + v1 = BME_bevel_split_edge(bm,v,ov1,NULL,NULL,value,td); + v1->tflag1 |= BME_BEVEL_NONMAN; + v2 = BME_bevel_split_edge(bm,v,ov2,NULL,NULL,value,td); + v2->tflag1 |= BME_BEVEL_NONMAN; + + if (value > 0.5) { + BME_bevel_set_max(v1,ov1,value,td); + BME_bevel_set_max(v2,ov2,value,td); + } + + /* remove the original vert */ + if (res) { + bmesh_jekv; + + //void BM_Collapse_Vert(BMesh *bm, BMEdge *ke, BMVert *kv, float fac, int calcnorm){ + //hrm, why is there a fac here? it just removes a vert + BM_Collapse_Vert(bm, v->edge, v, 1.0, 0); + //bmesh_jekv(bm,v->edge,v); + } + + return v1; +} + +static BMLoop *BME_bevel_edge(BMesh *bm, BMLoop *l, float value, int options, float *up_vec, BME_TransData_Head *td) { + BMVert *v1, *v2, *kv; + BMLoop *kl=NULL, *nl; + BMEdge *e; + BMFace *f; + + f = l->f; + e = l->e; + + if ((l->e->tflag1 & BME_BEVEL_BEVEL) == 0 + && ((l->v->tflag1 & BME_BEVEL_BEVEL) || (l->next->v->tflag1 & BME_BEVEL_BEVEL))) + { /* sanity check */ + return l; + } + + /* checks and operations for prev edge */ + /* first, check to see if this edge was inset previously */ + if ((l->prev->e->tflag1 & BME_BEVEL_ORIG) == 0 + && (l->v->tflag1 & BME_BEVEL_NONMAN) == 0) { + kl = l->prev->radial.next->data; + if (kl->v == l->v) kl = kl->prev; + else kl = kl->next; + kv = l->v; + } + else { + kv = NULL; + } + /* get/make the first vert to be used in SFME */ + if (l->v->tflag1 & BME_BEVEL_NONMAN){ + v1 = l->v; + } + else { /* we'll need to split the previous edge */ + v1 = BME_bevel_split_edge(bm,l->v,NULL,l->prev,up_vec,value,td); + } + /* if we need to clean up geometry... */ + if (kv) { + l = l->next; + if (kl->v == kv) { + BM_Split_Face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e); + bmesh_jfke(bm,((BMLoop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e); + BM_Collapse_Vert(bm, kl->e, kv, 1.0); + //BME_JEKV(bm,kl->e,kv); + + } + else { + BM_Split_Face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e); + bmesh_jfke(bm,((BMLoop*)kl->next->radial.next->data)->f,kl->f,kl->next->e); + BM_Collapse_Vert(bm, kl->e, kv, 1.0); + //BME_JEKV(bm,kl->e,kv); + } + l = l->prev; + } + + /* checks and operations for the next edge */ + /* first, check to see if this edge was inset previously */ + if ((l->next->e->tflag1 & BME_BEVEL_ORIG) == 0 + && (l->next->v->tflag1 & BME_BEVEL_NONMAN) == 0) { + kl = l->next->radial.next->data; + if (kl->v == l->next->v) kl = kl->prev; + else kl = kl->next; + kv = l->next->v; + } + else { + kv = NULL; + } + /* get/make the second vert to be used in SFME */ + if (l->next->v->tflag1 & BME_BEVEL_NONMAN) { + v2 = l->next->v; + } + else { /* we'll need to split the next edge */ + v2 = BME_bevel_split_edge(bm,l->next->v,NULL,l->next,up_vec,value,td); + } + /* if we need to clean up geometry... */ + if (kv) { + if (kl->v == kv) { + BM_Split_Face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e); + bmesh_jfke(bm,((BMLoop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e); + BM_Collapse_Vert(bm, kl->e, kv, 1.0); + //BME_JEKV(bm,kl->e,kv); + } + else { + BM_Split_Face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e); + bmesh_jfke(bm,((BMLoop*)kl->next->radial.next->data)->f,kl->f,kl->next->e); + BM_Collapse_Vert(bm, kl->e, kv, 1.0); + //BME_JEKV(bm,kl->e,kv); + } + } + + if ((v1->tflag1 & BME_BEVEL_NONMAN)==0 || (v2->tflag1 & BME_BEVEL_NONMAN)==0) { + BM_Split_Face(bm,f,v2,v1,&l,e); + l->e->tflag1 = BME_BEVEL_BEVEL; + l = l->radial.next->data; + } + + if (l->f != f){ + //printf("Whoops! You got something out of order in BME_bevel_edge()!\n"); + } + + return l; +} + +static BMLoop *BME_bevel_vert(BMesh *bm, BMLoop *l, float value, int options, float *up_vec, BME_TransData_Head *td) { + BMVert *v1, *v2; + BMFace *f; + + /* get/make the first vert to be used in SFME */ + /* may need to split the previous edge */ + v1 = BME_bevel_split_edge(bm,l->v,NULL,l->prev,up_vec,value,td); + + /* get/make the second vert to be used in SFME */ + /* may need to split this edge (so move l) */ + l = l->prev; + v2 = BME_bevel_split_edge(bm,l->next->v,NULL,l->next,up_vec,value,td); + l = l->next->next; + + /* "cut off" this corner */ + f = BM_Split_Face(bm,l->f,v2,v1,NULL,l->e); + + return l; +} + +/** + * BME_bevel_poly + * + * Polygon inset tool: + * + * Insets a polygon/face based on the tflag1's of its vertices + * and edges. Used by the bevel tool only, for now. + * The parameter "value" is the distance to inset (should be negative). + * The parameter "options" is not currently used. + * + * Returns - + * A BMFace pointer to the resulting inner face. +*/ +static BMFace *BME_bevel_poly(BMesh *bm, BMFace *f, float value, int options, BME_TransData_Head *td) { + BMLoop *l, *ol; + BME_TransData *vtd1, *vtd2; + float up_vec[3], vec1[3], vec2[3], vec3[3], fac1, fac2, max = -1; + int len, i; + + up_vec[0] = 0.0f; + up_vec[1] = 0.0f; + up_vec[2] = 0.0f; + /* find a good normal for this face (there's better ways, I'm sure) */ + ol = f->loopbase; + l = ol->next; + for (i=0,ol=f->loopbase,l=ol->next; l->next!=ol; l=l->next) { + BME_bevel_get_vec(vec1,l->next->v,ol->v,td); + BME_bevel_get_vec(vec2,l->v,ol->v,td); + Crossf(vec3,vec2,vec1); + VECADD(up_vec,up_vec,vec3); + i++; + } + VecMulf(up_vec,1.0f/i); + Normalize(up_vec); + + for (i=0,len=f->len; i<len; i++,l=l->next) { + if ((l->e->tflag1 & BME_BEVEL_BEVEL) && (l->e->tflag1 & BME_BEVEL_ORIG)) { + max = 1.0f; + l = BME_bevel_edge(bm, l, value, options, up_vec, td); + } + + else if ((l->v->tflag1 & BME_BEVEL_BEVEL) && (l->v->tflag1 & BME_BEVEL_ORIG) && (l->prev->e->tflag1 & BME_BEVEL_BEVEL) == 0) { + max = 1.0f; + l = BME_bevel_vert(bm, l, value, options, up_vec, td); + } + } + + /* max pass */ + if (value > 0.5 && max > 0) { + max = -1; + for (i=0,len=f->len; i<len; i++,l=l->next) { + if ((l->e->tflag1 & BME_BEVEL_BEVEL) || (l->e->tflag1 & BME_BEVEL_ORIG)) { + BME_bevel_get_vec(vec1,l->v,l->next->v,td); + vtd1 = BME_get_transdata(td,l->v); + vtd2 = BME_get_transdata(td,l->next->v); + if (vtd1->loc == NULL) { + fac1 = 0; + } + else { + VECCOPY(vec2,vtd1->vec); + VecMulf(vec2,vtd1->factor); + if (Inpf(vec1, vec1)) { + Projf(vec2,vec2,vec1); + fac1 = VecLength(vec2)/value; + } + else { + fac1 = 0; + } + } + if (vtd2->loc == NULL) { + fac2 = 0; + } + else { + VECCOPY(vec3,vtd2->vec); + VecMulf(vec3,vtd2->factor); + if (Inpf(vec1, vec1)) { + Projf(vec2,vec3,vec1); + fac2 = VecLength(vec2)/value; + } + else { + fac2 = 0; + } + } + if (fac1 || fac2) { + max = VecLength(vec1)/(fac1 + fac2); + if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) { + *vtd1->max = max; + } + if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) { + *vtd2->max = max; + } + } + } + } + } + + return l->f; +} + +static void BME_bevel_add_vweight(BME_TransData_Head *td, BMesh *bm, BMVert *v, float weight, float factor, int options) { + BME_TransData *vtd; + + if (v->tflag1 & BME_BEVEL_NONMAN) return; + v->tflag1 |= BME_BEVEL_BEVEL; + if ( (vtd = BME_get_transdata(td, v)) ) { + if (options & BME_BEVEL_EMIN) { + vtd->factor = 1.0; + if (vtd->weight < 0 || weight < vtd->weight) { + vtd->weight = weight; + } + } + else if (options & BME_BEVEL_EMAX) { + vtd->factor = 1.0; + if (weight > vtd->weight) { + vtd->weight = weight; + } + } + else if (vtd->weight < 0) { + vtd->factor = factor; + vtd->weight = weight; + } + else { + vtd->factor += factor; /* increment number of edges with weights (will be averaged) */ + vtd->weight += weight; /* accumulate all the weights */ + } + } + else { + /* we'll use vtd->loc == NULL to mark that this vert is not moving */ + vtd = BME_assign_transdata(td, bm, v, v->co, NULL, NULL, NULL, factor, weight, -1, NULL); + } +} + + +static bevel_init_verts(BMesh *bm, int options, BME_TransData_Head *td){ + BMVert *v; + float weight; + for(v=bm->verts.first; v; v=v->next){ + weight = 0.0; + if(!(v->tflag1 & BME_BEVEL_NONMAN)){ + if(options & BME_BEVEL_SELECT){ + if(v->flag & SELECT) weight = 1.0; + } + else if(options & BME_BEVEL_WEIGHT) weight = v->bweight; + else weight = 1.0; + if(weight > 0.0){ + v->tflag1 |= BME_BEVEL_BEVEL; + BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0,weight, -1, NULL); + } + } + } +} +static bevel_init_edges(BMesh *bm, int options, BME_TransData_Head *td){ + BMEdge *e; + int count; + float weight; + for( e = BM_first_element(bm, BME_EDGE); e; e = BM_next_element(bm, BME_EDGE, e)){ + weight = 0.0; + if(!(e->tflag1 & BME_BEVEL_NONMAN)){ + if(options & BME_BEVEL_SELECT){ + if(e->flag & SELECT) weight = 1.0; + } + else if(options & BME_BEVEL_WEIGHT){ + weight = e->bweight; + } + else{ + weight = 1.0; + } + if(weight > 0.0){ + e->tflag1 |= BME_BEVEL_BEVEL; + e->v1->tflag1 |= BME_BEVEL_BEVEL; + e->v2->tflag1 |= BME_BEVEL_BEVEL; + BME_bevel_add_vweight(td, bm, e->v1, weight, 1.0, options); + BME_bevel_add_vweight(td, bm, e->v2, weight, 1.0, options); + } + } + } + + /*clean up edges with 2 faces that share more than one edge*/ + for( e = BM_first_element(bm, BME_EDGE); e; e = BM_next_element(bm, BME_EDGE, e)){ + if(e->tflag1 & BME_BEVEL_BEVEL){ + count = BM_face_sharededges(e->loop->f, ((BMLoop*)e->loop->radial.next->data)->f); + if(count > 1) e->tflag1 &= ~BME_BEVEL_BEVEL; + } + } +} +static BMesh *BME_bevel_initialize(BMesh *bm, int options, int defgrp_index, float angle, BME_TransData_Head *td){ + + BMVert *v, *v2; + BMEdge *e, *curedge; + BMFace *f; + BMIter iter; + int wire, len; + + for (v = BMIter_New(&iter, bm, BM_VERTS, nm); v; v = BMIter_Step(&iter)) v->tflag1 = 0; + for (e = BMIter_New(&iter, bm, BM_EDGES, nm); e; e = BMIter_Step(&iter)) e->tflag1 = 0; + for (f = BMIter_New(&iter, bm, BM_FACES, nm); f; f = BMIter_Step(&iter)) f->tflag1 = 0; + + /*tag non-manifold geometry*/ + for (v = BMIter_New(&iter, bm, BM_VERTS, nm); v; v = BMIter_Step(&iter)) { + v->tflag1 = BME_BEVEL_ORIG; + if(v->edge){ + BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 0, -1, -1, NULL); + if (BM_Nonmanifold_Vert(bm,v)) v->tflag1 |= BME_BEVEL_NONMAN; + /*test wire vert*/ + len = bmesh_cycle_length(bmesh_disk_getpointer(v->edge,v)); + if(len == 2 && BME_wirevert(bm, v)) v->tflag1 &= ~BME_BEVEL_NONMAN; + }else v->tflag1 |= BME_BEVEL_NONMAN; + } + + for (e = BMIter_New(&iter, bm, BM_EDGES, nm); e; e = BMIter_Step(&iter)) { + e->tflag1 = BME_BEVEL_ORIG; + if (e->loop == NULL || BME_cycle_length(&(e->loop->radial)) > 2){ + e->v1->tflag1 |= BME_BEVEL_NONMAN; + e->v2->tflag1 |= BME_BEVEL_NONMAN; + e->tflag1 |= BME_BEVEL_NONMAN; + } + if((e->v1->tflag1 & BME_BEVEL_NONMAN) || (e->v2->tflag1 & BME_BEVEL_NONMAN)) e->tflag1 |= BME_BEVEL_NONMAN; + } + + for (f = BMIter_New(&iter, bm, BM_FACES, nm); f; f = BMIter_Step(&iter)) + f->tflag1 = BME_BEVEL_ORIG; + if(options & BME_BEVEL_VERT) bevel_init_verts(bm, options, td); + else bevel_init_edges(bm, options, td); + return bm; + +} +static BMesh *BME_bevel_reinitialize(BMesh *bm) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + for (v = BMIter_New(bm, BM_VERTS, NULL); v; v = BMIter_Step(bm)){ + v->tflag1 |= BME_BEVEL_ORIG; + v->tflag2 = 0; + } + for (e = BMIter_New(bm, BM_EDGES, NULL); e; e = BMIter_Step(bm)){ + e->tflag1 |= BME_BEVEL_ORIG; + } + for (f = BMIter_New(bm, BM_FACES, NULL); f; f = BMIter_Step(bm)){ + f->tflag1 |= BME_BEVEL_ORIG; + } + return bm; + +} + +/** + * BME_bevel_mesh + * + * Mesh beveling tool: + * + * Bevels an entire mesh. It currently uses the tflag1's of + * its vertices and edges to track topological changes. + * The parameter "value" is the distance to inset (should be negative). + * The parameter "options" is not currently used. + * + * Returns - + * A BMesh pointer to the BM passed as a parameter. +*/ + +static BMMesh *BME_bevel_mesh(BMMesh *bm, float value, int res, int options, int defgrp_index, BME_TransData_Head *td) { + BMVert *v, *nv; + BMEdge *e, *curedge, *ne; + BMLoop *l, *l2; + BMFace *f, *nf; + + BMeshIter verts; + BMeshIter edges; + BMeshIter loops; + BMeshIter faces; + + unsigned int i, len; + + /*bevel polys*/ + for(f = BMeshIter_init(faces, BM_FACES, bm, 0); f; f = BMeshIter_step(faces)){ + if(bmesh_test_flag(f, BME_BEVEL_ORIG){ + bevel_poly(bm,f,value,options,td); + } + } + /*get rid of beveled edges*/ + for(e = BMeshIter_init(edges, BM_EDGES, bm, 0); e;){ + ne = BMeshIter_step(edges); + if( bmesh_test_flag(e, BME_BEVEL_BEVEL) && bmesh_test_flag(e, BME_BEVEL_ORIG) ) bmesh_join_faces(bm, e->loop->f, ((BMLoop*)e->loop->radial.next->data)->f, e, 1); + e = ne; + } + /*link up corners and clip*/ + for(v = BMeshIter_init(verts, BM_VERTS, bm, 0); v;){ + nv = BMeshIter_step(verts) + if( bmesh_test_flag(v, BME_BEVEL_ORIG) && bmesh_test_flag(v, BME_BEVEL_BEVEL)){ + curedge = v->edge; + do{ + l = curedge->loop; + l2 = l->radial.next->data; + if(l->v != v) l = l->next; + if(l2->v != v) l2 = l2->next; + if(l->f->len > 3) BM_split_face(bm,l->f,l->next->v,l->prev->v,&l,l->e); /* clip this corner off */ + if(l2->f->len > 3) BM_split_face(bm,l2->f,l2->next->v,l2->prev->v,&l,l2->e); /* clip this corner off */ + curedge = BM_edge_of_vert(curedge, v); + }while(curedge != v->edge); + BM_dissolve_disk(bm,v); + } + v = nv; + } + + /*Debug print, remove*/ + for(f = BMeshIter_init(faces, BM_FACES, bm, 0); f;){ + if(f->len == 2){ + printf("warning"); + } + } + + return bm; +} + +BMesh *BME_bevel(BMMesh *bm, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd) { + BMVert *v; + BMEdge *e; + BMIter *verts; + + BME_TransData_Head *td; + BME_TransData *vtd; + int i; + double fac=1, d; + + + td = BME_init_transdata(BLI_MEMARENA_STD_BUFSIZE); + /* recursion math courtesy of Martin Poirier (theeth) */ + for (i=0; i<res-1; i++) { + if (i==0) fac += 1.0f/3.0f; else fac += 1.0f/(3 * i * 2.0f); + } + d = 1.0f/fac; + + + for (i=0; i<res || (res==0 && i==0); i++) { + BME_bevel_initialize(bm, options, defgrp_index, angle, td); + //if (i != 0) BME_bevel_reinitialize(bm); + bmesh_begin_edit(bm); + BME_bevel_mesh(bm,(float)d,res,options,defgrp_index,td); + bmesh_end_edit(bm); + if (i==0) d /= 3; else d /= 2; + } + + BME_model_begin(bm); + BME_tesselate(bm); + BME_model_end(bm); + + + /*interactive preview?*/ + if (rtd) { + *rtd = td; + return bm; + } + + /* otherwise apply transforms */ + for( v = BMeshIter_init(verts); v; v = BMeshIter_step(verts)){ + if ( (vtd = BME_get_transdata(td, v)) ) { + if (vtd->max && (*vtd->max > 0 && value > *vtd->max)) { + d = *vtd->max; + } + else { + d = value; + } + VECADDFAC(v->co,vtd->org,vtd->vec,vtd->factor*d); + } + v->tflag1 = 0; + } + + BME_free_transdata(td); + return bm; +} diff --git a/source/blender/bmesh/tools/BME_dupe_ops.c b/source/blender/bmesh/tools/BME_dupe_ops.c new file mode 100644 index 00000000000..533e278ea68 --- /dev/null +++ b/source/blender/bmesh/tools/BME_dupe_ops.c @@ -0,0 +1,318 @@ +/* + * BME_DUPLICATE.C + * + * This file contains functions for duplicating, copying, and splitting + * elements from a bmesh. + * + */ + +/* + * COPY VERTEX + * + * Copy an existing vertex from one bmesh to another. + * +*/ + +static BMVert *copy_vertex(BMMesh *source_mesh, BMVert *source_vertex, BMMesh *target_mesh, GHash *vhash) +{ + BMVert *target_vertex = NULL; + + /*create a new vertex*/ + target_vertex = BM_Make_Vert(target, source_vertex->co, NULL); + + /*insert new vertex into the vert hash*/ + BLI_ghash_insert(vhash, source_vertex, target_vertex); + + /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/ + CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->data, &target_vertex->data); + + /*Copy Markings*/ + if(BM_Is_Selected((BMHeader*)source_vertex)) BM_Select_Vert(target_mesh, target_vertex, 1); + if(BM_Is_Hidden((BMHeader*)source_vertex)) BM_Mark_Hidden((BMHeader*)target_vertex, 1); + + BMO_SetFlag(target_mesh, (BMHeader*)target_vertex, DUPE_NEW); + + return target_vertex; +} + +/* + * COPY EDGE + * + * Copy an existing edge from one bmesh to another. + * +*/ + +static BMEdge *copy_edge(BMMesh *source_mesh, BMEdge *source_edge, BMMesh *target_mesh, GHash *vhash, GHash *ehash) +{ + BMEdge *target_edge = NULL; + BMVert *target_vert1, *target_vert2; + + /*lookup v1 and v2*/ + target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1); + target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2); + + /*create a new edge*/ + target_edge = BM_Make_Edge(target_mesh, target_vert1, target_vert2, NULL, 0); + + /*insert new edge into the edge hash*/ + BLI_ghash_insert(ehash, source_edge, target_edge); + + /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/ + CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->data, &target_edge->data); + + /*copy flags*/ + if(BM_Is_Selected((BMHeader*) source_edge)) BM_Select_Edge(target_mesh, target_edge, 1); + if(BM_Is_Hidden((BMHeader*) source_edge)) BM_Mark_Hidden(target_mesh, target_edge, 1); + if(BM_Is_Sharp((BMHeader*) source_edge)) BM_Mark_Sharp(target_edge, 1); + if(BM_Is_Seam((BMHeader*) source_edge)) BM_Mark_Seam(target_edge, 1); + if(BM_Is_Fgon((BMHeader*) source_edge)) BM_Mark_Fgon(target_edge, 1); + + BMO_SetFlag(target_mesh, (BMHeader*)target_edge, DUPE_NEW); + + return target_edge; +} + +/* + * COPY FACE + * + * Copy an existing face from one bmesh to another. + * +*/ + +static BMFace *copy_face(BMMesh *source_mesh, BMFace *source_face, BMMesh *target_mesh, BMEdge **edar, GHash *verthash, GHash *ehash) +{ + BMEdge *target_edge; + BMVert *target_vert1, *target_vert2; + BMLoop *source_loop, *target_loop; + BMFace *target_face = NULL; + int i; + + /*lookup the first and second verts*/ + target_vert1 = BLI_ghash_lookup(vhash, source_face->loopbase->v); + target_vert2 = BLI_ghash_lookup(vhash, source_face->loopbase->next->v); + + /*lookup edges*/ + i = 0; + source_loop = source_face->loopbase; + do{ + edar[i] = BLI_ghash_lookup(ehash, source_loop->e); + i++; + source_loop = source_loop->next; + }while(source_loop != source_face->loopbase); + + /*create new face*/ + target_face = BM_Make_Ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0); + + /*we copy custom data by hand, we cannot assume that customdata byte layout will be exactly the same....*/ + CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->data, &target_face->data); + + /*copy flags*/ + if(BM_Is_Selected((BMHeader*)source_face)) BM_Select_face(target, target_face, 1); + if(BM_Is_Hidden((BMHeader*)source_face)) BM_Mark_Hidden((BMHeader*)target_face, 1); + + /*mark the face for output*/ + BMO_SetFlag(target_mesh, (BMHeader*)target_face, DUPE_NEW); + + /*copy per-loop custom data*/ + source_loop = source_face->loopbase; + target_loop = target_face->loopbase; + do{ + CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->data, &target_loop->data); + source_loop = source_loop->next; + target_loop = target_loop->next; + }while(source_loop != source_face->loopbase); + + return target_face; +} + +/* + * COPY MESH + * + * Internal Copy function. +*/ + +/*local flag defines*/ + +#define DUPE_INPUT 1 /*input from operator*/ +#define DUPE_NEW 2 +#define DUPE_DONE 3 + +static void copy_mesh(BMMesh *source, BMMesh *target) +{ + + BMVert *v = NULL; + BMEdge *e = NULL, **edar = NULL; + BMLoop *l = NULL; + BMFace *f = NULL; + + BMIter verts; + BMIter edges; + BMIter faces; + BMIter loops; + + GHash *vhash; + GHash *ehash; + + int maxlength = 0, flag; + + /*initialize pointer hashes*/ + vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + ehash = BLI_ghash_new(BLI_ghashutil_ptrrhash, BLI_ghashutil_ptrcmp); + + /*initialize edge pointer array*/ + for(f = BMIter_New(&faces, source, BM_FACES, source, 0, NULL); f; f = BMIter_Step(&faces)){ + if(f->len > maxlength) maxlength = f->len; + } + edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array"); + + + /*first we dupe all flagged faces and their elements from source*/ + for(f = BMIter_New(&faces, source, BM_FACES, source, 0, NULL); f; f= BMIter_Step(&faces)){ + if(BMO_TestFlag(source, (BMHeader*)f, DUPE_INPUT)){ + /*vertex pass*/ + for(v = BMIter_New(&verts, source, BM_VERT_OF_FACE, f, 0, NULL); v; v = BMIter_Step(&verts)){ + if(!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE)){ + copy_vertex(source,v, target, vhash); + BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE); + } + } + + /*edge pass*/ + for(e = BMIter_New(&edges, source, BM_EDGE_OF_FACE, f, 0, NULL); e; e = BMeshIter_step(&edges)){ + if(!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE)){ + copy_edge(source, e, target, vhash, ehash); + BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE); + } + } + copy_face(source, f, target, edar, vhash, ehash); + BMO_SetFlag(source, (BMHeader*)f, DUPE_DONE); + } + } + + /*now we dupe all the edges*/ + for(e = BMIter_New(&edges, source, BM_EDGES, source, 0, NULL); e; e = BMIter_Step(&edges)){ + if(BMO_TestFlag(source, (BMHeader*)e, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE))){ + /*make sure that verts are copied*/ + if(!BMO_TestFlag(source, (BMHeader*)e->v1, DUPE_DONE){ + copy_vertex(source, e->v1, target, vhash); + BMO_SetFlag(source, (BMHeader*)e->v1, DUPE_DONE); + } + if(!BMO_TestFlag(source, (BMHeader*)e->v2, DUPE_DONE){ + copy_vertex(source, e->v2, target, vhash); + BMO_SetFlag(source, (BMHeader*)e->v2, DUPE_DONE); + } + /*now copy the actual edge*/ + copy_edge(source, e, target, vhash, ehash); + BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE); + } + } + + /*finally dupe all loose vertices*/ + for(v = BMIter_New(&verts, source, BM_VERTS, source, 0, NULL); v; v = BMIter_Step(&verts)){ + if(BMO_TestFlag(source, (BMHeader*)v, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE))){ + copy_vertex(source, v, target, vhash); + BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE); + } + } + + /*free pointer hashes*/ + BLI_ghash_free(vhash, NULL, NULL); + BLI_ghash_free(ehash, NULL, NULL); + + /*free edge pointer array*/ + if(edar) + MEM_freeN(edar); +} +/* +BMMesh *bmesh_make_mesh_from_mesh(BMMesh *bm, int allocsize[4]) +{ + BMMesh *target = NULL; + target = bmesh_make_mesh(allocsize); + + + CustomData_copy(&bm->vdata, &target->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->edata, &target->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->ldata, &target->ldata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->pdata, &target->pdata, CD_MASK_BMESH, CD_CALLOC, 0); + + + CustomData_bmesh_init_pool(&target->vdata, allocsize[0]); + CustomData_bmesh_init_pool(&target->edata, allocsize[1]); + CustomData_bmesh_init_pool(&target->ldata, allocsize[2]); + CustomData_bmesh_init_pool(&target->pdata, allocsize[3]); + + bmesh_begin_edit(bm); + bmesh_begin_edit(target); + + bmesh_copy_mesh(bm, target, 0); + + bmesh_end_edit(bm); + bmesh_end_edit(target); + + return target; + +} +*/ + +void dupeop_exec(BMMesh *bm, BMOperator *op) +{ + BMOperator *dupeop = op; + BMOpSlot *vinput, *einput, *finput, *vnew, *enew, *fnew; + int i; + + vinput = BMO_Get_Slot(dupeop, BMOP_DUPE_VINPUT); + einput = BMO_Get_Slot(dupeop, BMOP_DUPE_EINPUT); + finput = BMO_Get_Slot(dupeop, BMOP_DUPE_FINPUT); + + /*go through vinput, einput, and finput and flag elements with private flags*/ + BMO_Flag_Buffer(bm, dupeop, BMOP_DUPE_VINPUT, DUPE_INPUT); + BMO_Flag_Buffer(bm, dupeop, BMOP_DUPE_EINPUT, DUPE_INPUT); + BMO_Flag_Buffer(bm, dupeop, BMOP_DUPE_FINPUT, DUPE_INPUT); + + /*use the internal copy function*/ + copy_mesh(bm, bm); + + /*Output*/ + /*First copy the input buffers to output buffers - original data*/ + BMO_Copy_Opslot_Buffer_Alloc(dupeop, vinput, BMO_Get_Slot(dupeop, BMOP_DUPE_VORIGINAL)); + BMO_Copy_Opslot_Buffer_Alloc(dupeop, einput, BMO_Get_Slot(dupeop, BMOP_DUPE_EORIGINAL)); + BMO_Copy_Opslot_Buffer_Alloc(dupeop, finput, BMO_Get_Slot(dupeop, BMOP_DUPE_FORIGINAL)); + + /*Now alloc the new output buffers*/ + BMO_Flag_To_Slot(bm, dupeop, BMOP_DUPE_VNEW, DUPE_NEW, BMESH_VERT); + BMO_Flag_To_Slot(bm, dupeop, BMOP_DUPE_ENEW, DUPE_NEW, BMESH_EDGE); + BMO_Flag_To_Slot(bm, dupeop, BMOP_DUPE_FNEW, DUPE_NEW, BMESH_FACE); +} + +void splitop_exec(BMMesh *bm, BMOperator *op) +{ + BMOperator *splitop = op; + BMOperator dupeop; + BMOperator delop; + + /*initialize our sub-operators*/ + BMO_Init_Op(&dupeop, BMOP_DUPE); + BMO_Init_Op(&delop, BMOP_DEL); + + BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_VINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_VINPUT)); + BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_EINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_EINPUT)); + BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_FINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_FINPUT)); + + BMO_Exec_Op(&dupeop); + + /*connect outputs of dupe to delete*/ + BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_VORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_VINPUT)); + BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_EORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_EINPUT)); + BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_FORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_FINPUT)); + + BMO_Exec_Op(&delop); + + /*now we make our outputs by copying the dupe outputs*/ + BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_VNEW), BMO_Get_Slot(splitop, BMOP_SPLIT_VOUTPUT)); + BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_ENEW), BMO_Get_Slot(splitop, BMOP_SPLIT_EOUTPUT)); + BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_FNEW), BMO_Get_Slot(splitop, BMOP_SPLIT_FOUTPUT)); + + /*cleanup*/ + BMO_Finish_Op(&dupeop); + BMO_Finish_Op(&delop); +}
\ No newline at end of file diff --git a/source/blender/bmesh/tools/BME_duplicate.c b/source/blender/bmesh/tools/BME_duplicate.c new file mode 100644 index 00000000000..7c679ff6a89 --- /dev/null +++ b/source/blender/bmesh/tools/BME_duplicate.c @@ -0,0 +1,307 @@ +/* + * BME_DUPLICATE.C + * + * This file contains functions for duplicating, copying, and splitting + * elements from a bmesh. + * + */ + +/* + * BMESH COPY VERTEX + * + * Copy an existing vertex from one bmesh to another. + * +*/ + +static BMVert *bmesh_copy_vertex(BMMesh *source_mesh, BMVert *source_vertex, BMMesh *target_mesh, GHash *vhash) +{ + BMVert *target_vertex = NULL; + + /*create a new vertex*/ + target_vertex = bmesh_make_vert(target, source_vertex->co, NULL); + + /*insert new vertex into the vert hash*/ + BLI_ghash_insert(vhash, source_vertex, target_vertex); + + /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/ + CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->data, &target_vertex->data); + + /*copy flags*/ + if(bmesh_test_flag(source_vertex, BMESH_SELECT)) bmesh_set_flag(target_vertex, BMESH_SELECT); + if(bmesh_test_flag(source_vertex, BMESH_HIDDEN)) bmesh_set_flag(target_vertex, BMESH_HIDDEN); + + return target_vertex; +} + +/* + * BMESH COPY EDGE + * + * Copy an existing edge from one bmesh to another. + * +*/ + +static BMEdge *bmesh_copy_edge(BMMesh *source_mesh, BMEdge *source_edge, BMMesh *target_mesh, GHash *vhash, GHash *ehash) +{ + BMEdge *target_edge = NULL; + BMVert *target_vert1, *target_vert2; + + /*lookup v1 and v2*/ + target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1); + target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2); + + /*create a new edge*/ + target_edge = bmesh_make_edge(target_mesh, target_vert1, target_vert2, NULL, 0); + + /*insert new edge into the edge hash*/ + BLI_ghash_insert(ehash, source_edge, target_edge); + + /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/ + CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->data, &target_edge->data); + + /*copy flags*/ + if(bmesh_test_flag(source_edge, BMESH_SELECT)) bmesh_set_flag(target_edge, BMESH_SELECT); + if(bmesh_test_flag(source_edge, BMESH_HIDDEN)) bmesh_set_flag(target_edge, BMESH_SELECT); + if(bmesh_test_flag(source_edge, BMESH_SHARP)) bmesh_set_flag(target_edge, BMESH_SHARP); + if(bmesh_test_flag(source_edge, BMESH_SEAM)) bmesh_set_flag(target_edge, BMESH_SEAM); + if(bmesh_test_flag(source_edge, BMESH_FGON)) bmesh_set_flag(target_edge, BMESH_FGON); + + return target_edge; +} + +/* + * BMESH COPY FACE + * + * Copy an existing face from one bmesh to another. + * +*/ + +static BMFace *bmesh_copy_face(BMMesh *source_mesh, BMFace *source_face, BMMesh *target_mesh, BMEdge **edar, GHash *verthash, GHash *ehash) +{ + BMEdge *target_edge; + BMVert *target_vert1, *target_vert2; + BMLoop *source_loop, *target_loop; + BMFace *target_face = NULL; + int i; + + + /*lookup the first and second verts*/ + target_vert1 = BLI_ghash_lookup(vhash, source_face->loopbase->v); + target_vert2 = BLI_ghash_lookup(vhash, source_face->loopbase->next->v); + + /*lookup edges*/ + i = 0; + source_loop = source_face->loopbase; + do{ + edar[i] = BLI_ghash_lookup(ehash, source_loop->e); + i++; + source_loop = source_loop->next; + }while(source_loop != source_face->loopbase); + + /*create new face*/ + target_face = bmesh_make_ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0); + + /*we copy custom data by hand, we cannot assume that customdata byte layout will be exactly the same....*/ + CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->data, &target_face->data); + + /*copy flags*/ + if(bmesh_test_flag(source_face, BMESH_SELECT)) bmesh_set_flag(target_face, BMESH_SELECT); + if(bmesh_test_flag(source_face, BMESH_HIDDEN)) bmesh_set_flag(target_face, BMESH_HIDDEN); + + /*mark the face as dirty for normal and tesselation calcs*/ + bmesh_set_flag(target_face, BMESH_DIRTY); + + /*copy per-loop custom data*/ + source_loop = source_face->loopbase; + target_loop = target_face->loopbase; + do{ + CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->data, &target_loop->data); + source_loop = source_loop->next; + target_loop = target_loop->next; + }while(source_loop != source_face->loopbase); + + return target_face; +} + +/* + * BMESH COPY MESH + * + * Internal Copy function. copies flagged elements from + * source to target, which may in fact be the same mesh. + * Note that if __flag is 0, all elements will be copied. + * +*/ + +static void bmesh_copy_mesh(BMMesh *source, BMMesh *target, int __flag) +{ + + BMVert *v; + BMEdge *e, **edar; + BMLoop *l; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + BMIter loops; + + GHash *vhash; + GHash *ehash; + + int maxlength = 0, flag; + + /*initialize pointer hashes*/ + vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + ehash = BLI_ghash_new(BLI_ghashutil_ptrrhash, BLI_ghashutil_ptrcmp); + + /*initialize edge pointer array*/ + for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f = BMeshIter_step(faces)){ + if(f->len > maxlength) maxlength = f->len; + } + edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array"); + + /*begin modelling loop for target*/ + bmesh_begin_edit(target); + + /*we make special exception for __flag == 0... we copy all*/ + if(!__flag){ + flag = BMESH_DUPE; + for(v = BMeshIter_init(verts, BM_VERTS, source, 0); v; v = BMeshIter_step(verts)) bmesh_set_flag(v, BMESH_DUPE); + for(e = BMeshIter_init(verts, BM_EDGES, source, 0); e; e = BMeshIter_step(edges)) bmesh_set_flag(e, BMESH_DUPE); + for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f = BMeshIter_step(faces)) bmesh_set_flag(f, BMESH_DUPE); + } else{ + flag = __flag; + } + + /*first we dupe all flagged faces and their elements from source*/ + for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f= BMeshIter_step(faces)){ + if(bmesh_test_flag(f, flag)){ + /*vertex pass*/ + for(l = BMeshIter_init(loops, BMESH_LOOP_OF_MESH, f, 0); l; l = BMeshIter_step(loops)){ + if(!bmesh_test_flag(l->v, BMESH_DUPED)){ + bmesh_copy_vertex(source,l->v, target, vhash); + bmesh_set_flag(l->v, BMESH_DUPED); + } + } + + /*edge pass*/ + for(l = BMeshIter_init(loops, BMESH_LOOP_OF_MESH, f, 0); l; l = BMeshIter_step(loops)){ + if(!bmesh_test_flag(l->e, BMESH_DUPED)){ + bmesh_copy_edge(source, l->e, target, vhash, ehash); + bmesh_set_flag(l->e, BMESH_DUPED); + } + } + bmesh_copy_face(source, f, target, edar, vhash, ehash); + bmesh_set_flag(f, BMESH_DUPED); + } + } + + /*now we dupe all the edges*/ + for(e = BMeshIter_init(edges, BM_EDGES, source, 0); e; e = BMeshIter_step(edges)){ + if(bmesh_test_flag(e, flag) && (!bmesh_test_flag(e, BMESH_DUPED))){ + /*make sure that verts are copied*/ + if(!bmesh_test_flag(e->v1, BMESH_DUPED)){ + bmesh_copy_vertex(source, e->v1, target, vhash); + bmesh_set_flag(e->v1, BMESH_DUPED); + } + if(!bmesh_test_flag(e->v2, BMESH_DUPED)){ + bmesh_copy_vertex(source, e->v2, target, vhash); + bmesh_set_flag(e->v2, BMESH_DUPED); + } + /*now copy the actual edge*/ + bmesh_copy_edge(source, e, target, vhash, ehash); + bmesh_set_flag(e, BMESH_DUPED); + } + } + + /*finally dupe all loose vertices*/ + for(v = BMeshIter_init(verts, BM_VERTS, bm, 0); v; v = BMeshIter_step(verts)){ + if(bmesh_test_flag(v, flag) && (!bmesh_test_flag(v, BMESH_DUPED))){ + bmesh_copy_vertex(source, v, target, vhash); + bmesh_set_flag(v, BMESH_DUPED); + } + } + + /*finish*/ + bmesh_end_edit(target, BMESH_CALC_NORM | BMESH_CALC_TESS); + + /*free pointer hashes*/ + BLI_ghash_free(vhash, NULL, NULL); + BLI_ghash_free(ehash, NULL, NULL); + + /*free edge pointer array*/ + MEM_freeN(edar); +} + +/* + * BMESH MAKE MESH FROM MESH + * + * Creates a new mesh by duplicating an existing one. + * +*/ + +BMMesh *bmesh_make_mesh_from_mesh(BMMesh *bm, int allocsize[4]) +{ + BMMesh *target = NULL; + target = bmesh_make_mesh(allocsize); + + /*copy custom data layout*/ + CustomData_copy(&bm->vdata, &target->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->edata, &target->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->ldata, &target->ldata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&bm->pdata, &target->pdata, CD_MASK_BMESH, CD_CALLOC, 0); + + /*initialize memory pools*/ + CustomData_bmesh_init_pool(&target->vdata, allocsize[0]); + CustomData_bmesh_init_pool(&target->edata, allocsize[1]); + CustomData_bmesh_init_pool(&target->ldata, allocsize[2]); + CustomData_bmesh_init_pool(&target->pdata, allocsize[3]); + + bmesh_begin_edit(bm); + bmesh_begin_edit(target); + + bmesh_copy_mesh(bm, target, 0); /*copy all elements*/ + + bmesh_end_edit(bm); + bmesh_end_edit(target); + + return target; + +} + +/* + * BMESH SPLIT MESH + * + * Copies flagged elements then deletes them. + * +*/ + +void bmesh_split_mesh(BMMesh *bm, int flag){ + + BMVert *v; + BMEdge *e; + BMFace *f; + + BMIter verts; + BMIter edges; + BMIter faces; + + bmesh_begin_edit(bm); + bmesh_copy_mesh(bm, bm, flag); + + /*mark verts for deletion*/ + for(v = BMeshIter_init(verts, BM_VERTS, bm, 0); v; v = BMeshIter_step(verts)){ + if(bmesh_test_flag(v, flag)) bmesh_delete_vert(bm, v); + } + /*mark edges for deletion*/ + for(e = BMeshIter_init(edges, BM_EDGES, bm, 0); e; e = BMeshIter_step(edges)){ + if(bmesh_test_flag(e, flag)) bmesh_delete_edge(bm, e); + + } + /*mark faces for deletion*/ + for(f = BMeshIter_init(faces, BM_FACES, bm, 0); f; f= BMeshIter_step(faces)){ + if(bmesh_tes t_flag(f, flag)) bmesh_delete_face(bm, f); + + } + bmesh_end_edit(bm); +} + diff --git a/source/blender/bmesh/tools/BME_extrude.c b/source/blender/bmesh/tools/BME_extrude.c new file mode 100644 index 00000000000..b7b3a94893d --- /dev/null +++ b/source/blender/bmesh/tools/BME_extrude.c @@ -0,0 +1,216 @@ +/** + * BMESH EXTRUDE TOOL + * + * A rewrite of the old editmesh extrude code with the + * redundant parts broken into multiple functions + * in an effort to reduce code. This works with multiple + * selection modes, and is intended to build the + * extrusion in steps, depending on what elements are selected. + * Also decoupled the calculation of transform normal + * and put it in UI where it probably is more appropriate + * for the moment. + * + * TODO: + * -Fit this into the new 'easy' API. +*/ + +void BME_extrude_verts(BME_Mesh *bm, GHash *vhash){ + BMVert *v, *nv = NULL; + BMEdge *ne = NULL; + float vec[3]; + + //extrude the vertices + for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ + if(BME_SELECTED(v)){ + VECCOPY(vec,v->co); + nv = BME_MV(bm,vec); + nv->tflag2 =1; //mark for select + ne = BME_ME(bm,v,nv); + ne->tflag1 = 2; //mark as part of skirt 'ring' + BLI_ghash_insert(vhash,v,nv); + BME_VISIT(v); + } + } +} + +void BME_extrude_skirt(BME_Mesh *bm, GHash *ehash){ + + BMFace *nf=NULL; + BMEdge *e, *l=NULL, *r=NULL, *edar[4], *ne; + BMVert *v, *v1, *v2, *lv, *rv, *nv; + + for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ + if(BME_SELECTED(e)){ + /*find one face incident upon e and use it for winding of new face*/ + if(e->loop){ + v1 = e->loop->next->v; + v2 = e->loop->v; + } + else{ + v1 = e->v1; + v2 = e->v2; + } + + if(v1->edge->tflag1 == 2) l = v1->edge; + else l = BME_disk_next_edgeflag(v1->edge, v1, 0, 2); + if(v2->edge->tflag1 == 2) r = v2->edge; + else r = BME_disk_next_edgeflag(v2->edge, v2, 0, 2); + + lv = BME_edge_getothervert(l,v1); + rv = BME_edge_getothervert(r,v2); + + ne = BME_ME(bm,lv,rv); + ne->tflag2 = 1; //mark for select + BLI_ghash_insert(ehash,e,ne); + BME_VISIT(e); + + edar[0] = e; + edar[1] = l; + edar[2] = ne; + edar[3] = r; + BME_MF(bm,v1,v2,edar,4); + } + } +} + +void BME_cap_skirt(BME_Mesh *bm, GHash *vhash, GHash *ehash){ + BMVert *v, *nv, *v1, *v2; + BMEdge *e, **edar, *ne; + BME_Loop *l; + BMFace *f, *nf; + MemArena *edgearena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + float vec[3]; + int i, j, del_old =0; + + + //loop through faces, then loop through their verts. If the verts havnt been visited yet, duplicate these. + for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ + if(BME_SELECTED(f)){ + l = f->loopbase; + do{ + if(!(BME_ISVISITED(l->v))){ //interior vertex + //dupe vert + VECCOPY(vec,l->v->co); + nv = BME_MV(bm,vec); + BLI_ghash_insert(vhash,l->v,nv); + //mark for delete + l->v->tflag1 = 1; + BME_VISIT(l->v); //we dont want to dupe it again. + } + l=l->next; + }while(l!=f->loopbase); + } + } + + //find out if we delete old faces or not. This needs to be improved a lot..... + for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ + if(BME_SELECTED(e) && e->loop){ + i= BME_cycle_length(&(e->loop->radial)); + if(i > 2){ + del_old = 1; + break; + } + } + } + + + //build a new edge net, insert the new edges into the edge hash + for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ + if(BME_SELECTED(f)){ + l=f->loopbase; + do{ + if(!(BME_ISVISITED(l->e))){ //interior edge + //dupe edge + ne = BME_ME(bm,BLI_ghash_lookup(vhash,l->e->v1),BLI_ghash_lookup(vhash,l->e->v2)); + BLI_ghash_insert(ehash,l->e,ne); + //mark for delete + l->e->tflag1 = 1; + BME_VISIT(l->e); //we dont want to dupe it again. + } + l=l->next; + }while(l!=f->loopbase); + } + } + + //build new faces. grab edges from edge hash. + for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ + if(BME_SELECTED(f)){ + edar = MEM_callocN(sizeof(BMEdge*)*f->len,"Extrude array"); + v1 = BLI_ghash_lookup(vhash,f->loopbase->v); + v2 = BLI_ghash_lookup(vhash,f->loopbase->next->v); + for(i=0,l=f->loopbase; i < f->len; i++,l=l->next){ + ne = BLI_ghash_lookup(ehash,l->e); + edar[i] = ne; + } + nf=BME_MF(bm,v1,v2,edar,f->len); + nf->tflag2 = 1; // mark for select + if(del_old) f->tflag1 = 1; //mark for delete + MEM_freeN(edar); + } + } + BLI_memarena_free(edgearena); +} + +/*unified extrude code*/ +void BME_extrude_mesh(BME_Mesh *bm, int type){ + + BMVert *v; + BMEdge *e; + BMFace *f; + BME_Loop *l; + + struct GHash *vhash, *ehash; + /*Build a hash table of old pointers and new pointers.*/ + vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + BME_selectmode_flush(bm); //ensure consistent selection. contains hack to make sure faces get consistent select. + if(type & BME_EXTRUDE_FACES){ //Find selected edges with more than one incident face that is also selected. deselect them. + for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ + int totsel=0; + if(e->loop){ + l= e->loop; + do{ + if(BME_SELECTED(l->f)) totsel++; + l=BME_radial_nextloop(l); + }while(l!=e->loop); + } + if(totsel > 1) BME_select_edge(bm,e,0); + } + } + + /*another hack to ensure consistent selection.....*/ + for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ + if(BME_SELECTED(e)) BME_select_edge(bm,e,1); + } + + /*now we are ready to extrude*/ + if(type & BME_EXTRUDE_VERTS) BME_extrude_verts(bm,vhash); + if(type & BME_EXTRUDE_EDGES) BME_extrude_skirt(bm,ehash); + if(type & BME_EXTRUDE_FACES) BME_cap_skirt(bm,vhash,ehash); + + /*clear all selection flags*/ + BME_clear_flag_all(bm, SELECT|BME_VISITED); + /*go through and fix up selection flags. Anything with BME_NEW should be selected*/ + for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ + if(f->tflag2 == 1) BME_select_poly(bm,f,1); + if(f->tflag1 == 1) BME_VISIT(f); //mark for delete + } + for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ + if(e->tflag2 == 1) BME_select_edge(bm,e,1); + if(e->tflag1 == 1) BME_VISIT(e); // mark for delete + } + for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ + if(v->tflag2 == 1) BME_select_vert(bm,v,1); + if(v->tflag1 == 1) BME_VISIT(v); //mark for delete + } + /*go through and delete all of our old faces , edges and vertices.*/ + remove_tagged_polys(bm); + remove_tagged_edges(bm); + remove_tagged_verts(bm); + /*free our hash tables*/ + BLI_ghash_free(vhash,NULL, NULL); //check usage! + BLI_ghash_free(ehash,NULL, NULL); //check usage! + BME_selectmode_flush(bm); +} + diff --git a/source/blender/bmesh/tools/BME_weld.c b/source/blender/bmesh/tools/BME_weld.c new file mode 100644 index 00000000000..a17c07addbc --- /dev/null +++ b/source/blender/bmesh/tools/BME_weld.c @@ -0,0 +1,333 @@ +/* + * BME_WELD.C + * + * This file contains functions for welding + * elements in a mesh togather (remove doubles, + * collapse, ect). + * + * TODO: + * -Rewrite this to fit into the new API + * -Seperate out find doubles code and put it in + * BME_queries.c + * +*/ + + +/********* qsort routines *********/ + + +typedef struct xvertsort { + float x; + BMVert *v1; +} xvertsort; + +static int vergxco(const void *v1, const void *v2) +{ + const xvertsort *x1=v1, *x2=v2; + + if( x1->x > x2->x ) return 1; + else if( x1->x < x2->x) return -1; + return 0; +} + +struct facesort { + unsigned long x; + struct BMFace *f; +}; + + +static int vergface(const void *v1, const void *v2) +{ + const struct facesort *x1=v1, *x2=v2; + + if( x1->x > x2->x ) return 1; + else if( x1->x < x2->x) return -1; + return 0; +} + + + +/*break this into two functions.... 'find doubles' and 'remove doubles'?*/ + +static void BME_remove_doubles__splitface(BME_Mesh *bm,BMFace *f,GHash *vhash){ + BMVert *doub=NULL, *target=NULL; + BME_Loop *l; + BMFace *f2=NULL; + int split=0; + + l=f->loopbase; + do{ + if(l->v->tflag1 == 2){ + target = BLI_ghash_lookup(vhash,l->v); + if((BME_vert_in_face(target,f)) && (target != l->next->v) && (target != l->prev->v)){ + doub = l->v; + split = 1; + break; + } + } + + l= l->next; + }while(l!= f->loopbase); + + if(split){ + f2 = BME_SFME(bm,f,doub,target,NULL); + BME_remove_doubles__splitface(bm,f,vhash); + BME_remove_doubles__splitface(bm,f2,vhash); + } +} + +int BME_remove_doubles(BME_Mesh *bm, float limit) +{ + + /* all verts with (flag & 'flag') are being evaluated */ + BMVert *v, *v2, *target; + BMEdge *e, **edar, *ne; + BME_Loop *l; + BMFace *f, *nf; + xvertsort *sortblock, *sb, *sb1; + struct GHash *vhash; + struct facesort *fsortblock, *vsb, *vsb1; + int a, b, test, amount=0, found; + float dist; + + /*Build a hash table of doubles to thier target vert/edge.*/ + vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + /*count amount of selected vertices*/ + for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ + if(BME_SELECTED(v))amount++; + } + + /*qsort vertices based upon average of coordinate. We test this way first.*/ + sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub"); + + for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ + if(BME_SELECTED(v)){ + sb->x = v->co[0]+v->co[1]+v->co[2]; + sb->v1 = v; + sb++; + } + } + qsort(sortblock, amount, sizeof(xvertsort), vergxco); + + /* test for doubles */ + sb= sortblock; + for(a=0; a<amount; a++) { + v= sb->v1; + if(!(v->tflag1)) { //have we tested yet? + sb1= sb+1; + for(b=a+1; b<amount; b++) { + /* first test: simple distance. Simple way to discard*/ + dist= sb1->x - sb->x; + if(dist > limit) break; + + /* second test: have we already done this vertex? + (eh this should be swapped, simple equality test should be cheaper than math above... small savings + though) */ + v2= sb1->v1; + if(!(v2->tflag1)) { + dist= (float)fabs(v2->co[0]-v->co[0]); + if(dist<=limit) { + dist= (float)fabs(v2->co[1]-v->co[1]); + if(dist<=limit) { + dist= (float)fabs(v2->co[2]-v->co[2]); + if(dist<=limit) { + /*v2 is a double of v. We want to throw out v1 and relink everything to v*/ + BLI_ghash_insert(vhash,v2, v); + v->tflag1 = 1; //mark this vertex as a target + v->tflag2++; //increase user count for this vert. + v2->tflag1 = 2; //mark this vertex as a double. + BME_VISIT(v2); //mark for delete + } + } + } + } + sb1++; + } + } + sb++; + } + MEM_freeN(sortblock); + + + /*todo... figure out what this is for... + for(eve = em->verts.first; eve; eve=eve->next) + if((eve->f & flag) && (eve->f & 128)) + EM_data_interp_from_verts(eve, eve->tmp.v, eve->tmp.v, 0.5f); + */ + + /*We cannot collapse a vertex onto another vertex if they share a face and are not connected via a collapsable edge. + so to deal with this we simply find these offending vertices and split the faces. Note that this is not optimal, but works. + */ + + + for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ + if(!(BME_NEWELEM(f))){ + BME_remove_doubles__splitface(bm,f,vhash); + } + } + + for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ + /*If either vertices of this edge are a double, we must mark it for removal and we create a new one.*/ + if(e->v1->tflag1 == 2 || e->v2->tflag1 == 2){ + v = v2 = NULL; + /*For each vertex in the edge, test to find out what it should equal now.*/ + if(e->v1->tflag1 == 2) v= BLI_ghash_lookup(vhash,e->v1); + else v = e->v1; + if(e->v2->tflag1 == 2) v2 = BLI_ghash_lookup(vhash,e->v2); + else v2 = e->v2; + + /*small optimization, test to see if the edge needs to be rebuilt at all*/ + if((e->v1 != v) || (e->v2 != v2)){ /*will this always be true of collapsed edges?*/ + if(v == v2) e->tflag1 = 2; /*mark as a collapsed edge*/ + else if(!BME_disk_existedge(v,v2)) ne = BME_ME(bm,v,v2); + BME_VISIT(e); /*mark for delete*/ + } + } + } + + + /*need to remove double edges as well. To do this we decide on one edge to keep, and if its inserted into hash then we need to remove all other + edges incident upon and relink.*/ + /* + * REBUILD FACES + * + * Loop through double faces and if they have vertices that have been flagged, they need to be rebuilt. + * We do this by looking up the face + *rebuild faces. loop through original face, for each loop, if the edge it is attached to is marked for delete and has no + *other edge in the hash edge, then we know to skip that loop on face recreation. Simple. + */ + + /*1st loop through, just marking elements*/ + for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ //insert bit here about double edges, mark with a flag (e->tflag2) so that we can nuke it later. + l = f->loopbase; + do{ + if(l->v->tflag1 == 2) f->tflag1 = 1; //double, mark for rebuild + if(l->e->tflag1 != 2) f->tflag2++; //count number of edges in the new face. + l=l->next; + }while(l!=f->loopbase); + } + + /*now go through and create new faces*/ + for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ + if(f->tflag1 && f->tflag2 < 3) BME_VISIT(f); //mark for delete + else if (f->tflag1 == 1){ /*is the face marked for rebuild*/ + edar = MEM_callocN(sizeof(BMEdge *)*f->tflag2,"Remove doubles face creation array."); + a=0; + l = f->loopbase; + do{ + v = l->v; + v2 = l->next->v; + if(l->v->tflag1 == 2) v = BLI_ghash_lookup(vhash,l->v); + if(l->next->v->tflag1 == 2) v2 = BLI_ghash_lookup(vhash,l->next->v); + ne = BME_disk_existedge(v,v2); //use BME_disk_next_edgeflag here or something to find the edge that is marked as 'target'. + //add in call here to edge doubles hash array... then bobs your uncle. + if(ne){ + edar[a] = ne; + a++; + } + l=l->next; + }while(l!=f->loopbase); + + if(BME_vert_in_edge(edar[1],edar[0]->v2)){ + v = edar[0]->v1; + v2 = edar[0]->v2; + } + else{ + v = edar[0]->v2; + v2 = edar[0]->v1; + } + + nf = BME_MF(bm,v,v2,edar,f->tflag2); + + /*copy per loop data here*/ + if(nf){ + BME_VISIT(f); //mark for delete + } + MEM_freeN(edar); + } + } + + /*count amount of removed vert doubles*/ + a = 0; + for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ + if(v->tflag1 == 2) a++; + } + + /*free memory and return amount removed*/ + remove_tagged_polys(bm); + remove_tagged_edges(bm); + remove_tagged_verts(bm); + BLI_ghash_free(vhash,NULL, NULL); + BME_selectmode_flush(bm); + return a; +} + +static void BME_MeshWalk__collapsefunc(void *userData, BMEdge *applyedge){ + int index; + GHash *collected = userData; + index = BLI_ghash_size(collected); + if(!BLI_ghash_lookup(collected,applyedge->v1)){ + BLI_ghash_insert(collected,index,applyedge->v1); + index++; + } + if(!BLI_ghash_lookup(collected,applyedge->v2)){ + BLI_ghash_insert(collected,index,applyedge->v2); + } +} + +void BME_collapse_edges(BME_Mesh *bm){ + + BMVert *v, *cvert; + GHash *collected; + float min[3], max[3], cent[3]; + int size, i=0, j, num=0; + + for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ + if(!(BME_ISVISITED(v)) && v->edge){ + /*initiate hash table*/ + collected = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + /*do the walking.*/ + BME_MeshWalk(bm,v,BME_MeshWalk__collapsefunc,collected,BME_RESTRICTSELECT); + /*now loop through the hash table twice, once to calculate bounding box, second time to do the actual collapse*/ + size = BLI_ghash_size(collected); + /*initial values*/ + VECCOPY(min,v->co); + VECCOPY(max,v->co); + cent[0] = cent[1] = cent[2]=0; + for(i=0; i<size; i++){ + cvert = BLI_ghash_lookup(collected,i); + cent[0] = cent[0] + cvert->co[0]; + cent[1] = cent[1] + cvert->co[1]; + cent[2] = cent[2] + cvert->co[2]; + } + + cent[0] = cent[0] / size; + cent[1] = cent[1] / size; + cent[2] = cent[2] / size; + + for(i=0; i<size; i++){ + cvert = BLI_ghash_lookup(collected,i); + VECCOPY(cvert->co,cent); + num++; + } + /*free the hash table*/ + BLI_ghash_free(collected,NULL, NULL); + } + } + /*if any collapsed, call remove doubles*/ + if(num){ + //need to change selection mode here, OR do something else? Or does tool change selection mode? + //selectgrep + //first clear flags + BMEdge *e; + BMFace *f; + BME_clear_flag_all(bm,BME_VISITED); + for(v=BME_first(bm,BME_VERT); v; v=BME_next(bm,BME_VERT,v)) v->tflag1 = v->tflag2 = 0; + for(e=BME_first(bm,BME_EDGE); e; e=BME_next(bm,BME_EDGE,e)) e->tflag1 = e->tflag2 = 0; + for(f=BME_first(bm,BME_POLY); f; f=BME_next(bm,BME_POLY,f)) f->tflag1 = f->tflag2 = 0; + /*now call remove doubles*/ + BME_remove_doubles(bm,0.0000001); + } + BME_selectmode_flush(bm); +}
\ No newline at end of file diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c deleted file mode 100644 index 7a618f4d222..00000000000 --- a/source/blender/editors/animation/fmodifier_ui.c +++ /dev/null @@ -1,679 +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) 2009 Blender Foundation. - * All rights reserved. - * - * - * Contributor(s): Blender Foundation, Joshua Leung - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/* User-Interface Stuff for F-Modifiers: - * This file defines the (C-Coded) templates + editing callbacks needed - * by the interface stuff or F-Modifiers, as used by F-Curves in the Graph Editor, - * and NLA-Strips in the NLA Editor. - */ - -#include <string.h> -#include <stdio.h> -#include <math.h> -#include <float.h> - -#include "DNA_anim_types.h" -#include "DNA_action_types.h" -#include "DNA_object_types.h" -#include "DNA_space_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_userdef_types.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_arithb.h" -#include "BLI_blenlib.h" -#include "BLI_editVert.h" -#include "BLI_rand.h" - -#include "BKE_animsys.h" -#include "BKE_action.h" -#include "BKE_context.h" -#include "BKE_curve.h" -#include "BKE_customdata.h" -#include "BKE_depsgraph.h" -#include "BKE_fcurve.h" -#include "BKE_object.h" -#include "BKE_global.h" -#include "BKE_nla.h" -#include "BKE_scene.h" -#include "BKE_screen.h" -#include "BKE_utildefines.h" - -#include "BIF_gl.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "ED_anim_api.h" -#include "ED_keyframing.h" -#include "ED_screen.h" -#include "ED_types.h" -#include "ED_util.h" - -#include "UI_interface.h" -#include "UI_resources.h" -#include "UI_view2d.h" - -// XXX! -------------------------------- -/* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */ -#define UI_FLT_MAX 10000.0f - -/* ********************************************** */ - -#define B_REDR 1 -#define B_FMODIFIER_REDRAW 20 - -/* macro for use here to draw background box and set height */ -// XXX for now, roundbox has it's callback func set to NULL to not intercept events -#define DRAW_BACKDROP(height) \ - { \ - uiDefBut(block, ROUNDBOX, B_REDR, "", -3, yco-height, width+3, height-1, NULL, 5.0, 0.0, 12.0, (float)rb_col, ""); \ - } - -/* callback to verify modifier data */ -static void validate_fmodifier_cb (bContext *C, void *fcm_v, void *dummy) -{ - FModifier *fcm= (FModifier *)fcm_v; - FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); - - /* call the verify callback on the modifier if applicable */ - if (fmi && fmi->verify_data) - fmi->verify_data(fcm); -} - -/* callback to set the active modifier */ -static void activate_fmodifier_cb (bContext *C, void *fmods_v, void *fcm_v) -{ - ListBase *modifiers = (ListBase *)fmods_v; - FModifier *fcm= (FModifier *)fcm_v; - - /* call API function to set the active modifier for active modifier-stack */ - set_active_fmodifier(modifiers, fcm); -} - -/* callback to remove the given modifier */ -static void delete_fmodifier_cb (bContext *C, void *fmods_v, void *fcm_v) -{ - ListBase *modifiers = (ListBase *)fmods_v; - FModifier *fcm= (FModifier *)fcm_v; - - /* remove the given F-Modifier from the active modifier-stack */ - remove_fmodifier(modifiers, fcm); -} - -/* --------------- */ - -/* draw settings for generator modifier */ -static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, short width) -{ - FMod_Generator *data= (FMod_Generator *)fcm->data; - uiLayout *col, *row; - uiBlock *block; - uiBut *but; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr); - - /* basic settings (backdrop + mode selector + some padding) */ - col= uiLayoutColumn(layout, 1); - block= uiLayoutGetBlock(layout); - uiBlockBeginAlign(block); - but= uiDefButR(block, MENU, B_FMODIFIER_REDRAW, NULL, 0, 0, width-30, UI_UNIT_Y, &ptr, "mode", -1, 0, 0, -1, -1, NULL); - uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL); - - uiDefButR(block, TOG, B_FMODIFIER_REDRAW, NULL, 0, 0, width-30, UI_UNIT_Y, &ptr, "additive", -1, 0, 0, -1, -1, NULL); - uiBlockEndAlign(block); - - /* now add settings for individual modes */ - switch (data->mode) { - case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */ - { - float *cp = NULL; - char xval[32]; - unsigned int i; - - /* draw polynomial order selector */ - row= uiLayoutRow(layout, 0); - block= uiLayoutGetBlock(row); - but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 10,0,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1"); - uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL); - - - /* draw controls for each coefficient and a + sign at end of row */ - row= uiLayoutRow(layout, 1); - block= uiLayoutGetBlock(row); - uiDefBut(block, LABEL, 1, "y = ", 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, ""); - - cp= data->coefficients; - for (i=0; (i < data->arraysize) && (cp); i++, cp++) { - /* coefficient */ - uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 150, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient for polynomial"); - - /* 'x' param (and '+' if necessary) */ - if (i) { - if (i == 1) - strcpy(xval, "x"); - else - sprintf(xval, "x^%d", i); - uiDefBut(block, LABEL, 1, xval, 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "Power of x"); - } - - if ( (i != (data->arraysize - 1)) || ((i==0) && data->arraysize==2) ) { - uiDefBut(block, LABEL, 1, "+", 0,0 , 30, 20, NULL, 0.0, 0.0, 0, 0, ""); - - /* next coefficient on a new row */ - row= uiLayoutRow(layout, 1); - block= uiLayoutGetBlock(row); - } - } - } - break; - - case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial expression */ - { - float *cp = NULL; - unsigned int i; - - /* draw polynomial order selector */ - row= uiLayoutRow(layout, 0); - block= uiLayoutGetBlock(row); - but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 0,0,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1"); - uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL); - - - /* draw controls for each pair of coefficients */ - row= uiLayoutRow(layout, 1); - block= uiLayoutGetBlock(row); - uiDefBut(block, LABEL, 1, "y=", 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, ""); - - cp= data->coefficients; - for (i=0; (i < data->poly_order) && (cp); i++, cp+=2) { - /* opening bracket */ - uiDefBut(block, LABEL, 1, "(", 0, 0, 20, 20, NULL, 0.0, 0.0, 0, 0, ""); - - /* coefficients */ - uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 100, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient of x"); - - uiDefBut(block, LABEL, 1, "x+", 0, 0, 40, 20, NULL, 0.0, 0.0, 0, 0, ""); - - uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 100, 20, cp+1, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Second coefficient"); - - /* closing bracket and '+' sign */ - if ( (i != (data->poly_order - 1)) || ((i==0) && data->poly_order==2) ) { - uiDefBut(block, LABEL, 1, ") +", 0, 0, 30, 20, NULL, 0.0, 0.0, 0, 0, ""); - - /* set up new row for the next pair of coefficients*/ - row= uiLayoutRow(layout, 1); - block= uiLayoutGetBlock(row); - } - else - uiDefBut(block, LABEL, 1, ")", 0, 0, 20, 20, NULL, 0.0, 0.0, 0, 0, ""); - } - } - break; - } -} - -/* --------------- */ - -/* draw settings for noise modifier */ -static void draw_modifier__fn_generator(uiLayout *layout, ID *id, FModifier *fcm, short width) -{ - uiLayout *col; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr); - - /* add the settings */ - col= uiLayoutColumn(layout, 1); - uiItemR(col, "", 0, &ptr, "type", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "additive", 0, 0, 1); - - col= uiLayoutColumn(layout, 0); // no grouping for now - uiItemR(col, NULL, 0, &ptr, "amplitude", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "phase_multiplier", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "phase_offset", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "value_offset", 0, 0, 0); -} - -/* --------------- */ - -/* draw settings for cycles modifier */ -static void draw_modifier__cycles(uiLayout *layout, ID *id, FModifier *fcm, short width) -{ - uiLayout *split, *col; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(id, &RNA_FModifierCycles, fcm, &ptr); - - /* split into 2 columns - * NOTE: the mode comboboxes shouldn't get labels, otherwise there isn't enough room - */ - split= uiLayoutSplit(layout, 0.5f); - - /* before range */ - col= uiLayoutColumn(split, 1); - uiItemL(col, "Before:", 0); - uiItemR(col, "", 0, &ptr, "before_mode", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "before_cycles", 0, 0, 0); - - /* after range */ - col= uiLayoutColumn(split, 1); - uiItemL(col, "After:", 0); - uiItemR(col, "", 0, &ptr, "after_mode", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "after_cycles", 0, 0, 0); -} - -/* --------------- */ - -/* draw settings for noise modifier */ -static void draw_modifier__noise(uiLayout *layout, ID *id, FModifier *fcm, short width) -{ - uiLayout *split, *col; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(id, &RNA_FModifierNoise, fcm, &ptr); - - /* blending mode */ - uiItemR(layout, NULL, 0, &ptr, "modification", 0, 0, 0); - - /* split into 2 columns */ - split= uiLayoutSplit(layout, 0.5f); - - /* col 1 */ - col= uiLayoutColumn(split, 0); - uiItemR(col, NULL, 0, &ptr, "size", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "strength", 0, 0, 0); - - /* col 2 */ - col= uiLayoutColumn(split, 0); - uiItemR(col, NULL, 0, &ptr, "phase", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "depth", 0, 0, 0); -} - -/* --------------- */ - -#define BINARYSEARCH_FRAMEEQ_THRESH 0.0001 - -/* Binary search algorithm for finding where to insert Envelope Data Point. - * Returns the index to insert at (data already at that index will be offset if replace is 0) - */ -static int binarysearch_fcm_envelopedata_index (FCM_EnvelopeData array[], float frame, int arraylen, short *exists) -{ - int start=0, end=arraylen; - int loopbreaker= 0, maxloop= arraylen * 2; - - /* initialise exists-flag first */ - *exists= 0; - - /* sneaky optimisations (don't go through searching process if...): - * - keyframe to be added is to be added out of current bounds - * - keyframe to be added would replace one of the existing ones on bounds - */ - if ((arraylen <= 0) || (array == NULL)) { - printf("Warning: binarysearch_fcm_envelopedata_index() encountered invalid array \n"); - return 0; - } - else { - /* check whether to add before/after/on */ - float framenum; - - /* 'First' Point (when only one point, this case is used) */ - framenum= array[0].time; - if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) { - *exists = 1; - return 0; - } - else if (frame < framenum) - return 0; - - /* 'Last' Point */ - framenum= array[(arraylen-1)].time; - if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) { - *exists= 1; - return (arraylen - 1); - } - else if (frame > framenum) - return arraylen; - } - - - /* most of the time, this loop is just to find where to put it - * - 'loopbreaker' is just here to prevent infinite loops - */ - for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) { - /* compute and get midpoint */ - int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */ - float midfra= array[mid].time; - - /* check if exactly equal to midpoint */ - if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) { - *exists = 1; - return mid; - } - - /* repeat in upper/lower half */ - if (frame > midfra) - start= mid + 1; - else if (frame < midfra) - end= mid - 1; - } - - /* print error if loop-limit exceeded */ - if (loopbreaker == (maxloop-1)) { - printf("Error: binarysearch_fcm_envelopedata_index() was taking too long \n"); - - // include debug info - printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen); - } - - /* not found, so return where to place it */ - return start; -} - -/* callback to add new envelope data point */ -// TODO: should we have a separate file for things like this? -static void fmod_envelope_addpoint_cb (bContext *C, void *fcm_dv, void *dummy) -{ - Scene *scene= CTX_data_scene(C); - FMod_Envelope *env= (FMod_Envelope *)fcm_dv; - FCM_EnvelopeData *fedn; - FCM_EnvelopeData fed; - - /* init template data */ - fed.min= -1.0f; - fed.max= 1.0f; - fed.time= (float)scene->r.cfra; // XXX make this int for ease of use? - fed.f1= fed.f2= 0; - - /* check that no data exists for the current frame... */ - if (env->data) { - short exists = -1; - int i= binarysearch_fcm_envelopedata_index(env->data, (float)(scene->r.cfra), env->totvert, &exists); - - /* binarysearch_...() will set exists by default to 0, so if it is non-zero, that means that the point exists already */ - if (exists) - return; - - /* add new */ - fedn= MEM_callocN((env->totvert+1)*sizeof(FCM_EnvelopeData), "FCM_EnvelopeData"); - - /* add the points that should occur before the point to be pasted */ - if (i > 0) - memcpy(fedn, env->data, i*sizeof(FCM_EnvelopeData)); - - /* add point to paste at index i */ - *(fedn + i)= fed; - - /* add the points that occur after the point to be pasted */ - if (i < env->totvert) - memcpy(fedn+i+1, env->data+i, (env->totvert-i)*sizeof(FCM_EnvelopeData)); - - /* replace (+ free) old with new */ - MEM_freeN(env->data); - env->data= fedn; - - env->totvert++; - } - else { - env->data= MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData"); - *(env->data)= fed; - - env->totvert= 1; - } -} - -/* callback to remove envelope data point */ -// TODO: should we have a separate file for things like this? -static void fmod_envelope_deletepoint_cb (bContext *C, void *fcm_dv, void *ind_v) -{ - FMod_Envelope *env= (FMod_Envelope *)fcm_dv; - FCM_EnvelopeData *fedn; - int index= GET_INT_FROM_POINTER(ind_v); - - /* check that no data exists for the current frame... */ - if (env->totvert > 1) { - /* allocate a new smaller array */ - fedn= MEM_callocN(sizeof(FCM_EnvelopeData)*(env->totvert-1), "FCM_EnvelopeData"); - - memcpy(fedn, &env->data, sizeof(FCM_EnvelopeData)*(index)); - memcpy(&fedn[index], &env->data[index+1], sizeof(FCM_EnvelopeData)*(env->totvert-index-1)); - - /* free old array, and set the new */ - MEM_freeN(env->data); - env->data= fedn; - env->totvert--; - } - else { - /* just free array, since the only vert was deleted */ - if (env->data) - MEM_freeN(env->data); - env->totvert= 0; - } -} - -/* draw settings for envelope modifier */ -static void draw_modifier__envelope(uiLayout *layout, ID *id, FModifier *fcm, short width) -{ - FMod_Envelope *env= (FMod_Envelope *)fcm->data; - FCM_EnvelopeData *fed; - uiLayout *col, *row; - uiBlock *block; - uiBut *but; - PointerRNA ptr; - int i; - - /* init the RNA-pointer */ - RNA_pointer_create(id, &RNA_FModifierEnvelope, fcm, &ptr); - - /* general settings */ - col= uiLayoutColumn(layout, 1); - uiItemL(col, "Envelope:", 0); - uiItemR(col, NULL, 0, &ptr, "reference_value", 0, 0, 0); - - row= uiLayoutRow(col, 1); - uiItemR(row, "Min", 0, &ptr, "default_minimum", 0, 0, 0); - uiItemR(row, "Max", 0, &ptr, "default_maximum", 0, 0, 0); - - /* control points header */ - // TODO: move this control-point control stuff to using the new special widgets for lists - // the current way is far too cramped - row= uiLayoutRow(layout, 0); - block= uiLayoutGetBlock(row); - - uiDefBut(block, LABEL, 1, "Control Points:", 0, 0, 150, 20, NULL, 0.0, 0.0, 0, 0, ""); - - but= uiDefBut(block, BUT, B_FMODIFIER_REDRAW, "Add Point", 0,0,150,19, NULL, 0, 0, 0, 0, "Adds a new control-point to the envelope on the current frame"); - uiButSetFunc(but, fmod_envelope_addpoint_cb, env, NULL); - - /* control points list */ - for (i=0, fed=env->data; i < env->totvert; i++, fed++) { - /* get a new row to operate on */ - row= uiLayoutRow(layout, 1); - block= uiLayoutGetBlock(row); - - uiBlockBeginAlign(block); - but=uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Fra:", 0, 0, 90, 20, &fed->time, -UI_FLT_MAX, UI_FLT_MAX, 10, 1, "Frame that envelope point occurs"); - uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL); - - uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Min:", 0, 0, 100, 20, &fed->min, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Minimum bound of envelope at this point"); - uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Max:", 0, 0, 100, 20, &fed->max, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Maximum bound of envelope at this point"); - - but= uiDefIconBut(block, BUT, B_FMODIFIER_REDRAW, ICON_X, 0, 0, 18, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Delete envelope control point"); - uiButSetFunc(but, fmod_envelope_deletepoint_cb, env, SET_INT_IN_POINTER(i)); - uiBlockBeginAlign(block); - } -} - -/* --------------- */ - -/* draw settings for limits modifier */ -static void draw_modifier__limits(uiLayout *layout, ID *id, FModifier *fcm, short width) -{ - uiLayout *split, *col, *row; - PointerRNA ptr; - - /* init the RNA-pointer */ - RNA_pointer_create(id, &RNA_FModifierLimits, fcm, &ptr); - - /* row 1: minimum */ - { - row= uiLayoutRow(layout, 0); - - /* split into 2 columns */ - split= uiLayoutSplit(layout, 0.5f); - - /* x-minimum */ - col= uiLayoutColumn(split, 1); - uiItemR(col, NULL, 0, &ptr, "use_minimum_x", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "minimum_x", 0, 0, 0); - - /* y-minimum*/ - col= uiLayoutColumn(split, 1); - uiItemR(col, NULL, 0, &ptr, "use_minimum_y", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "minimum_y", 0, 0, 0); - } - - /* row 2: minimum */ - { - row= uiLayoutRow(layout, 0); - - /* split into 2 columns */ - split= uiLayoutSplit(layout, 0.5f); - - /* x-minimum */ - col= uiLayoutColumn(split, 1); - uiItemR(col, NULL, 0, &ptr, "use_maximum_x", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "maximum_x", 0, 0, 0); - - /* y-minimum*/ - col= uiLayoutColumn(split, 1); - uiItemR(col, NULL, 0, &ptr, "use_maximum_y", 0, 0, 0); - uiItemR(col, NULL, 0, &ptr, "maximum_y", 0, 0, 0); - } -} - -/* --------------- */ - - -void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm) -{ - FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); - uiLayout *box, *row, *subrow; - uiBlock *block; - uiBut *but; - short width= 314; - - /* draw header */ - { - /* get layout-row + UI-block for this */ - box= uiLayoutBox(layout); - - row= uiLayoutRow(box, 0); - block= uiLayoutGetBlock(row); // err... - - uiBlockSetEmboss(block, UI_EMBOSSN); - - /* left-align -------------------------------------------- */ - subrow= uiLayoutRow(row, 0); - uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT); - - /* expand */ - uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_EXPANDED, B_REDR, ICON_TRIA_RIGHT, 0, -1, UI_UNIT_X, UI_UNIT_Y, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is expanded."); - - /* checkbox for 'active' status (for now) */ - but= uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_ACTIVE, B_REDR, ICON_RADIOBUT_OFF, 0, -1, UI_UNIT_X, UI_UNIT_Y, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is active one."); - uiButSetFunc(but, activate_fmodifier_cb, modifiers, fcm); - - /* name */ - if (fmi) - uiDefBut(block, LABEL, 1, fmi->name, 0, 0, 150, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type. Click to make modifier active one."); - else - uiDefBut(block, LABEL, 1, "<Unknown Modifier>", 0, 0, 150, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type. Click to make modifier active one."); - - /* right-align ------------------------------------------- */ - subrow= uiLayoutRow(row, 0); - uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT); - - /* 'mute' button */ - uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_MUTED, B_REDR, ICON_MUTE_IPO_OFF, 0, 0, UI_UNIT_X, UI_UNIT_Y, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is temporarily muted (not evaluated)."); - - /* delete button */ - but= uiDefIconBut(block, BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Delete F-Curve Modifier."); - uiButSetFunc(but, delete_fmodifier_cb, modifiers, fcm); - - uiBlockSetEmboss(block, UI_EMBOSS); - } - - /* when modifier is expanded, draw settings */ - if (fcm->flag & FMODIFIER_FLAG_EXPANDED) { - /* set up the flexible-box layout which acts as the backdrop for the modifier settings */ - box= uiLayoutBox(layout); - - /* draw settings for individual modifiers */ - switch (fcm->type) { - case FMODIFIER_TYPE_GENERATOR: /* Generator */ - draw_modifier__generator(box, id, fcm, width); - break; - - case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */ - draw_modifier__fn_generator(box, id, fcm, width); - break; - - case FMODIFIER_TYPE_CYCLES: /* Cycles */ - draw_modifier__cycles(box, id, fcm, width); - break; - - case FMODIFIER_TYPE_ENVELOPE: /* Envelope */ - draw_modifier__envelope(box, id, fcm, width); - break; - - case FMODIFIER_TYPE_LIMITS: /* Limits */ - draw_modifier__limits(box, id, fcm, width); - break; - - case FMODIFIER_TYPE_NOISE: /* Noise */ - draw_modifier__noise(box, id, fcm, width); - break; - - default: /* unknown type */ - break; - } - } -} - -/* ********************************************** */ diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 8807b21e653..83179dd3843 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -1151,8 +1151,8 @@ static void meshdeform_ray_tree_create(MeshDeformBind *mdb) MESHDEFORM_BIND= mdb; - mface= mdb->cagedm->getFaceArray(mdb->cagedm); - totface= mdb->cagedm->getNumFaces(mdb->cagedm); + mface= mdb->cagedm->getTessFaceArray(mdb->cagedm); + totface= mdb->cagedm->getNumTessFaces(mdb->cagedm); mdb->raytree= RE_ray_tree_create(64, totface, min, max, meshdeform_ray_coords_func, meshdeform_ray_check_func); @@ -1178,8 +1178,8 @@ static int meshdeform_intersect(MeshDeformBind *mdb, Isect *isec) isec->labda= 1e10; - mface= mdb->cagedm->getFaceArray(mdb->cagedm); - totface= mdb->cagedm->getNumFaces(mdb->cagedm); + mface= mdb->cagedm->getTessFaceArray(mdb->cagedm); + totface= mdb->cagedm->getNumTessFaces(mdb->cagedm); for(f=0; f<totface; f++, mface++) { VECCOPY(face[0], mdb->cagecos[mface->v1]); diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c index 132d9edf8d0..2a012437b42 100644 --- a/source/blender/editors/armature/reeb.c +++ b/source/blender/editors/armature/reeb.c @@ -64,6 +64,7 @@ #include "BKE_global.h" #include "BKE_utildefines.h" #include "BKE_customdata.h" +#include "BKE_mesh.h" //#include "blendef.h" @@ -3387,7 +3388,7 @@ ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C) { Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); - EditMesh *em =( (Mesh*)obedit->data)->edit_mesh; + EditMesh *em =BKE_mesh_get_editmesh(((Mesh*)obedit->data)); EdgeIndex indexed_edges; VertexData *data; ReebGraph *rg = NULL; @@ -3483,6 +3484,12 @@ ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C) MEM_freeN(data); + /*no need to load the editmesh back into the object, just + free it (avoids ngon conversion issues too going back the + other way)*/ + free_editMesh(em); + MEM_freeN(em); + return rg; } diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 0face00f82b..dd29f270680 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -36,7 +36,6 @@ struct EditVert; struct EditEdge; struct EditFace; struct bContext; -struct wmOperator; struct wmWindowManager; struct EditSelection; struct ViewContext; @@ -49,35 +48,68 @@ struct MCol; struct UvVertMap; struct UvMapVert; struct CustomData; +struct BMEditSelection; +struct BMesh; +struct BMVert; +struct BMEdge; +struct BMFace; -#define EM_FGON_DRAW 1 // face flag -#define EM_FGON 2 // edge and face flag both +// edge and face flag both +#define EM_FGON 2 +// face flag +#define EM_FGON_DRAW 1 /* editbutflag */ -#define B_CLOCKWISE 1 -#define B_KEEPORIG 2 -#define B_BEAUTY 4 -#define B_SMOOTH 8 -#define B_BEAUTY_SHORT 0x10 -#define B_AUTOFGON 0x20 -#define B_KNIFE 0x80 +#define B_CLOCKWISE 1 +#define B_KEEPORIG 2 +#define B_BEAUTY 4 +#define B_SMOOTH 8 +#define B_BEAUTY_SHORT 16 +#define B_AUTOFGON 32 +#define B_KNIFE 0x80 #define B_PERCENTSUBD 0x40 #define B_MESH_X_MIRROR 0x100 #define B_JOINTRIA_UV 0x200 #define B_JOINTRIA_VCOL 0X400 #define B_JOINTRIA_SHARP 0X800 #define B_JOINTRIA_MAT 0X1000 -#define B_FRACTAL 0x2000 -#define B_SPHERE 0x4000 +#define B_FRACTAL 0x2000 +#define B_SPHERE 0x4000 + +/* bmeshutils.c */ + +/*this function is currently defunct, dead*/ +void EDBM_Tesselate(struct EditMesh *em); +void EDBM_RecalcNormals(struct BMEditMesh *em); +void EDBM_MakeEditBMesh(struct Scene *scene, struct Object *ob); +void EDBM_FreeEditBMesh(struct BMEditMesh *tm); +void EDBM_LoadEditBMesh(struct Scene *scene, struct Object *ob); +void EDBM_init_index_arrays(struct BMEditMesh *tm, int forvert, int foredge, int forface); +void EDBM_free_index_arrays(struct BMEditMesh *tm); +struct BMVert *EDBM_get_vert_for_index(struct BMEditMesh *tm, int index); +struct BMEdge *EDBM_get_edge_for_index(struct BMEditMesh *tm, int index); +struct BMFace *EDBM_get_face_for_index(struct BMEditMesh *tm, int index); +struct BMFace *EDBM_get_actFace(struct BMEditMesh *em, int sloppy); +void EDBM_selectmode_flush(struct BMEditMesh *em); +int EDBM_get_actSelection(struct BMEditMesh *em, struct BMEditSelection *ese); +void EDBM_editselection_center(struct BMEditMesh *em, float *center, struct BMEditSelection *ese); +void EDBM_editselection_plane(struct BMEditMesh *em, float *plane, struct BMEditSelection *ese); +void EDBM_editselection_normal(float *normal, struct BMEditSelection *ese); +void EDBM_selectmode_set(struct BMEditMesh *em); +void EDBM_convertsel(struct BMEditMesh *em, short oldmode, short selectmode); + +int EDBM_check_backbuf(unsigned int index); +int EDBM_mask_init_backbuf_border(struct ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax); +void EDBM_free_backbuf(void); +int EDBM_init_backbuf_border(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax); +int EDBM_init_backbuf_circle(struct ViewContext *vc, short xs, short ys, short rads); /* meshtools.c */ -intptr_t mesh_octree_table(struct Object *ob, struct EditMesh *em, float *co, char mode); -struct EditVert *editmesh_get_x_mirror_vert(struct Object *ob, struct EditMesh *em, float *co); +intptr_t mesh_octree_table(struct Object *ob, struct BMEditMesh *em, float *co, char mode); +struct BMVert *editmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em, float *co); int mesh_get_x_mirror_vert(struct Object *ob, int index); -int *mesh_get_x_mirror_faces(struct Object *ob, struct EditMesh *em); - -int join_mesh_exec(struct bContext *C, struct wmOperator *op); +int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em); /* mesh_ops.c */ void ED_operatortypes_mesh(void); @@ -89,8 +121,8 @@ void ED_keymap_mesh(struct wmWindowManager *wm); void ED_spacetypes_init(void); void ED_keymap_mesh(struct wmWindowManager *wm); -void make_editMesh(struct Scene *scene, Object *ob); -void load_editMesh(struct Scene *scene, Object *ob); +struct EditMesh *make_editMesh(struct Scene *scene, Object *ob); +void load_editMesh(struct Scene *scene, Object *ob, struct EditMesh *em); void remake_editMesh(struct Scene *scene, Object *ob); void free_editMesh(struct EditMesh *em); @@ -112,6 +144,7 @@ void undo_push_mesh(struct bContext *C, char *name); struct EditFace *EM_get_actFace(struct EditMesh *em, int sloppy); void EM_set_actFace(struct EditMesh *em, struct EditFace *efa); float EM_face_area(struct EditFace *efa); +void EM_add_data_layer(struct EditMesh *em, struct CustomData *data, int type); void EM_select_edge(struct EditEdge *eed, int sel); void EM_select_face(struct EditFace *efa, int sel); @@ -135,11 +168,8 @@ struct UvVertMap *EM_make_uv_vert_map(struct EditMesh *em, int selected, int do_ struct UvMapVert *EM_get_uv_map_vert(struct UvVertMap *vmap, unsigned int v); void EM_free_uv_vert_map(struct UvVertMap *vmap); -void EM_add_data_layer(struct EditMesh *em, struct CustomData *data, int type); -void EM_free_data_layer(struct EditMesh *em, struct CustomData *data, int type); - /* editmesh_mods.c */ -extern unsigned int em_vertoffs, em_solidoffs, em_wireoffs; +extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs; void mouse_mesh(struct bContext *C, short mval[2], short extend); int EM_check_backbuf(unsigned int index); @@ -151,9 +181,6 @@ int EM_init_backbuf_circle(struct ViewContext *vc, short xs, short ys, short r void EM_hide_mesh(struct EditMesh *em, int swap); void EM_reveal_mesh(struct EditMesh *em); -void EM_select_by_material(struct EditMesh *em, int index); -void EM_deselect_by_material(struct EditMesh *em, int index); - /* editface.c */ struct MTFace *EM_get_active_mtface(struct EditMesh *em, struct EditFace **act_efa, struct MCol **mcol, int sloppy); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index b576299c1d0..6360bf49f1a 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -37,9 +37,9 @@ struct bglMats; struct BPoint; struct Nurb; struct BezTriple; -struct EditVert; -struct EditEdge; -struct EditFace; +struct BMVert; +struct BMEdge; +struct BMFace; struct ImBuf; struct Scene; struct bContext; @@ -52,7 +52,7 @@ typedef struct ViewContext { struct ARegion *ar; struct View3D *v3d; struct RegionView3D *rv3d; - struct EditMesh *em; + struct BMEditMesh *em; short mval[2]; } ViewContext; @@ -96,9 +96,9 @@ void view3d_get_object_project_mat(struct RegionView3D *v3d, struct Object *ob, void view3d_project_float(struct ARegion *a, float *vec, float *adr, float mat[4][4]); /* drawobject.c itterators */ -void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct EditVert *eve, int x, int y, int index), void *userData, int clipVerts); -void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts); -void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct EditFace *efa, int x, int y, int index), void *userData); +void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BMVert *eve, int x, int y, int index), void *userData, int clipVerts); +void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts); +void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct BMFace *efa, int x, int y, int index), void *userData); void nurbs_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, int x, int y), void *userData); void lattice_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BPoint *bp, int x, int y), void *userData); diff --git a/source/blender/editors/mesh/SConscript b/source/blender/editors/mesh/SConscript index df1f297698d..80536b5e431 100644 --- a/source/blender/editors/mesh/SConscript +++ b/source/blender/editors/mesh/SConscript @@ -7,5 +7,6 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' #/intern/guardedalloc ../../gpu' incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern' +incs += ' ../../bmesh ' env.BlenderLib ( 'bf_editors_mesh', sources, Split(incs), [], libtype=['core'], priority=[45] ) diff --git a/source/blender/editors/mesh/bmesh_select.c b/source/blender/editors/mesh/bmesh_select.c new file mode 100644 index 00000000000..c4f2a294d0b --- /dev/null +++ b/source/blender/editors/mesh/bmesh_select.c @@ -0,0 +1,1424 @@ +/** + * $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) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* + +BMEditMesh_mods.c, UI level access, no geometry changes + +*/ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "MTC_matrixops.h" + +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_texture_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "BKE_context.h" +#include "BKE_displist.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" +#include "BKE_report.h" +#include "BKE_tessmesh.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "RE_render_ext.h" /* externtex */ + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_view3d.h" +#include "bmesh.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "mesh_intern.h" + +#include "BLO_sys_types.h" // for intptr_t support + +/* XXX */ +static void waitcursor() {} +static int pupmenu() {return 0;} + +/* ****************************** MIRROR **************** */ + +void EDBM_select_mirrored(Object *obedit, BMEditMesh *em) +{ +#if 0 //BMESH_TODO + if(em->selectmode & SCE_SELECT_VERTEX) { + BMVert *eve, *v1; + + for(eve= em->verts.first; eve; eve= eve->next) { + if(eve->f & SELECT) { + v1= BMEditMesh_get_x_mirror_vert(obedit, em, eve->co); + if(v1) { + eve->f &= ~SELECT; + v1->f |= SELECT; + } + } + } + } +#endif +} + +void EDBM_automerge(int update) +{ +// XXX int len; + +// if ((scene->automerge) && +// (obedit && obedit->type==OB_MESH) && +// (((Mesh*)obedit->data)->mr==NULL) +// ) { +// len = removedoublesflag(1, 1, scene->toolsettings->doublimit); +// if (len) { +// em->totvert -= len; /* saves doing a countall */ +// if (update) { +// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); +// } +// } +// } +} + +/* ****************************** SELECTION ROUTINES **************** */ + +unsigned int bm_solidoffs=0, bm_wireoffs=0, bm_vertoffs=0; /* set in drawobject.c ... for colorindices */ + +/* facilities for border select and circle select */ +static char *selbuf= NULL; + +/* opengl doesn't support concave... */ +static void draw_triangulated(short mcords[][2], short tot) +{ + ListBase lb={NULL, NULL}; + DispList *dl; + float *fp; + int a; + + /* make displist */ + dl= MEM_callocN(sizeof(DispList), "poly disp"); + dl->type= DL_POLY; + dl->parts= 1; + dl->nr= tot; + dl->verts= fp= MEM_callocN(tot*3*sizeof(float), "poly verts"); + BLI_addtail(&lb, dl); + + for(a=0; a<tot; a++, fp+=3) { + fp[0]= (float)mcords[a][0]; + fp[1]= (float)mcords[a][1]; + } + + /* do the fill */ + filldisplist(&lb, &lb); + + /* do the draw */ + dl= lb.first; /* filldisplist adds in head of list */ + if(dl->type==DL_INDEX3) { + int *index; + + a= dl->parts; + fp= dl->verts; + index= dl->index; + glBegin(GL_TRIANGLES); + while(a--) { + glVertex3fv(fp+3*index[0]); + glVertex3fv(fp+3*index[1]); + glVertex3fv(fp+3*index[2]); + index+= 3; + } + glEnd(); + } + + freedisplist(&lb); +} + + +/* reads rect, and builds selection array for quick lookup */ +/* returns if all is OK */ +int EDBM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax) +{ + struct ImBuf *buf; + unsigned int *dr; + int a; + + if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0; + + buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); + if(buf==NULL) return 0; + if(bm_vertoffs==0) return 0; + + dr = buf->rect; + + /* build selection lookup */ + selbuf= MEM_callocN(bm_vertoffs+1, "selbuf"); + + a= (xmax-xmin+1)*(ymax-ymin+1); + while(a--) { + if(*dr>0 && *dr<=bm_vertoffs) + selbuf[*dr]= 1; + dr++; + } + IMB_freeImBuf(buf); + return 1; +} + +int EDBM_check_backbuf(unsigned int index) +{ + if(selbuf==NULL) return 1; + if(index>0 && index<=bm_vertoffs) + return selbuf[index]; + return 0; +} + +void EDBM_free_backbuf(void) +{ + if(selbuf) MEM_freeN(selbuf); + selbuf= NULL; +} + +/* mcords is a polygon mask + - grab backbuffer, + - draw with black in backbuffer, + - grab again and compare + returns 'OK' +*/ +int EDBM_mask_init_backbuf_border(ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax) +{ + unsigned int *dr, *drm; + struct ImBuf *buf, *bufmask; + int a; + + /* method in use for face selecting too */ + if(vc->obedit==NULL) { + if(FACESEL_PAINT_TEST); + else return 0; + } + else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0; + + buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); + if(buf==NULL) return 0; + if(bm_vertoffs==0) return 0; + + dr = buf->rect; + + /* draw the mask */ + glDisable(GL_DEPTH_TEST); + + glColor3ub(0, 0, 0); + + /* yah, opengl doesn't do concave... tsk! */ + ED_region_pixelspace(vc->ar); + draw_triangulated(mcords, tot); + + glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */ + for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]); + glEnd(); + + glFinish(); /* to be sure readpixels sees mask */ + + /* grab mask */ + bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); + drm = bufmask->rect; + if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */ + + /* build selection lookup */ + selbuf= MEM_callocN(bm_vertoffs+1, "selbuf"); + + a= (xmax-xmin+1)*(ymax-ymin+1); + while(a--) { + if(*dr>0 && *dr<=bm_vertoffs && *drm==0) selbuf[*dr]= 1; + dr++; drm++; + } + IMB_freeImBuf(buf); + IMB_freeImBuf(bufmask); + return 1; + +} + +/* circle shaped sample area */ +int EDBM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads) +{ + struct ImBuf *buf; + unsigned int *dr; + short xmin, ymin, xmax, ymax, xc, yc; + int radsq; + + /* method in use for face selecting too */ + if(vc->obedit==NULL) { + if(FACESEL_PAINT_TEST); + else return 0; + } + else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0; + + xmin= xs-rads; xmax= xs+rads; + ymin= ys-rads; ymax= ys+rads; + buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); + if(bm_vertoffs==0) return 0; + if(buf==NULL) return 0; + + dr = buf->rect; + + /* build selection lookup */ + selbuf= MEM_callocN(bm_vertoffs+1, "selbuf"); + radsq= rads*rads; + for(yc= -rads; yc<=rads; yc++) { + for(xc= -rads; xc<=rads; xc++, dr++) { + if(xc*xc + yc*yc < radsq) { + if(*dr>0 && *dr<=bm_vertoffs) selbuf[*dr]= 1; + } + } + } + + IMB_freeImBuf(buf); + return 1; + +} + +static void findnearestvert__doClosest(void *userData, BMVert *eve, int x, int y, int index) +{ + struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } *data = userData; + + if (data->pass==0) { + if (index<=data->lastIndex) + return; + } else { + if (index>data->lastIndex) + return; + } + + if (data->dist>3) { + int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y); + if (BM_TestHFlag(eve, BM_SELECT) == data->select) { + if (data->strict == 1) + return; + else + temp += 5; + } + + if (temp<data->dist) { + data->dist = temp; + data->closest = eve; + data->closestIndex = index; + } + } +} + + + + +static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index) +{ + BMEditMesh *em= (BMEditMesh *)handle; + BMIter iter; + BMVert *eve = BMIter_AtIndex(em->bm, BM_VERTS_OF_MESH, NULL, index-1); + + if(eve && BM_TestHFlag(eve, BM_SELECT)) return 0; + return 1; +} +/** + * findnearestvert + * + * dist (in/out): minimal distance to the nearest and at the end, actual distance + * sel: selection bias + * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts + * if 0, unselected vertice are given the bias + * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased + */ +BMVert *EDBM_findnearestvert(ViewContext *vc, int *dist, short sel, short strict) +{ + if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){ + int distance; + unsigned int index; + BMVert *eve; + + if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest); + else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL); + + eve = BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, index-1); + + if(eve && distance < *dist) { + *dist = distance; + return eve; + } else { + return NULL; + } + + } + else { + struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } data; + static int lastSelectedIndex=0; + static BMVert *lastSelected=NULL; + + if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) { + lastSelectedIndex = 0; + lastSelected = NULL; + } + + data.lastIndex = lastSelectedIndex; + data.mval[0] = vc->mval[0]; + data.mval[1] = vc->mval[1]; + data.select = sel; + data.dist = *dist; + data.strict = strict; + data.closest = NULL; + data.closestIndex = 0; + + data.pass = 0; + mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1); + + if (data.dist>3) { + data.pass = 1; + mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1); + } + + *dist = data.dist; + lastSelected = data.closest; + lastSelectedIndex = data.closestIndex; + + return data.closest; + } +} + +/* returns labda for closest distance v1 to line-piece v2-v3 */ +static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3) +{ + float rc[2], len; + + rc[0]= v3[0]-v2[0]; + rc[1]= v3[1]-v2[1]; + len= rc[0]*rc[0]+ rc[1]*rc[1]; + if(len==0.0f) + return 0.0f; + + return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len; +} + +/* note; uses v3d, so needs active 3d window */ +static void findnearestedge__doClosest(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index) +{ + struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } *data = userData; + float v1[2], v2[2]; + int distance; + + v1[0] = x0; + v1[1] = y0; + v2[0] = x1; + v2[1] = y1; + + distance= PdistVL2Dfl(data->mval, v1, v2); + + if(BM_TestHFlag(eed, BM_SELECT)) distance+=5; + if(distance < data->dist) { + if(data->vc.rv3d->rflag & RV3D_CLIPPING) { + float labda= labda_PdistVL2Dfl(data->mval, v1, v2); + float vec[3]; + + vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]); + vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]); + vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]); + Mat4MulVecfl(data->vc.obedit->obmat, vec); + + if(view3d_test_clipping(data->vc.rv3d, vec)==0) { + data->dist = distance; + data->closest = eed; + } + } + else { + data->dist = distance; + data->closest = eed; + } + } +} +BMEdge *EDBM_findnearestedge(ViewContext *vc, int *dist) +{ + + if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) { + int distance; + unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance,0, NULL, NULL); + BMEdge *eed = BMIter_AtIndex(vc->em->bm, BM_EDGES_OF_MESH, NULL, index-1); + + if (eed && distance<*dist) { + *dist = distance; + return eed; + } else { + return NULL; + } + } + else { + struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } data; + + data.vc= *vc; + data.mval[0] = vc->mval[0]; + data.mval[1] = vc->mval[1]; + data.dist = *dist; + data.closest = NULL; + + mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2); + + *dist = data.dist; + return data.closest; + } +} + +static void findnearestface__getDistance(void *userData, BMFace *efa, int x, int y, int index) +{ + struct { short mval[2]; int dist; BMFace *toFace; } *data = userData; + + if (efa==data->toFace) { + int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y); + + if (temp<data->dist) + data->dist = temp; + } +} +static void findnearestface__doClosest(void *userData, BMFace *efa, int x, int y, int index) +{ + struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } *data = userData; + + if (data->pass==0) { + if (index<=data->lastIndex) + return; + } else { + if (index>data->lastIndex) + return; + } + + if (data->dist>3) { + int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y); + + if (temp<data->dist) { + data->dist = temp; + data->closest = efa; + data->closestIndex = index; + } + } +} +static BMFace *EDBM_findnearestface(ViewContext *vc, int *dist) +{ + + if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) { + unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]); + BMFace *efa = BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, index-1); + + if (efa) { + struct { short mval[2]; int dist; BMFace *toFace; } data; + + data.mval[0] = vc->mval[0]; + data.mval[1] = vc->mval[1]; + data.dist = 0x7FFF; /* largest short */ + data.toFace = efa; + + mesh_foreachScreenFace(vc, findnearestface__getDistance, &data); + + if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */ + *dist= data.dist; + return efa; + } + } + + return NULL; + } + else { + struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } data; + static int lastSelectedIndex=0; + static BMFace *lastSelected=NULL; + + if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) { + lastSelectedIndex = 0; + lastSelected = NULL; + } + + data.lastIndex = lastSelectedIndex; + data.mval[0] = vc->mval[0]; + data.mval[1] = vc->mval[1]; + data.dist = *dist; + data.closest = NULL; + data.closestIndex = 0; + + data.pass = 0; + mesh_foreachScreenFace(vc, findnearestface__doClosest, &data); + + if (data.dist>3) { + data.pass = 1; + mesh_foreachScreenFace(vc, findnearestface__doClosest, &data); + } + + *dist = data.dist; + lastSelected = data.closest; + lastSelectedIndex = data.closestIndex; + + return data.closest; + } +} + +/* best distance based on screen coords. + use em->selectmode to define how to use + selected vertices and edges get disadvantage + return 1 if found one +*/ +static int unified_findnearest(ViewContext *vc, BMVert **eve, BMEdge **eed, BMFace **efa) +{ + BMEditMesh *em= vc->em; + int dist= 75; + + *eve= NULL; + *eed= NULL; + *efa= NULL; + + /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ + view3d_validate_backbuf(vc); + + if(em->selectmode & SCE_SELECT_VERTEX) + *eve= EDBM_findnearestvert(vc, &dist, BM_SELECT, 0); + if(em->selectmode & SCE_SELECT_FACE) + *efa= EDBM_findnearestface(vc, &dist); + + dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */ + if(em->selectmode & SCE_SELECT_EDGE) + *eed= EDBM_findnearestedge(vc, &dist); + + /* return only one of 3 pointers, for frontbuffer redraws */ + if(*eed) { + *efa= NULL; *eve= NULL; + } + else if(*efa) { + *eve= NULL; + } + + return (*eve || *eed || *efa); +} + + +/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */ + +/* selects new faces/edges/verts based on the + existing selection + +FACES GROUP + mode 1: same material + mode 2: same image + mode 3: same area + mode 4: same perimeter + mode 5: same normal + mode 6: same co-planer +*/ + +static EnumPropertyItem prop_simface_types[] = { + {1, "MATERIAL", 0, "Material", ""}, + {2, "IMAGE", 0, "Image", ""}, + {3, "AREA", 0, "Area", ""}, + {4, "PERIMETER", 0, "Perimeter", ""}, + {5, "NORMAL", 0, "Normal", ""}, + {6, "COPLANAR", 0, "Co-planar", ""}, + {0, NULL, 0, NULL, NULL} +}; + + +/* this as a way to compare the ares, perim of 2 faces thay will scale to different sizes +*0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */ +#define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b)) + +static int similar_face_select__internal(Scene *scene, BMEditMesh *em, int mode) +{ +#if 0 //BMESH_TODO + BMFace *efa, *base_efa=NULL; + unsigned int selcount=0; /*count how many new faces we select*/ + + /*deselcount, count how many deselected faces are left, so we can bail out early + also means that if there are no deselected faces, we can avoid a lot of looping */ + unsigned int deselcount=0; + float thresh= scene->toolsettings->select_thresh; + short ok=0; + + for(efa= em->faces.first; efa; efa= efa->next) { + if (!efa->h) { + if (efa->f & SELECT) { + efa->f1=1; + ok=1; + } else { + efa->f1=0; + deselcount++; /* a deselected face we may select later */ + } + } + } + + if (!ok || !deselcount) /* no data selected OR no more data to select */ + return 0; + + /*if mode is 3 then record face areas, 4 record perimeter */ + if (mode==3) { + for(efa= em->faces.first; efa; efa= efa->next) { + efa->tmp.fp= EM_face_area(efa); + } + } else if (mode==4) { + for(efa= em->faces.first; efa; efa= efa->next) { + efa->tmp.fp= EM_face_perimeter(efa); + } + } + + for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) { + if (base_efa->f1) { /* This was one of the faces originaly selected */ + if (mode==1) { /* same material */ + for(efa= em->faces.first; efa; efa= efa->next) { + if ( + !(efa->f & SELECT) && + !efa->h && + base_efa->mat_nr == efa->mat_nr + ) { + EM_select_face(efa, 1); + selcount++; + deselcount--; + if (!deselcount) /*have we selected all posible faces?, if so return*/ + return selcount; + } + } + } else if (mode==2) { /* same image */ + MTFace *tf, *base_tf; + + base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data, + CD_MTFACE); + + if(!base_tf) + return selcount; + + for(efa= em->faces.first; efa; efa= efa->next) { + if (!(efa->f & SELECT) && !efa->h) { + tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data, + CD_MTFACE); + + if(base_tf->tpage == tf->tpage) { + EM_select_face(efa, 1); + selcount++; + deselcount--; + if (!deselcount) /*have we selected all posible faces?, if so return*/ + return selcount; + } + } + } + } else if (mode==3 || mode==4) { /* same area OR same perimeter, both use the same temp var */ + for(efa= em->faces.first; efa; efa= efa->next) { + if ( + (!(efa->f & SELECT) && !efa->h) && + SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp) + ) { + EM_select_face(efa, 1); + selcount++; + deselcount--; + if (!deselcount) /*have we selected all posible faces?, if so return*/ + return selcount; + } + } + } else if (mode==5) { /* same normal */ + float angle; + for(efa= em->faces.first; efa; efa= efa->next) { + if (!(efa->f & SELECT) && !efa->h) { + angle= VecAngle2(base_efa->n, efa->n); + if (angle/180.0<=thresh) { + EM_select_face(efa, 1); + selcount++; + deselcount--; + if (!deselcount) /*have we selected all posible faces?, if so return*/ + return selcount; + } + } + } + } else if (mode==6) { /* same planer */ + float angle, base_dot, dot; + base_dot= Inpf(base_efa->cent, base_efa->n); + for(efa= em->faces.first; efa; efa= efa->next) { + if (!(efa->f & SELECT) && !efa->h) { + angle= VecAngle2(base_efa->n, efa->n); + if (angle/180.0<=thresh) { + dot=Inpf(efa->cent, base_efa->n); + if (fabs(base_dot-dot) <= thresh) { + EM_select_face(efa, 1); + selcount++; + deselcount--; + if (!deselcount) /*have we selected all posible faces?, if so return*/ + return selcount; + } + } + } + } + } + } + } /* end base_efa loop */ + return selcount; +#endif +} + +/* ***************************************************** */ + +/* **************** LOOP SELECTS *************** */ +static void walker_select(BMEditMesh *em, int walkercode, void *start, int select) +{ + BMesh *bm = em->bm; + BMHeader *h; + BMWalker walker; + + BMW_Init(&walker, bm, walkercode, 0); + h = BMW_Begin(&walker, start); + for (; h; h=BMW_Step(&walker)) { + BM_Select(bm, h, select); + } + BMW_End(&walker); +} + +#if 0 +/* selects quads in loop direction of indicated edge */ +/* only flush over edges with valence <= 2 */ +void faceloop_select(EditMesh *em, EditEdge *startedge, int select) +{ + EditEdge *eed; + EditFace *efa; + int looking= 1; + + /* in eed->f1 we put the valence (amount of faces in edge) */ + /* in eed->f2 we put tagged flag as correct loop */ + /* in efa->f1 we put tagged flag as correct to select */ + + for(eed= em->edges.first; eed; eed= eed->next) { + eed->f1= 0; + eed->f2= 0; + } + for(efa= em->faces.first; efa; efa= efa->next) { + efa->f1= 0; + if(efa->h==0) { + efa->e1->f1++; + efa->e2->f1++; + efa->e3->f1++; + if(efa->e4) efa->e4->f1++; + } + } + + /* tag startedge OK*/ + startedge->f2= 1; + + while(looking) { + looking= 0; + + for(efa= em->faces.first; efa; efa= efa->next) { + if(efa->h==0 && efa->e4 && efa->f1==0) { /* not done quad */ + if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */ + + /* if edge tagged, select opposing edge and mark face ok */ + if(efa->e1->f2) { + efa->e3->f2= 1; + efa->f1= 1; + looking= 1; + } + else if(efa->e2->f2) { + efa->e4->f2= 1; + efa->f1= 1; + looking= 1; + } + if(efa->e3->f2) { + efa->e1->f2= 1; + efa->f1= 1; + looking= 1; + } + if(efa->e4->f2) { + efa->e2->f2= 1; + efa->f1= 1; + looking= 1; + } + } + } + } + } + + /* (de)select the faces */ + if(select!=2) { + for(efa= em->faces.first; efa; efa= efa->next) { + if(efa->f1) EM_select_face(efa, select); + } + } +} +#endif + + +/* selects or deselects edges that: +- if edges has 2 faces: + - has vertices with valence of 4 + - not shares face with previous edge +- if edge has 1 face: + - has vertices with valence 4 + - not shares face with previous edge + - but also only 1 face +- if edge no face: + - has vertices with valence 2 +*/ + +/* + Almostly exactly the same code as faceloop select +*/ +static void edgering_select(BMEditMesh *em, BMEdge *startedge, int select) +{ +#if 0 //BMESH_TODO + BMEdge *eed; + BMFace *efa; + int looking= 1; + + /* in eed->f1 we put the valence (amount of faces in edge) */ + /* in eed->f2 we put tagged flag as correct loop */ + /* in efa->f1 we put tagged flag as correct to select */ + + for(eed= em->edges.first; eed; eed= eed->next) { + eed->f1= 0; + eed->f2= 0; + } + for(efa= em->faces.first; efa; efa= efa->next) { + efa->f1= 0; + if(efa->h==0) { + efa->e1->f1++; + efa->e2->f1++; + efa->e3->f1++; + if(efa->e4) efa->e4->f1++; + } + } + + /* tag startedge OK */ + startedge->f2= 1; + + while(looking) { + looking= 0; + + for(efa= em->faces.first; efa; efa= efa->next) { + if(efa->e4 && efa->f1==0 && !efa->h) { /* not done quad */ + if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */ + + /* if edge tagged, select opposing edge and mark face ok */ + if(efa->e1->f2) { + efa->e3->f2= 1; + efa->f1= 1; + looking= 1; + } + else if(efa->e2->f2) { + efa->e4->f2= 1; + efa->f1= 1; + looking= 1; + } + if(efa->e3->f2) { + efa->e1->f2= 1; + efa->f1= 1; + looking= 1; + } + if(efa->e4->f2) { + efa->e2->f2= 1; + efa->f1= 1; + looking= 1; + } + } + } + } + } + + /* (de)select the edges */ + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->f2) EM_select_edge(eed, select); + } +#endif +} + +static int loop_multiselect(bContext *C, wmOperator *op) +{ +#if 0 //BMESH_TODO + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= EM_GetBMEditMesh(((Mesh *)obedit->data)); + BMEdge *eed; + BMEdge **edarray; + int edindex, edfirstcount; + int looptype= RNA_boolean_get(op->ptr, "ring"); + + /* sets em->totedgesel */ + EM_nedges_selected(em); + + edarray = MEM_mallocN(sizeof(BMEdge*)*em->totedgesel,"edge array"); + edindex = 0; + edfirstcount = em->totedgesel; + + for(eed=em->edges.first; eed; eed=eed->next){ + if(eed->f&SELECT){ + edarray[edindex] = eed; + edindex += 1; + } + } + + if(looptype){ + for(edindex = 0; edindex < edfirstcount; edindex +=1){ + eed = edarray[edindex]; + edgering_select(em, eed,SELECT); + } + EM_selectmode_flush(em); + } + else{ + for(edindex = 0; edindex < edfirstcount; edindex +=1){ + eed = edarray[edindex]; + edgeloop_select(em, eed,SELECT); + } + EM_selectmode_flush(em); + } + MEM_freeN(edarray); +// if (EM_texFaceCheck()) + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + EM_EndBMEditMesh(obedit->data, em); +#endif + return OPERATOR_FINISHED; +} + +void MESH_OT_loop_multi_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Multi Select Loops"; + ot->idname= "MESH_OT_loop_multi_select"; + + /* api callbacks */ + ot->exec= loop_multiselect; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "ring", 0, "Ring", ""); +} + + +/* ***************** MAIN MOUSE SELECTION ************** */ + + +/* ***************** loop select (non modal) ************** */ + +static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring) +{ + ViewContext vc; + BMEditMesh *em; + BMEdge *eed; + int select= 1; + int dist= 50; + + em_setup_viewcontext(C, &vc); + vc.mval[0]= mval[0]; + vc.mval[1]= mval[1]; + em= vc.em; + + eed= EDBM_findnearestedge(&vc, &dist); + if(eed) { + if(extend==0) EDBM_clear_flag_all(em, BM_SELECT); + + if(BM_TestHFlag(em, BM_SELECT)==0) select=1; + else if(extend) select=0; + + if(em->selectmode & SCE_SELECT_FACE) { + walker_select(em, BMW_FACELOOP, eed, select); + } + else if(em->selectmode & SCE_SELECT_EDGE) { + if(ring) + edgering_select(em, eed, select); + else + walker_select(em, BMW_LOOP, eed, select); + } + else if(em->selectmode & SCE_SELECT_VERTEX) { + if(ring) + edgering_select(em, eed, select); + else + walker_select(em, BMW_LOOP, eed, select); + } + + EDBM_selectmode_flush(em); +// if (EM_texFaceCheck()) + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); + } +} + +static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + + view3d_operator_needs_opengl(C); + + mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"), + RNA_boolean_get(op->ptr, "ring")); + + /* cannot do tweaks for as long this keymap is after transform map */ + return OPERATOR_FINISHED; +} + +void MESH_OT_loop_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Loop Select"; + ot->idname= "MESH_OT_loop_select"; + + /* api callbacks */ + ot->invoke= mesh_select_loop_invoke; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); + RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", ""); +} + +/* ******************* mesh shortest path select, uses prev-selected edge ****************** */ + +/* since you want to create paths with multiple selects, it doesn't have extend option */ +static void mouse_mesh_shortest_path(bContext *C, short mval[2]) +{ +#if 0 //BMESH_TODO + ViewContext vc; + BMEditMesh *em; + BMEdge *eed; + int dist= 50; + + em_setup_viewcontext(C, &vc); + vc.mval[0]= mval[0]; + vc.mval[1]= mval[1]; + em= vc.em; + + eed= findnearestedge(&vc, &dist); + if(eed) { + Mesh *me= vc.obedit->data; + int path = 0; + + if (em->selected.last) { + EditSelection *ese = em->selected.last; + + if(ese && ese->type == BMEdge) { + BMEdge *eed_act; + eed_act = (BMEdge*)ese->data; + if (eed_act != eed) { + if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) { + EM_remove_selection(em, eed_act, BMEdge); + path = 1; + } + } + } + } + if (path==0) { + int act = (edgetag_context_check(vc.scene, eed)==0); + edgetag_context_set(vc.scene, eed, act); /* switch the edge option */ + } + + EM_selectmode_flush(em); + + /* even if this is selected it may not be in the selection list */ + if(edgetag_context_check(vc.scene, eed)==0) + EDBM_remove_selection(em, eed); + else + EDBM_store_selection(em, eed); + + /* force drawmode for mesh */ + switch (vc.scene->toolsettings->edge_mode) { + + case EDGE_MODE_TAG_SEAM: + me->drawflag |= ME_DRAWSEAMS; + break; + case EDGE_MODE_TAG_SHARP: + me->drawflag |= ME_DRAWSHARP; + break; + case EDGE_MODE_TAG_CREASE: + me->drawflag |= ME_DRAWCREASES; + break; + case EDGE_MODE_TAG_BEVEL: + me->drawflag |= ME_DRAWBWEIGHTS; + break; + } + + DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA); + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); + } +#endif +} + + +static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + + view3d_operator_needs_opengl(C); + + mouse_mesh_shortest_path(C, event->mval); + + return OPERATOR_FINISHED; +} + +void MESH_OT_select_shortest_path(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Shortest Path Select"; + ot->idname= "MESH_OT_select_shortest_path"; + + /* api callbacks */ + ot->invoke= mesh_shortest_path_select_invoke; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); +} + + +/* ************************************************** */ +/* here actual select happens */ +/* gets called via generic mouse select operator */ +void mouse_mesh(bContext *C, short mval[2], short extend) +{ + ViewContext vc; + BMVert *eve = NULL; + BMEdge *eed = NULL; + BMFace *efa = NULL; + + /* setup view context for argument to callbacks */ + em_setup_viewcontext(C, &vc); + vc.mval[0]= mval[0]; + vc.mval[1]= mval[1]; + + if(unified_findnearest(&vc, &eve, &eed, &efa)) { + + if(extend==0) EDBM_clear_flag_all(vc.em, BM_SELECT); + + if(efa) { + /* set the last selected face */ + EDBM_set_actFace(vc.em, efa); + + if(!BM_TestHFlag(efa, BM_SELECT)) { + EDBM_store_selection(vc.em, efa); + BM_Select(vc.em->bm, efa, 1); + } + else if(extend) { + EDBM_remove_selection(vc.em, efa); + BM_Select(vc.em->bm, efa, 1); + } + } + else if(eed) { + if(!BM_TestHFlag(eed, BM_SELECT)) { + EDBM_store_selection(vc.em, eed); + BM_Select(vc.em->bm, eed, 1); + } + else if(extend) { + EDBM_remove_selection(vc.em, eed); + BM_Select(vc.em->bm, eed, 0); + } + } + else if(eve) { + if(!BM_TestHFlag(eve, BM_SELECT)) { + EDBM_store_selection(vc.em, eve); + BM_Select(vc.em->bm, eve, 1); + } + else if(extend){ + EDBM_remove_selection(vc.em, eve); + BM_Select(vc.em->bm, eve, 0); + } + } + + EDBM_selectmode_flush(vc.em); + +// if (EM_texFaceCheck()) { + + if (efa && efa->mat_nr != vc.obedit->actcol-1) { + vc.obedit->actcol= efa->mat_nr+1; + vc.em->mat_nr= efa->mat_nr; +// BIF_preview_changed(ID_MA); + } + } + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); +} + +static void EDBM_strip_selections(BMEditMesh *em) +{ + BMEditSelection *ese, *nextese; + + if(!(em->selectmode & SCE_SELECT_VERTEX)){ + ese = em->selected.first; + while(ese){ + nextese = ese->next; + if(ese->type == BM_VERT) BLI_freelinkN(&(em->selected),ese); + ese = nextese; + } + } + if(!(em->selectmode & SCE_SELECT_EDGE)){ + ese=em->selected.first; + while(ese){ + nextese = ese->next; + if(ese->type == BM_EDGE) BLI_freelinkN(&(em->selected), ese); + ese = nextese; + } + } + if(!(em->selectmode & SCE_SELECT_FACE)){ + ese=em->selected.first; + while(ese){ + nextese = ese->next; + if(ese->type == BM_FACE) BLI_freelinkN(&(em->selected), ese); + ese = nextese; + } + } +} + +/* when switching select mode, makes sure selection is consistant for editing */ +/* also for paranoia checks to make sure edge or face mode works */ +void EDBM_selectmode_set(BMEditMesh *em) +{ + BMVert *eve; + BMEdge *eed; + BMFace *efa; + BMIter iter; + + em->bm->selectmode = em->selectmode; + + EDBM_strip_selections(em); /*strip BMEditSelections from em->selected that are not relevant to new mode*/ + + if(em->selectmode & SCE_SELECT_VERTEX) { + BMIter iter; + + /*eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0); + + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter)) BM_Select(em->bm, efa, 0);*/ + + EDBM_selectmode_flush(em); + } + else if(em->selectmode & SCE_SELECT_EDGE) { + /* deselect vertices, and select again based on edge select */ + eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for ( ; eve; eve=BMIter_Step(&iter)) BM_Select(em->bm, eve, 0); + + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter)) { + if (BM_TestHFlag(eed, BM_SELECT)) + BM_Select(em->bm, eed, 1); + } + + /* selects faces based on edge status */ + EDBM_selectmode_flush(em); + } + else if(em->selectmode & SCE_SELECT_FACE) { + /* deselect eges, and select again based on face select */ + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0); + + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter)) { + if (BM_TestHFlag(efa, BM_SELECT)) + BM_Select(em->bm, efa, 1); + } + } +} + +void EDBM_convertsel(BMEditMesh *em, short oldmode, short selectmode) +{ + BMVert *eve; + BMEdge *eed; + BMFace *efa; + BMIter iter; + + /*have to find out what the selectionmode was previously*/ + if(oldmode == SCE_SELECT_VERTEX) { + if(selectmode == SCE_SELECT_EDGE) { + /*select all edges associated with every selected vertex*/ + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter)) { + if(BM_TestHFlag(eed->v1, BM_SELECT)) BM_Select(em->bm, eed, 1); + else if(BM_TestHFlag(eed->v2, BM_SELECT)) BM_Select(em->bm, eed, 1); + } + } + else if(selectmode == SCE_SELECT_FACE) { + BMIter liter; + BMLoop *l; + + /*select all faces associated with every selected vertex*/ + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter)) { + l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa); + for (; l; l=BMIter_Step(&liter)) { + if (BM_TestHFlag(l->v, BM_SELECT)) { + BM_Select(em->bm, efa, 1); + break; + } + } + } + } + } + + if(oldmode == SCE_SELECT_EDGE){ + if(selectmode == SCE_SELECT_FACE) { + BMIter liter; + BMLoop *l; + + /*select all faces associated with every selected vertex*/ + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter)) { + l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa); + for (; l; l=BMIter_Step(&liter)) { + if (BM_TestHFlag(l->v, BM_SELECT)) { + BM_Select(em->bm, efa, 1); + break; + } + } + } + } + } +} diff --git a/source/blender/editors/mesh/bmesh_selecthistory.c b/source/blender/editors/mesh/bmesh_selecthistory.c new file mode 100644 index 00000000000..9421a98a11c --- /dev/null +++ b/source/blender/editors/mesh/bmesh_selecthistory.c @@ -0,0 +1,270 @@ +/** + * $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) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* ********* Selection History ************ */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "MTC_matrixops.h" + +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_texture_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "BKE_context.h" +#include "BKE_displist.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" +#include "BKE_report.h" +#include "BKE_tessmesh.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "RE_render_ext.h" /* externtex */ + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_view3d.h" +#include "bmesh.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "mesh_intern.h" + +#include "BLO_sys_types.h" // for intptr_t support + +/* XXX */ +static void waitcursor() {} +static int pupmenu() {return 0;} + +/* generic way to get data from an EditSelection type +These functions were written to be used by the Modifier widget when in Rotate about active mode, +but can be used anywhere. +EM_editselection_center +EM_editselection_normal +EM_editselection_plane +*/ +void EDBM_editselection_center(BMEditMesh *em, float *center, BMEditSelection *ese) +{ + if (ese->type==BM_VERT) { + BMVert *eve= ese->data; + VecCopyf(center, eve->co); + } else if (ese->type==BM_EDGE) { + BMEdge *eed= ese->data; + VecAddf(center, eed->v1->co, eed->v2->co); + VecMulf(center, 0.5); + } else if (ese->type==BM_FACE) { + BMFace *efa= ese->data; + BM_Compute_Face_Center(em->bm, efa, center); + } +} + +void EDBM_editselection_normal(float *normal, BMEditSelection *ese) +{ + if (ese->type==BM_VERT) { + BMVert *eve= ese->data; + VecCopyf(normal, eve->no); + } else if (ese->type==BM_EDGE) { + BMEdge *eed= ese->data; + float plane[3]; /* need a plane to correct the normal */ + float vec[3]; /* temp vec storage */ + + VecAddf(normal, eed->v1->no, eed->v2->no); + VecSubf(plane, eed->v2->co, eed->v1->co); + + /* the 2 vertex normals will be close but not at rightangles to the edge + for rotate about edge we want them to be at right angles, so we need to + do some extra colculation to correct the vert normals, + we need the plane for this */ + Crossf(vec, normal, plane); + Crossf(normal, plane, vec); + Normalize(normal); + + } else if (ese->type==BM_FACE) { + BMFace *efa= ese->data; + VecCopyf(normal, efa->no); + } +} + +/* Calculate a plane that is rightangles to the edge/vert/faces normal +also make the plane run allong an axis that is related to the geometry, +because this is used for the manipulators Y axis.*/ +void EDBM_editselection_plane(BMEditMesh *em, float *plane, BMEditSelection *ese) +{ + if (ese->type==BM_VERT) { + BMVert *eve= ese->data; + float vec[3]={0,0,0}; + + if (ese->prev) { /*use previously selected data to make a usefull vertex plane */ + EDBM_editselection_center(em, vec, ese->prev); + VecSubf(plane, vec, eve->co); + } else { + /* make a fake plane thats at rightangles to the normal + we cant make a crossvec from a vec thats the same as the vec + unlikely but possible, so make sure if the normal is (0,0,1) + that vec isnt the same or in the same direction even.*/ + if (eve->no[0]<0.5) vec[0]=1; + else if (eve->no[1]<0.5) vec[1]=1; + else vec[2]=1; + Crossf(plane, eve->no, vec); + } + } else if (ese->type==BM_EDGE) { + BMEdge *eed= ese->data; + + /*the plane is simple, it runs allong the edge + however selecting different edges can swap the direction of the y axis. + this makes it less likely for the y axis of the manipulator + (running along the edge).. to flip less often. + at least its more pradictable */ + if (eed->v2->co[1] > eed->v1->co[1]) /*check which to do first */ + VecSubf(plane, eed->v2->co, eed->v1->co); + else + VecSubf(plane, eed->v1->co, eed->v2->co); + + } else if (ese->type==BM_FACE) { + BMFace *efa= ese->data; + float vec[3] = {0.0f, 0.0f, 0.0f}; + + /*for now, use face normal*/ + + /* make a fake plane thats at rightangles to the normal + we cant make a crossvec from a vec thats the same as the vec + unlikely but possible, so make sure if the normal is (0,0,1) + that vec isnt the same or in the same direction even.*/ + if (efa->no[0]<0.5) vec[0]=1.0f; + else if (efa->no[1]<0.5) vec[1]=1.0f; + else vec[2]=1.0f; + Crossf(plane, efa->no, vec); +#if 0 + + if (efa->v4) { /*if its a quad- set the plane along the 2 longest edges.*/ + float vecA[3], vecB[3]; + VecSubf(vecA, efa->v4->co, efa->v3->co); + VecSubf(vecB, efa->v1->co, efa->v2->co); + VecAddf(plane, vecA, vecB); + + VecSubf(vecA, efa->v1->co, efa->v4->co); + VecSubf(vecB, efa->v2->co, efa->v3->co); + VecAddf(vec, vecA, vecB); + /*use the biggest edge length*/ + if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]) + VecCopyf(plane, vec); + } else { + /*start with v1-2 */ + VecSubf(plane, efa->v1->co, efa->v2->co); + + /*test the edge between v2-3, use if longer */ + VecSubf(vec, efa->v2->co, efa->v3->co); + if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]) + VecCopyf(plane, vec); + + /*test the edge between v1-3, use if longer */ + VecSubf(vec, efa->v3->co, efa->v1->co); + if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]) + VecCopyf(plane, vec); + } +#endif + } + Normalize(plane); +} + +static int EDBM_check_selection(BMEditMesh *em, void *data) +{ + BMEditSelection *ese; + + for(ese = em->selected.first; ese; ese = ese->next){ + if(ese->data == data) return 1; + } + + return 0; +} + +void EDBM_remove_selection(BMEditMesh *em, void *data) +{ + BMEditSelection *ese; + for(ese=em->selected.first; ese; ese = ese->next){ + if(ese->data == data){ + BLI_freelinkN(&(em->selected),ese); + break; + } + } +} + +void EDBM_store_selection(BMEditMesh *em, void *data) +{ + BMEditSelection *ese; + if(!EDBM_check_selection(em, data)){ + ese = (BMEditSelection*) MEM_callocN( sizeof(BMEditSelection), "BMEdit Selection"); + ese->type = ((BMHeader*)data)->type; + ese->data = data; + BLI_addtail(&(em->selected),ese); + } +} + +void EDBM_validate_selections(BMEditMesh *em) +{ + BMEditSelection *ese, *nextese; + + ese = em->selected.first; + + while(ese){ + nextese = ese->next; + if (!BM_TestHFlag(ese->data, BM_SELECT)) BLI_freelinkN(&(em->selected), ese); + ese = nextese; + } +} diff --git a/source/blender/editors/mesh/bmesh_tools.c b/source/blender/editors/mesh/bmesh_tools.c new file mode 100644 index 00000000000..103bcbcebce --- /dev/null +++ b/source/blender/editors/mesh/bmesh_tools.c @@ -0,0 +1,1321 @@ + /* $Id: bmesh_tools.c + * + * ***** 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) 2004 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <math.h> +#include <float.h> + +#include "MEM_guardedalloc.h" +#include "PIL_time.h" + +#include "BLO_sys_types.h" // for intptr_t support + +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_key_types.h" +#include "DNA_windowmanager_types.h" + +#include "RNA_types.h" +#include "RNA_define.h" +#include "RNA_access.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" +#include "BLI_rand.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_heap.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_utildefines.h" +#include "BKE_bmesh.h" +#include "BKE_report.h" +#include "BKE_tessmesh.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_view3d.h" +#include "ED_util.h" +#include "ED_screen.h" +#include "ED_transform.h" + +#include "UI_interface.h" + +#include "mesh_intern.h" +#include "bmesh.h" + +static void add_normal_aligned(float *nor, float *add) +{ + if( INPR(nor, add) < -0.9999f) + VecSubf(nor, nor, add); + else + VecAddf(nor, nor, add); +} + + +static int subdivide_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + int cuts= RNA_int_get(op->ptr,"number_cuts"); + float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness"); + float fractal= RNA_float_get(op->ptr, "fractal")/100; + int flag= 0; + + if(smooth != 0.0f) + flag |= B_SMOOTH; + if(fractal != 0.0f) + flag |= B_FRACTAL; + + BM_esubdivideflag(obedit, em->bm, BM_SELECT, smooth, fractal, scene->toolsettings->editbutflag|flag, cuts, 0); + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_subdivide(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Subdivide"; + ot->idname= "MESH_OT_subdivide"; + + /* api callbacks */ + ot->exec= subdivide_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX); + RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f); + RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1000.0f, "Smoothness", "Smoothness factor.", 0.0f, FLT_MAX); +} + +#if 0 +static int subdivide_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, 1, 0); + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + + return OPERATOR_FINISHED; +} + +void MESH_OT_subdivide(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Subdivide"; + ot->idname= "MESH_OT_subdivide"; + + /* api callbacks */ + ot->exec= subdivide_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int subdivide_multi_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, RNA_int_get(op->ptr,"number_cuts"), 0); + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + + return OPERATOR_FINISHED; +} + +void MESH_OT_subdivide_multi(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Subdivide Multi"; + ot->idname= "MESH_OT_subdivide_multi"; + + /* api callbacks */ + ot->exec= subdivide_multi_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX); +} + +static int subdivide_multi_fractal_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + BM_esubdivideflag(obedit, em->bm, 1, -(RNA_float_get(op->ptr, "random_factor")/100), scene->toolsettings->editbutflag, RNA_int_get(op->ptr, "number_cuts"), 0); + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + + return OPERATOR_FINISHED; +} + +void MESH_OT_subdivide_multi_fractal(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Subdivide Multi Fractal"; + ot->idname= "MESH_OT_subdivide_multi_fractal"; + + /* api callbacks */ + ot->exec= subdivide_multi_fractal_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX); + RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f); +} + +static int subdivide_smooth_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + BM_esubdivideflag(obedit, em->bm, 1, 0.292f*RNA_float_get(op->ptr, "smoothness"), scene->toolsettings->editbutflag | B_SMOOTH, 1, 0); + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + + return OPERATOR_FINISHED; +} + +void MESH_OT_subdivide_smooth(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Subdivide Smooth"; + ot->idname= "MESH_OT_subdivide_smooth"; + + /* api callbacks */ + ot->exec= subdivide_smooth_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX); +} + +static int subdivs_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + uiPopupMenu *pup; + uiLayout *layout; + + pup= uiPupMenuBegin(C, "Subdivision Type", 0); + layout= uiPupMenuLayout(pup); + uiItemsEnumO(layout, "MESH_OT_subdivs", "type"); + uiPupMenuEnd(C, pup); + + return OPERATOR_CANCELLED; +} + +static int subdivs_exec(bContext *C, wmOperator *op) +{ + switch(RNA_int_get(op->ptr, "type")) + { + case 0: // simple + subdivide_exec(C,op); + break; + case 1: // multi + subdivide_multi_exec(C,op); + break; + case 2: // fractal; + subdivide_multi_fractal_exec(C,op); + break; + case 3: //smooth + subdivide_smooth_exec(C,op); + break; + } + + return OPERATOR_FINISHED; +} + +void MESH_OT_subdivs(wmOperatorType *ot) +{ + static EnumPropertyItem type_items[]= { + {0, "SIMPLE", 0, "Simple", ""}, + {1, "MULTI", 0, "Multi", ""}, + {2, "FRACTAL", 0, "Fractal", ""}, + {3, "SMOOTH", 0, "Smooth", ""}, + {0, NULL, NULL}}; + + /* identifiers */ + ot->name= "subdivs"; + ot->idname= "MESH_OT_subdivs"; + + /* api callbacks */ + ot->invoke= subdivs_invoke; + ot->exec= subdivs_exec; + + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /*props */ + RNA_def_enum(ot->srna, "type", type_items, 0, "Type", ""); + + /* this is temp, the ops are different, but they are called from subdivs, so all the possible props should be here as well*/ + RNA_def_int(ot->srna, "number_cuts", 4, 1, 10, "Number of Cuts", "", 1, INT_MAX); + RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f); + RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX); +} +#endif + +/* individual face extrude */ +/* will use vertex normals for extrusion directions, so *nor is unaffected */ +short EDBM_Extrude_face_indiv(BMEditMesh *em, short flag, float *nor) +{ +#if 0 + EditVert *eve, *v1, *v2, *v3, *v4; + EditEdge *eed; + EditFace *efa, *nextfa; + + if(em==NULL) return 0; + + /* selected edges with 1 or more selected face become faces */ + /* selected faces each makes new faces */ + /* always remove old faces, keeps volumes manifold */ + /* select the new extrusion, deselect old */ + + /* step 1; init, count faces in edges */ + recalc_editnormals(em); + + for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; // new select flag + + for(eed= em->edges.first; eed; eed= eed->next) { + eed->f2= 0; // amount of unselected faces + } + for(efa= em->faces.first; efa; efa= efa->next) { + if(efa->f & SELECT); + else { + efa->e1->f2++; + efa->e2->f2++; + efa->e3->f2++; + if(efa->e4) efa->e4->f2++; + } + } + + /* step 2: make new faces from faces */ + for(efa= em->faces.last; efa; efa= efa->prev) { + if(efa->f & SELECT) { + v1= addvertlist(em, efa->v1->co, efa->v1); + v2= addvertlist(em, efa->v2->co, efa->v2); + v3= addvertlist(em, efa->v3->co, efa->v3); + + v1->f1= v2->f1= v3->f1= 1; + VECCOPY(v1->no, efa->n); + VECCOPY(v2->no, efa->n); + VECCOPY(v3->no, efa->n); + if(efa->v4) { + v4= addvertlist(em, efa->v4->co, efa->v4); + v4->f1= 1; + VECCOPY(v4->no, efa->n); + } + else v4= NULL; + + /* side faces, clockwise */ + addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL); + addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL); + if(efa->v4) { + addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL); + addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL); + } + else { + addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL); + } + /* top face */ + addfacelist(em, v1, v2, v3, v4, efa, NULL); + } + } + + /* step 3: remove old faces */ + efa= em->faces.first; + while(efa) { + nextfa= efa->next; + if(efa->f & SELECT) { + BLI_remlink(&em->faces, efa); + free_editface(em, efa); + } + efa= nextfa; + } + + /* step 4: redo selection */ + EM_clear_flag_all(em, SELECT); + + for(eve= em->verts.first; eve; eve= eve->next) { + if(eve->f1) eve->f |= SELECT; + } + + EM_select_flush(em); + + return 'n'; +#endif +} + + +/* extrudes individual edges */ +/* nor is filled with constraint vector */ +short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor) +{ +#if 0 + EditVert *eve; + EditEdge *eed; + EditFace *efa; + + for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL; + for(eed= em->edges.first; eed; eed= eed->next) { + eed->tmp.f = NULL; + eed->f2= ((eed->f & flag)!=0); + } + + set_edge_directions_f2(em, 2); + + /* sample for next loop */ + for(efa= em->faces.first; efa; efa= efa->next) { + efa->e1->tmp.f = efa; + efa->e2->tmp.f = efa; + efa->e3->tmp.f = efa; + if(efa->e4) efa->e4->tmp.f = efa; + } + /* make the faces */ + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->f & flag) { + if(eed->v1->tmp.v == NULL) + eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1); + if(eed->v2->tmp.v == NULL) + eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2); + + if(eed->dir==1) + addfacelist(em, eed->v1, eed->v2, + eed->v2->tmp.v, eed->v1->tmp.v, + eed->tmp.f, NULL); + else + addfacelist(em, eed->v2, eed->v1, + eed->v1->tmp.v, eed->v2->tmp.v, + eed->tmp.f, NULL); + + /* for transform */ + if(eed->tmp.f) { + efa = eed->tmp.f; + if (efa->f & SELECT) add_normal_aligned(nor, efa->n); + } + } + } + Normalize(nor); + + /* set correct selection */ + EM_clear_flag_all(em, SELECT); + for(eve= em->verts.last; eve; eve= eve->prev) { + if(eve->tmp.v) { + eve->tmp.v->f |= flag; + } + } + + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->v1->f & eed->v2->f & flag) eed->f |= flag; + } + + if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab +#endif + return 'n'; // n is for normal constraint +} + +/* extrudes individual vertices */ +short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) +{ + BMOperator bmop; + BMOIter siter; + BMVert *v; + + EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag); + + /*deselect original verts*/ + v = BMO_IterNew(&siter, em->bm, &bmop, "verts", BM_VERT); + for (; v; v=BMO_IterStep(&siter)) { + BM_Select(em->bm, v, 0); + } + + BMO_Exec_Op(em->bm, &bmop); + + v = BMO_IterNew(&siter, em->bm, &bmop, "vertout", BM_VERT); + for (; v; v=BMO_IterStep(&siter)) { + BM_Select(em->bm, v, 1); + } + + if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0; + + return 'g'; // g is grab +} + +short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor) +{ + BMesh *bm = em->bm; + BMIter iter; + BMOIter siter; + BMOperator extop; + BMVert *vert; + BMEdge *edge; + BMFace *f; + ModifierData *md; + BMHeader *el; + + BMO_Init_Op(&extop, "extrudefaceregion"); + BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein", + flag, BM_VERT|BM_EDGE|BM_FACE); + + BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) { + BM_Select(bm, vert, 0); + } + + BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) { + BM_Select(bm, edge, 0); + } + + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + BM_Select(bm, f, 0); + } + + /* If a mirror modifier with clipping is on, we need to adjust some + * of the cases above to handle edges on the line of symmetry. + */ + md = obedit->modifiers.first; + for (; md; md=md->next) { + if (md->type==eModifierType_Mirror) { + MirrorModifierData *mmd = (MirrorModifierData*) md; + + if(mmd->flag & MOD_MIR_CLIPPING) { + float mtx[4][4]; + if (mmd->mirror_ob) { + float imtx[4][4]; + Mat4Invert(imtx, mmd->mirror_ob->obmat); + Mat4MulMat4(mtx, obedit->obmat, imtx); + } + + for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL); + edge; edge=BMIter_Step(&iter)) + { + if(edge->head.flag & flag) { + float co1[3], co2[3]; + + VecCopyf(co1, edge->v1->co); + VecCopyf(co2, edge->v2->co); + + if (mmd->mirror_ob) { + VecMat4MulVecfl(co1, mtx, co1); + VecMat4MulVecfl(co2, mtx, co2); + } + + if (mmd->flag & MOD_MIR_AXIS_X) + if ( (fabs(co1[0]) < mmd->tolerance) && + (fabs(co2[0]) < mmd->tolerance) ) + BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL); + + if (mmd->flag & MOD_MIR_AXIS_Y) + if ( (fabs(co1[1]) < mmd->tolerance) && + (fabs(co2[1]) < mmd->tolerance) ) + BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL); + + if (mmd->flag & MOD_MIR_AXIS_Z) + if ( (fabs(co1[2]) < mmd->tolerance) && + (fabs(co2[2]) < mmd->tolerance) ) + BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL); + } + } + } + } + } + + BMO_Exec_Op(bm, &extop); + + nor[0] = nor[1] = nor[2] = 0.0f; + + BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) { + BM_Select(bm, el, 1); + + if (el->type == BM_FACE) { + f = (BMFace*)el; + add_normal_aligned(nor, f->no); + }; + } + + Normalize(nor); + + BMO_Finish_Op(bm, &extop); + + if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab + return 'n'; // normal constraint + +} +short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor) +{ + BMIter iter; + BMEdge *eed; + + /*ensure vert flags are consistent for edge selections*/ + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter)) { + if (BM_TestHFlag(eed, flag)) { + if (flag != BM_SELECT) { + BM_SetHFlag(eed->v1, flag); + BM_SetHFlag(eed->v2, flag); + } else { + BM_Select(em->bm, eed->v1, 1); + BM_Select(em->bm, eed->v2, 1); + } + } else { + if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) { + if (flag != BM_SELECT) + BM_SetHFlag(eed, flag); + else BM_Select(em->bm, eed, 1); + } + } + } + + return EDBM_Extrude_edge(obedit, em, flag, nor); + +} + +static int extrude_repeat_mesh(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + RegionView3D *rv3d = CTX_wm_region_view3d(C); + + int steps = RNA_int_get(op->ptr,"steps"); + + float offs = RNA_float_get(op->ptr,"offset"); + + float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0}; + short a; + + /* dvec */ + dvec[0]= rv3d->persinv[2][0]; + dvec[1]= rv3d->persinv[2][1]; + dvec[2]= rv3d->persinv[2][2]; + Normalize(dvec); + dvec[0]*= offs; + dvec[1]*= offs; + dvec[2]*= offs; + + /* base correction */ + Mat3CpyMat4(bmat, obedit->obmat); + Mat3Inv(tmat, bmat); + Mat3MulVecfl(tmat, dvec); + + for(a=0; a<steps; a++) { + EDBM_Extrude_edge(obedit, em, BM_SELECT, nor); + //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT); + BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT); + //extrudeflag(obedit, em, SELECT, nor); + //translateflag(em, SELECT, dvec); + } + + EDBM_RecalcNormals(em); + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + return OPERATOR_FINISHED; +} + +void MESH_OT_extrude_repeat(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Extrude Repeat Mesh"; + ot->idname= "MESH_OT_extrude_repeat"; + + /* api callbacks */ + ot->exec= extrude_repeat_mesh; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX); + RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX); +} + +/* generic extern called extruder */ +int EDBM_Extrude_Mesh(Object *obedit, BMEditMesh *em, wmOperator *op, float *norin) +{ + Scene *scene= NULL; // XXX CTX! + short nr, transmode= 0; + float stacknor[3] = {0.0f, 0.0f, 0.0f}; + float *nor = norin ? norin : stacknor; + + nor[0] = nor[1] = nor[2] = 0.0f; + if(em->selectmode & SCE_SELECT_VERTEX) { + if(em->bm->totvertsel==0) nr= 0; + else if(em->bm->totvertsel==1) nr= 4; + else if(em->bm->totedgesel==0) nr= 4; + else if(em->bm->totfacesel==0) + nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4"); + else if(em->bm->totfacesel==1) + nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4"); + else + nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4"); + } + else if(em->selectmode & SCE_SELECT_EDGE) { + if (em->bm->totedgesel==0) nr = 0; + + nr = 1; + /*else if (em->totedgesel==1) nr = 3; + else if(em->totfacesel==0) nr = 3; + else if(em->totfacesel==1) + nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3"); + else + nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3"); + */ + } + else { + if (em->bm->totfacesel == 0) nr = 0; + else if (em->bm->totfacesel == 1) nr = 1; + else + nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2"); + } + + if(nr<1) return 'g'; + + if(nr==1 && em->selectmode & SCE_SELECT_VERTEX) + transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor); + else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor); + else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor); + else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, SELECT, nor); + else transmode= EDBM_Extrude_face_indiv(em, SELECT, nor); + + if(transmode==0) { + BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude"); + } + else { + + /* We need to force immediate calculation here because + * transform may use derived objects (which are now stale). + * + * This shouldn't be necessary, derived queries should be + * automatically building this data if invalid. Or something. + */ +// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + object_handle_update(scene, obedit); + + /* individual faces? */ +// BIF_TransformSetUndo("Extrude"); + if(nr==2) { +// initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR); +// Transform(); + } + else { +// initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR); + if(transmode=='n') { + Mat4MulVecfl(obedit->obmat, nor); + VecSubf(nor, nor, obedit->obmat[3]); +// BIF_setSingleAxisConstraint(nor, "along normal"); + } +// Transform(); + } + } + + return transmode; +} + +static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + Scene *scene= CTX_data_scene(C); + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + int constraint_axis[3] = {0, 0, 1}; + int tmode; + + tmode = EDBM_Extrude_Mesh(obedit, em, op, NULL); + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + RNA_enum_set(op->ptr, "proportional", 0); + RNA_boolean_set(op->ptr, "mirror", 0); + + if (tmode == 'n') { + RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL); + RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis); + } + WM_operator_name_call(C, "TFM_OT_translation", WM_OP_INVOKE_REGION_WIN, op->ptr); + + return OPERATOR_FINISHED; +} + +/* extrude without transform */ +static int mesh_extrude_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + + EDBM_Extrude_Mesh(obedit, em, op, NULL); + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + return OPERATOR_FINISHED; +} + + +void MESH_OT_extrude(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Extrude"; + ot->idname= "MESH_OT_extrude"; + + /* api callbacks */ + ot->invoke= mesh_extrude_invoke; + ot->exec= mesh_extrude_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* to give to transform */ + Properties_Proportional(ot); + Properties_Constraints(ot); + RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", ""); +} + +/* ******************** (de)select all operator **************** */ + +void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */ +{ + if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) + EDBM_clear_flag_all(em, SELECT); + else + EDBM_set_flag_all(em, SELECT); +} + +static int toggle_select_all_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + EDBM_toggle_select_all(em); + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_select_all_toggle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select/Deselect All"; + ot->idname= "MESH_OT_select_all_toggle"; + + /* api callbacks */ + ot->exec= toggle_select_all_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* *************** add-click-mesh (extrude) operator ************** */ + +static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event) +{ + ViewContext vc; + BMVert *eve, *v1; + BMIter iter; + float min[3], max[3]; + int done= 0; + + em_setup_viewcontext(C, &vc); + + INIT_MINMAX(min, max); + + BM_ITER(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(v1, BM_SELECT)) { + DO_MINMAX(v1->co, min, max); + done= 1; + } + } + + /* call extrude? */ + if(done) { + BMEdge *eed; + float vec[3], cent[3], mat[3][3]; + float nor[3]= {0.0, 0.0, 0.0}; + + /* check for edges that are half selected, use for rotation */ + done= 0; + BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(eed->v1, BM_SELECT) ^ BM_TestHFlag(eed->v2, BM_SELECT)) { + if(BM_TestHFlag(eed->v1, BM_SELECT)) + VecSubf(vec, eed->v1->co, eed->v2->co); + else + VecSubf(vec, eed->v2->co, eed->v1->co); + VecAddf(nor, nor, vec); + done= 1; + } + } + if(done) Normalize(nor); + + /* center */ + VecAddf(cent, min, max); + VecMulf(cent, 0.5f); + VECCOPY(min, cent); + + Mat4MulVecfl(vc.obedit->obmat, min); // view space + view3d_get_view_aligned_coordinate(&vc, min, event->mval); + Mat4Invert(vc.obedit->imat, vc.obedit->obmat); + Mat4MulVecfl(vc.obedit->imat, min); // back in object space + + VecSubf(min, min, cent); + + /* calculate rotation */ + Mat3One(mat); + if(done) { + float dot; + + VECCOPY(vec, min); + Normalize(vec); + dot= INPR(vec, nor); + + if( fabs(dot)<0.999) { + float cross[3], si, q1[4]; + + Crossf(cross, nor, vec); + Normalize(cross); + dot= 0.5f*saacos(dot); + si= (float)sin(dot); + q1[0]= (float)cos(dot); + q1[1]= cross[0]*si; + q1[2]= cross[1]*si; + q1[3]= cross[2]*si; + + QuatToMat3(q1, mat); + } + } + + + EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor); + EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3", + BM_SELECT, cent, mat); + EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v", + BM_SELECT, min); + } + else { + float *curs= give_cursor(vc.scene, vc.v3d); + BMOperator bmop; + BMOIter oiter; + + VECCOPY(min, curs); + + view3d_get_view_aligned_coordinate(&vc, min, event->mval); + Mat4Invert(vc.obedit->imat, vc.obedit->obmat); + Mat4MulVecfl(vc.obedit->imat, min); // back in object space + + EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min); + BMO_Exec_Op(vc.em->bm, &bmop); + + BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) { + BM_Select(vc.em->bm, v1, 1); + } + + if (!EDBM_FinishOp(vc.em, &bmop, op, 1)) + return OPERATOR_CANCELLED; + } + + //retopo_do_all(); + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); + DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA); + + return OPERATOR_FINISHED; +} + +void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Duplicate or Extrude at 3D Cursor"; + ot->idname= "MESH_OT_dupli_extrude_cursor"; + + /* api callbacks */ + ot->invoke= dupli_extrude_cursor; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int delete_mesh(Object *obedit, wmOperator *op, int event, Scene *scene) +{ + BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh; + + if(event<1) return OPERATOR_CANCELLED; + + if(event==10 ) { + //"Erase Vertices"; + + if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS)) + return OPERATOR_CANCELLED; + } + else if(event==11) { + //"Edge Loop" + if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT)) + return OPERATOR_CANCELLED; + } + else if(event==7) { + //"Dissolve" + if (bem->selectmode & SCE_SELECT_FACE) { + if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT)) + return OPERATOR_CANCELLED; + } else if (bem->selectmode & SCE_SELECT_EDGE) { + if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT)) + return OPERATOR_CANCELLED; + } else if (bem->selectmode & SCE_SELECT_VERTEX) { + if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT)) + return OPERATOR_CANCELLED; + } + } + else if(event==4) { + //Edges and Faces + if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES)) + return OPERATOR_CANCELLED; + } + else if(event==1) { + //"Erase Edges" + if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES)) + return OPERATOR_CANCELLED; + } + else if(event==2) { + //"Erase Faces"; + if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES)) + return OPERATOR_CANCELLED; + } + else if(event==5) { + //"Erase Only Faces"; + if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d", + BM_SELECT, DEL_ONLYFACES)) + return OPERATOR_CANCELLED; + } + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + + return OPERATOR_FINISHED; +} + +/* Note, these values must match delete_mesh() event values */ +static EnumPropertyItem prop_mesh_delete_types[] = { + {7, "DISSOLVE", 0, "Dissolve", ""}, + {10,"VERT", 0, "Vertices", ""}, + {1, "EDGE", 0, "Edges", ""}, + {2, "FACE", 0, "Faces", ""}, + {11, "EDGE_LOOP", 0, "Edge Loop", ""}, + {4, "EDGE_FACE", 0, "Edges & Faces", ""}, + {5, "ONLY_FACE", 0, "Only Faces", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static int delete_mesh_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + + delete_mesh(obedit, op, RNA_enum_get(op->ptr, "type"), scene); + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA|ND_GEOM_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_delete(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Delete"; + ot->idname= "MESH_OT_delete"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= delete_mesh_exec; + + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /*props */ + RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data"); +} + + +static int addedgeface_mesh_exec(bContext *C, wmOperator *op) +{ + BMOperator bmop; + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT)) + return OPERATOR_CANCELLED; + + BMO_Exec_Op(em->bm, &bmop); + BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT); + + if (!EDBM_FinishOp(em, &bmop, op, 1)) + return OPERATOR_CANCELLED; + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA); + + return OPERATOR_FINISHED; +} + +void MESH_OT_edge_face_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Make Edge/Face"; + ot->idname= "MESH_OT_edge_face_add"; + + /* api callbacks */ + ot->exec= addedgeface_mesh_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + +} + +static EnumPropertyItem prop_mesh_edit_types[] = { + {1, "VERT", 0, "Vertices", ""}, + {2, "EDGE", 0, "Edges", ""}, + {3, "FACE", 0, "Faces", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static int mesh_selection_type_exec(bContext *C, wmOperator *op) +{ + + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + int type = RNA_enum_get(op->ptr,"type"); + + switch (type) { + case 1: + em->selectmode = SCE_SELECT_VERTEX; + break; + case 2: + em->selectmode = SCE_SELECT_EDGE; + break; + case 3: + em->selectmode = SCE_SELECT_FACE; + break; + } + + EDBM_selectmode_set(em); + CTX_data_scene(C)->toolsettings->selectmode = em->selectmode; + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_selection_type(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Selection Mode"; + ot->idname= "MESH_OT_selection_type"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= mesh_selection_type_exec; + + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type"); + RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode"); +} + +/* ************************* SEAMS AND EDGES **************** */ + +static int editbmesh_mark_seam(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit= CTX_data_edit_object(C); + Mesh *me= ((Mesh *)obedit->data); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMEdge *eed; + BMIter iter; + int clear = RNA_boolean_get(op->ptr, "clear"); + + /* auto-enable seams drawing */ + if(clear==0) { + me->drawflag |= ME_DRAWSEAMS; + } + + if(clear) { + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(eed, BM_HIDDEN) == 0 && + BM_TestHFlag(eed, BM_SELECT) != 0) + { + BM_ClearHFlag(eed, BM_SEAM); + } + } + } + else { + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(eed, BM_HIDDEN) == 0 && + BM_TestHFlag(eed, BM_SELECT) != 0) + { + BM_SetHFlag(eed, BM_SEAM); + } + } + } + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_mark_seam(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mark Seam"; + ot->idname= "MESH_OT_mark_seam"; + + /* api callbacks */ + ot->exec= editbmesh_mark_seam; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); +} + +static int editbmesh_mark_sharp(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit= CTX_data_edit_object(C); + Mesh *me= ((Mesh *)obedit->data); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMEdge *eed; + BMIter iter; + int clear = RNA_boolean_get(op->ptr, "clear"); + + /* auto-enable sharp edge drawing */ + if(clear == 0) { + me->drawflag |= ME_DRAWSHARP; + } + + if(!clear) { + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(eed, BM_HIDDEN) == 0 && + BM_TestHFlag(eed, BM_SELECT) != 0) + { + BM_SetHFlag(eed, BM_SHARP); + } + } + } else { + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(eed, BM_HIDDEN) == 0 && + BM_TestHFlag(eed, BM_SELECT) != 0) + { + BM_ClearHFlag(eed, BM_SHARP); + } + } + } + + + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_mark_sharp(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mark Sharp"; + ot->idname= "MESH_OT_mark_sharp"; + + /* api callbacks */ + ot->exec= editbmesh_mark_sharp; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); +} diff --git a/source/blender/editors/mesh/bmeshutils.c b/source/blender/editors/mesh/bmeshutils.c new file mode 100644 index 00000000000..e3ec1c16ce3 --- /dev/null +++ b/source/blender/editors/mesh/bmeshutils.c @@ -0,0 +1,523 @@ + /* $Id: bmeshutils.c + * + * ***** 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) 2004 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <math.h> +#include <float.h> + +#include "MEM_guardedalloc.h" +#include "PIL_time.h" + +#include "BLO_sys_types.h" // for intptr_t support + +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_key_types.h" +#include "DNA_windowmanager_types.h" + +#include "RNA_types.h" +#include "RNA_define.h" +#include "RNA_access.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_editVert.h" +#include "BLI_rand.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_heap.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_utildefines.h" +#include "BKE_bmesh.h" +#include "BKE_report.h" +#include "BKE_tessmesh.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_view3d.h" +#include "ED_util.h" +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "mesh_intern.h" +#include "bmesh.h" + +void EDBM_RecalcNormals(BMEditMesh *em) +{ + BM_Compute_Normals(em->bm); +} + +void EDBM_stats_update(BMEditMesh *em) +{ + BMIter iter; + BMHeader *ele; + int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH}; + int *tots[3]; + int i; + + tots[0] = &em->bm->totvertsel; + tots[1] = &em->bm->totedgesel; + tots[2] = &em->bm->totfacesel; + + em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0; + + for (i=0; i<3; i++) { + ele = BMIter_New(&iter, em->bm, types[i], NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + if (BM_TestHFlag(ele, BM_SELECT)) { + *tots[i]++; + } + } + } +} + +/*this function is defunct, dead*/ +void EDBM_Tesselate(EditMesh *em) +{ + EditMesh *em2; + EditFace *efa; + BMesh *bm; + int found=0; + + for (efa=em->faces.first; efa; efa=efa->next) { + if ((efa->e1->h & EM_FGON) || (efa->e2->h & EM_FGON) || + (efa->e3->h & EM_FGON) || (efa->e4&&(efa->e4->h&EM_FGON))) + { + found = 1; + break; + } + } + + if (found) { + bm = editmesh_to_bmesh(em); + em2 = bmesh_to_editmesh(bm); + set_editMesh(em, em2); + + MEM_freeN(em2); + BM_Free_Mesh(bm); + } +} + +int EDBM_InitOpf(BMEditMesh *em, BMOperator *bmop, wmOperator *op, char *fmt, ...) +{ + BMesh *bm = em->bm; + va_list list; + + va_start(list, fmt); + + if (!BMO_VInitOpf(bm, bmop, fmt, list)) { + BKE_report(op->reports, RPT_ERROR, + "Parse error in EDBM_CallOpf"); + va_end(list); + return 0; + } + + em->emcopy = BMEdit_Copy(em); + + va_end(list); +} + + +/*returns 0 on error, 1 on success. executes and finishes a bmesh operator*/ +int EDBM_FinishOp(BMEditMesh *em, BMOperator *bmop, wmOperator *op, int report) { + char *errmsg; + + BMO_Finish_Op(em->bm, bmop); + + if (BMO_GetError(em->bm, &errmsg, NULL)) { + BMEditMesh *emcopy = em->emcopy; + + if (report) BKE_report(op->reports, RPT_ERROR, errmsg); + + BMEdit_Free(em); + *em = *emcopy; + + MEM_freeN(emcopy); + return 0; + } else { + BMEdit_Free(em->emcopy); + MEM_freeN(em->emcopy); + em->emcopy = NULL; + } + + return 1; +} + +int EDBM_CallOpf(BMEditMesh *em, wmOperator *op, char *fmt, ...) +{ + BMesh *bm = em->bm; + BMOperator bmop; + va_list list; + + va_start(list, fmt); + + if (!BMO_VInitOpf(bm, &bmop, fmt, list)) { + BKE_report(op->reports, RPT_ERROR, + "Parse error in EDBM_CallOpf"); + va_end(list); + return 0; + } + + em->emcopy = BMEdit_Copy(em); + + BMO_Exec_Op(bm, &bmop); + + va_end(list); + return EDBM_FinishOp(em, &bmop, op, 1); +} + +int EDBM_CallOpfSilent(BMEditMesh *em, char *fmt, ...) +{ + BMesh *bm = em->bm; + BMOperator bmop; + va_list list; + + va_start(list, fmt); + + if (!BMO_VInitOpf(bm, &bmop, fmt, list)) { + va_end(list); + return 0; + } + + em->emcopy = BMEdit_Copy(em); + + BMO_Exec_Op(bm, &bmop); + + va_end(list); + return EDBM_FinishOp(em, &bmop, NULL, 0); +} + +void EDBM_MakeEditBMesh(Scene *scene, Object *ob) +{ + Mesh *me = ob->data; + EditMesh *em; + BMesh *bm; + + if (!me->mpoly && me->totface) { + em = make_editMesh(scene, ob); + bm = editmesh_to_bmesh(em); + + free_editMesh(em); + } else { + bm = BKE_mesh_to_bmesh(me); + } + + me->edit_btmesh = BMEdit_Create(bm); + me->edit_btmesh->selectmode = scene->toolsettings->selectmode; +} + +void EDBM_LoadEditBMesh(Scene *scene, Object *ob) +{ + Mesh *me = ob->data; + BMesh *bm = me->edit_btmesh->bm; + + BMO_CallOpf(bm, "object_load_bmesh scene=%p object=%p", scene, ob); + +#if 0 + EditMesh *em = bmesh_to_editmesh(me->edit_btmesh->bm); + + load_editMesh(scene, ob, em); + free_editMesh(em); + MEM_freeN(em); +#endif +} + +void EDBM_FreeEditBMesh(BMEditMesh *tm) +{ + BMEdit_Free(tm); +} + +void EDBM_init_index_arrays(BMEditMesh *tm, int forvert, int foredge, int forface) +{ + EDBM_free_index_arrays(tm); + + if (forvert) { + BMIter iter; + BMVert *ele; + int i=0; + + tm->vert_index = MEM_mallocN(sizeof(void**)*tm->bm->totvert, "tm->vert_index"); + + ele = BMIter_New(&iter, tm->bm, BM_VERTS_OF_MESH, NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + tm->vert_index[i++] = ele; + } + } + + if (foredge) { + BMIter iter; + BMEdge *ele; + int i=0; + + tm->edge_index = MEM_mallocN(sizeof(void**)*tm->bm->totedge, "tm->edge_index"); + + ele = BMIter_New(&iter, tm->bm, BM_EDGES_OF_MESH, NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + tm->edge_index[i++] = ele; + } + } + + if (forface) { + BMIter iter; + BMFace *ele; + int i=0; + + tm->face_index = MEM_mallocN(sizeof(void**)*tm->bm->totface, "tm->face_index"); + + ele = BMIter_New(&iter, tm->bm, BM_FACES_OF_MESH, NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + tm->face_index[i++] = ele; + } + } +} + +void EDBM_free_index_arrays(BMEditMesh *tm) +{ + if (tm->vert_index) { + MEM_freeN(tm->vert_index); + tm->vert_index = NULL; + } + + if (tm->edge_index) { + MEM_freeN(tm->edge_index); + tm->edge_index = NULL; + } + + if (tm->face_index) { + MEM_freeN(tm->face_index); + tm->face_index = NULL; + } +} + +BMVert *EDBM_get_vert_for_index(BMEditMesh *tm, int index) +{ + return tm->vert_index?tm->vert_index[index]:NULL; +} + +BMEdge *EDBM_get_edge_for_index(BMEditMesh *tm, int index) +{ + return tm->edge_index?tm->edge_index[index]:NULL; +} + +BMFace *EDBM_get_face_for_index(BMEditMesh *tm, int index) +{ + return tm->face_index?tm->face_index[index]:NULL; +} + +/* this replaces the active flag used in uv/face mode */ +void EDBM_set_actFace(BMEditMesh *em, BMFace *efa) +{ + em->bm->act_face = efa; +} + +BMFace *EDBM_get_actFace(BMEditMesh *em, int sloppy) +{ + if (em->bm->act_face) { + return em->bm->act_face; + } else if (sloppy) { + BMFace *efa= NULL; + BMEditSelection *ese; + + ese = em->selected.last; + for (; ese; ese=ese->prev){ + if(ese->type == BM_FACE) { + efa = (BMFace *)ese->data; + + if (BM_TestHFlag(efa, BM_HIDDEN)) efa= NULL; + else break; + } + } + if (efa==NULL) { + BMIter iter; + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter)) { + if (BM_TestHFlag(efa, BM_SELECT)) + break; + } + } + return efa; /* can still be null */ + } + return NULL; + +} + +void EDBM_selectmode_flush(BMEditMesh *em) +{ + em->bm->selectmode = em->selectmode; + BM_SelectMode_Flush(em->bm); +} + + +int EDBM_get_actSelection(BMEditMesh *em, BMEditSelection *ese) +{ + BMEditSelection *ese_last = em->selected.last; + BMFace *efa = EDBM_get_actFace(em, 0); + + ese->next = ese->prev = NULL; + + if (ese_last) { + if (ese_last->type == BM_FACE) { /* if there is an active face, use it over the last selected face */ + if (efa) { + ese->data = (void *)efa; + } else { + ese->data = ese_last->data; + } + ese->type = BM_FACE; + } else { + ese->data = ese_last->data; + ese->type = ese_last->type; + } + } else if (efa) { /* no */ + ese->data = (void *)efa; + ese->type = BM_FACE; + } else { + ese->data = NULL; + return 0; + } + return 1; +} + +void EDBM_clear_flag_all(BMEditMesh *em, int flag) +{ + BMIter iter; + BMHeader *ele; + int i, type; + + for (i=0; i<3; i++) { + switch (i) { + case 0: + type = BM_VERTS_OF_MESH; + break; + case 1: + type = BM_EDGES_OF_MESH; + break; + case 2: + type = BM_FACES_OF_MESH; + break; + } + ele = BMIter_New(&iter, em->bm, type, NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + if (flag & BM_SELECT) BM_Select(em->bm, ele, 0); + BM_ClearHFlag(ele, flag); + } + } +} + + +void EDBM_set_flag_all(BMEditMesh *em, int flag) +{ + BMIter iter; + BMHeader *ele; + int i, type; + + for (i=0; i<3; i++) { + switch (i) { + case 0: + type = BM_VERTS_OF_MESH; + break; + case 1: + type = BM_EDGES_OF_MESH; + break; + case 2: + type = BM_FACES_OF_MESH; + break; + } + ele = BMIter_New(&iter, em->bm, type, NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + if (flag & BM_SELECT) BM_Select(em->bm, ele, 1); + BM_SetHFlag(ele, flag); + } + } +} + +/**************-------------- Undo ------------*****************/ + +/* for callbacks */ + +static void *getEditMesh(bContext *C) +{ + Object *obedit= CTX_data_edit_object(C); + if(obedit && obedit->type==OB_MESH) { + Mesh *me= obedit->data; + return me->edit_btmesh; + } + return NULL; +} + +/*undo simply makes copies of a bmesh*/ +static void *editbtMesh_to_undoMesh(void *emv) +{ + /*we recalc the tesselation here, to avoid seeding calls to + BMEdit_RecalcTesselation throughout the code.*/ + BMEdit_RecalcTesselation(emv); + + return BMEdit_Copy(emv); +} + +static void undoMesh_to_editbtMesh(void *umv, void *emv) +{ + BMEditMesh *bm1 = umv, *bm2 = emv; + + BMEdit_Free(bm2); + + *bm2 = *BMEdit_Copy(bm1); +} + + +static void free_undo(void *umv) +{ + BMEditMesh *em = umv; + + BMEdit_Free(em); +} + +/* and this is all the undo system needs to know */ +void undo_push_mesh(bContext *C, char *name) +{ + undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL); +} diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c index 6c66ae468fa..49872eae897 100644 --- a/source/blender/editors/mesh/editmesh.c +++ b/source/blender/editors/mesh/editmesh.c @@ -53,6 +53,7 @@ #include "BLI_editVert.h" #include "BLI_dynstr.h" #include "BLI_rand.h" +#include "BLI_mempool.h" #include "BKE_cloth.h" #include "BKE_context.h" @@ -71,6 +72,7 @@ #include "BKE_softbody.h" #include "BKE_texture.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #include "LBM_fluidsim.h" @@ -91,6 +93,8 @@ /* own include */ #include "mesh_intern.h" +#include "bmesh.h" + /* editmesh.c: - add/alloc/free data @@ -112,22 +116,21 @@ static void error() {} /* ************ ADD / REMOVE / FIND ****************** */ -static void *calloc_em(EditMesh *em, size_t size, size_t nr) -{ - return calloc(size, nr); +static void init_editMesh(EditMesh *em) { + if (!em->vertpool) em->vertpool = BLI_mempool_create(sizeof(EditVert), 1, 512); + if (!em->edgepool) em->edgepool = BLI_mempool_create(sizeof(EditEdge), 1, 512); + if (!em->facepool) em->facepool = BLI_mempool_create(sizeof(EditFace), 1, 512); } -/* used to bypass normal calloc with fast one */ -static void *(*callocvert)(EditMesh *, size_t, size_t) = calloc_em; -static void *(*callocedge)(EditMesh *, size_t, size_t) = calloc_em; -static void *(*callocface)(EditMesh *, size_t, size_t) = calloc_em; - EditVert *addvertlist(EditMesh *em, float *vec, EditVert *example) { EditVert *eve; static int hashnr= 0; + + if (!em->vertpool) init_editMesh(em); + + eve= BLI_mempool_calloc(em->vertpool); - eve= callocvert(em, sizeof(EditVert), 1); BLI_addtail(&em->verts, eve); em->totvert++; @@ -157,8 +160,7 @@ void free_editvert (EditMesh *em, EditVert *eve) EM_remove_selection(em, eve, EDITVERT); CustomData_em_free_block(&em->vdata, &eve->data); - if(eve->fast==0) - free(eve); + BLI_mempool_free(em->vertpool, eve); em->totvert--; } @@ -256,11 +258,12 @@ EditEdge *addedgelist(EditMesh *em, EditVert *v1, EditVert *v2, EditEdge *exampl } /* find in hashlist */ + if (!em->edgepool) init_editMesh(em); eed= findedgelist(em, v1, v2); if(eed==NULL) { - eed= (EditEdge *)callocedge(em, sizeof(EditEdge), 1); + eed= (EditEdge *)BLI_mempool_calloc(em->edgepool); eed->v1= v1; eed->v2= v2; BLI_addtail(&em->edges, eed); @@ -293,9 +296,8 @@ void remedge(EditMesh *em, EditEdge *eed) void free_editedge(EditMesh *em, EditEdge *eed) { EM_remove_selection(em, eed, EDITEDGE); - if(eed->fast==0){ - free(eed); - } + + BLI_mempool_free(em->edgepool, eed); } void free_editface(EditMesh *em, EditFace *efa) @@ -307,8 +309,7 @@ void free_editface(EditMesh *em, EditFace *efa) } CustomData_em_free_block(&em->fdata, &efa->data); - if(efa->fast==0) - free(efa); + BLI_mempool_free(em->facepool, efa); em->totface--; } @@ -384,7 +385,9 @@ EditFace *addfacelist(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, Ed if(v1==v2 || v2==v3 || v1==v3) return NULL; if(e2==0) return NULL; - efa= (EditFace *)callocface(em, sizeof(EditFace), 1); + if (!em->facepool) init_editMesh(em); + efa= (EditFace *)BLI_mempool_calloc(em->facepool); + efa->v1= v1; efa->v2= v2; efa->v3= v3; @@ -467,55 +470,10 @@ int editface_containsEdge(EditFace *efa, EditEdge *eed) /* ************************ stuct EditMesh manipulation ***************************** */ -/* fake callocs for fastmalloc below */ -static void *calloc_fastvert(EditMesh *em, size_t size, size_t nr) -{ - EditVert *eve= em->curvert++; - eve->fast= 1; - return eve; -} -static void *calloc_fastedge(EditMesh *em, size_t size, size_t nr) -{ - EditEdge *eed= em->curedge++; - eed->fast= 1; - return eed; -} -static void *calloc_fastface(EditMesh *em, size_t size, size_t nr) -{ - EditFace *efa= em->curface++; - efa->fast= 1; - return efa; -} - -/* allocate 1 chunk for all vertices, edges, faces. These get tagged to - prevent it from being freed -*/ -static void init_editmesh_fastmalloc(EditMesh *em, int totvert, int totedge, int totface) -{ - if(totvert) em->allverts= MEM_callocN(totvert*sizeof(EditVert), "allverts"); - else em->allverts= NULL; - em->curvert= em->allverts; - - if(totedge==0) totedge= 4*totface; // max possible - - if(totedge) em->alledges= MEM_callocN(totedge*sizeof(EditEdge), "alledges"); - else em->alledges= NULL; - em->curedge= em->alledges; - - if(totface) em->allfaces= MEM_callocN(totface*sizeof(EditFace), "allfaces"); - else em->allfaces= NULL; - em->curface= em->allfaces; - - callocvert= calloc_fastvert; - callocedge= calloc_fastedge; - callocface= calloc_fastface; -} - -static void end_editmesh_fastmalloc(void) +void set_editMesh(EditMesh *dst, EditMesh *src) { - callocvert= calloc_em; - callocedge= calloc_em; - callocface= calloc_em; + free_editMesh(dst); + *dst = *src; } /* do not free editmesh itself here */ @@ -527,7 +485,12 @@ void free_editMesh(EditMesh *em) if(em->edges.first) free_edgelist(em, &em->edges); if(em->faces.first) free_facelist(em, &em->faces); if(em->selected.first) BLI_freelistN(&(em->selected)); - + + if (em->vertpool) BLI_mempool_destroy(em->vertpool); + if (em->edgepool) BLI_mempool_destroy(em->edgepool); + if (em->facepool) BLI_mempool_destroy(em->facepool); + em->vertpool = em->edgepool = em->facepool = NULL; + CustomData_free(&em->vdata, 0); CustomData_free(&em->fdata, 0); @@ -815,7 +778,7 @@ static int editmesh_pointcache_edit(Scene *scene, Object *ob, int totvert, PTCac } /* turns Mesh into editmesh */ -void make_editMesh(Scene *scene, Object *ob) +EditMesh *make_editMesh(Scene *scene, Object *ob) { Mesh *me= ob->data; MFace *mface; @@ -833,13 +796,7 @@ void make_editMesh(Scene *scene, Object *ob) float cacheco[3], cachemat[4][4], *co; int tot, a, cacheedit= 0, eekadoodle= 0; - if(me->edit_mesh==NULL) - me->edit_mesh= MEM_callocN(sizeof(EditMesh), "editmesh"); - else - /* because of reload */ - free_editMesh(me->edit_mesh); - - em= me->edit_mesh; + em= MEM_callocN(sizeof(EditMesh), "editmesh"); em->selectmode= scene->toolsettings->selectmode; // warning needs to be synced em->act_face = NULL; @@ -847,18 +804,9 @@ void make_editMesh(Scene *scene, Object *ob) em->totedge= me->totedge; em->totface= me->totface; - if(tot==0) { - return; - } - - /* initialize fastmalloc for editmesh */ - init_editmesh_fastmalloc(em, me->totvert, me->totedge, me->totface); - actkey = ob_get_keyblock(ob); if(actkey) { tot= actkey->totelem; - /* undo-ing in past for previous editmode sessions gives corrupt 'keyindex' values */ - undo_editmode_clear(); } @@ -979,8 +927,6 @@ void make_editMesh(Scene *scene, Object *ob) error("This Mesh has old style edgecodes, please put it in the bugtracker!"); MEM_freeN(evlist); - - end_editmesh_fastmalloc(); // resets global function pointers if(me->mselect){ //restore editselections @@ -1014,18 +960,18 @@ void make_editMesh(Scene *scene, Object *ob) /* vertex coordinates change with cache edit, need to recalc */ if(cacheedit) recalc_editnormals(em); - + + return em; } /* makes Mesh out of editmesh */ -void load_editMesh(Scene *scene, Object *ob) +void load_editMesh(Scene *scene, Object *ob, EditMesh *em) { Mesh *me= ob->data; MVert *mvert, *oldverts; MEdge *medge; MFace *mface; MSelect *mselect; - EditMesh *em= me->edit_mesh; EditVert *eve; EditFace *efa, *efa_act; EditEdge *eed; @@ -1489,8 +1435,8 @@ static int mesh_separate_selected(Scene *scene, Base *editbase) /* 2 */ basenew->object->data= menew= add_mesh(me->id.name); /* empty */ me->id.us--; - make_editMesh(scene, basenew->object); - emnew= menew->edit_mesh; + emnew = make_editMesh(scene, basenew->object); + //emnew= menew->edit_mesh; /* 3 */ /* SPLIT: first make duplicate */ @@ -1531,7 +1477,7 @@ static int mesh_separate_selected(Scene *scene, Base *editbase) } /* 5 */ - load_editMesh(scene, basenew->object); + load_editMesh(scene, basenew->object, emnew); free_editMesh(emnew); /* hashedges are invalid now, make new! */ @@ -1682,6 +1628,7 @@ typedef struct UndoMesh { EditVertC *verts; EditEdgeC *edges; EditFaceC *faces; + EditFaceC *act_face; EditSelectionC *selected; int totvert, totedge, totface, totsel; short selectmode; @@ -1690,247 +1637,6 @@ typedef struct UndoMesh { CustomData vdata, edata, fdata; } UndoMesh; -/* for callbacks */ - -static void free_undoMesh(void *umv) -{ - UndoMesh *um= umv; - - if(um->verts) MEM_freeN(um->verts); - if(um->edges) MEM_freeN(um->edges); - if(um->faces) MEM_freeN(um->faces); - if(um->selected) MEM_freeN(um->selected); -// XXX if(um->retopo_paint_data) retopo_free_paint_data(um->retopo_paint_data); - CustomData_free(&um->vdata, um->totvert); - CustomData_free(&um->edata, um->totedge); - CustomData_free(&um->fdata, um->totface); - MEM_freeN(um); -} - -static void *editMesh_to_undoMesh(void *emv) -{ - EditMesh *em= (EditMesh *)emv; - UndoMesh *um; - EditVert *eve; - EditEdge *eed; - EditFace *efa; - EditSelection *ese; - EditVertC *evec=NULL; - EditEdgeC *eedc=NULL; - EditFaceC *efac=NULL; - EditSelectionC *esec=NULL; - int a; - - um= MEM_callocN(sizeof(UndoMesh), "undomesh"); - - um->selectmode = em->selectmode; - - for(eve=em->verts.first; eve; eve= eve->next) um->totvert++; - for(eed=em->edges.first; eed; eed= eed->next) um->totedge++; - for(efa=em->faces.first; efa; efa= efa->next) um->totface++; - for(ese=em->selected.first; ese; ese=ese->next) um->totsel++; - /* malloc blocks */ - - if(um->totvert) evec= um->verts= MEM_callocN(um->totvert*sizeof(EditVertC), "allvertsC"); - if(um->totedge) eedc= um->edges= MEM_callocN(um->totedge*sizeof(EditEdgeC), "alledgesC"); - if(um->totface) efac= um->faces= MEM_callocN(um->totface*sizeof(EditFaceC), "allfacesC"); - if(um->totsel) esec= um->selected= MEM_callocN(um->totsel*sizeof(EditSelectionC), "allselections"); - - if(um->totvert) CustomData_copy(&em->vdata, &um->vdata, CD_MASK_EDITMESH, CD_CALLOC, um->totvert); - if(um->totedge) CustomData_copy(&em->edata, &um->edata, CD_MASK_EDITMESH, CD_CALLOC, um->totedge); - if(um->totface) CustomData_copy(&em->fdata, &um->fdata, CD_MASK_EDITMESH, CD_CALLOC, um->totface); - - /* now copy vertices */ - a = 0; - for(eve=em->verts.first; eve; eve= eve->next, evec++, a++) { - VECCOPY(evec->co, eve->co); - VECCOPY(evec->no, eve->no); - - evec->f= eve->f; - evec->h= eve->h; - evec->keyindex= eve->keyindex; - eve->tmp.l = a; /*store index*/ - evec->bweight= (short)(eve->bweight*255.0); - - CustomData_from_em_block(&em->vdata, &um->vdata, eve->data, a); - } - - /* copy edges */ - a = 0; - for(eed=em->edges.first; eed; eed= eed->next, eedc++, a++) { - eedc->v1= (int)eed->v1->tmp.l; - eedc->v2= (int)eed->v2->tmp.l; - eedc->f= eed->f; - eedc->h= eed->h; - eedc->seam= eed->seam; - eedc->sharp= eed->sharp; - eedc->crease= (short)(eed->crease*255.0); - eedc->bweight= (short)(eed->bweight*255.0); - eedc->fgoni= eed->fgoni; - eed->tmp.l = a; /*store index*/ - CustomData_from_em_block(&em->edata, &um->edata, eed->data, a); - - } - - /* copy faces */ - a = 0; - for(efa=em->faces.first; efa; efa= efa->next, efac++, a++) { - efac->v1= (int)efa->v1->tmp.l; - efac->v2= (int)efa->v2->tmp.l; - efac->v3= (int)efa->v3->tmp.l; - if(efa->v4) efac->v4= (int)efa->v4->tmp.l; - else efac->v4= -1; - - efac->mat_nr= efa->mat_nr; - efac->flag= efa->flag; - efac->f= efa->f; - efac->h= efa->h; - efac->fgonf= efa->fgonf; - - efa->tmp.l = a; /*store index*/ - - CustomData_from_em_block(&em->fdata, &um->fdata, efa->data, a); - } - - a = 0; - for(ese=em->selected.first; ese; ese=ese->next, esec++){ - esec->type = ese->type; - if(ese->type == EDITVERT) a = esec->index = ((EditVert*)ese->data)->tmp.l; - else if(ese->type == EDITEDGE) a = esec->index = ((EditEdge*)ese->data)->tmp.l; - else if(ese->type == EDITFACE) a = esec->index = ((EditFace*)ese->data)->tmp.l; - } - -// XXX um->retopo_paint_data= retopo_paint_data_copy(em->retopo_paint_data); -// um->retopo_mode= scene->toolsettings->retopo_mode; - - return um; -} - -static void undoMesh_to_editMesh(void *umv, void *emv) -{ - EditMesh *em= (EditMesh *)emv; - UndoMesh *um= (UndoMesh *)umv; - EditVert *eve, **evar=NULL; - EditEdge *eed; - EditFace *efa; - EditSelection *ese; - EditVertC *evec; - EditEdgeC *eedc; - EditFaceC *efac; - EditSelectionC *esec; - int a=0; - - free_editMesh(em); - - /* malloc blocks */ - memset(em, 0, sizeof(EditMesh)); - - em->selectmode = um->selectmode; - - init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface); - - CustomData_free(&em->vdata, 0); - CustomData_free(&em->edata, 0); - CustomData_free(&em->fdata, 0); - - CustomData_copy(&um->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0); - CustomData_copy(&um->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0); - CustomData_copy(&um->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0); - - /* now copy vertices */ - - if(um->totvert) evar= MEM_mallocN(um->totvert*sizeof(EditVert *), "vertex ar"); - for(a=0, evec= um->verts; a<um->totvert; a++, evec++) { - eve= addvertlist(em, evec->co, NULL); - evar[a]= eve; - - VECCOPY(eve->no, evec->no); - eve->f= evec->f; - eve->h= evec->h; - eve->keyindex= evec->keyindex; - eve->bweight= ((float)evec->bweight)/255.0f; - - CustomData_to_em_block(&um->vdata, &em->vdata, a, &eve->data); - } - - /* copy edges */ - for(a=0, eedc= um->edges; a<um->totedge; a++, eedc++) { - eed= addedgelist(em, evar[eedc->v1], evar[eedc->v2], NULL); - - eed->f= eedc->f; - eed->h= eedc->h; - eed->seam= eedc->seam; - eed->sharp= eedc->sharp; - eed->fgoni= eedc->fgoni; - eed->crease= ((float)eedc->crease)/255.0f; - eed->bweight= ((float)eedc->bweight)/255.0f; - CustomData_to_em_block(&um->edata, &em->edata, a, &eed->data); - } - - /* copy faces */ - for(a=0, efac= um->faces; a<um->totface; a++, efac++) { - if(efac->v4 != -1) - efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], evar[efac->v4], NULL, NULL); - else - efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], NULL, NULL ,NULL); - - efa->mat_nr= efac->mat_nr; - efa->flag= efac->flag; - efa->f= efac->f; - efa->h= efac->h; - efa->fgonf= efac->fgonf; - - CustomData_to_em_block(&um->fdata, &em->fdata, a, &efa->data); - } - - end_editmesh_fastmalloc(); - if(evar) MEM_freeN(evar); - - em->totvert = um->totvert; - em->totedge = um->totedge; - em->totface = um->totface; - /*restore stored editselections*/ - if(um->totsel){ - EM_init_index_arrays(em, 1,1,1); - for(a=0, esec= um->selected; a<um->totsel; a++, esec++){ - ese = MEM_callocN(sizeof(EditSelection), "Edit Selection"); - ese->type = esec->type; - if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(esec->index); else - if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(esec->index); else - if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(esec->index); - BLI_addtail(&(em->selected),ese); - } - EM_free_index_arrays(); - } - -// XXX retopo_free_paint(); -// em->retopo_paint_data= retopo_paint_data_copy(um->retopo_paint_data); -// scene->toolsettings->retopo_mode= um->retopo_mode; -// if(scene->toolsettings->retopo_mode) { -// XXX if(G.vd->depths) G.vd->depths->damaged= 1; -// retopo_queue_updates(G.vd); -// retopo_paint_view_update(G.vd); -// } - -} - -static void *getEditMesh(bContext *C) -{ - Object *obedit= CTX_data_edit_object(C); - if(obedit && obedit->type==OB_MESH) { - Mesh *me= obedit->data; - return me->edit_mesh; - } - return NULL; -} - -/* and this is all the undo system needs to know */ -void undo_push_mesh(bContext *C, char *name) -{ - undo_editmode_push(C, name, getEditMesh, free_undoMesh, undoMesh_to_editMesh, editMesh_to_undoMesh, NULL); -} - - /* *************** END UNDO *************/ @@ -2033,6 +1739,6 @@ void em_setup_viewcontext(bContext *C, ViewContext *vc) if(vc->obedit) { Mesh *me= vc->obedit->data; - vc->em= me->edit_mesh; + vc->em= me->edit_btmesh; } } diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index c24670aa856..4b891843f5e 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -60,6 +60,7 @@ #include "BKE_object.h" #include "BKE_utildefines.h" #include "BKE_report.h" +#include "BKE_tessmesh.h" #include "WM_api.h" #include "WM_types.h" @@ -71,6 +72,8 @@ #include "ED_util.h" #include "ED_view3d.h" +#include "bmesh.h" + #include "mesh_intern.h" /* bpymenu removed XXX */ @@ -116,127 +119,6 @@ static short icoface[20][3] = { {10,9,11} }; -/* *************** add-click-mesh (extrude) operator ************** */ - -static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event) -{ - ViewContext vc; - EditVert *eve, *v1; - float min[3], max[3]; - int done= 0; - - em_setup_viewcontext(C, &vc); - - INIT_MINMAX(min, max); - - for(v1= vc.em->verts.first;v1; v1=v1->next) { - if(v1->f & SELECT) { - DO_MINMAX(v1->co, min, max); - done= 1; - } - } - - /* call extrude? */ - if(done) { - EditEdge *eed; - float vec[3], cent[3], mat[3][3]; - float nor[3]= {0.0, 0.0, 0.0}; - - /* check for edges that are half selected, use for rotation */ - done= 0; - for(eed= vc.em->edges.first; eed; eed= eed->next) { - if( (eed->v1->f & SELECT)+(eed->v2->f & SELECT) == SELECT ) { - if(eed->v1->f & SELECT) VecSubf(vec, eed->v1->co, eed->v2->co); - else VecSubf(vec, eed->v2->co, eed->v1->co); - VecAddf(nor, nor, vec); - done= 1; - } - } - if(done) Normalize(nor); - - /* center */ - VecAddf(cent, min, max); - VecMulf(cent, 0.5f); - VECCOPY(min, cent); - - Mat4MulVecfl(vc.obedit->obmat, min); // view space - view3d_get_view_aligned_coordinate(&vc, min, event->mval); - Mat4Invert(vc.obedit->imat, vc.obedit->obmat); - Mat4MulVecfl(vc.obedit->imat, min); // back in object space - - VecSubf(min, min, cent); - - /* calculate rotation */ - Mat3One(mat); - if(done) { - float dot; - - VECCOPY(vec, min); - Normalize(vec); - dot= INPR(vec, nor); - - if( fabs(dot)<0.999) { - float cross[3], si, q1[4]; - - Crossf(cross, nor, vec); - Normalize(cross); - dot= 0.5f*saacos(dot); - si= (float)sin(dot); - q1[0]= (float)cos(dot); - q1[1]= cross[0]*si; - q1[2]= cross[1]*si; - q1[3]= cross[2]*si; - - QuatToMat3(q1, mat); - } - } - - extrudeflag(vc.obedit, vc.em, SELECT, nor); - rotateflag(vc.em, SELECT, cent, mat); - translateflag(vc.em, SELECT, min); - - recalc_editnormals(vc.em); - } - else { - float mat[3][3],imat[3][3]; - float *curs= give_cursor(vc.scene, vc.v3d); - - VECCOPY(min, curs); - view3d_get_view_aligned_coordinate(&vc, min, event->mval); - - eve= addvertlist(vc.em, 0, NULL); - - Mat3CpyMat4(mat, vc.obedit->obmat); - Mat3Inv(imat, mat); - - VECCOPY(eve->co, min); - Mat3MulVecfl(imat, eve->co); - VecSubf(eve->co, eve->co, vc.obedit->obmat[3]); - - eve->f= SELECT; - } - - //retopo_do_all(); - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); - DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA); - - return OPERATOR_FINISHED; -} - -void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Duplicate or Extrude at 3D Cursor"; - ot->idname= "MESH_OT_dupli_extrude_cursor"; - - /* api callbacks */ - ot->invoke= dupli_extrude_cursor; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - /* ********************** */ @@ -666,12 +548,53 @@ void addfaces_from_edgenet(EditMesh *em) // XXX DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); } -static void addedgeface_mesh(EditMesh *em, wmOperator *op) +static void addedgeface_mesh(Mesh *me, BMEditMesh *bem, wmOperator *op) { + EditMesh *em; EditVert *eve, *neweve[4]; EditEdge *eed; EditFace *efa; short amount=0; + + /*return if bmesh vert connect does anything.*/ + if (bem->selectmode & SCE_SELECT_VERTEX) { + BMesh *bm = bem->bm; + BMOperator bmop; + int len, ok; + + EDBM_InitOpf(bem, &bmop, op, "connectverts verts=%hv", BM_SELECT); + BMO_Exec_Op(bem->bm, &bmop); + + len = BMO_GetSlot(&bmop, "edgeout")->len; + + ok = EDBM_FinishOp(bem, &bmop, op, 1); + if (!ok) return OPERATOR_CANCELLED; + + if (len) return; + } + + /*return if bmesh face dissolve finds stuff to + dissolve. this entire tool should be + bmeshafied eventually, but until then + hacks like this to integrate with it + are necassary.*/ + if (bem->selectmode & SCE_SELECT_VERTEX) { + BMesh *bm = bem->bm; + BMOperator bmop; + int len, ok; + + EDBM_InitOpf(bem, &bmop, op, "dissolvefaces faces=%hf", BM_SELECT); + BMO_Exec_Op(bem->bm, &bmop); + + len = BMO_GetSlot(&bmop, "regionout")->len; + + ok = EDBM_FinishOp(bem, &bmop, op, 1); + if (!ok) return OPERATOR_CANCELLED; + + if (len) return; + } + + em = BKE_mesh_get_editmesh(me); /* how many selected ? */ if(em->selectmode & SCE_SELECT_EDGE) { @@ -691,16 +614,19 @@ static void addedgeface_mesh(EditMesh *em, wmOperator *op) if(amount==2) { eed= addedgelist(em, neweve[0], neweve[1], NULL); EM_select_edge(eed, 1); - + + BKE_mesh_end_editmesh(me, em); // XXX DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); return; } else if(amount > 4) { addfaces_from_edgenet(em); + BKE_mesh_end_editmesh(me, em); return; } else if(amount<2) { BKE_report(op->reports, RPT_ERROR, "More vertices are needed to make an edge/face"); + BKE_mesh_end_editmesh(me, em); return; } @@ -739,6 +665,7 @@ static void addedgeface_mesh(EditMesh *em, wmOperator *op) if(count++ > 4){ addfaces_from_edgenet(em); + BKE_mesh_end_editmesh(me, em); return; } else { /* if 4 edges exist, we just create the face, convex or not */ @@ -780,40 +707,10 @@ static void addedgeface_mesh(EditMesh *em, wmOperator *op) recalc_editnormals(em); } - } -static int addedgeface_mesh_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - addedgeface_mesh(em, op); - - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); - - DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_edge_face_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Make Edge/Face"; - ot->idname= "MESH_OT_edge_face_add"; - - /* api callbacks */ - ot->exec= addedgeface_mesh_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - + BKE_mesh_end_editmesh(me, em); } - - /* ************************ primitives ******************* */ // HACK: these can also be found in cmoview.tga.c, but are here so that they can be found by linker @@ -1104,7 +1001,9 @@ static void make_prim(Object *obedit, int type, float mat[4][4], int tot, int se } dia*=200; - for(a=1; a<subdiv; a++) esubdivideflag(obedit, em, 2, dia, 0, B_SPHERE,1,0); + + for(a=1; a<subdiv; a++) esubdivideflag(obedit, em, 2, dia, 0.0, 0, 1, 0); + /* and now do imat */ eve= em->verts.first; while(eve) { diff --git a/source/blender/editors/mesh/editmesh_lib.c b/source/blender/editors/mesh/editmesh_lib.c index e1b63022dd4..d9e0cc0f339 100644 --- a/source/blender/editors/mesh/editmesh_lib.c +++ b/source/blender/editors/mesh/editmesh_lib.c @@ -61,6 +61,7 @@ editmesh_lib: generic (no UI, no menus) operations/evaluators for editmesh data #include "ED_view3d.h" #include "mesh_intern.h" +#include "bmesh.h" /* ****************** stats *************** */ @@ -1139,10 +1140,128 @@ short extrudeflag_verts_indiv(EditMesh *em, short flag, float *nor) return 'g'; // g is grab } +short BM_extrude_edgeflag(Object *obedit, BMesh *bm, int eflag, float *nor) +{ + BMIter iter; + BMOIter siter; + BMOperator extop; + BMEdge *edge; + BMFace *f; + void *el; + ModifierData *md; + int flag; + + switch (eflag) { + case SELECT: + flag = BM_SELECT; + break; + default: + flag = BM_SELECT; + break; + } + + for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);f;f=BMIter_Step(&iter)) { + add_normal_aligned(nor, f->no); + } + Normalize(nor); + + BMO_Init_Op(&extop, "extrudefaceregion"); + BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein", + flag, BM_VERT|BM_EDGE|BM_FACE); + + for (edge=BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); edge; edge=BMIter_Step(&iter)) { + BM_Select_Edge(bm, edge, 0); + } + + for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)) { + BM_Select_Face(bm, f, 0); + } + + /* If a mirror modifier with clipping is on, we need to adjust some + * of the cases above to handle edges on the line of symmetry. + */ + md = obedit->modifiers.first; + for (; md; md=md->next) { + if (md->type==eModifierType_Mirror) { + MirrorModifierData *mmd = (MirrorModifierData*) md; + + if(mmd->flag & MOD_MIR_CLIPPING) { + float mtx[4][4]; + if (mmd->mirror_ob) { + float imtx[4][4]; + Mat4Invert(imtx, mmd->mirror_ob->obmat); + Mat4MulMat4(mtx, obedit->obmat, imtx); + } + + for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL); + edge; edge=BMIter_Step(&iter)) + { + if(edge->head.flag & flag) { + float co1[3], co2[3]; + + VecCopyf(co1, edge->v1->co); + VecCopyf(co2, edge->v2->co); + + if (mmd->mirror_ob) { + VecMat4MulVecfl(co1, mtx, co1); + VecMat4MulVecfl(co2, mtx, co2); + } + + if (mmd->flag & MOD_MIR_AXIS_X) + if ( (fabs(co1[0]) < mmd->tolerance) && + (fabs(co2[0]) < mmd->tolerance) ) + BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL); + + if (mmd->flag & MOD_MIR_AXIS_Y) + if ( (fabs(co1[1]) < mmd->tolerance) && + (fabs(co2[1]) < mmd->tolerance) ) + BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL); + + if (mmd->flag & MOD_MIR_AXIS_Z) + if ( (fabs(co1[2]) < mmd->tolerance) && + (fabs(co2[2]) < mmd->tolerance) ) + BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL); + } + } + } + } + } + + + BMO_Exec_Op(bm, &extop); + + el = BMO_IterNew(&siter, bm, &extop, "geomout", BM_ALL); + for (; el; el=BMO_IterStep(&siter)) { + BM_Select(bm, el, 1); + } + + BMO_Finish_Op(bm, &extop); + + if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab + return 'n'; // normal constraint + +} + + +static short extrudeflag_edge(Object *obedit, EditMesh *em, short flag, float *nor) { + short ret; + EditMesh *em2; + BMesh *bm = editmesh_to_bmesh(em); + + ret = BM_extrude_edgeflag(obedit, bm, flag, nor); + em2 = bmesh_to_editmesh(bm); + + set_editMesh(em, em2); + MEM_freeN(em2); + + EM_select_flush(em); + + return ret; +} /* this is actually a recode of extrudeflag(), using proper edge/face select */ /* hurms, doesnt use 'flag' yet, but its not called by primitive making stuff anyway */ -static short extrudeflag_edge(Object *obedit, EditMesh *em, short flag, float *nor) +static short extrudeflag_edge_old(Object *obedit, EditMesh *em, short flag, float *nor) { /* all select edges/faces: extrude */ /* old select is cleared, in new ones it is set */ @@ -1686,9 +1805,22 @@ short extrudeflag_vert(Object *obedit, EditMesh *em, short flag, float *nor) /* generic extrude */ short extrudeflag(Object *obedit, EditMesh *em, short flag, float *nor) { - if(em->selectmode & SCE_SELECT_VERTEX) - return extrudeflag_vert(obedit, em, flag, nor); - else + if(em->selectmode & SCE_SELECT_VERTEX) { + EditEdge *eed; + + /*ensure vert flags are consistent for edge selections*/ + for (eed=em->edges.first; eed; eed=eed->next) { + if (eed->f & flag) { + eed->v1->f |= flag; + eed->v2->f |= flag; + } else { + if ((eed->v1->f & flag) && (eed->v2->f & flag)) + eed->f |= flag; + } + } + + return extrudeflag_edge(obedit, em, flag, nor); + } else return extrudeflag_edge(obedit, em, flag, nor); } @@ -1912,6 +2044,9 @@ void recalc_editnormals(EditMesh *em) } for(efa= em->faces.first; efa; efa=efa->next) { + if (efa->e1->fgoni||efa->e2->fgoni||efa->e3->fgoni) continue; + if (efa->e4 && efa->e4->fgoni) continue; + if(efa->v4) { CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n); CalcCent4f(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co); diff --git a/source/blender/editors/mesh/editmesh_loop.c b/source/blender/editors/mesh/editmesh_loop.c index 7fc3753eefb..9b5de48a644 100644 --- a/source/blender/editors/mesh/editmesh_loop.c +++ b/source/blender/editors/mesh/editmesh_loop.c @@ -61,6 +61,7 @@ editmesh_loop: tools with own drawing subloops, select, knife, subdiv #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #include "PIL_time.h" @@ -77,6 +78,7 @@ editmesh_loop: tools with own drawing subloops, select, knife, subdiv #include "ED_view3d.h" #include "mesh_intern.h" +#include "bmesh.h" /* **** XXX ******** */ static void BIF_undo_push() {} @@ -201,6 +203,7 @@ static void edgering_sel(EditMesh *em, EditEdge *startedge, int select, int prev } void CutEdgeloop(Object *obedit, wmOperator *op, EditMesh *em, int numcuts) { +#if 0 ViewContext vc; // XXX EditEdge *nearest=NULL, *eed; float fac; @@ -391,6 +394,7 @@ void CutEdgeloop(Object *obedit, wmOperator *op, EditMesh *em, int numcuts) // DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); return; +#endif } @@ -474,7 +478,7 @@ static float seg_intersect(EditEdge *e, CutCurve *c, int len, char mode, struct float m1, b1, m2, b2, x21, x22, y21, y22, xi; float yi, x1min, x1max, y1max, y1min, perc=0; float *scr; - float threshold; + float threshold = 0.0; int i; threshold = 0.000001; /*tolerance for vertex intersection*/ @@ -620,26 +624,184 @@ static float seg_intersect(EditEdge *e, CutCurve *c, int len, char mode, struct } +static float bm_seg_intersect(BMEdge *e, CutCurve *c, int len, char mode, + struct GHash *gh, int *isected) +{ +#define MAXSLOPE 100000 + float x11, y11, x12=0, y12=0, x2max, x2min, y2max; + float y2min, dist, lastdist=0, xdiff2, xdiff1; + float m1, b1, m2, b2, x21, x22, y21, y22, xi; + float yi, x1min, x1max, y1max, y1min, perc=0; + float *scr; + float threshold = 0.0; + int i; + + //threshold = 0.000001; /*tolerance for vertex intersection*/ + // XXX threshold = scene->toolsettings->select_thresh / 100; + + /* Get screen coords of verts */ + scr = BLI_ghash_lookup(gh, e->v1); + x21=scr[0]; + y21=scr[1]; + + scr = BLI_ghash_lookup(gh, e->v2); + x22=scr[0]; + y22=scr[1]; + + xdiff2=(x22-x21); + if (xdiff2) { + m2=(y22-y21)/xdiff2; + b2= ((x22*y21)-(x21*y22))/xdiff2; + } + else { + m2=MAXSLOPE; /* Verticle slope */ + b2=x22; + } + + *isected = 0; + + /*check for *exact* vertex intersection first*/ + if(mode!=KNIFE_MULTICUT){ + for (i=0; i<len; i++){ + if (i>0){ + x11=x12; + y11=y12; + } + else { + x11=c[i].x; + y11=c[i].y; + } + x12=c[i].x; + y12=c[i].y; + + /*test e->v1*/ + if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){ + perc = 0; + *isected = 1; + return(perc); + } + /*test e->v2*/ + else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){ + perc = 0; + *isected = 2; + return(perc); + } + } + } + + /*now check for edge interesect (may produce vertex intersection as well)*/ + for (i=0; i<len; i++){ + if (i>0){ + x11=x12; + y11=y12; + } + else { + x11=c[i].x; + y11=c[i].y; + } + x12=c[i].x; + y12=c[i].y; + + /* Perp. Distance from point to line */ + if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */ + /* change in sign. Skip extra math */ + else dist=x22-x12; + + if (i==0) lastdist=dist; + + /* if dist changes sign, and intersect point in edge's Bound Box*/ + if ((lastdist*dist)<=0){ + xdiff1=(x12-x11); /* Equation of line between last 2 points */ + if (xdiff1){ + m1=(y12-y11)/xdiff1; + b1= ((x12*y11)-(x11*y12))/xdiff1; + } + else{ + m1=MAXSLOPE; + b1=x12; + } + x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */ + x2min=MIN2(x21,x22)-0.001; /* due to round off error */ + y2max=MAX2(y21,y22)+0.001; + y2min=MIN2(y21,y22)-0.001; + + /* Found an intersect, calc intersect point */ + if (m1==m2){ /* co-incident lines */ + /* cut at 50% of overlap area*/ + x1max=MAX2(x11, x12); + x1min=MIN2(x11, x12); + xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0; + + y1max=MAX2(y11, y12); + y1min=MIN2(y11, y12); + yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0; + } + else if (m2==MAXSLOPE){ + xi=x22; + yi=m1*x22+b1; + } + else if (m1==MAXSLOPE){ + xi=x12; + yi=m2*x12+b2; + } + else { + xi=(b1-b2)/(m2-m1); + yi=(b1*m2-m1*b2)/(m2-m1); + } + + /* Intersect inside bounding box of edge?*/ + if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){ + /*test for vertex intersect that may be 'close enough'*/ + if(mode!=KNIFE_MULTICUT){ + if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){ + if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){ + *isected = 1; + perc = 0; + break; + } + } + if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){ + if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){ + *isected = 2; + perc = 0; + break; + } + } + } + if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21); + else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/ + //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */ + + break; + } + } + lastdist=dist; + } + return(perc); +} + #define MAX_CUTS 256 static int knife_cut_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); + BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; + BMesh *bm = em->bm; ARegion *ar= CTX_wm_region(C); - EditEdge *eed; - EditVert *eve; + BMVert *bv; + BMIter iter; + BMEdge **edges = NULL, *be; + BMOperator bmop; CutCurve curve[MAX_CUTS]; struct GHash *gh; float isect=0.0; - float *scr, co[4]; - int len=0; + float *scr, co[4], *percents = NULL; + int len=0, isected, flag, i; short numcuts=1, mode= RNA_int_get(op->ptr, "type"); - if (EM_nvertices_selected(em) < 2) { + if (bm->totvertsel < 2) { error("No edges are selected to operate on"); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED;; } @@ -653,57 +815,60 @@ static int knife_cut_exec(bContext *C, wmOperator *op) RNA_END; if(len<2) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } - /*store percentage of edge cut for KNIFE_EXACT here.*/ - for(eed=em->edges.first; eed; eed= eed->next) - eed->tmp.fp = 0.0; - /*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/ gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); - for(eve=em->verts.first; eve; eve=eve->next){ + for(bv=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);bv;bv=BMIter_Step(&iter)){ scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates"); - VECCOPY(co, eve->co); + VECCOPY(co, bv->co); co[3]= 1.0; Mat4MulVec4fl(obedit->obmat, co); project_float(ar, co, scr); - BLI_ghash_insert(gh, eve, scr); - eve->f1 = 0; /*store vertex intersection flag here*/ - + BLI_ghash_insert(gh, bv, scr); } - eed= em->edges.first; - while(eed) { - if( eed->v1->f & eed->v2->f & SELECT ){ // NOTE: uses vertex select, subdiv doesnt do edges yet - isect= seg_intersect(eed, curve, len, mode, gh); - if (isect!=0.0f) eed->f2= 1; - else eed->f2=0; - eed->tmp.fp= isect; - //printf("isect=%i\n", isect); - } - else { - eed->f2=0; - eed->f1=0; + BMO_Init_Op(&bmop, "esubd"); + + i = 0; + /*store percentage of edge cut for KNIFE_EXACT here.*/ + for (be=BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); be; be=BMIter_Step(&iter)) { + if( BM_Is_Selected(bm, be) ) { + isect= bm_seg_intersect(be, curve, len, mode, gh, &isected); + + if (isect != 0.0f) { + if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) { + BMO_Insert_MapFloat(bm, &bmop, + "edgepercents", + be, isect); + + } + BMO_SetFlag(bm, be, 1); + } } - eed= eed->next; } - if (mode==KNIFE_MIDPOINT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, 1, SUBDIV_SELECT_ORIG); - else if (mode==KNIFE_MULTICUT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, numcuts, SUBDIV_SELECT_ORIG); - else esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE|B_PERCENTSUBD, 1, SUBDIV_SELECT_ORIG); + BMO_Flag_To_Slot(bm, &bmop, "edges", 1, BM_EDGE); - eed=em->edges.first; - while(eed){ - eed->f2=0; - eed->f1=0; - eed=eed->next; - } + BMO_Set_Int(&bmop, "numcuts", numcuts); + flag = B_KNIFE; + if (mode == KNIFE_MIDPOINT) numcuts = 1; + BMO_Set_Int(&bmop, "flag", flag); + BMO_Set_Float(&bmop, "radius", 0); - BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); + BMO_Exec_Op(bm, &bmop); + BMO_Finish_Op(bm, &bmop); - BKE_mesh_end_editmesh(obedit->data, em); + V_FREE(edges); + V_FREE(percents); + + //if (mode==KNIFE_MIDPOINT) esubdivideflag(obedit, em, SELECT, 0, B_KNIFE, 1, SUBDIV_SELECT_ORIG); + //else if (mode==KNIFE_MULTICUT) esubdivideflag(obedit, em, SELECT, 0, B_KNIFE, numcuts, SUBDIV_SELECT_ORIG); + //else esubdivideflag(obedit, em, SELECT, 0, B_KNIFE|B_PERCENTSUBD, 1, SUBDIV_SELECT_ORIG); + + BLI_ghash_free(gh, NULL, (GHashValFreeFP)WMEM_freeN); + DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index 5fc2ce46792..aa7a5e6b292 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -83,6 +83,7 @@ editmesh_mods.c, UI level access, no geometry changes #include "ED_mesh.h" #include "ED_screen.h" #include "ED_view3d.h" +#include "bmesh.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -99,6 +100,7 @@ static int pupmenu() {return 0;} void EM_select_mirrored(Object *obedit, EditMesh *em) { +#if 0 if(em->selectmode & SCE_SELECT_VERTEX) { EditVert *eve, *v1; @@ -112,6 +114,7 @@ void EM_select_mirrored(Object *obedit, EditMesh *em) } } } +#endif } void EM_automerge(int update) @@ -326,320 +329,6 @@ int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads) } -static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index) -{ - struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData; - - if (data->pass==0) { - if (index<=data->lastIndex) - return; - } else { - if (index>data->lastIndex) - return; - } - - if (data->dist>3) { - int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y); - if ((eve->f&1) == data->select) { - if (data->strict == 1) - return; - else - temp += 5; - } - - if (temp<data->dist) { - data->dist = temp; - data->closest = eve; - data->closestIndex = index; - } - } -} - - - - -static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index) -{ - EditMesh *em= (EditMesh *)handle; - EditVert *eve = BLI_findlink(&em->verts, index-1); - - if(eve && (eve->f & SELECT)) return 0; - return 1; -} -/** - * findnearestvert - * - * dist (in/out): minimal distance to the nearest and at the end, actual distance - * sel: selection bias - * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts - * if 0, unselected vertice are given the bias - * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased - */ -EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict) -{ - if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){ - int distance; - unsigned int index; - EditVert *eve; - - if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest); - else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL); - - eve = BLI_findlink(&vc->em->verts, index-1); - - if(eve && distance < *dist) { - *dist = distance; - return eve; - } else { - return NULL; - } - - } - else { - struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data; - static int lastSelectedIndex=0; - static EditVert *lastSelected=NULL; - - if (lastSelected && BLI_findlink(&vc->em->verts, lastSelectedIndex)!=lastSelected) { - lastSelectedIndex = 0; - lastSelected = NULL; - } - - data.lastIndex = lastSelectedIndex; - data.mval[0] = vc->mval[0]; - data.mval[1] = vc->mval[1]; - data.select = sel; - data.dist = *dist; - data.strict = strict; - data.closest = NULL; - data.closestIndex = 0; - - data.pass = 0; - mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1); - - if (data.dist>3) { - data.pass = 1; - mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1); - } - - *dist = data.dist; - lastSelected = data.closest; - lastSelectedIndex = data.closestIndex; - - return data.closest; - } -} - -/* returns labda for closest distance v1 to line-piece v2-v3 */ -static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3) -{ - float rc[2], len; - - rc[0]= v3[0]-v2[0]; - rc[1]= v3[1]-v2[1]; - len= rc[0]*rc[0]+ rc[1]*rc[1]; - if(len==0.0f) - return 0.0f; - - return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len; -} - -/* note; uses v3d, so needs active 3d window */ -static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index) -{ - struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } *data = userData; - float v1[2], v2[2]; - int distance; - - v1[0] = x0; - v1[1] = y0; - v2[0] = x1; - v2[1] = y1; - - distance= PdistVL2Dfl(data->mval, v1, v2); - - if(eed->f & SELECT) distance+=5; - if(distance < data->dist) { - if(data->vc.rv3d->rflag & RV3D_CLIPPING) { - float labda= labda_PdistVL2Dfl(data->mval, v1, v2); - float vec[3]; - - vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]); - vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]); - vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]); - Mat4MulVecfl(data->vc.obedit->obmat, vec); - - if(view3d_test_clipping(data->vc.rv3d, vec)==0) { - data->dist = distance; - data->closest = eed; - } - } - else { - data->dist = distance; - data->closest = eed; - } - } -} -EditEdge *findnearestedge(ViewContext *vc, int *dist) -{ - - if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) { - int distance; - unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL, NULL); - EditEdge *eed = BLI_findlink(&vc->em->edges, index-1); - - if (eed && distance<*dist) { - *dist = distance; - return eed; - } else { - return NULL; - } - } - else { - struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } data; - - data.vc= *vc; - data.mval[0] = vc->mval[0]; - data.mval[1] = vc->mval[1]; - data.dist = *dist; - data.closest = NULL; - - mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2); - - *dist = data.dist; - return data.closest; - } -} - -static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int index) -{ - struct { short mval[2]; int dist; EditFace *toFace; } *data = userData; - - if (efa==data->toFace) { - int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y); - - if (temp<data->dist) - data->dist = temp; - } -} -static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index) -{ - struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } *data = userData; - - if (data->pass==0) { - if (index<=data->lastIndex) - return; - } else { - if (index>data->lastIndex) - return; - } - - if (data->dist>3) { - int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y); - - if (temp<data->dist) { - data->dist = temp; - data->closest = efa; - data->closestIndex = index; - } - } -} -static EditFace *findnearestface(ViewContext *vc, int *dist) -{ - - if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) { - unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]); - EditFace *efa = BLI_findlink(&vc->em->faces, index-1); - - if (efa) { - struct { short mval[2]; int dist; EditFace *toFace; } data; - - data.mval[0] = vc->mval[0]; - data.mval[1] = vc->mval[1]; - data.dist = 0x7FFF; /* largest short */ - data.toFace = efa; - - mesh_foreachScreenFace(vc, findnearestface__getDistance, &data); - - if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */ - *dist= data.dist; - return efa; - } - } - - return NULL; - } - else { - struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } data; - static int lastSelectedIndex=0; - static EditFace *lastSelected=NULL; - - if (lastSelected && BLI_findlink(&vc->em->faces, lastSelectedIndex)!=lastSelected) { - lastSelectedIndex = 0; - lastSelected = NULL; - } - - data.lastIndex = lastSelectedIndex; - data.mval[0] = vc->mval[0]; - data.mval[1] = vc->mval[1]; - data.dist = *dist; - data.closest = NULL; - data.closestIndex = 0; - - data.pass = 0; - mesh_foreachScreenFace(vc, findnearestface__doClosest, &data); - - if (data.dist>3) { - data.pass = 1; - mesh_foreachScreenFace(vc, findnearestface__doClosest, &data); - } - - *dist = data.dist; - lastSelected = data.closest; - lastSelectedIndex = data.closestIndex; - - return data.closest; - } -} - -/* best distance based on screen coords. - use em->selectmode to define how to use - selected vertices and edges get disadvantage - return 1 if found one -*/ -static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed, EditFace **efa) -{ - EditMesh *em= vc->em; - int dist= 75; - - *eve= NULL; - *eed= NULL; - *efa= NULL; - - /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ - view3d_validate_backbuf(vc); - - if(em->selectmode & SCE_SELECT_VERTEX) - *eve= findnearestvert(vc, &dist, SELECT, 0); - if(em->selectmode & SCE_SELECT_FACE) - *efa= findnearestface(vc, &dist); - - dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */ - if(em->selectmode & SCE_SELECT_EDGE) - *eed= findnearestedge(vc, &dist); - - /* return only one of 3 pointers, for frontbuffer redraws */ - if(*eed) { - *efa= NULL; *eve= NULL; - } - else if(*efa) { - *eve= NULL; - } - - return (*eve || *eed || *efa); -} - - /* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */ /* selects new faces/edges/verts based on the existing selection */ @@ -1715,9 +1404,9 @@ void mesh_copy_menu(EditMesh *em, wmOperator *op) } } - /* **************** LOOP SELECTS *************** */ +#if 0 /* selects quads in loop direction of indicated edge */ /* only flush over edges with valence <= 2 */ void faceloop_select(EditMesh *em, EditEdge *startedge, int select) @@ -1787,6 +1476,7 @@ void faceloop_select(EditMesh *em, EditEdge *startedge, int select) } } } +#endif /* helper for edgeloop_select, checks for eed->f2 tag in faces */ @@ -1819,6 +1509,34 @@ static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed) */ static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select) { + BMesh *bm; + BMEdge *e; + EditMesh *em2; + BMOperator op; + BMWalker walker; + + bm = init_editmesh_to_bmesh(em, &op); + BMO_Exec_Op(bm, &op); + + e = BMO_Get_MapPointer(bm, &op, "map", starteed); + + BMW_Init(&walker, bm, BMW_LOOP, 0); + e = BMW_Begin(&walker, e); + for (; e; e=BMW_Step(&walker)) { + BM_Select(bm, e, 1); + } + BMW_End(&walker); + + BMO_Finish_Op(bm, &op); + + em2 = bmesh_to_editmesh(bm); + BM_Free_Mesh(bm); + set_editMesh(em, em2); + MEM_freeN(em2); +} + +static void edgeloop_select_old(EditMesh *em, EditEdge *starteed, int select) +{ EditVert *eve; EditEdge *eed; EditFace *efa; @@ -1995,6 +1713,7 @@ static int loop_multiselect(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +#if 0 //moved to bmeshutils_mods.c void MESH_OT_loop_multi_select(wmOperatorType *ot) { /* identifiers */ @@ -2011,255 +1730,15 @@ void MESH_OT_loop_multi_select(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "ring", 0, "Ring", ""); } - +#endif /* ***************** MAIN MOUSE SELECTION ************** */ -/* ***************** loop select (non modal) ************** */ - -static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring) -{ - ViewContext vc; - EditMesh *em; - EditEdge *eed; - int select= 1; - int dist= 50; - - em_setup_viewcontext(C, &vc); - vc.mval[0]= mval[0]; - vc.mval[1]= mval[1]; - em= vc.em; - - eed= findnearestedge(&vc, &dist); - if(eed) { - if(extend==0) EM_clear_flag_all(em, SELECT); - - if((eed->f & SELECT)==0) select=1; - else if(extend) select=0; - - if(em->selectmode & SCE_SELECT_FACE) { - faceloop_select(em, eed, select); - } - else if(em->selectmode & SCE_SELECT_EDGE) { - if(ring) - edgering_select(em, eed, select); - else - edgeloop_select(em, eed, select); - } - else if(em->selectmode & SCE_SELECT_VERTEX) { - if(ring) - edgering_select(em, eed, select); - else - edgeloop_select(em, eed, select); - } - - EM_selectmode_flush(em); -// if (EM_texFaceCheck()) - - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); - } -} - -static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - - view3d_operator_needs_opengl(C); - - mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"), - RNA_boolean_get(op->ptr, "ring")); - - /* cannot do tweaks for as long this keymap is after transform map */ - return OPERATOR_FINISHED; -} - -void MESH_OT_loop_select(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Loop Select"; - ot->idname= "MESH_OT_loop_select"; - - /* api callbacks */ - ot->invoke= mesh_select_loop_invoke; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); - RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", ""); -} - /* ******************* mesh shortest path select, uses prev-selected edge ****************** */ -/* since you want to create paths with multiple selects, it doesn't have extend option */ -static void mouse_mesh_shortest_path(bContext *C, short mval[2]) -{ - ViewContext vc; - EditMesh *em; - EditEdge *eed; - int dist= 50; - - em_setup_viewcontext(C, &vc); - vc.mval[0]= mval[0]; - vc.mval[1]= mval[1]; - em= vc.em; - - eed= findnearestedge(&vc, &dist); - if(eed) { - Mesh *me= vc.obedit->data; - int path = 0; - - if (em->selected.last) { - EditSelection *ese = em->selected.last; - - if(ese && ese->type == EDITEDGE) { - EditEdge *eed_act; - eed_act = (EditEdge*)ese->data; - if (eed_act != eed) { - if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) { - EM_remove_selection(em, eed_act, EDITEDGE); - path = 1; - } - } - } - } - if (path==0) { - int act = (edgetag_context_check(vc.scene, eed)==0); - edgetag_context_set(vc.scene, eed, act); /* switch the edge option */ - } - - EM_selectmode_flush(em); - - /* even if this is selected it may not be in the selection list */ - if(edgetag_context_check(vc.scene, eed)==0) - EM_remove_selection(em, eed, EDITEDGE); - else - EM_store_selection(em, eed, EDITEDGE); - - /* force drawmode for mesh */ - switch (vc.scene->toolsettings->edge_mode) { - - case EDGE_MODE_TAG_SEAM: - me->drawflag |= ME_DRAWSEAMS; - break; - case EDGE_MODE_TAG_SHARP: - me->drawflag |= ME_DRAWSHARP; - break; - case EDGE_MODE_TAG_CREASE: - me->drawflag |= ME_DRAWCREASES; - break; - case EDGE_MODE_TAG_BEVEL: - me->drawflag |= ME_DRAWBWEIGHTS; - break; - } - - DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA); - - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); - } -} - - -static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - - view3d_operator_needs_opengl(C); - - mouse_mesh_shortest_path(C, event->mval); - - return OPERATOR_FINISHED; -} - -void MESH_OT_select_shortest_path(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Shortest Path Select"; - ot->idname= "MESH_OT_select_shortest_path"; - - /* api callbacks */ - ot->invoke= mesh_shortest_path_select_invoke; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); -} - - /* ************************************************** */ - -/* here actual select happens */ -/* gets called via generic mouse select operator */ -void mouse_mesh(bContext *C, short mval[2], short extend) -{ - ViewContext vc; - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - /* setup view context for argument to callbacks */ - em_setup_viewcontext(C, &vc); - vc.mval[0]= mval[0]; - vc.mval[1]= mval[1]; - - if(unified_findnearest(&vc, &eve, &eed, &efa)) { - - if(extend==0) EM_clear_flag_all(vc.em, SELECT); - - if(efa) { - /* set the last selected face */ - EM_set_actFace(vc.em, efa); - - if( (efa->f & SELECT)==0 ) { - EM_store_selection(vc.em, efa, EDITFACE); - EM_select_face_fgon(vc.em, efa, 1); - } - else if(extend) { - EM_remove_selection(vc.em, efa, EDITFACE); - EM_select_face_fgon(vc.em, efa, 0); - } - } - else if(eed) { - if((eed->f & SELECT)==0) { - EM_store_selection(vc.em, eed, EDITEDGE); - EM_select_edge(eed, 1); - } - else if(extend) { - EM_remove_selection(vc.em, eed, EDITEDGE); - EM_select_edge(eed, 0); - } - } - else if(eve) { - if((eve->f & SELECT)==0) { - eve->f |= SELECT; - EM_store_selection(vc.em, eve, EDITVERT); - } - else if(extend){ - EM_remove_selection(vc.em, eve, EDITVERT); - eve->f &= ~SELECT; - } - } - - EM_selectmode_flush(vc.em); - -// if (EM_texFaceCheck()) { - - if (efa && efa->mat_nr != vc.obedit->actcol-1) { - vc.obedit->actcol= efa->mat_nr+1; - vc.em->mat_nr= efa->mat_nr; -// BIF_preview_changed(ID_MA); - } - } - - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); - -} - /* *********** select linked ************* */ /* for use with selectconnected_delimit_mesh only! */ @@ -2277,6 +1756,7 @@ else efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1; /* legacy warning, this function combines too much :) */ static int select_linked_limited_invoke(ViewContext *vc, short all, short sel) { +#if 0 //BMESH_TODO EditMesh *em= vc->em; EditFace *efa; EditEdge *eed; @@ -2367,7 +1847,7 @@ static int select_linked_limited_invoke(ViewContext *vc, short all, short sel) EM_select_face(efa, 1); // if (EM_texFaceCheck()) - +#endif return OPERATOR_FINISHED; } @@ -2377,6 +1857,7 @@ static int select_linked_limited_invoke(ViewContext *vc, short all, short sel) static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) { +#if 0 //BMESH_TODO Object *obedit= CTX_data_edit_object(C); ViewContext vc; EditVert *eve, *v1, *v2; @@ -2461,6 +1942,7 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); return OPERATOR_FINISHED; +#endif } void MESH_OT_select_linked_pick(wmOperatorType *ot) @@ -3264,40 +2746,21 @@ void MESH_OT_select_inverse(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } -/* ******************** (de)select all operator **************** */ - -void EM_toggle_select_all(EditMesh *em) /* exported for UV */ +static int bmesh_test_exec(bContext *C, wmOperator *op) { - if(EM_nvertices_selected(em)) - EM_clear_flag_all(em, SELECT); - else - EM_set_flag_all(em, SELECT); -} - -static int toggle_select_all_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - EM_toggle_select_all(em); - - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; } -void MESH_OT_select_all_toggle(wmOperatorType *ot) +void MESH_OT_bmesh_test(wmOperatorType *ot) { /* identifiers */ - ot->name= "Select/Deselect All"; - ot->idname= "MESH_OT_select_all_toggle"; + ot->name= "bmesh test op"; + ot->idname= "MESH_OT_bmesh_test"; /* api callbacks */ - ot->exec= toggle_select_all_exec; + ot->exec= bmesh_test_exec; ot->poll= ED_operator_editmesh; - - /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } @@ -3585,157 +3048,6 @@ static void mesh_selection_type(Scene *scene, EditMesh *em, int val) } } -static EnumPropertyItem prop_mesh_edit_types[] = { - {1, "VERT", 0, "Vertices", ""}, - {2, "EDGE", 0, "Edges", ""}, - {3, "FACE", 0, "Faces", ""}, - {0, NULL, 0, NULL, NULL} -}; - -static int mesh_selection_type_exec(bContext *C, wmOperator *op) -{ - - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - mesh_selection_type(CTX_data_scene(C), em, RNA_enum_get(op->ptr,"type")); - - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_selection_type(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Selection Mode"; - ot->idname= "MESH_OT_selection_type"; - - /* api callbacks */ - ot->invoke= WM_menu_invoke; - ot->exec= mesh_selection_type_exec; - - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type"); - -} -/* ************************* SEAMS AND EDGES **************** */ - -static int editmesh_mark_seam(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - Mesh *me= ((Mesh *)obedit->data); - EditEdge *eed; - int clear = RNA_boolean_get(op->ptr, "clear"); - - /* auto-enable seams drawing */ - if(clear==0) { - me->drawflag |= ME_DRAWSEAMS; - } - - if(clear) { - eed= em->edges.first; - while(eed) { - if((eed->h==0) && (eed->f & SELECT)) { - eed->seam = 0; - } - eed= eed->next; - } - } - else { - eed= em->edges.first; - while(eed) { - if((eed->h==0) && (eed->f & SELECT)) { - eed->seam = 1; - } - eed= eed->next; - } - } - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -void MESH_OT_mark_seam(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Mark Seam"; - ot->idname= "MESH_OT_mark_seam"; - - /* api callbacks */ - ot->exec= editmesh_mark_seam; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); -} - -static int editmesh_mark_sharp(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - Mesh *me= ((Mesh *)obedit->data); - int clear = RNA_boolean_get(op->ptr, "clear"); - EditEdge *eed; - - /* auto-enable sharp edge drawing */ - if(clear == 0) { - me->drawflag |= ME_DRAWSHARP; - } - - if(!clear) { - eed= em->edges.first; - while(eed) { - if(!eed->h && (eed->f & SELECT)) eed->sharp = 1; - eed = eed->next; - } - } else { - eed= em->edges.first; - while(eed) { - if(!eed->h && (eed->f & SELECT)) eed->sharp = 0; - eed = eed->next; - } - } - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -void MESH_OT_mark_sharp(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Mark Sharp"; - ot->idname= "MESH_OT_mark_sharp"; - - /* api callbacks */ - ot->exec= editmesh_mark_sharp; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); -} - /* **************** NORMALS ************** */ /* XXX value of select is messed up, it means two things */ @@ -3954,6 +3266,7 @@ static int righthandfaces_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); + EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); /* 'standard' behaviour - check if selected, then apply relevant selection */ @@ -4163,6 +3476,7 @@ void editmesh_align_view_to_selected(Object *obedit, EditMesh *em, wmOperator *o static int smooth_vertex(bContext *C, wmOperator *op) { +#if 0 //BMESH_TODO Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); @@ -4173,12 +3487,18 @@ static int smooth_vertex(bContext *C, wmOperator *op) int teller=0; ModifierData *md; + if(em==NULL) { + BKE_mesh_end_editmesh(obedit->data, em); + return OPERATOR_CANCELLED; + } + /* count */ eve= em->verts.first; while(eve) { if(eve->f & SELECT) teller++; eve= eve->next; } + if(teller==0) { BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; @@ -4296,6 +3616,7 @@ static int smooth_vertex(bContext *C, wmOperator *op) DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); +#endif return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index efb68f69dac..50ac7894120 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -75,6 +75,8 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise #include "BKE_utildefines.h" #include "BKE_bmesh.h" #include "BKE_report.h" +#include "BKE_tessmesh.h" + #include "BIF_gl.h" #include "BIF_glutil.h" @@ -91,6 +93,7 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise #include "UI_interface.h" #include "mesh_intern.h" +#include "bmesh.h" /* XXX */ static int extern_qread() {return 0;} @@ -529,6 +532,7 @@ static void xsortvert_flag__doSetX(void *userData, EditVert *eve, int x, int y, /* all verts with (flag & 'flag') are sorted */ void xsortvert_flag(bContext *C, int flag) { +#if 0 //BMESH_TODO ViewContext vc; EditVert *eve; xvertsort *sortblock; @@ -560,7 +564,7 @@ void xsortvert_flag(bContext *C, int flag) addlisttolist(&vc.em->verts, &tbase); MEM_freeN(sortblock); - +#endif } /* called from buttons */ @@ -641,12 +645,15 @@ void extrude_mesh(Object *obedit, EditMesh *em, wmOperator *op) } else if(em->selectmode & SCE_SELECT_EDGE) { if (em->totedgesel==0) nr = 0; - else if (em->totedgesel==1) nr = 3; + + nr = 1; + /*else if (em->totedgesel==1) nr = 3; else if(em->totfacesel==0) nr = 3; else if(em->totfacesel==1) nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3"); else nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3"); + */ } else { if (em->totfacesel == 0) nr = 0; @@ -696,6 +703,8 @@ void extrude_mesh(Object *obedit, EditMesh *em, wmOperator *op) } +#if 0 +//need to see if this really had new stuff I should merge over // XXX should be a menu item static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event) { @@ -752,6 +761,7 @@ void MESH_OT_extrude(wmOperatorType *ot) Properties_Proportional(ot); RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", ""); } +#endif static int split_mesh(bContext *C, wmOperator *op) { @@ -790,7 +800,9 @@ void MESH_OT_split(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } - +#if 0 +//this also showed up in a merge, need to check if it +//needs changes ported over to new extrude code too static int extrude_repeat_mesh(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); @@ -853,7 +865,7 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot) RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX); RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX); } - +#endif /* ************************** spin operator ******************** */ @@ -1146,190 +1158,6 @@ static void erase_vertices(EditMesh *em, ListBase *l) } } -void delete_mesh(Object *obedit, EditMesh *em, wmOperator *op, int event) -{ - EditFace *efa, *nextvl; - EditVert *eve,*nextve; - EditEdge *eed,*nexted; - int count; - char *str="Erase"; - - - if(event<1) return; - - if(event==10 ) { - str= "Erase Vertices"; - erase_edges(em, &em->edges); - erase_faces(em, &em->faces); - erase_vertices(em, &em->verts); - } - else if(event==6) { - if(!EdgeLoopDelete(em, op)) - return; - - str= "Erase Edge Loop"; - } - else if(event==4) { - str= "Erase Edges & Faces"; - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - /* delete only faces with 1 or more edges selected */ - count= 0; - if(efa->e1->f & SELECT) count++; - if(efa->e2->f & SELECT) count++; - if(efa->e3->f & SELECT) count++; - if(efa->e4 && (efa->e4->f & SELECT)) count++; - if(count) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextvl; - } - eed= em->edges.first; - while(eed) { - nexted= eed->next; - if(eed->f & SELECT) { - remedge(em, eed); - free_editedge(em, eed); - } - eed= nexted; - } - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - event=0; - if( efa->v1->f & SELECT) event++; - if( efa->v2->f & SELECT) event++; - if( efa->v3->f & SELECT) event++; - if(efa->v4 && (efa->v4->f & SELECT)) event++; - - if(event>1) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextvl; - } - } - else if(event==1) { - str= "Erase Edges"; - // faces first - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - event=0; - if( efa->e1->f & SELECT) event++; - if( efa->e2->f & SELECT) event++; - if( efa->e3->f & SELECT) event++; - if(efa->e4 && (efa->e4->f & SELECT)) event++; - - if(event) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextvl; - } - eed= em->edges.first; - while(eed) { - nexted= eed->next; - if(eed->f & SELECT) { - remedge(em, eed); - free_editedge(em, eed); - } - eed= nexted; - } - /* to remove loose vertices: */ - eed= em->edges.first; - while(eed) { - if( eed->v1->f & SELECT) eed->v1->f-=SELECT; - if( eed->v2->f & SELECT) eed->v2->f-=SELECT; - eed= eed->next; - } - eve= em->verts.first; - while(eve) { - nextve= eve->next; - if(eve->f & SELECT) { - BLI_remlink(&em->verts,eve); - free_editvert(em, eve); - } - eve= nextve; - } - - } - else if(event==2) { - str="Erase Faces"; - delfaceflag(em, SELECT); - } - else if(event==3) { - str= "Erase All"; - if(em->verts.first) free_vertlist(em, &em->verts); - if(em->edges.first) free_edgelist(em, &em->edges); - if(em->faces.first) free_facelist(em, &em->faces); - if(em->selected.first) BLI_freelistN(&(em->selected)); - } - else if(event==5) { - str= "Erase Only Faces"; - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - if(efa->f & SELECT) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextvl; - } - } - - EM_fgon_flags(em); // redo flags and indices for fgons -} - -/* Note, these values must match delete_mesh() event values */ -static EnumPropertyItem prop_mesh_delete_types[] = { - {10,"VERT", 0, "Vertices", ""}, - {1, "EDGE", 0, "Edges", ""}, - {2, "FACE", 0, "Faces", ""}, - {3, "ALL", 0, "All", ""}, - {4, "EDGE_FACE",0, "Edges & Faces", ""}, - {5, "ONLY_FACE",0, "Only Faces", ""}, - {6, "EDGE_LOOP",0, "Edge Loop", ""}, - {0, NULL, 0, NULL, NULL} -}; - -static int delete_mesh_exec(bContext *C, wmOperator *op) -{ - Scene *scene= CTX_data_scene(C); - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - delete_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type")); - - DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_delete(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Delete"; - ot->idname= "MESH_OT_delete"; - - /* api callbacks */ - ot->invoke= WM_menu_invoke; - ot->exec= delete_mesh_exec; - - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /*props */ - RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data"); -} - - /*GB*/ /*-------------------------------------------------------------------------------*/ /*--------------------------- Edge Based Subdivide ------------------------------*/ @@ -1382,7 +1210,7 @@ static void alter_co(float *co, EditEdge *edge, float smooth, float fractal, int co[1] += vec1[1]; co[2] += vec1[2]; } - else if(beauty & B_SPHERE) { /* subdivide sphere */ + /*else if(beauty & B_SPHERE) { // subdivide sphere Normalize(co); co[0]*= smooth; co[1]*= smooth; @@ -1395,7 +1223,7 @@ static void alter_co(float *co, EditEdge *edge, float smooth, float fractal, int vec1[1]= fac*(float)(0.5-BLI_drand()); vec1[2]= fac*(float)(0.5-BLI_drand()); VecAddf(co, co, vec1); - } + }*/ } /* assumes in the edge is the correct interpolated vertices already */ @@ -2243,7 +2071,7 @@ static void fill_quad_quadruple(EditMesh *em, EditFace *efa, struct GHash *gh, i for(i=1;i<=numcuts;i++) { /* we create a fake edge for the next loop */ - temp.v2 = innerverts[i][0] = verts[1][i]; + temp.v2 = innerverts[i][0] = verts[1][i]; temp.v1 = innerverts[i][numcuts+1] = verts[3][i]; for(j=1;j<=numcuts;j++) { @@ -2382,7 +2210,7 @@ static void fill_tri_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int n MEM_freeN(innerverts); } -//Next two fill types are for knife exact only and are provided to allow for knifing through vertices +//Next two fill types are for exact only and are provided to allow for knifing through vertices //This means there is no multicut! static void fill_quad_doublevert(EditMesh *em, EditFace *efa, int v1, int v2) { @@ -4780,6 +4608,7 @@ static void mesh_rip_setface(EditMesh *em, EditFace *sefa) /* based on mouse cursor position, it defines how is being ripped */ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event) { +#if 0 //BMESH_TODO Scene *scene= CTX_data_scene(C); ARegion *ar= CTX_wm_region(C); RegionView3D *rv3d= ar->regiondata; @@ -4984,6 +4813,7 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event) RNA_enum_set(op->ptr, "proportional", 0); RNA_boolean_set(op->ptr, "mirror", 0); WM_operator_name_call(C, "TFM_OT_translation", WM_OP_INVOKE_REGION_WIN, op->ptr); +#endif return OPERATOR_FINISHED; } @@ -5053,6 +4883,7 @@ void shape_propagate(Scene *scene, Object *obedit, EditMesh *em, wmOperator *op) void shape_copy_from_lerp(EditMesh *em, KeyBlock* thisBlock, KeyBlock* fromBlock) { +#if 0 //BMESH_TODO EditVert *ev = NULL; short mval[2], curval[2], event = 0, finished = 0, canceled = 0, fullcopy=0 ; float perc = 0; @@ -5129,6 +4960,7 @@ void shape_copy_from_lerp(EditMesh *em, KeyBlock* thisBlock, KeyBlock* fromBlock } } return; +#endif } @@ -6645,52 +6477,6 @@ void MESH_OT_colors_mirror(wmOperatorType *ot) RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around."); } -/********************** Subdivide Operator *************************/ - -static int subdivide_exec(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - int cuts= RNA_int_get(op->ptr,"number_cuts"); - float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness"); - float fractal= RNA_float_get(op->ptr, "fractal")/100; - int flag= 0; - - if(smooth != 0.0f) - flag |= B_SMOOTH; - if(fractal != 0.0f) - flag |= B_FRACTAL; - - esubdivideflag(obedit, em, 1, smooth, fractal, scene->toolsettings->editbutflag|flag, cuts, 0); - - DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); - - return OPERATOR_FINISHED; -} - -void MESH_OT_subdivide(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Subdivide"; - ot->idname= "MESH_OT_subdivide"; - - /* api callbacks */ - ot->exec= subdivide_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX); - RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f); - RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1000.0f, "Smoothness", "Smoothness factor.", 0.0f, FLT_MAX); -} - -/********************** Fill Operators *************************/ - /* note; the EM_selectmode_set() calls here illustrate how badly constructed it all is... from before the edge/face flags, with very mixed results.... */ static void beauty_fill(EditMesh *em) @@ -7002,14 +6788,15 @@ static int quads_convert_to_tris_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; - convert_to_triface(em,0); + //convert_to_triface(em,0); + if (!EDBM_CallOpf(em, op, "triangulate faces=%hf", BM_SELECT)) + return OPERATOR_CANCELLED; DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 6e098e04a14..7f974a532d8 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -32,11 +32,54 @@ #ifndef MESH_INTERN_H #define MESH_INTERN_H +#include "BLI_editVert.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" + struct bContext; struct wmOperatorType; +struct ViewContext; +struct BMEditMesh; +struct BMesh; +struct BMEdge; +struct BMFace; #define UVCOPY(t, s) memcpy(t, s, 2 * sizeof(float)); +/* ******************** bmeshutils.c */ + +/* +ok: the EDBM module is for editmode bmesh stuff. in contrast, the + BMEdit module is for code shared with blenkernel that concerns + the BMEditMesh structure. +*/ + +/*calls a bmesh op, reporting errors to the user, doing conversions, + etc.*/ +int EDBM_CallOpf(struct BMEditMesh *em, struct wmOperator *op, char *fmt, ...); + +/*same as above, but doesn't report errors.*/ +int EDBM_CallOpfSilent(struct BMEditMesh *em, char *fmt, ...); + +/*these next two functions are the split version of EDBM_CallOpf, so you can + do stuff with a bmesh operator, after initializing it but before executing + it. + + execute the operator with BM_Exec_Op*/ +int EDBM_InitOpf(struct BMEditMesh *em, struct BMOperator *bmop, + struct wmOperator *op, char *fmt, ...); +/*cleans up after a bmesh operator*/ +int EDBM_FinishOp(struct BMEditMesh *em, struct BMOperator *bmop, + struct wmOperator *op, int report); + +void EDBM_clear_flag_all(struct BMEditMesh *em, int flag); +void EDBM_set_actFace(struct BMEditMesh *em, struct BMFace *efa); +void EDBM_store_selection(struct BMEditMesh *em, void *data); +void EDBM_validate_selections(struct BMEditMesh *em); +void EDBM_remove_selection(struct BMEditMesh *em, void *data); +void EDBM_stats_update(struct BMEditMesh *em); + /* ******************** editface.c */ int edgetag_context_check(Scene *scene, EditEdge *eed); @@ -45,11 +88,18 @@ int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge /* ******************* editmesh.c */ +void EM_beginEditMesh(struct Object *ob); +void EM_endEditMesh(struct Object *ob, EditMesh *em); + extern void free_editvert(EditMesh *em, EditVert *eve); extern void free_editedge(EditMesh *em, EditEdge *eed); extern void free_editface(EditMesh *em, EditFace *efa); void free_editMesh(EditMesh *em); +/*frees dst mesh, then copies the contents of + *src (the struct) to dst. */ +void set_editMesh(EditMesh *dst, EditMesh *src); + extern void free_vertlist(EditMesh *em, ListBase *edve); extern void free_edgelist(EditMesh *em, ListBase *lb); extern void free_facelist(EditMesh *em, ListBase *lb); @@ -67,7 +117,7 @@ int editedge_containsVert(struct EditEdge *eed, struct EditVert *eve); int editface_containsVert(struct EditFace *efa, struct EditVert *eve); int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed); -void em_setup_viewcontext(struct bContext *C, ViewContext *vc); +void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); void MESH_OT_separate(struct wmOperatorType *ot); @@ -149,6 +199,7 @@ void MESH_OT_knife_cut(struct wmOperatorType *ot); /* ******************* editmesh_mods.c */ void MESH_OT_loop_select(struct wmOperatorType *ot); void MESH_OT_select_all_toggle(struct wmOperatorType *ot); +void MESH_OT_bmesh_test(struct wmOperatorType *ot); void MESH_OT_select_more(struct wmOperatorType *ot); void MESH_OT_select_less(struct wmOperatorType *ot); void MESH_OT_select_inverse(struct wmOperatorType *ot); @@ -172,13 +223,13 @@ void MESH_OT_mark_sharp(struct wmOperatorType *ot); void MESH_OT_vertices_smooth(struct wmOperatorType *ot); void MESH_OT_flip_normals(struct wmOperatorType *ot); -extern EditEdge *findnearestedge(ViewContext *vc, int *dist); +extern EditEdge *findnearestedge(struct ViewContext *vc, int *dist); extern void EM_automerge(int update); void editmesh_select_by_material(EditMesh *em, int index); void righthandfaces(EditMesh *em, int select); /* makes faces righthand turning */ void EM_select_more(EditMesh *em); void selectconnected_mesh_all(EditMesh *em); -void faceloop_select(EditMesh *em, EditEdge *startedge, int select); +void faceloop_select(struct BMEditMesh *em, struct BMEdge *startedge, int select); /** * findnearestvert @@ -189,7 +240,7 @@ void faceloop_select(EditMesh *em, EditEdge *startedge, int select); * if 0, unselected vertice are given the bias * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased */ -extern EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict); +extern EditVert *findnearestvert(struct ViewContext *vc, int *dist, short sel, short strict); /* ******************* editmesh_tools.c */ @@ -202,7 +253,7 @@ extern EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short st void join_triangles(EditMesh *em); int removedoublesflag(EditMesh *em, short flag, short automerge, float limit); /* return amount */ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float fractal, int beauty, int numcuts, int seltype); -int EdgeSlide(EditMesh *em, wmOperator *op, short immediate, float imperc); +int EdgeSlide(EditMesh *em, struct wmOperator *op, short immediate, float imperc); void MESH_OT_merge(struct wmOperatorType *ot); void MESH_OT_subdivide(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_layers.c b/source/blender/editors/mesh/mesh_layers.c index 99d50d1a9b0..bad2fa99434 100644 --- a/source/blender/editors/mesh/mesh_layers.c +++ b/source/blender/editors/mesh/mesh_layers.c @@ -44,6 +44,7 @@ #include "BKE_displist.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_tessmesh.h" #include "BLI_editVert.h" @@ -57,10 +58,11 @@ #include "ED_view3d.h" #include "mesh_intern.h" +#include "bmesh.h" static void delete_customdata_layer(Mesh *me, CustomDataLayer *layer) { - CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata; + CustomData *data= (me->edit_btmesh)? &me->edit_btmesh->bm->pdata: &me->pdata; void *actlayerdata, *rndlayerdata, *clonelayerdata, *masklayerdata, *layerdata=layer->data; int type= layer->type; int index= CustomData_get_layer_index(data, type); @@ -79,8 +81,8 @@ static void delete_customdata_layer(Mesh *me, CustomDataLayer *layer) masklayerdata = data->layers[CustomData_get_mask_layer_index(data, type)].data; CustomData_set_layer_active(data, type, layer - &data->layers[index]); - if(me->edit_mesh) { - EM_free_data_layer(me->edit_mesh, data, type); + if(me->edit_btmesh) { + BM_free_data_layer(me->edit_btmesh->bm, data, type); } else { CustomData_free_layer_active(data, type, me->totface); @@ -88,7 +90,7 @@ static void delete_customdata_layer(Mesh *me, CustomDataLayer *layer) } if(!CustomData_has_layer(data, type)) - if(type == CD_MCOL && (G.f & G_VERTEXPAINT)) + if(type == CD_MLOOPCOL && (G.f & G_VERTEXPAINT)) G.f &= ~G_VERTEXPAINT; /* get out of vertexpaint mode */ /* reconstruct active layer */ @@ -156,7 +158,7 @@ static int uv_texture_add_exec(bContext *C, wmOperator *op) Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; Mesh *me; - EditMesh *em; + BMEditMesh *em; int layernum; if(!ob || ob->type!=OB_MESH) @@ -165,26 +167,30 @@ static int uv_texture_add_exec(bContext *C, wmOperator *op) me= (Mesh*)ob->data; if(scene->obedit == ob) { - em= me->edit_mesh; + em= me->edit_btmesh; - layernum= CustomData_number_of_layers(&em->fdata, CD_MTFACE); + layernum= CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY); if(layernum >= MAX_MTFACE) return OPERATOR_CANCELLED; - EM_add_data_layer(em, &em->fdata, CD_MTFACE); - CustomData_set_layer_active(&em->fdata, CD_MTFACE, layernum); + BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY); + BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV); + CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum); } else if(ob) { - layernum= CustomData_number_of_layers(&me->fdata, CD_MTFACE); + layernum= CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); if(layernum >= MAX_MTFACE) return OPERATOR_CANCELLED; - if(me->mtface) - CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DUPLICATE, me->mtface, me->totface); - else - CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface); - - CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum); + if (me->mtpoly) { + CustomData_add_layer(&me->pdata, CD_MTEXPOLY, CD_DUPLICATE, me->mtpoly, me->totpoly); + CustomData_add_layer(&me->ldata, CD_MLOOPUV, CD_DUPLICATE, me->mloopuv, me->totloop); + } else { + CustomData_add_layer(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly); + CustomData_add_layer(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop); + } + + CustomData_set_layer_active(&me->pdata, CD_MTEXPOLY, layernum); mesh_update_customdata_pointers(me); } @@ -212,20 +218,24 @@ static int uv_texture_remove_exec(bContext *C, wmOperator *op) Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; Mesh *me; - CustomDataLayer *cdl; + CustomDataLayer *cdl, *cdl2; int index; if(!ob || ob->type!=OB_MESH) return OPERATOR_CANCELLED; me= (Mesh*)ob->data; - index= CustomData_get_active_layer_index(&me->fdata, CD_MTFACE); - cdl= (index == -1)? NULL: &me->fdata.layers[index]; + index= CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY); + cdl= (index == -1)? NULL: &me->pdata.layers[index]; + + index= CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV); + cdl2= (index == -1)? NULL: &me->ldata.layers[index]; if(!cdl) return OPERATOR_CANCELLED; delete_customdata_layer(me, cdl); + delete_customdata_layer(me, cdl2); DAG_object_flush_update(scene, ob, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob); @@ -253,8 +263,8 @@ static int vertex_color_add_exec(bContext *C, wmOperator *op) Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; Mesh *me; - EditMesh *em; - MCol *mcol; + BMEditMesh *em; + MLoopCol *mcol; int layernum; if(!ob || ob->type!=OB_MESH) @@ -263,28 +273,28 @@ static int vertex_color_add_exec(bContext *C, wmOperator *op) me= (Mesh*)ob->data; if(scene->obedit == ob) { - em= me->edit_mesh; + em= me->edit_btmesh; - layernum= CustomData_number_of_layers(&em->fdata, CD_MCOL); + layernum= CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL); if(layernum >= MAX_MCOL) return OPERATOR_CANCELLED; - EM_add_data_layer(em, &em->fdata, CD_MCOL); - CustomData_set_layer_active(&em->fdata, CD_MCOL, layernum); + BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPCOL); + CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum); } else { - layernum= CustomData_number_of_layers(&me->fdata, CD_MCOL); + layernum= CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); if(layernum >= MAX_MCOL) return OPERATOR_CANCELLED; - mcol= me->mcol; + mcol= me->mloopcol; - if(me->mcol) - CustomData_add_layer(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mcol, me->totface); + if(me->mloopcol) + CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DUPLICATE, me->mloopcol, me->totloop); else - CustomData_add_layer(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface); + CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop); - CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum); + CustomData_set_layer_active(&me->ldata, CD_MLOOPCOL, layernum); mesh_update_customdata_pointers(me); if(!mcol) @@ -322,8 +332,8 @@ static int vertex_color_remove_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; me= (Mesh*)ob->data; - index= CustomData_get_active_layer_index(&me->fdata, CD_MCOL); - cdl= (index == -1)? NULL: &me->fdata.layers[index]; + index= CustomData_get_active_layer_index(&me->ldata, CD_MLOOPCOL); + cdl= (index == -1)? NULL: &me->ldata.layers[index]; if(!cdl) return OPERATOR_CANCELLED; diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index c10fdbcfd8f..5f406cb4db8 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -72,6 +72,7 @@ #include "BKE_object.h" #include "BKE_utildefines.h" #include "BKE_report.h" +#include "BKE_tessmesh.h" #include "RE_pipeline.h" #include "RE_shader_ext.h" @@ -118,15 +119,17 @@ int join_mesh_exec(bContext *C, wmOperator *op) MVert *mvert, *mv, *mvertmain; MEdge *medge = NULL, *medgemain; MFace *mface = NULL, *mfacemain; + MPoly *mpoly = NULL, *mpolymain; + MLoop *mloop = NULL, *mloopmain; Key *key, *nkey=NULL; KeyBlock *kb, *okb, *kbn; float imat[4][4], cmat[4][4], *fp1, *fp2, curpos; int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0; - int vertofs, *matmap; - int i, j, index, haskey=0, edgeofs, faceofs; + int totloop=0, totpoly=0, vertofs, *matmap; + int i, j, index, haskey=0, edgeofs, faceofs, loopofs, polyofs; bDeformGroup *dg, *odg; MDeformVert *dvert; - CustomData vdata, edata, fdata; + CustomData vdata, edata, fdata, ldata, pdata; if(scene->obedit) return OPERATOR_CANCELLED; @@ -143,6 +146,8 @@ int join_mesh_exec(bContext *C, wmOperator *op) totvert+= me->totvert; totedge+= me->totedge; totface+= me->totface; + totloop+= me->totloop; + totpoly+= me->totpoly; totmat+= base->object->totcol; if(base->object == ob) @@ -290,18 +295,26 @@ int join_mesh_exec(bContext *C, wmOperator *op) memset(&vdata, 0, sizeof(vdata)); memset(&edata, 0, sizeof(edata)); memset(&fdata, 0, sizeof(fdata)); + memset(&ldata, 0, sizeof(ldata)); + memset(&pdata, 0, sizeof(pdata)); mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface); + mloop= CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop); + mpoly= CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly); mvertmain= mvert; medgemain= medge; mfacemain= mface; + mloopmain = mloop; + mpolymain = mpoly; vertofs= 0; edgeofs= 0; faceofs= 0; + loopofs= 0; + polyofs= 0; /* inverse transform for all selected meshes in this object */ Mat4Invert(imat, ob->obmat); @@ -451,7 +464,43 @@ int join_mesh_exec(bContext *C, wmOperator *op) edgeofs += me->totedge; } + + if (me->totloop) { + CustomData_merge(&me->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop); + CustomData_copy_data(&me->ldata, &ldata, 0, loopofs, me->totloop); + + for(a=0; a<me->totloop; a++, mloop++) { + mloop->v += vertofs; + mloop->e += edgeofs; + } + + loopofs += me->totloop; + } + if(me->totpoly) { + /* make mapping for materials */ + for(a=1; a<=base->object->totcol; a++) { + ma= give_current_material(base->object, a); + + for(b=0; b<totcol; b++) { + if(ma == matar[b]) { + matmap[a-1]= b; + break; + } + } + } + + CustomData_merge(&me->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly); + CustomData_copy_data(&me->pdata, &pdata, 0, polyofs, me->totpoly); + + for(a=0; a<me->totpoly; a++, mpoly++) { + mpoly->loopstart += loopofs; + mpoly->mat_nr= matmap[(int)mpoly->mat_nr]; + } + + polyofs += me->totface; + } + /* vertofs is used to help newly added verts be reattached to their edge/face * (cannot be set earlier, or else reattaching goes wrong) */ @@ -470,14 +519,20 @@ int join_mesh_exec(bContext *C, wmOperator *op) CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); + CustomData_free(&me->ldata, me->totloop); + CustomData_free(&me->pdata, me->totpoly); me->totvert= totvert; me->totedge= totedge; me->totface= totface; + me->totloop= totloop; + me->totpoly= totpoly; me->vdata= vdata; me->edata= edata; me->fdata= fdata; + me->ldata= ldata; + me->pdata= pdata; mesh_update_customdata_pointers(me); @@ -838,7 +893,7 @@ static struct { /* mode is 's' start, or 'e' end, or 'u' use */ /* if end, ob can be NULL */ -intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode) +intptr_t mesh_octree_table(Object *ob, BMEditMesh *em, float *co, char mode) { MocNode **bt; @@ -864,10 +919,12 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode) * we are using the undeformed coordinates*/ INIT_MINMAX(min, max); - if(em && me->edit_mesh==em) { - EditVert *eve; + if(em && me->edit_btmesh==em) { + BMIter iter; + BMVert *eve; - for(eve= em->verts.first; eve; eve= eve->next) + eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for (; eve; eve=BMIter_Step(&iter)) DO_MINMAX(eve->co, min, max) } else { @@ -905,10 +962,12 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode) MeshOctree.table= MEM_callocN(MOC_RES*MOC_RES*MOC_RES*sizeof(void *), "sym table"); - if(em && me->edit_mesh==em) { - EditVert *eve; + if(em && me->edit_btmesh==em) { + BMVert *eve; + BMIter iter; - for(eve= em->verts.first; eve; eve= eve->next) { + eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for (; eve; eve=BMIter_Step(&iter)) { mesh_octree_add_nodes(MeshOctree.table, eve->co, MeshOctree.offs, MeshOctree.div, (intptr_t)(eve)); } } @@ -964,7 +1023,7 @@ int mesh_get_x_mirror_vert(Object *ob, int index) return mesh_octree_table(ob, NULL, vec, 'u'); } -EditVert *editmesh_get_x_mirror_vert(Object *ob, EditMesh *em, float *co) +BMVert *editmesh_get_x_mirror_vert(Object *ob, BMEditMesh *em, float *co) { float vec[3]; intptr_t poinval; @@ -982,7 +1041,7 @@ EditVert *editmesh_get_x_mirror_vert(Object *ob, EditMesh *em, float *co) poinval= mesh_octree_table(ob, em, vec, 'u'); if(poinval != -1) - return (EditVert *)(poinval); + return (BMVert *)(poinval); return NULL; } @@ -1032,7 +1091,7 @@ static int mirror_facecmp(void *a, void *b) return (mirror_facerotation((MFace*)a, (MFace*)b) == -1); } -int *mesh_get_x_mirror_faces(Object *ob, EditMesh *em) +int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em) { Mesh *me= ob->data; MVert *mv, *mvert= me->mvert; diff --git a/source/blender/editors/object/SConscript b/source/blender/editors/object/SConscript index 3371e172a82..0b7a4e41192 100644 --- a/source/blender/editors/object/SConscript +++ b/source/blender/editors/object/SConscript @@ -6,7 +6,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc' incs += ' #/intern/guardedalloc' -incs += ' ../../makesrna ../../python' +incs += ' ../../makesrna ../../python ../../bmesh' defs = [] diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 0746fbaefb6..a938018d97b 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -96,6 +96,7 @@ #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_mesh.h" +#include "BKE_tessmesh.h" #include "BKE_nla.h" #include "BKE_object.h" #include "BKE_particle.h" @@ -845,13 +846,14 @@ static void copy_object_set_idnew(Scene *scene, View3D *v3d, int dupflag) } -static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float *cent) +static int return_editmesh_indexar(BMEditMesh *em, int *tot, int **indexar, float *cent) { - EditVert *eve; + BMVert *eve; + BMIter iter; int *index, nr, totvert=0; - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) totvert++; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT)) totvert++; } if(totvert==0) return 0; @@ -860,8 +862,8 @@ static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float nr= 0; cent[0]= cent[1]= cent[2]= 0.0; - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT)) { *index= nr; index++; VecAddf(cent, cent, eve->co); } @@ -873,19 +875,19 @@ static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float return totvert; } -static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, float *cent) +static int return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *name, float *cent) { MDeformVert *dvert; - EditVert *eve; + BMVert *eve; + BMIter iter; int i, totvert=0; cent[0]= cent[1]= cent[2]= 0.0; if(obedit->actdef) { - /* find the vertices */ - for(eve= em->verts.first; eve; eve= eve->next) { - dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + dvert= CustomData_em_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); if(dvert) { for(i=0; i<dvert->totweight; i++){ @@ -910,19 +912,18 @@ static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, floa static void select_editmesh_hook(Object *ob, HookModifierData *hmd) { Mesh *me= ob->data; - EditMesh *em= BKE_mesh_get_editmesh(me); - EditVert *eve; + BMEditMesh *em= me->edit_btmesh; + BMVert *eve; + BMIter iter; int index=0, nr=0; - for(eve= em->verts.first; eve; eve= eve->next, nr++) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { if(nr==hmd->indexar[index]) { - eve->f |= SELECT; + BM_Select(em->bm, eve, 1); if(index < hmd->totindex-1) index++; } + nr++; } - EM_select_flush(em); - - BKE_mesh_end_editmesh(me, em); } static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent) @@ -1095,16 +1096,13 @@ int hook_getIndexArray(Object *obedit, int *tot, int **indexar, char *name, floa case OB_MESH: { Mesh *me= obedit->data; - EditMesh *em = BKE_mesh_get_editmesh(me); + BMEditMesh *em = me->edit_btmesh; /* check selected vertices first */ if( return_editmesh_indexar(em, tot, indexar, cent_r)) { - BKE_mesh_end_editmesh(me, em); return 1; } else { - int ret = return_editmesh_vgroup(obedit, em, name, cent_r); - BKE_mesh_end_editmesh(me, em); - return ret; + return return_editmesh_vgroup(obedit, em, name, cent_r); } } case OB_CURVE: @@ -2541,10 +2539,10 @@ void make_vertex_parent(Scene *scene, Object *obedit, View3D *v3d) if(obedit->type==OB_MESH) { Mesh *me= obedit->data; - EditMesh *em = BKE_mesh_get_editmesh(me); + BMEditMesh *em = me->edit_btmesh; + BMIter iter; - eve= em->verts.first; - while(eve) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { if(eve->f & 1) { if(v1==0) v1= nr; else if(v2==0) v2= nr; @@ -2553,10 +2551,7 @@ void make_vertex_parent(Scene *scene, Object *obedit, View3D *v3d) else break; } nr++; - eve= eve->next; } - - BKE_mesh_end_editmesh(me, em); } else if(ELEM(obedit->type, OB_SURF, OB_CURVE)) { ListBase *editnurb= curve_get_editcurve(obedit); @@ -3179,9 +3174,10 @@ static int object_center_set_exec(bContext *C, wmOperator *op) if(obedit->type==OB_MESH) { Mesh *me= obedit->data; - EditMesh *em = BKE_mesh_get_editmesh(me); + BMEditMesh *em = me->edit_btmesh; + BMIter iter; - for(eve= em->verts.first; eve; eve= eve->next) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { if(v3d->around==V3D_CENTROID) { total++; VECADD(cent, cent, eve->co); @@ -3200,14 +3196,13 @@ static int object_center_set_exec(bContext *C, wmOperator *op) cent[2]= (min[2]+max[2])/2.0f; } - for(eve= em->verts.first; eve; eve= eve->next) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { VecSubf(eve->co, eve->co, cent); } - recalc_editnormals(em); + EDBM_RecalcNormals(em); tot_change++; DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); - BKE_mesh_end_editmesh(me, em); } } @@ -3504,16 +3499,17 @@ void ED_object_exit_editmode(bContext *C, int flag) // if(retopo_mesh_paint_check()) // retopo_end_okee(); - if(me->edit_mesh->totvert>MESH_MAX_VERTS) { + if(me->edit_btmesh->bm->totvert>MESH_MAX_VERTS) { error("Too many vertices"); return; } - load_editMesh(scene, obedit); + + EDBM_LoadEditBMesh(scene, obedit); if(freedata) { - free_editMesh(me->edit_mesh); - MEM_freeN(me->edit_mesh); - me->edit_mesh= NULL; + EDBM_FreeEditBMesh(me->edit_btmesh); + MEM_freeN(me->edit_btmesh); + me->edit_btmesh= NULL; } if(G.f & G_WEIGHTPAINT) @@ -3597,7 +3593,7 @@ void ED_object_enter_editmode(bContext *C, int flag) ok= 1; scene->obedit= ob; // context sees this - make_editMesh(scene, ob); + EDBM_MakeEditBMesh(scene, ob); WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MESH, scene); } diff --git a/source/blender/editors/physics/editparticle.c b/source/blender/editors/physics/editparticle.c index 3f7880b7fef..da8bcaab0b5 100644 --- a/source/blender/editors/physics/editparticle.c +++ b/source/blender/editors/physics/editparticle.c @@ -1015,7 +1015,7 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys) mvert=dm->getVertDataArray(dm,CD_MVERT); for(i=0; i<totface; i++, vec+=6, nor+=6) { - mface=dm->getFaceData(dm,i,CD_MFACE); + mface=dm->getTessFaceData(dm,i,CD_MFACE); mvert=dm->getVertData(dm,mface->v1,CD_MVERT); VECCOPY(vec,mvert->co); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 113e7249e65..19cbf93a83c 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -201,7 +201,7 @@ int ED_operator_editmesh(bContext *C) { Object *obedit= CTX_data_edit_object(C); if(obedit && obedit->type==OB_MESH) - return NULL != ((Mesh *)obedit->data)->edit_mesh; + return NULL != ((Mesh *)obedit->data)->edit_btmesh; return 0; } diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 720e64d260f..08a1c014a10 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -2966,11 +2966,11 @@ static void project_paint_begin(ProjPaintState *ps) return; } ps->dm_mvert = ps->dm->getVertArray(ps->dm); - ps->dm_mface = ps->dm->getFaceArray(ps->dm); - ps->dm_mtface= ps->dm->getFaceDataArray(ps->dm, CD_MTFACE); + ps->dm_mface = ps->dm->getTessFaceArray(ps->dm); + ps->dm_mtface= ps->dm->getTessFaceDataArray(ps->dm, CD_MTFACE); ps->dm_totvert = ps->dm->getNumVerts(ps->dm); - ps->dm_totface = ps->dm->getNumFaces(ps->dm); + ps->dm_totface = ps->dm->getNumTessFaces(ps->dm); /* use clone mtface? */ diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 85ea55331dc..46d41c043bd 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -80,9 +80,9 @@ static void imapaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, fl void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceindex, int *xy, float *uv) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX); - MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf; - int numfaces = dm->getNumFaces(dm), a; + int *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + MTFace *tface = dm->getTessFaceDataArray(dm, CD_MTFACE), *tf; + int numfaces = dm->getNumTessFaces(dm), a; float p[2], w[3], absw, minabsw; MFace mf; MVert mv[4]; @@ -93,7 +93,7 @@ void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceind /* test all faces in the derivedmesh with the original index of the picked face */ for(a = 0; a < numfaces; a++) { if(index[a] == faceindex) { - dm->getFace(dm, a, &mf); + dm->getTessFace(dm, a, &mf); dm->getVert(dm, mf.v1, &mv[0]); dm->getVert(dm, mf.v2, &mv[1]); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 7245218c688..f3108e02159 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1001,8 +1001,8 @@ static void sculpt_update_mesh_elements(bContext *C) ss->totvert = dm->getNumVerts(dm); ss->totface = dm->getNumFaces(dm); ss->mvert = dm->getVertDataArray(dm, CD_MVERT); - ss->mface = dm->getFaceDataArray(dm, CD_MFACE); - ss->face_normals = dm->getFaceDataArray(dm, CD_NORMAL); + ss->mface = dm->getTessFaceDataArray(dm, CD_MFACE); + ss->face_normals = dm->getTessFaceDataArray(dm, CD_NORMAL); } else { Mesh *me = get_mesh(ob); diff --git a/source/blender/editors/space_buttons/SConscript b/source/blender/editors/space_buttons/SConscript index a0a7dad4077..71530d6f92d 100644 --- a/source/blender/editors/space_buttons/SConscript +++ b/source/blender/editors/space_buttons/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' -incs += ' ../../makesrna ../../render/extern/include' +incs += ' ../../makesrna ../../render/extern/include ../../bmesh' defs = [] diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index fb1e9d1214d..0c3bda5b9b8 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -50,6 +50,7 @@ #include "BKE_texture.h" #include "BKE_utildefines.h" #include "BKE_world.h" +#include "BKE_tessmesh.h" #include "BLI_editVert.h" #include "BLI_listbase.h" @@ -128,12 +129,13 @@ static int material_slot_assign_exec(bContext *C, wmOperator *op) if(ob && ob->actcol>0) { if(ob->type == OB_MESH) { - EditMesh *em= ((Mesh*)ob->data)->edit_mesh; - EditFace *efa; + BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh; + BMFace *efa; + BMIter iter; if(em) { - for(efa= em->faces.first; efa; efa=efa->next) - if(efa->f & SELECT) + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) + if(BM_TestHFlag(efa, BM_SELECT)) efa->mat_nr= ob->actcol-1; } } @@ -185,7 +187,7 @@ static int material_slot_de_select(bContext *C, int select) return OPERATOR_CANCELLED; if(ob->type == OB_MESH) { - EditMesh *em= ((Mesh*)ob->data)->edit_mesh; + EditMesh *em= BKE_mesh_get_editmesh(((Mesh*)ob->data)); if(em) { if(select) @@ -193,6 +195,8 @@ static int material_slot_de_select(bContext *C, int select) else EM_deselect_by_material(em, ob->actcol-1); } + + BKE_mesh_end_editmesh(ob->data, em); } else if ELEM(ob->type, OB_CURVE, OB_SURF) { ListBase *editnurb= ((Curve*)ob->data)->editnurb; diff --git a/source/blender/editors/space_image/image_header.c b/source/blender/editors/space_image/image_header.c index 35088f0e4d1..e4cd5c77703 100644 --- a/source/blender/editors/space_image/image_header.c +++ b/source/blender/editors/space_image/image_header.c @@ -48,6 +48,7 @@ #include "BKE_mesh.h" #include "BKE_screen.h" #include "BKE_utildefines.h" +#include "BKE_mesh.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript index 7d51d237ef0..b90ac30cd41 100644 --- a/source/blender/editors/space_view3d/SConscript +++ b/source/blender/editors/space_view3d/SConscript @@ -7,7 +7,7 @@ defs = [] incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' ../../render/extern/include #/intern/guardedalloc' -incs += ' ../../gpu ../../makesrna ../../blenfont' +incs += ' ../../gpu ../../makesrna ../../blenfont ../../bmesh ' if env['WITH_BF_GAMEENGINE']: defs.append('GAMEBLENDER=1') diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index 1807de9efbb..a04d6d07d24 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -550,6 +550,7 @@ void draw_mesh_text(Scene *scene, Object *ob, int glsl) void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, int faceselect) { +#if 0 Mesh *me= ob->data; /* correct for negative scale */ @@ -586,5 +587,6 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *o /* in editmode, the blend mode needs to be set incase it was ADD */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +#endif } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 93c6c535a31..0c521512c12 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -88,6 +88,7 @@ #include "BKE_particle.h" #include "BKE_property.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -227,7 +228,7 @@ static int check_material_alpha(Base *base, Mesh *me, int glsl) if(G.f & G_PICKSEL) return 0; - if(me->edit_mesh) + if(me->edit_btmesh) return 0; return (glsl || (base->object->dtx & OB_DRAWTRANSP)); @@ -1278,10 +1279,10 @@ static void drawlattice(Scene *scene, View3D *v3d, Object *ob) static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { - struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData; - EditVert *eve = EM_get_vert_for_index(index); + struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData; + BMVert *eve = EDBM_get_vert_for_index(data->vc.em, index); - if (eve->h==0) { + if (!BM_TestHFlag(eve, BM_HIDDEN)) { short s[2]= {IS_CLIPPED, 0}; if (data->clipVerts) { @@ -1295,30 +1296,30 @@ static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co } } -void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, EditVert *eve, int x, int y, int index), void *userData, int clipVerts) +void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BMVert *eve, int x, int y, int index), void *userData, int clipVerts) { - struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } data; - DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data; + DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; data.userData = userData; data.clipVerts = clipVerts; - EM_init_index_arrays(vc->em, 1, 0, 0); + EDBM_init_index_arrays(vc->em, 1, 0, 0); dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data); - EM_free_index_arrays(); + EDBM_free_index_arrays(vc->em); dm->release(dm); } static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co) { - struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData; - EditEdge *eed = EM_get_edge_for_index(index); + struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData; + BMEdge *eed = EDBM_get_edge_for_index(data->vc.em, index); short s[2][2]; - if (eed->h==0) { + if (!BM_TestHFlag(eed, BM_HIDDEN)) { if (data->clipVerts==1) { view3d_project_short_clip(data->vc.ar, v0co, s[0]); view3d_project_short_clip(data->vc.ar, v1co, s[1]); @@ -1337,48 +1338,48 @@ static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0 } } -void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts) +void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts) { - struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } data; - DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data; + DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; data.userData = userData; data.clipVerts = clipVerts; - EM_init_index_arrays(vc->em, 0, 1, 0); + EDBM_init_index_arrays(vc->em, 0, 1, 0); dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data); - EM_free_index_arrays(); + EDBM_free_index_arrays(vc->em); dm->release(dm); } static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *no) { - struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } *data = userData; - EditFace *efa = EM_get_face_for_index(index); + struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } *data = userData; + BMFace *efa = EDBM_get_face_for_index(data->vc.em, index); short s[2]; - if (efa && efa->h==0 && efa->fgonf!=EM_FGON) { + if (efa && !BM_TestHFlag(efa, BM_HIDDEN)) { view3d_project_short_clip(data->vc.ar, cent, s); data->func(data->userData, efa, s[0], s[1], index); } } -void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, EditFace *efa, int x, int y, int index), void *userData) +void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, BMFace *efa, int x, int y, int index), void *userData) { - struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } data; - DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } data; + DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; data.userData = userData; - EM_init_index_arrays(vc->em, 0, 0, 1); + EDBM_init_index_arrays(vc->em, 0, 0, 1); dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data); - EM_free_index_arrays(); + EDBM_free_index_arrays(vc->em); dm->release(dm); } @@ -1441,46 +1442,54 @@ void nurbs_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, Nurb static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no) { + Scene *scene= ((void **)userData)[0]; + BMEditMesh *em = ((void **)userData)[1]; + BMFace *efa = EDBM_get_face_for_index(em, index); ToolSettings *ts= ((Scene *)userData)->toolsettings; - EditFace *efa = EM_get_face_for_index(index); - if (efa->h==0 && efa->fgonf!=EM_FGON) { + if (!BM_TestHFlag(efa, BM_HIDDEN)) { glVertex3fv(cent); glVertex3f( cent[0] + no[0]*ts->normalsize, cent[1] + no[1]*ts->normalsize, cent[2] + no[2]*ts->normalsize); } } -static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm) +static void draw_dm_face_normals(BMEditMesh *tm, Scene *scene, DerivedMesh *dm) { + void *ptrs[2] = {scene, tm}; + glBegin(GL_LINES); - dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, scene); + dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, ptrs); glEnd(); } static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *no) { - EditFace *efa = EM_get_face_for_index(index); - int sel = *((int*) userData); + BMFace *efa = EDBM_get_face_for_index(((void **)userData)[0], index); + BMEditMesh *em = ((void **)userData)[0]; + int sel = *(((int **)userData)[1]); - if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) { + if (!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)==sel) { bglVertex3fv(cent); } } -static void draw_dm_face_centers(DerivedMesh *dm, int sel) +static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, int sel) { + void *ptrs[2] = {em, &sel}; + bglBegin(GL_POINTS); - dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &sel); + dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs); bglEnd(); } static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { - Scene *scene= (Scene *)userData; + Scene *scene= ((void **)userData)[0]; ToolSettings *ts= scene->toolsettings; - EditVert *eve = EM_get_vert_for_index(index); + BMEditMesh *em = ((void **)userData)[1]; + BMVert *eve = EDBM_get_vert_for_index(em, index); - if (eve->h==0) { + if (!BM_TestHFlag(eve, BM_HIDDEN)) { glVertex3fv(co); if (no_f) { @@ -1494,20 +1503,22 @@ static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, } } } -static void draw_dm_vert_normals(Scene *scene, DerivedMesh *dm) +static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm) { + void *ptrs[2] = {scene, em}; + glBegin(GL_LINES); - dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, scene); + dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, ptrs); glEnd(); } /* Draw verts with color set based on selection */ static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { - struct { int sel; EditVert *eve_act; } * data = userData; - EditVert *eve = EM_get_vert_for_index(index); + struct { BMEditMesh *em; int sel; BMVert *eve_act; } *data = userData; + BMVert *eve = EDBM_get_vert_for_index(data->em, index); - if (eve->h==0 && (eve->f&SELECT)==data->sel) { + if (!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)==data->sel) { /* draw active larger - need to stop/start point drawing for this :/ */ if (eve==data->eve_act) { float size = UI_GetThemeValuef(TH_VERTEX_SIZE); @@ -1528,11 +1539,12 @@ static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float * } } } -static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act) +static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, int sel, BMVert *eve_act) { - struct { int sel; EditVert *eve_act; } data; + struct { BMEditMesh *em; int sel; BMVert *eve_act; } data; data.sel = sel; data.eve_act = eve_act; + data.em = em; bglBegin(GL_POINTS); dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data); @@ -1542,16 +1554,18 @@ static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act) /* Draw edges with color set based on selection */ static int draw_dm_edges_sel__setDrawOptions(void *userData, int index) { - EditEdge *eed = EM_get_edge_for_index(index); + BMEdge *eed; //unsigned char **cols = userData, *col; - struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } * data = userData; + struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } * data = userData; unsigned char *col; - if (eed->h==0) { + eed = EDBM_get_edge_for_index(data->em, index); + + if (!BM_TestHFlag(eed, BM_HIDDEN)) { if (eed==data->eed_act) { glColor4ubv(data->actCol); } else { - if (eed->f&SELECT) { + if (BM_TestHFlag(eed, BM_SELECT)) { col = data->selCol; } else { col = data->baseCol; @@ -1566,13 +1580,15 @@ static int draw_dm_edges_sel__setDrawOptions(void *userData, int index) return 0; } } -static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditEdge *eed_act) +static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, + unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act) { - struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } data; + struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } data; data.baseCol = baseCol; data.selCol = selCol; data.actCol = actCol; + data.em = em; data.eed_act = eed_act; dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data); } @@ -1580,60 +1596,65 @@ static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned /* Draw edges */ static int draw_dm_edges__setDrawOptions(void *userData, int index) { - return EM_get_edge_for_index(index)->h==0; + return !BM_TestHFlag(EDBM_get_edge_for_index(userData, index), BM_HIDDEN); } -static void draw_dm_edges(DerivedMesh *dm) +static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm) { - dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, NULL); + dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em); } /* Draw edges with color interpolated based on selection */ static int draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index) { - return EM_get_edge_for_index(index)->h==0; + return !BM_TestHFlag(EDBM_get_edge_for_index(((void**)userData)[1], index), BM_HIDDEN); } static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t) { - EditEdge *eed = EM_get_edge_for_index(index); - unsigned char **cols = userData; - unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0]; - unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0]; + BMEdge *eed = EDBM_get_edge_for_index(((void**)userData)[1], index); + unsigned char **cols = ((void**)userData)[0]; + unsigned char *col0 = cols[(BM_TestHFlag(eed->v1, BM_SELECT))?1:0]; + unsigned char *col1 = cols[(BM_TestHFlag(eed->v2, BM_SELECT))?1:0]; glColor4ub( col0[0] + (col1[0]-col0[0])*t, col0[1] + (col1[1]-col0[1])*t, col0[2] + (col1[2]-col0[2])*t, col0[3] + (col1[3]-col0[3])*t); } -static void draw_dm_edges_sel_interp(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol) +static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, + unsigned char *baseCol, unsigned char *selCol) { unsigned char *cols[2]; + void *ptrs[2] = {cols, em}; + cols[0] = baseCol; cols[1] = selCol; - dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols); + dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, + draw_dm_edges_sel_interp__setDrawInterpOptions, ptrs); } /* Draw only seam edges */ static int draw_dm_edges_seams__setDrawOptions(void *userData, int index) { - EditEdge *eed = EM_get_edge_for_index(index); + BMEdge *eed = EDBM_get_edge_for_index(userData, index); - return (eed->h==0 && eed->seam); + return !BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SEAM); } -static void draw_dm_edges_seams(DerivedMesh *dm) + +static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm) { - dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, NULL); + dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em); } /* Draw only sharp edges */ static int draw_dm_edges_sharp__setDrawOptions(void *userData, int index) { - EditEdge *eed = EM_get_edge_for_index(index); + BMEdge *eed = EDBM_get_edge_for_index(userData, index); - return (eed->h==0 && eed->sharp); + return !BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SHARP); } -static void draw_dm_edges_sharp(DerivedMesh *dm) +static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm) { - dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL); + dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em); } @@ -1641,16 +1662,16 @@ static void draw_dm_edges_sharp(DerivedMesh *dm) * return 2 for the active face so it renders with stipple enabled */ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *drawSmooth_r) { - struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData; - EditFace *efa = EM_get_face_for_index(index); + struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; } *data = userData; + BMFace *efa = EDBM_get_face_for_index(data->em, index); unsigned char *col; - if (efa->h==0) { + if (!BM_TestHFlag(efa, BM_HIDDEN)) { if (efa == data->efa_act) { glColor4ubv(data->cols[2]); return 2; /* stipple */ } else { - col = data->cols[(efa->f&SELECT)?1:0]; + col = data->cols[BM_TestHFlag(efa, BM_SELECT)?1:0]; if (col[3]==0) return 0; glColor4ubv(col); return 1; @@ -1660,10 +1681,13 @@ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *dra } /* also draws the active face */ -static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act) +static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, + unsigned char *selCol, unsigned char *actCol, BMFace *efa_act) { - struct { unsigned char *cols[3]; EditFace *efa_act; } data; + struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; } data; + data.cols[0] = baseCol; + data.em = em; data.cols[1] = selCol; data.cols[2] = actCol; data.efa_act = efa_act; @@ -1673,27 +1697,27 @@ static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned static int draw_dm_creases__setDrawOptions(void *userData, int index) { - EditEdge *eed = EM_get_edge_for_index(index); + BMEdge *eed = EDBM_get_edge_for_index(userData, index); - if (eed->h==0 && eed->crease!=0.0) { + if (!BM_TestHFlag(eed, BM_HIDDEN) && eed->crease!=0.0) { UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->crease); return 1; } else { return 0; } } -static void draw_dm_creases(DerivedMesh *dm) +static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm) { glLineWidth(3.0); - dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, NULL); + dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, em); glLineWidth(1.0); } static int draw_dm_bweights__setDrawOptions(void *userData, int index) { - EditEdge *eed = EM_get_edge_for_index(index); + BMEdge *eed = EDBM_get_edge_for_index(userData, index); - if (eed->h==0 && eed->bweight!=0.0) { + if (!BM_TestHFlag(eed, BM_HIDDEN) && eed->bweight!=0.0) { UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight); return 1; } else { @@ -1702,26 +1726,26 @@ static int draw_dm_bweights__setDrawOptions(void *userData, int index) } static void draw_dm_bweights__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { - EditVert *eve = EM_get_vert_for_index(index); + BMVert *eve = EDBM_get_vert_for_index(userData, index); - if (eve->h==0 && eve->bweight!=0.0) { + if (!BM_TestHFlag(eve, BM_HIDDEN) && eve->bweight!=0.0) { UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->bweight); bglVertex3fv(co); } } -static void draw_dm_bweights(Scene *scene, DerivedMesh *dm) +static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm) { ToolSettings *ts= scene->toolsettings; if (ts->selectmode & SCE_SELECT_VERTEX) { glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2); bglBegin(GL_POINTS); - dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, NULL); + dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, em); bglEnd(); } else { glLineWidth(3.0); - dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, NULL); + dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, em); glLineWidth(1.0); } } @@ -1735,7 +1759,8 @@ static void draw_dm_bweights(Scene *scene, DerivedMesh *dm) /* EditMesh drawing routines*/ -static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, EditMesh *em, DerivedMesh *cageDM, EditVert *eve_act) +static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, + BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act) { ToolSettings *ts= scene->toolsettings; int sel; @@ -1772,13 +1797,13 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, EditM if(ts->selectmode & SCE_SELECT_VERTEX) { glPointSize(size); glColor4ubv((GLubyte *)col); - draw_dm_verts(cageDM, sel, eve_act); + draw_dm_verts(em, cageDM, sel, eve_act); } if( CHECK_OB_DRAWFACEDOT(scene, v3d, obedit->dt) ) { glPointSize(fsize); glColor4ubv((GLubyte *)fcol); - draw_dm_face_centers(cageDM, sel); + draw_dm_face_centers(em, cageDM, sel); } if (pass==0) { @@ -1792,7 +1817,9 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, EditM glPointSize(1.0); } -static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh *cageDM, short sel_only, EditEdge *eed_act) +static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d, + Mesh *me, DerivedMesh *cageDM, short sel_only, + BMEdge *eed_act) { ToolSettings *ts= scene->toolsettings; int pass; @@ -1825,21 +1852,21 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh } if(ts->selectmode == SCE_SELECT_FACE) { - draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act); + draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act); } else if( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) { if(cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) { glShadeModel(GL_SMOOTH); - draw_dm_edges_sel_interp(cageDM, wireCol, selCol); + draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol); glShadeModel(GL_FLAT); } else { - draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act); + draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act); } } else { if (!sel_only) { glColor4ubv(wireCol); - draw_dm_edges(cageDM); + draw_dm_edges(em, cageDM); } } @@ -1850,8 +1877,10 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh } } -static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em) +static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, + Object *ob, BMEditMesh *em) { +#if 0 Mesh *me= ob->data; EditEdge *eed; EditFace *efa; @@ -2014,13 +2043,14 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E glEnable(GL_DEPTH_TEST); bglPolygonOffset(rv3d->dist, 0.0); } +#endif } static int draw_em_fancy__setFaceOpts(void *userData, int index, int *drawSmooth_r) { - EditFace *efa = EM_get_face_for_index(index); + BMFace *efa = EDBM_get_face_for_index(userData, index); - if (efa->h==0) { + if (!BM_TestHFlag(efa, BM_HIDDEN)) { GPU_enable_material(efa->mat_nr+1, NULL); return 1; } @@ -2030,31 +2060,33 @@ static int draw_em_fancy__setFaceOpts(void *userData, int index, int *drawSmooth static int draw_em_fancy__setGLSLFaceOpts(void *userData, int index) { - EditFace *efa = EM_get_face_for_index(index); + BMFace *efa = EDBM_get_face_for_index(userData, index); - return (efa->h==0); + return !BM_TestHFlag(efa, BM_HIDDEN); } -static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt) +static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, + BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt) + { Mesh *me = ob->data; - EditFace *efa_act = EM_get_actFace(em, 0); /* annoying but active faces is stored differently */ - EditEdge *eed_act = NULL; - EditVert *eve_act = NULL; + BMFace *efa_act = EDBM_get_actFace(em, 0); /* annoying but active faces is stored differently */ + BMEdge *eed_act = NULL; + BMVert *eve_act = NULL; if (em->selected.last) { - EditSelection *ese = em->selected.last; + BMEditSelection *ese = em->selected.last; /* face is handeled above */ /*if (ese->type == EDITFACE ) { efa_act = (EditFace *)ese->data; } else */ if ( ese->type == EDITEDGE ) { - eed_act = (EditEdge *)ese->data; + eed_act = (BMEdge *)ese->data; } else if ( ese->type == EDITVERT ) { - eve_act = (EditVert *)ese->data; + eve_act = (BMVert *)ese->data; } } - EM_init_index_arrays(em, 1, 1, 1); + EDBM_init_index_arrays(em, 1, 1, 1); if(dt>OB_WIRE) { if(CHECK_OB_DRAWTEXTURE(v3d, dt)) { @@ -2062,7 +2094,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material, - draw_em_fancy__setGLSLFaceOpts, NULL); + draw_em_fancy__setGLSLFaceOpts, em); GPU_disable_material(); glFrontFace(GL_CCW); @@ -2077,7 +2109,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object glEnable(GL_LIGHTING); glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); - finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0); + finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, em, 0); glFrontFace(GL_CCW); glDisable(GL_LIGHTING); @@ -2111,7 +2143,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object if CHECK_OB_DRAWTEXTURE(v3d, dt) col1[3] = 0; - draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act); + draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act); glDisable(GL_BLEND); glDepthMask(1); // restore write in zbuffer @@ -2126,7 +2158,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object glEnable(GL_BLEND); glDepthMask(0); // disable write in zbuffer, needed for nice transp - draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act); + draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act); glDisable(GL_BLEND); glDepthMask(1); // restore write in zbuffer @@ -2138,14 +2170,14 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object /* we are drawing textures and 'ME_DRAWEDGES' is disabled, dont draw any edges */ /* only draw selected edges otherwise there is no way of telling if a face is selected */ - draw_em_fancy_edges(scene, v3d, me, cageDM, 1, eed_act); + draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act); } else { if(me->drawflag & ME_DRAWSEAMS) { UI_ThemeColor(TH_EDGE_SEAM); glLineWidth(2); - draw_dm_edges_seams(cageDM); + draw_dm_edges_seams(em, cageDM); glColor3ub(0,0,0); glLineWidth(1); @@ -2155,20 +2187,20 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object UI_ThemeColor(TH_EDGE_SHARP); glLineWidth(2); - draw_dm_edges_sharp(cageDM); + draw_dm_edges_sharp(em, cageDM); glColor3ub(0,0,0); glLineWidth(1); } if(me->drawflag & ME_DRAWCREASES) { - draw_dm_creases(cageDM); + draw_dm_creases(em, cageDM); } if(me->drawflag & ME_DRAWBWEIGHTS) { - draw_dm_bweights(scene, cageDM); + draw_dm_bweights(em, scene, cageDM); } - draw_em_fancy_edges(scene, v3d, me, cageDM, 0, eed_act); + draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act); } if(em) { // XXX retopo_matrix_update(v3d); @@ -2177,11 +2209,11 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object if(me->drawflag & ME_DRAWNORMALS) { UI_ThemeColor(TH_NORMAL); - draw_dm_face_normals(scene, cageDM); + draw_dm_face_normals(em, scene, cageDM); } if(me->drawflag & ME_DRAW_VNORMALS) { UI_ThemeColor(TH_NORMAL); - draw_dm_vert_normals(scene, cageDM); + draw_dm_vert_normals(em, scene, cageDM); } if(me->drawflag & (ME_DRAW_EDGELEN|ME_DRAW_FACEAREA|ME_DRAW_EDGEANG)) @@ -2249,7 +2281,7 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base totvert = dm->getNumVerts(dm); totedge = dm->getNumEdges(dm); - totface = dm->getNumFaces(dm); + totface = dm->getNumTessFaces(dm); /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */ if(dt!=OB_SHADED) @@ -2443,7 +2475,7 @@ static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base Object *ob= base->object; Object *obedit= scene->obedit; Mesh *me= ob->data; - EditMesh *em= me->edit_mesh; + BMEditMesh *em= me->edit_btmesh; int do_alpha_pass= 0, drawlinked= 0, retval= 0, glsl, check_alpha; if(obedit && ob!=obedit && ob->data==obedit->data) { @@ -2455,9 +2487,9 @@ static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base DerivedMesh *finalDM, *cageDM; if (obedit!=ob) - finalDM = cageDM = editmesh_get_derived_base(ob, em); + finalDM = cageDM = editbmesh_get_derived_base(ob, em); else - cageDM = editmesh_get_derived_cage_and_final(scene, ob, em, &finalDM, + cageDM = editbmesh_get_derived_cage_and_final(scene, ob, em, &finalDM, v3d->customdata_mask); if(dt>OB_WIRE) { @@ -5432,44 +5464,49 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) static void bbs_mesh_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { - int offset = (intptr_t) userData; - EditVert *eve = EM_get_vert_for_index(index); + void **ptrs = userData; + int offset = (intptr_t) ptrs[0]; + BMVert *eve = EDBM_get_vert_for_index(ptrs[1], index); - if (eve->h==0) { + if (!BM_TestHFlag(eve, BM_HIDDEN)) { WM_set_framebuffer_index_color(offset+index); bglVertex3fv(co); } } -static void bbs_mesh_verts(DerivedMesh *dm, int offset) +static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset) { + void *ptrs[2] = {(void*)(intptr_t) offset, em}; + glPointSize( UI_GetThemeValuef(TH_VERTEX_SIZE) ); bglBegin(GL_POINTS); - dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, (void*)(intptr_t) offset); + dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, ptrs); bglEnd(); glPointSize(1.0); } static int bbs_mesh_wire__setDrawOptions(void *userData, int index) { - int offset = (intptr_t) userData; - EditEdge *eed = EM_get_edge_for_index(index); + void **ptrs = userData; + int offset = (intptr_t) ptrs[0]; + BMEdge *eed = EDBM_get_edge_for_index(ptrs[1], index); - if (eed->h==0) { + if (!BM_TestHFlag(eed, BM_HIDDEN)) { WM_set_framebuffer_index_color(offset+index); return 1; } else { return 0; } } -static void bbs_mesh_wire(DerivedMesh *dm, int offset) +static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) { - dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, (void*)(intptr_t) offset); + void *ptrs[2] = {(void*)(intptr_t) offset, em}; + dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, ptrs); } static int bbs_mesh_solid__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r) { - if (EM_get_face_for_index(index)->h==0) { - if (userData) { + if (!BM_TestHFlag(EDBM_get_face_for_index(((void**)userData)[0], index), BM_HIDDEN)) { + if (((void**)userData)[1]) { WM_set_framebuffer_index_color(index+1); } return 1; @@ -5480,9 +5517,9 @@ static int bbs_mesh_solid__setSolidDrawOptions(void *userData, int index, int *d static void bbs_mesh_solid__drawCenter(void *userData, int index, float *cent, float *no) { - EditFace *efa = EM_get_face_for_index(index); + BMFace *efa = EDBM_get_face_for_index(((void**)userData)[0], index); - if (efa->h==0 && efa->fgonf!=EM_FGON) { + if (!BM_TestHFlag(efa, BM_HIDDEN)) { WM_set_framebuffer_index_color(index+1); bglVertex3fv(cent); @@ -5490,23 +5527,26 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, float *cent, f } /* two options, facecolors or black */ -static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh *dm, int facecol) +static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d, + Object *ob, DerivedMesh *dm, int facecol) { + void *ptrs[2] = {em, NULL}; //second one being null means to draw black cpack(0); if (facecol) { - dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, 0); + ptrs[1] = (void*)(intptr_t) 1; + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, ptrs, 0); if( CHECK_OB_DRAWFACEDOT(scene, v3d, ob->dt) ) { glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE)); bglBegin(GL_POINTS); - dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, NULL); + dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, ptrs); bglEnd(); } } else { - dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0); + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, ptrs, 0); } } @@ -5548,36 +5588,36 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec { if(ob == scene->obedit) { Mesh *me= ob->data; - EditMesh *em= me->edit_mesh; + BMEditMesh *em= me->edit_btmesh; - DerivedMesh *dm = editmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); + DerivedMesh *dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); - EM_init_index_arrays(em, 1, 1, 1); + EDBM_init_index_arrays(em, 1, 1, 1); - bbs_mesh_solid_EM(scene, v3d, ob, dm, ts->selectmode & SCE_SELECT_FACE); + bbs_mesh_solid_EM(em, scene, v3d, ob, dm, ts->selectmode & SCE_SELECT_FACE); if(ts->selectmode & SCE_SELECT_FACE) - em_solidoffs = 1+em->totface; + bm_solidoffs = 1+em->bm->totface; else - em_solidoffs= 1; + bm_solidoffs= 1; bglPolygonOffset(rv3d->dist, 1.0); // we draw edges always, for loop (select) tools - bbs_mesh_wire(dm, em_solidoffs); - em_wireoffs= em_solidoffs + em->totedge; + bbs_mesh_wire(em, dm, bm_solidoffs); + bm_wireoffs= bm_solidoffs + em->bm->totedge; // we draw verts if vert select mode or if in transform (for snap). if(ts->selectmode & SCE_SELECT_VERTEX || G.moving & G_TRANSFORM_EDIT) { - bbs_mesh_verts(dm, em_wireoffs); - em_vertoffs= em_wireoffs + em->totvert; + bbs_mesh_verts(em, dm, bm_wireoffs); + bm_vertoffs= bm_wireoffs + em->bm->totvert; } - else em_vertoffs= em_wireoffs; + else bm_vertoffs= bm_wireoffs; bglPolygonOffset(rv3d->dist, 0.0); dm->release(dm); - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } else bbs_mesh_solid(scene, v3d, ob); } @@ -5603,7 +5643,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r int glsl; if(ob == scene->obedit) - edm= editmesh_get_derived_base(ob, me->edit_mesh); + edm= editbmesh_get_derived_base(ob, me->edit_btmesh); else dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 7db577bf139..fcfc48eff84 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -69,6 +69,7 @@ #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #include "BIF_gl.h" @@ -164,31 +165,30 @@ static void v3d_editvertex_buts(const bContext *C, uiBlock *block, View3D *v3d, if(ob->type==OB_MESH) { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); - EditVert *eve, *evedef=NULL; - EditEdge *eed; + BMEditMesh *em = me->edit_btmesh; + BMesh *bm = em->bm; + BMVert *eve, *evedef=NULL; + BMEdge *eed; + BMIter iter; - eve= em->verts.first; - while(eve) { - if(eve->f & SELECT) { + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT)) { evedef= eve; tot++; VecAddf(median, median, eve->co); } - eve= eve->next; } - eed= em->edges.first; - while(eed) { - if((eed->f & SELECT)) { + + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if(BM_TestHFlag(eed, BM_SELECT)) { totedge++; median[3]+= eed->crease; } - eed= eed->next; } /* check for defgroups */ if(evedef) - dvert= CustomData_em_get(&em->vdata, evedef->data, CD_MDEFORMVERT); + dvert= CustomData_bmesh_get(&em->bm->vdata, evedef->head.data, CD_MDEFORMVERT); if(tot==1 && dvert && dvert->totweight) { bDeformGroup *dg; int i, max=1, init=1; @@ -212,8 +212,6 @@ static void v3d_editvertex_buts(const bContext *C, uiBlock *block, View3D *v3d, tfp->defweightp= &dvert->dw[0].weight; } } - - BKE_mesh_end_editmesh(me, em); } else if(ob->type==OB_CURVE || ob->type==OB_SURF) { Curve *cu= ob->data; diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index e68a1c8a10a..51ba58b3020 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -64,6 +64,7 @@ #include "BKE_particle.h" #include "BKE_screen.h" #include "BKE_utildefines.h" /* for VECCOPY */ +#include "BKE_tessmesh.h" #include "ED_armature.h" #include "ED_particle.h" @@ -4012,11 +4013,11 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event) Base *basact= CTX_data_active_base(C); Object *ob= CTX_data_active_object(C); Object *obedit = CTX_data_edit_object(C); - EditMesh *em= NULL; + BMEditMesh *em= NULL; int bit, ctrl= win->eventstate->ctrl, shift= win->eventstate->shift; if(obedit && obedit->type==OB_MESH) { - em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + em= ((Mesh *)obedit->data)->edit_btmesh; } /* watch it: if sa->win does not exist, check that when calling direct drawing routines */ @@ -4142,7 +4143,7 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event) if(shift==0 || em->selectmode==0) em->selectmode= SCE_SELECT_VERTEX; ts->selectmode= em->selectmode; - EM_selectmode_set(em); + EDBM_selectmode_set(em); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); ED_undo_push(C, "Selectmode Set: Vertex"); } @@ -4151,12 +4152,12 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event) if(em) { if(shift==0 || em->selectmode==0){ if( (em->selectmode ^ SCE_SELECT_EDGE) == SCE_SELECT_VERTEX){ - if(ctrl) EM_convertsel(em, SCE_SELECT_VERTEX,SCE_SELECT_EDGE); + if(ctrl) EDBM_convertsel(em, SCE_SELECT_VERTEX,SCE_SELECT_EDGE); } em->selectmode = SCE_SELECT_EDGE; } ts->selectmode= em->selectmode; - EM_selectmode_set(em); + EDBM_selectmode_set(em); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); ED_undo_push(C, "Selectmode Set: Edge"); } @@ -4165,12 +4166,12 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event) if(em) { if( shift==0 || em->selectmode==0){ if( ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_VERTEX) || ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_EDGE)){ - if(ctrl) EM_convertsel(em, (ts->selectmode ^ SCE_SELECT_FACE),SCE_SELECT_FACE); + if(ctrl) EDBM_convertsel(em, (ts->selectmode ^ SCE_SELECT_FACE),SCE_SELECT_FACE); } em->selectmode = SCE_SELECT_FACE; } ts->selectmode= em->selectmode; - EM_selectmode_set(em); + EDBM_selectmode_set(em); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); ED_undo_push(C, "Selectmode Set: Face"); } @@ -4253,9 +4254,6 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event) } break; } - - if(obedit && obedit->type==OB_MESH) - BKE_mesh_end_editmesh(obedit->data, em); } static void view3d_header_pulldowns(const bContext *C, uiBlock *block, Object *ob, int *xcoord, int yco) @@ -4622,7 +4620,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) /* selection modus */ if(obedit && (obedit->type == OB_MESH)) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; uiBlockBeginAlign(block); uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, xco,yco,XIC,YIC, &em->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode (Ctrl Tab 1)"); @@ -4638,8 +4636,6 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) } uiBlockEndAlign(block); header_xco_step(ar, &xco, &yco, &maxco, XIC); - - BKE_mesh_end_editmesh(obedit->data, em); } else if(G.f & G_PARTICLEEDIT) { uiBlockBeginAlign(block); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 112847272e5..32305b5c76b 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -203,7 +203,7 @@ void view3d_keymap(wmWindowManager *wm) /* selection*/ WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); - RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "type", 1); WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT|KM_CTRL, 0)->ptr, "deselect", 1); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 2537982210a..31ea1070b32 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -62,6 +62,7 @@ #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #include "RE_pipeline.h" // make_stars @@ -78,10 +79,10 @@ #include "ED_particle.h" #include "ED_mesh.h" #include "ED_object.h" -#include "ED_retopo.h" #include "ED_screen.h" #include "ED_types.h" #include "ED_util.h" +#include "ED_retopo.h" #include "UI_interface.h" #include "UI_resources.h" @@ -149,43 +150,49 @@ static void BIF_undo_push() {} /* local prototypes */ -void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select) +void EM_backbuf_checkAndSelectVerts(BMEditMesh *em, int select) { - EditVert *eve; - int index= em_wireoffs; + BMVert *eve; + BMIter iter; + int index= bm_wireoffs; - for(eve= em->verts.first; eve; eve= eve->next, index++) { - if(eve->h==0) { + eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for ( ; eve; eve=BMIter_Step(&iter), index++) { + if(!BM_TestHFlag(eve, BM_HIDDEN)) { if(EM_check_backbuf(index)) { - eve->f = select?(eve->f|1):(eve->f&~1); + BM_Select_Vert(em->bm, eve, select); } } } } -void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select) +void EM_backbuf_checkAndSelectEdges(BMEditMesh *em, int select) { - EditEdge *eed; - int index= em_solidoffs; + BMEdge *eed; + BMIter iter; + int index= bm_solidoffs; - for(eed= em->edges.first; eed; eed= eed->next, index++) { - if(eed->h==0) { + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter), index++) { + if(!BM_TestHFlag(eed, BM_HIDDEN)) { if(EM_check_backbuf(index)) { - EM_select_edge(eed, select); + BM_Select_Edge(em->bm, eed, select); } } } } -void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select) +void EM_backbuf_checkAndSelectFaces(BMEditMesh *em, int select) { - EditFace *efa; + BMFace *efa; + BMIter iter; int index= 1; - for(efa= em->faces.first; efa; efa= efa->next, index++) { - if(efa->h==0) { + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter), index++) { + if(!BM_TestHFlag(efa, BM_HIDDEN)) { if(EM_check_backbuf(index)) { - EM_select_face_fgon(em, efa, select); + BM_Select_Face(em->bm, efa, select); } } } @@ -399,53 +406,52 @@ void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves) } } -static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index) +static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, int x, int y, int index) { struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData; if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) { - eve->f = data->select?(eve->f|1):(eve->f&~1); + BM_Select_Vert(data->vc.em->bm, eve, data->select); } } -static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index) +static void do_lasso_select_mesh__doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index) { struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData; - if (EM_check_backbuf(em_solidoffs+index)) { + if (EM_check_backbuf(bm_solidoffs+index)) { if (data->pass==0) { if ( edge_fully_inside_rect(data->rect, x0, y0, x1, y1) && lasso_inside(data->mcords, data->moves, x0, y0) && lasso_inside(data->mcords, data->moves, x1, y1)) { - EM_select_edge(eed, data->select); + BM_Select_Edge(data->vc.em->bm, eed, data->select); data->done = 1; } } else { if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) { - EM_select_edge(eed, data->select); + BM_Select_Edge(data->vc.em->bm, eed, data->select); } } } } -static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index) +static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, int x, int y, int index) { struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData; if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) { - EM_select_face_fgon(data->vc.em, efa, data->select); + BM_Select_Face(data->vc.em->bm, efa, data->select); } } static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves, short select) { struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } data; - ToolSettings *ts= vc->scene->toolsettings; rcti rect; int bbsel; lasso_select_boundbox(&rect, mcords, moves); /* set editmesh */ - vc->em= ((Mesh *)vc->obedit->data)->edit_mesh; + vc->em= ((Mesh *)vc->obedit->data)->edit_btmesh; data.vc= *vc; data.rect = ▭ @@ -457,14 +463,14 @@ static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - if(ts->selectmode & SCE_SELECT_VERTEX) { + if(vc->scene->toolsettings->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { EM_backbuf_checkAndSelectVerts(vc->em, select); } else { mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1); } } - if(ts->selectmode & SCE_SELECT_EDGE) { + if(vc->scene->toolsettings->selectmode & SCE_SELECT_EDGE) { /* Does both bbsel and non-bbsel versions (need screen cos for both) */ data.pass = 0; @@ -476,7 +482,7 @@ static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves } } - if(ts->selectmode & SCE_SELECT_FACE) { + if(vc->scene->toolsettings->selectmode & SCE_SELECT_FACE) { if (bbsel) { EM_backbuf_checkAndSelectFaces(vc->em, select); } else { @@ -485,7 +491,7 @@ static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves } EM_free_backbuf(); - EM_selectmode_flush(vc->em); + EDBM_selectmode_flush(vc->em); } #if 0 @@ -647,7 +653,7 @@ static void do_lasso_select_facemode(ViewContext *vc, short mcords[][2], short m if(me==NULL || me->mtface==NULL) return; if(me->totface==0) return; - em_vertoffs= me->totface+1; /* max index array */ + bm_vertoffs= me->totface+1; /* max index array */ lasso_select_boundbox(&rect, mcords, moves); EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); @@ -715,6 +721,12 @@ void view3d_lasso_select(bContext *C, ViewContext *vc, short mcords[][2], short } +static EnumPropertyItem lasso_select_types[] = { + {0, "SELECT", 0, "Select", ""}, + {1, "DESELECT", 0, "Deselect", ""}, + {0, NULL, 0, NULL, NULL} +}; + /* lasso operator gives properties, but since old code works with short array we convert */ @@ -741,7 +753,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) /* setup view context for argument to callbacks */ view3d_set_viewcontext(C, &vc); - select= !RNA_boolean_get(op->ptr, "deselect"); + select= RNA_enum_is_equal(C, op->ptr, "type", "SELECT"); view3d_lasso_select(C, &vc, mcords, i, select); return OPERATOR_FINISHED; @@ -763,7 +775,7 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot) ot->flag= OPTYPE_UNDO; RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); - RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items."); + RNA_def_enum(ot->srna, "type", lasso_select_types, 0, "Type", ""); } @@ -1236,43 +1248,47 @@ static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select) lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data); } -static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index) +static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, int x, int y, int index) { struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData; if (BLI_in_rcti(data->rect, x, y)) { - eve->f = data->select?(eve->f|1):(eve->f&~1); + BM_Select_Vert(data->vc.em->bm, eve, data->select); } } -static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index) +static void do_mesh_box_select__doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index) { struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData; - if(EM_check_backbuf(em_solidoffs+index)) { + if(EM_check_backbuf(bm_solidoffs+index)) { if (data->pass==0) { if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) { - EM_select_edge(eed, data->select); + BM_Select_Edge(data->vc.em->bm, eed, data->select); data->done = 1; } } else { if (edge_inside_rect(data->rect, x0, y0, x1, y1)) { - EM_select_edge(eed, data->select); + BM_Select_Edge(data->vc.em->bm, eed, data->select); } } } } -static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index) + +static void +do_mesh_box_select__doSelectFace(void *userData, BMFace + *efa, int x, int y, + int index) + { struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData; if (BLI_in_rcti(data->rect, x, y)) { - EM_select_face_fgon(data->vc.em, efa, data->select); + BM_Select_Face(data->vc.em->bm, efa, data->select); } } static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select) { struct { ViewContext vc; rcti *rect; short select, pass, done; } data; - ToolSettings *ts= vc->scene->toolsettings; int bbsel; data.vc= *vc; @@ -1281,16 +1297,16 @@ static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select) data.pass = 0; data.done = 0; - bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + bbsel= EDBM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax); - if(ts->selectmode & SCE_SELECT_VERTEX) { + if(vc->scene->toolsettings->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { EM_backbuf_checkAndSelectVerts(vc->em, select); } else { mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1); } } - if(ts->selectmode & SCE_SELECT_EDGE) { + if(vc->scene->toolsettings->selectmode & SCE_SELECT_EDGE) { /* Does both bbsel and non-bbsel versions (need screen cos for both) */ data.pass = 0; @@ -1302,7 +1318,7 @@ static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select) } } - if(ts->selectmode & SCE_SELECT_FACE) { + if(vc->scene->toolsettings->selectmode & SCE_SELECT_FACE) { if(bbsel) { EM_backbuf_checkAndSelectFaces(vc->em, select); } else { @@ -1312,7 +1328,7 @@ static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select) EM_free_backbuf(); - EM_selectmode_flush(vc->em); + EDBM_selectmode_flush(vc->em); } static int view3d_borderselect_exec(bContext *C, wmOperator *op) @@ -1351,7 +1367,7 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op) if(obedit) { if(obedit->type==OB_MESH) { Mesh *me= obedit->data; - vc.em= me->edit_mesh; + vc.em= me->edit_btmesh; do_mesh_box_select(&vc, &rect, (val==LEFTMOUSE)); // if (EM_texFaceCheck()) WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); @@ -1436,7 +1452,6 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op) } } - ED_armature_sync_selection(arm->edbo); } else if(obedit->type==OB_LATTICE) { do_lattice_box_select(&vc, &rect, val==LEFTMOUSE); @@ -1522,6 +1537,11 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op) /* *****************Selection Operators******************* */ +static EnumPropertyItem prop_select_types[] = { + {0, "EXCLUSIVE", 0, "Exclusive", ""}, + {1, "EXTEND", 0, "Extend", ""}, + {0, NULL, 0, NULL, NULL} +}; /* ****** Border Select ****** */ void VIEW3D_OT_select_border(wmOperatorType *ot) @@ -1547,7 +1567,7 @@ void VIEW3D_OT_select_border(wmOperatorType *ot) RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX); RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX); - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first."); + RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", ""); } /* ****** Mouse Select ****** */ @@ -1556,7 +1576,7 @@ void VIEW3D_OT_select_border(wmOperatorType *ot) static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event) { Object *obedit= CTX_data_edit_object(C); - short extend= RNA_boolean_get(op->ptr, "extend"); + short extend= RNA_enum_is_equal(C, op->ptr, "type", "EXTEND"); view3d_operator_needs_opengl(C); @@ -1594,44 +1614,43 @@ void VIEW3D_OT_select(wmOperatorType *ot) ot->flag= OPTYPE_UNDO; /* properties */ - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first."); + RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", ""); } /* -------------------- circle select --------------------------------------------- */ -static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index) +static void mesh_circle_doSelectVert(void *userData, BMVert *eve, int x, int y, int index) { struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData; int mx = x - data->mval[0], my = y - data->mval[1]; float r = sqrt(mx*mx + my*my); if (r<=data->radius) { - eve->f = data->select?(eve->f|1):(eve->f&~1); + BM_Select_Vert(data->vc->em->bm, eve, data->select); } } -static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index) +static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index) { struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData; if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) { - EM_select_edge(eed, data->select); + BM_Select_Edge(data->vc->em->bm, eed, data->select); } } -static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index) +static void mesh_circle_doSelectFace(void *userData, BMFace *efa, int x, int y, int index) { struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData; int mx = x - data->mval[0], my = y - data->mval[1]; float r = sqrt(mx*mx + my*my); if (r<=data->radius) { - EM_select_face_fgon(data->vc->em, efa, data->select); + BM_Select_Face(data->vc->em->bm, efa, data->select); } } static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad) { - ToolSettings *ts= vc->scene->toolsettings; int bbsel; if(vc->obedit==NULL && (FACESEL_PAINT_TEST)) { @@ -1639,9 +1658,9 @@ static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, floa Mesh *me = ob?ob->data:NULL; if (me) { - em_vertoffs= me->totface+1; /* max index array */ + bm_vertoffs= me->totface+1; /* max index array */ - bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0)); + bbsel= EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0)); EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE); EM_free_backbuf(); @@ -1651,15 +1670,15 @@ static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, floa else { struct {ViewContext *vc; short select, mval[2]; float radius; } data; - bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0)); - vc->em= ((Mesh *)vc->obedit->data)->edit_mesh; + bbsel= EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0)); + vc->em= ((Mesh *)vc->obedit->data)->edit_btmesh; data.select = selecting; data.mval[0] = mval[0]; data.mval[1] = mval[1]; data.radius = rad; - if(ts->selectmode & SCE_SELECT_VERTEX) { + if(vc->scene->toolsettings->selectmode & SCE_SELECT_VERTEX) { if(bbsel) { EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE); } else { @@ -1667,7 +1686,7 @@ static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, floa } } - if(ts->selectmode & SCE_SELECT_EDGE) { + if(vc->scene->toolsettings->selectmode & SCE_SELECT_EDGE) { if (bbsel) { EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE); } else { @@ -1675,7 +1694,7 @@ static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, floa } } - if(ts->selectmode & SCE_SELECT_FACE) { + if(vc->scene->toolsettings->selectmode & SCE_SELECT_FACE) { if(bbsel) { EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE); } else { @@ -1684,7 +1703,7 @@ static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, floa } EM_free_backbuf(); - EM_selectmode_flush(vc->em); + EDBM_selectmode_flush(vc->em); } } diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index fba8d13c6a5..98980548b86 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -1,5 +1,5 @@ /** - * $Id$ + * $Id: view3d_snap.c 18967 2009-02-14 13:07:09Z ton $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -66,6 +66,7 @@ #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #include "WM_api.h" #include "WM_types.h" @@ -110,7 +111,7 @@ static void special_transvert_update(Scene *scene, Object *obedit) if(obedit->type==OB_MESH) { Mesh *me= obedit->data; - recalc_editnormals(me->edit_mesh); // does face centers too + BM_Compute_Normals(me->edit_btmesh->bm); // does face centers too } else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { Curve *cu= obedit->data; @@ -178,7 +179,8 @@ static void make_trans_verts(Object *obedit, float *min, float *max, int mode) BPoint *bp; TransVert *tv=NULL; MetaElem *ml; - EditVert *eve; + BMVert *eve; + BMIter iter; EditBone *ebo; float total, center[3], centroid[3]; int a; @@ -190,45 +192,70 @@ static void make_trans_verts(Object *obedit, float *min, float *max, int mode) if(obedit->type==OB_MESH) { Mesh *me= obedit->data; - EditMesh *em= me->edit_mesh; + BMEditMesh *em= me->edit_btmesh; + BMesh *bm = em->bm; int proptrans= 0; // transform now requires awareness for select mode, so we tag the f1 flags in verts tottrans= 0; - if(em->selectmode & SCE_SELECT_VERTEX) { - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0 && (eve->f & SELECT)) { - eve->f1= SELECT; + if(em->bm->selectmode & SCE_SELECT_VERTEX) { + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (; eve; eve=BMIter_Step(&iter)) { + if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)) { + BMINDEX_SET(eve, 1); tottrans++; } - else eve->f1= 0; + else BMINDEX_SET(eve, 0); } } - else if(em->selectmode & SCE_SELECT_EDGE) { - EditEdge *eed; - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT; + else if(em->bm->selectmode & SCE_SELECT_EDGE) { + BMEdge *eed; + + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (; eve; eve=BMIter_Step(&iter)) + BMINDEX_SET(eve, 0); + + eed = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); + for (; eed; eed=BMIter_Step(&iter)) { + if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)) + BMINDEX_SET(eed->v1, 0), BMINDEX_SET(eed->v2, 0); } - for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++; + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (; eve; eve=BMIter_Step(&iter)) + if(BMINDEX_GET(eve)) tottrans++; } else { - EditFace *efa; - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0 && (efa->f & SELECT)) { - efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT; - if(efa->v4) efa->v4->f1= SELECT; + BMFace *efa; + + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (; eve; eve=BMIter_Step(&iter)) + BMINDEX_SET(eve, 0); + + efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); + for (; efa; efa=BMIter_Step(&iter)) { + if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)) { + BMIter liter; + BMLoop *l; + + l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, efa); + for (; l; l=BMIter_Step(&iter)) { + BMINDEX_SET(l->v, 1); + } } } - for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++; + + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (; eve; eve=BMIter_Step(&iter)) + if(BMINDEX_GET(eve)) tottrans++; } /* proportional edit exception... */ if((mode & 1) && tottrans) { - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0) { - eve->f1 |= 2; + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (; eve; eve=BMIter_Step(&iter)) { + if(BMINDEX_GET(eve)) tottrans++; + if(!BM_TestHFlag(eve, BM_HIDDEN)) { + BMINDEX_SET(eve, BMINDEX_GET(eve)|2); proptrans++; } } @@ -239,13 +266,14 @@ static void make_trans_verts(Object *obedit, float *min, float *max, int mode) if(tottrans) { tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts"); - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f1) { + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for (; eve; eve=BMIter_Step(&iter)) { + if(BMINDEX_GET(eve)) { VECCOPY(tv->oldloc, eve->co); tv->loc= eve->co; if(eve->no[0]!=0.0 || eve->no[1]!=0.0 ||eve->no[2]!=0.0) tv->nor= eve->no; // note this is a hackish signal (ton) - tv->flag= eve->f1 & SELECT; + tv->flag= BMINDEX_GET(eve) & SELECT; tv++; } } @@ -846,10 +874,10 @@ static int snap_curs_to_active(bContext *C, wmOperator *op) if (obedit->type == OB_MESH) { /* check active */ Mesh *me= obedit->data; - EditSelection ese; + BMEditSelection ese; - if (EM_get_actSelection(me->edit_mesh, &ese)) { - EM_editselection_center(curs, &ese); + if (EDBM_get_actSelection(me->edit_btmesh, &ese)) { + EDBM_editselection_center(me->edit_btmesh, curs, &ese); } Mat4MulVecfl(obedit->obmat, curs); diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript index b2dee8c3358..8501a95b981 100644 --- a/source/blender/editors/transform/SConscript +++ b/source/blender/editors/transform/SConscript @@ -6,6 +6,6 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' ../../render/extern/include #/intern/guardedalloc' -incs += ' ../../gpu ../../makesrna' +incs += ' ../../gpu ../../makesrna ../../bmesh' env.BlenderLib ( 'bf_editors_transform', sources, Split(incs), [], libtype=['core'], priority=[40] )
\ No newline at end of file diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index d45a6f42232..c62ea07e398 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1170,7 +1170,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) if (RNA_struct_find_property(op->ptr, "constraint_axis")) { - RNA_int_set(op->ptr, "constraint_orientation", t->current_orientation); + RNA_enum_set(op->ptr, "constraint_orientation", t->current_orientation); if (t->con.mode & CON_APPLY) { diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 3d643a2dec1..aeccaee070e 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -100,6 +100,7 @@ #include "BKE_bmesh.h" #include "BKE_context.h" #include "BKE_report.h" +#include "BKE_tessmesh.h" //#include "BIF_editview.h" //#include "BIF_editlattice.h" @@ -149,6 +150,7 @@ extern ListBase editelems; #include "transform.h" +#include "bmesh.h" #include "BLO_sys_types.h" // for intptr_t support @@ -1883,22 +1885,31 @@ static void editmesh_set_connectivity_distance(EditMesh *em, int total, float *v } /* loop-in-a-loop I know, but we need it! (ton) */ -static void get_face_center(float *cent, EditMesh *em, EditVert *eve) + static void get_face_center(float *centout, BMesh *bm, BMVert *eve) + { - EditFace *efa; + BMFace *efa; + BMLoop *l; + BMIter iter; + float cent[3] = {0.0, 0.0, 0.0}; - for(efa= em->faces.first; efa; efa= efa->next) - if(efa->f & SELECT) - if(efa->v1==eve || efa->v2==eve || efa->v3==eve || efa->v4==eve) - break; - if(efa) { - VECCOPY(cent, efa->cent); + efa = BMIter_New(&iter, bm, BM_FACES_OF_VERT, eve); + if (efa) { + l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa); + for ( ; l; l=BMIter_Step(&iter)) { + VECADD(cent, cent, l->v->co); + } + + VECMUL(cent, 1.0f / (float)efa->len); } + + if (cent[0] == 0.0f && cent[1] == 0.0f && cent[2] == 0.0f) cent[2] = 1.0f; + VECCOPY(centout, cent); } //way to overwrite what data is edited with transform //static void VertsToTransData(TransData *td, EditVert *eve, BakeKey *key) -static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert *eve) +static void VertsToTransData(TransInfo *t, TransData *td, BMesh *em, BMVert *eve) { td->flag = 0; //if(key) @@ -1965,13 +1976,13 @@ static float *get_crazy_mapped_editverts(TransInfo *t) /* disable subsurf temporal, get mapped cos, and enable it */ if(modifiers_disable_subsurf_temporary(t->obedit)) { /* need to make new derivemesh */ - makeDerivedMesh(t->scene, t->obedit, me->edit_mesh, CD_MASK_BAREMESH); + makeDerivedMesh(t->scene, t->obedit, me->edit_btmesh, CD_MASK_BAREMESH); } /* now get the cage */ - dm= editmesh_get_derived_cage(t->scene, t->obedit, me->edit_mesh, CD_MASK_BAREMESH); + dm= editbmesh_get_derived_cage(t->scene, t->obedit, me->edit_btmesh, CD_MASK_BAREMESH); - vertexcos= MEM_mallocN(3*sizeof(float)*me->edit_mesh->totvert, "vertexcos map"); + vertexcos= MEM_mallocN(3*sizeof(float)*me->edit_btmesh->bm->totvert, "vertexcos map"); dm->foreachMappedVert(dm, make_vertexcos__mapFunc, vertexcos); dm->release(dm); @@ -2000,17 +2011,18 @@ static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3, } #undef TAN_MAKE_VEC -static void set_crazyspace_quats(EditMesh *em, float *origcos, float *mappedcos, float *quats) +static void set_crazyspace_quats(BMEditMesh *em, float *origcos, float *mappedcos, float *quats) { - EditVert *eve, *prev; - EditFace *efa; +#if 0 + BMVert *eve, *prev; + BMFace *efa; float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4; intptr_t index= 0; /* two abused locations in vertices */ for(eve= em->verts.first; eve; eve= eve->next, index++) { eve->tmp.p = NULL; - eve->prev= (EditVert *)index; + eve->prev= (BMVert *)index; } /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */ @@ -2068,7 +2080,7 @@ static void set_crazyspace_quats(EditMesh *em, float *origcos, float *mappedcos, /* restore abused prev pointer */ for(prev= NULL, eve= em->verts.first; eve; prev= eve, eve= eve->next) eve->prev= prev; - +#endif } void createTransBMeshVerts(TransInfo *t, BME_Mesh *bm, BME_TransData_Head *td) { @@ -2100,10 +2112,12 @@ static void createTransEditVerts(bContext *C, TransInfo *t) { ToolSettings *ts = CTX_data_tool_settings(C); TransData *tob = NULL; - EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh; - EditVert *eve; - EditVert **nears = NULL; - EditVert *eve_act = NULL; + BMEditMesh *em = ((Mesh *)t->obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMVert *eve; + BMVert **nears = NULL; + BMIter iter; + BMVert *eve_act = NULL; float *vectors = NULL, *mappedcos = NULL, *quats= NULL; float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL; int count=0, countsel=0, a, totleft; @@ -2117,36 +2131,49 @@ static void createTransEditVerts(bContext *C, TransInfo *t) // transform now requires awareness for select mode, so we tag the f1 flags in verts if(ts->selectmode & SCE_SELECT_VERTEX) { - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0 && (eve->f & SELECT)) - eve->f1= SELECT; + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)) + BMINDEX_SET(eve, SELECT); else - eve->f1= 0; + BMINDEX_SET(eve, 0); } } else if(ts->selectmode & SCE_SELECT_EDGE) { - EditEdge *eed; - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0 && (eed->f & SELECT)) - eed->v1->f1= eed->v2->f1= SELECT; + BMEdge *eed; + + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for( ; eve; eve=BMIter_Step(&iter)) BMINDEX_SET(eve, 0); + + eed = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); + for( ; eed; eed=BMIter_Step(&iter)) { + if(!BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SELECT)) + BMINDEX_SET(eed->v1, SELECT), BMINDEX_SET(eed->v2, SELECT); } } else { - EditFace *efa; - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0 && (efa->f & SELECT)) { - efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT; - if(efa->v4) efa->v4->f1= SELECT; + BMFace *efa; + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for( ; eve; eve=BMIter_Step(&iter)) BMINDEX_SET(eve, 0); + + efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); + for( ; efa; efa=BMIter_Step(&iter)) { + if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)) { + BMIter liter; + BMLoop *l; + + l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, efa); + for (; l; l=BMIter_Step(&liter)) { + BMINDEX_SET(l->v, SELECT); + } } } } /* now we can count */ - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0) { - if(eve->f1) countsel++; + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for( ; eve; eve=BMIter_Step(&iter)) { + if(!BM_TestHFlag(eve, BM_HIDDEN)) { + if(BMINDEX_GET(eve)) countsel++; if(propmode) count++; } } @@ -2156,9 +2183,9 @@ static void createTransEditVerts(bContext *C, TransInfo *t) /* check active */ if (em->selected.last) { - EditSelection *ese = em->selected.last; + BMEditSelection *ese = em->selected.last; if ( ese->type == EDITVERT ) { - eve_act = (EditVert *)ese->data; + eve_act = (BMVert *)ese->data; } } @@ -2168,7 +2195,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t) /* allocating scratch arrays */ vectors = (float *)MEM_mallocN(t->total * 3 * sizeof(float), "scratch vectors"); - nears = (EditVert**)MEM_mallocN(t->total * sizeof(EditVert*), "scratch nears"); + nears = (BMVert**)MEM_mallocN(t->total * sizeof(BMVert*), "scratch nears"); } else t->total = countsel; tob= t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Mesh EditMode)"); @@ -2176,7 +2203,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t) Mat3CpyMat4(mtx, t->obedit->obmat); Mat3Inv(smtx, mtx); - if(propmode) editmesh_set_connectivity_distance(em, t->total, vectors, nears); + //BMESH_TODO if(propmode) editmesh_set_connectivity_distance(em, t->total, vectors, nears); /* detect CrazySpace [tm] */ if(propmode==0) { @@ -2184,7 +2211,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t) if(modifiers_isDeformed(t->scene, t->obedit)) { /* check if we can use deform matrices for modifier from the start up to stack, they are more accurate than quats */ - totleft= editmesh_get_first_deform_matrices(t->obedit, em, &defmats, &defcos); + totleft= editbmesh_get_first_deform_matrices(t->obedit, em, &defmats, &defcos); /* if we still have more modifiers, also do crazyspace correction with quats, relative to the coordinates after @@ -2205,8 +2232,9 @@ static void createTransEditVerts(bContext *C, TransInfo *t) /* find out which half we do */ if(mirror) { - for (eve=em->verts.first; eve; eve=eve->next) { - if(eve->h==0 && eve->f1 && eve->co[0]!=0.0f) { + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for( ; eve; eve=BMIter_Step(&iter)) { + if(!BM_TestHFlag(eve, BM_HIDDEN) && BMINDEX_GET(eve) && eve->co[0]!=0.0f) { if(eve->co[0]<0.0f) mirror = -1; break; @@ -2214,36 +2242,41 @@ static void createTransEditVerts(bContext *C, TransInfo *t) } } - for (a=0, eve=em->verts.first; eve; eve=eve->next, a++) { - if(eve->h==0) { - if(propmode || eve->f1) { - VertsToTransData(t, tob, em, eve); + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for(a=0; eve; eve=BMIter_Step(&iter), a++) { + if(!BM_TestHFlag(eve, BM_HIDDEN)) { + if(propmode || BMINDEX_GET(eve)) { + VertsToTransData(t, tob, bm, eve); /* selected */ - if(eve->f1) tob->flag |= TD_SELECTED; + if(BMINDEX_GET(eve)) tob->flag |= TD_SELECTED; /* active */ if(eve == eve_act) tob->flag |= TD_ACTIVE; if(propmode) { + /*BMESH_TODO + this has to do with edge connectivity + PEP mode, I think. -joeedh if (eve->f2) { float vec[3]; VECCOPY(vec, E_VEC(eve)); Mat3MulVecfl(mtx, vec); tob->dist= VecLength(vec); } - else { + else {*/ tob->flag |= TD_NOTCONNECTED; tob->dist = MAXFLOAT; - } + //} } /* CrazySpace */ - if(defmats || (quats && eve->tmp.p)) { + if(defmats) { // || (quats && eve->tmp.p)) { float mat[3][3], imat[3][3], qmat[3][3]; /* use both or either quat and defmat correction */ - if(quats && eve->tmp.f) { + //BMESH_TODO, need to restore this quats thing + /*if(quats && eve->tmp.f) { QuatToMat3(eve->tmp.p, qmat); if(defmats) @@ -2252,7 +2285,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t) else Mat3MulMat3(mat, mtx, qmat); } - else + else*/ Mat3MulMat3(mat, mtx, defmats[a]); Mat3Inv(imat, mat); @@ -2266,10 +2299,12 @@ static void createTransEditVerts(bContext *C, TransInfo *t) } /* Mirror? */ - if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) { - EditVert *vmir= editmesh_get_x_mirror_vert(t->obedit, em, tob->iloc); /* initializes octree on first call */ - if(vmir != eve) tob->extra = vmir; - } + + //BMESH_TODO + //if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) { + // EditVert *vmir= editmesh_get_x_mirror_vert(t->obedit, em, tob->iloc); /* initializes octree on first call */ + // if(vmir != eve) tob->extra = vmir; + //} tob++; } } @@ -2416,6 +2451,7 @@ static void UVsToTransData(SpaceImage *sima, TransData *td, TransData2D *td2d, f static void createTransUVs(bContext *C, TransInfo *t) { +#if 0 SpaceImage *sima = (SpaceImage*)CTX_wm_space_data(C); Image *ima = CTX_data_edit_image(C); Scene *scene = CTX_data_scene(C); @@ -2482,6 +2518,7 @@ static void createTransUVs(bContext *C, TransInfo *t) if (sima->flag & SI_LIVE_UNWRAP) ED_uvedit_live_unwrap_begin(t->scene, t->obedit); +#endif } void flushTransUVs(TransInfo *t) @@ -4856,7 +4893,7 @@ void special_aftertrans_update(TransInfo *t) if (t->obedit->type == OB_MESH) { - EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh; + BMEditMesh *em = ((Mesh *)t->obedit->data)->edit_btmesh; /* table needs to be created for each edit command, since vertices can move etc */ mesh_octree_table(t->obedit, em, NULL, 'e'); } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 560b37caf0a..3fc9fe73a5b 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -83,6 +83,7 @@ #include "BKE_object.h" #include "BKE_utildefines.h" #include "BKE_context.h" +#include "BKE_tessmesh.h" #include "ED_anim_api.h" #include "ED_armature.h" @@ -241,10 +242,11 @@ static void clipMirrorModifier(TransInfo *t, Object *ob) } /* assumes obedit set to mesh object */ -static void editmesh_apply_to_mirror(TransInfo *t) +static void editbmesh_apply_to_mirror(TransInfo *t) { TransData *td = t->data; - EditVert *eve; + BMVert *eve; + BMIter iter; int i; for(i = 0 ; i < t->total; i++, td++) { @@ -607,7 +609,7 @@ void recalcData(TransInfo *t) DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); } else { - EditMesh *em = ((Mesh*)t->obedit->data)->edit_mesh; + BMEditMesh *em = ((Mesh*)t->obedit->data)->edit_btmesh; /* mirror modifier clipping? */ if(t->state != TRANS_CANCEL) { /* TRANSFORM_FIX_ME */ @@ -618,11 +620,12 @@ void recalcData(TransInfo *t) clipMirrorModifier(t, t->obedit); } if((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR)) - editmesh_apply_to_mirror(t); + editbmesh_apply_to_mirror(t); DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */ - recalc_editnormals(em); + EDBM_RecalcNormals(em); + BMEdit_RecalcTesselation(em); } } else if(t->obedit->type==OB_ARMATURE) { /* no recalc flag, does pose */ @@ -886,7 +889,7 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event) if (op && RNA_struct_find_property(op->ptr, "constraint_axis") && RNA_property_is_set(op->ptr, "constraint_orientation")) { - t->current_orientation = RNA_int_get(op->ptr, "constraint_orientation"); + t->current_orientation = RNA_enum_get(op->ptr, "constraint_orientation"); if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C) - 1) { @@ -1018,8 +1021,7 @@ void postTrans (TransInfo *t) else if(ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) { if (t->customData) MEM_freeN(t->customData); - } -} + }} void applyTransObjects(TransInfo *t) { diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index c656b097cb9..bf87319d05c 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -63,6 +63,7 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #include "BLI_arithb.h" #include "BLI_editVert.h" @@ -204,20 +205,22 @@ int calc_manipulator_stats(const bContext *C) if((ob->lay & v3d->lay)==0) return 0; if(obedit->type==OB_MESH) { - EditMesh *em = BKE_mesh_get_editmesh(obedit->data); - EditVert *eve; - EditSelection ese; + BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMVert *eve; + BMEditSelection ese; + BMIter iter; float vec[3]= {0,0,0}; /* USE LAST SELECTE WITH ACTIVE */ - if (v3d->around==V3D_ACTIVE && EM_get_actSelection(em, &ese)) { - EM_editselection_center(vec, &ese); + if (v3d->around==V3D_ACTIVE && EDBM_get_actSelection(em, &ese)) { + EDBM_editselection_center(em, vec, &ese); calc_tw_center(scene, vec); totsel= 1; } else { /* do vertices for center, and if still no normal found, use vertex normals */ - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT)) { totsel++; calc_tw_center(scene, eve->co); } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index f2630f40c9c..2fc3d2f1e53 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -81,6 +81,13 @@ EnumPropertyItem proportional_falloff_types[] = { {0, NULL, 0, NULL, NULL} }; +EnumPropertyItem orientation_items[]= { + {V3D_MANIP_GLOBAL, "GLOBAL", 0, "Global", ""}, + {V3D_MANIP_NORMAL, "NORMAL", 0, "Normal", ""}, + {V3D_MANIP_LOCAL, "LOCAL", 0, "Local", ""}, + {V3D_MANIP_VIEW, "VIEW", 0, "View", ""}, + {0, NULL, 0, NULL, NULL}}; + char OP_TRANSLATION[] = "TFM_OT_translation"; char OP_ROTATION[] = "TFM_OT_rotation"; char OP_TOSPHERE[] = "TFM_OT_tosphere"; @@ -137,12 +144,6 @@ static EnumPropertyItem *select_orientation_itemf(bContext *C, PointerRNA *ptr, void TFM_OT_select_orientation(struct wmOperatorType *ot) { PropertyRNA *prop; - static EnumPropertyItem orientation_items[]= { - {V3D_MANIP_GLOBAL, "GLOBAL", 0, "Global", ""}, - {V3D_MANIP_NORMAL, "NORMAL", 0, "Normal", ""}, - {V3D_MANIP_LOCAL, "LOCAL", 0, "Local", ""}, - {V3D_MANIP_VIEW, "VIEW", 0, "View", ""}, - {0, NULL, 0, NULL, NULL}}; /* identifiers */ ot->name = "Select Orientation"; @@ -293,8 +294,11 @@ void Properties_Snapping(struct wmOperatorType *ot, short align) void Properties_Constraints(struct wmOperatorType *ot) { + PropertyRNA *prop; + RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", ""); - RNA_def_int(ot->srna, "constraint_orientation", 0, 0, INT_MAX, "Constraint Orientation", "", 0, INT_MAX); + prop= RNA_def_enum(ot->srna, "constraint_orientation", orientation_items, V3D_MANIP_GLOBAL, "Orientation", "DOC_BROKEN"); + RNA_def_enum_funcs(prop, select_orientation_itemf); } void TFM_OT_translation(struct wmOperatorType *ot) @@ -557,9 +561,8 @@ void TFM_OT_transform(struct wmOperatorType *ot) Properties_Proportional(ot); RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", ""); - - RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", ""); - RNA_def_int(ot->srna, "constraint_orientation", 0, 0, INT_MAX, "Constraint Orientation", "", 0, INT_MAX); + + Properties_Constraints(ot); } void transform_operatortypes(void) diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 6d60c7602f4..6cda535516e 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -43,6 +43,7 @@ #include "BKE_utildefines.h" #include "BKE_armature.h" #include "BKE_context.h" +#include "BKE_tessmesh.h" #include "BLI_arithb.h" #include "BLI_blenlib.h" @@ -590,16 +591,16 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], if(ob->type==OB_MESH) { Mesh *me= ob->data; - EditMesh *em = me->edit_mesh; - EditVert *eve; - EditSelection ese; + BMEditMesh *em = me->edit_btmesh; + BMVert *eve; + BMEditSelection ese; float vec[3]= {0,0,0}; /* USE LAST SELECTED WITH ACTIVE */ - if (activeOnly && EM_get_actSelection(em, &ese)) + if (activeOnly && EDBM_get_actSelection(em, &ese)) { - EM_editselection_normal(normal, &ese); - EM_editselection_plane(plane, &ese); + EDBM_editselection_normal(normal, &ese); + EDBM_editselection_plane(em, plane, &ese); switch (ese.type) { @@ -616,30 +617,30 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], } else { - if (em->totfacesel >= 1) + if (em->bm->totfacesel >= 1) { - EditFace *efa; - - for(efa= em->faces.first; efa; efa= efa->next) - { - if(efa->f & SELECT) - { - VECADD(normal, normal, efa->n); - VecSubf(vec, efa->v2->co, efa->v1->co); + BMFace *efa; + BMIter iter; + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(BM_TestHFlag(efa, BM_SELECT)) { + VECADD(normal, normal, efa->no); + VecSubf(vec, efa->loopbase->v->co, + ((BMLoop*)efa->loopbase->head.next)->v->co); VECADD(plane, plane, vec); } } result = ORIENTATION_FACE; } - else if (em->totvertsel == 3) + else if (em->bm->totvertsel == 3) { - EditVert *v1 = NULL, *v2 = NULL, *v3 = NULL; + BMVert *v1 = NULL, *v2 = NULL, *v3 = NULL; + BMIter iter; float cotangent[3]; - for (eve = em->verts.first; eve; eve = eve->next) - { - if ( eve->f & SELECT ) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT)) { if (v1 == NULL) { v1 = eve; } @@ -658,12 +659,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], } /* if there's an edge available, use that for the tangent */ - if (em->totedgesel >= 1) + if (em->bm->totedgesel >= 1) { - EditEdge *eed = NULL; - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { + BMEdge *eed = NULL; + BMIter iter; + + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if(BM_TestHFlag(eed, BM_SELECT)) { VecSubf(plane, eed->v2->co, eed->v1->co); break; } @@ -672,12 +674,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], result = ORIENTATION_FACE; } - else if (em->totedgesel == 1) + else if (em->bm->totedgesel == 1) { - EditEdge *eed; - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { + BMEdge *eed = NULL; + BMIter iter; + + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if(BM_TestHFlag(eed, BM_SELECT)) { /* use average vert normals as plane and edge vector as normal */ VECCOPY(plane, eed->v1->no); VECADD(plane, plane, eed->v2->no); @@ -687,13 +690,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], } result = ORIENTATION_EDGE; } - else if (em->totvertsel == 2) + else if (em->bm->totvertsel == 2) { - EditVert *v1 = NULL, *v2 = NULL; - - for (eve = em->verts.first; eve; eve = eve->next) - { - if ( eve->f & SELECT ) { + BMVert *v1 = NULL, *v2 = NULL; + BMIter iter; + + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT)) { if (v1 == NULL) { v1 = eve; } @@ -709,24 +712,25 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], } result = ORIENTATION_EDGE; } - else if (em->totvertsel == 1) + else if (em->bm->totvertsel == 1) { - for (eve = em->verts.first; eve; eve = eve->next) - { - if ( eve->f & SELECT ) { + BMIter iter; + + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT)) { VECCOPY(normal, eve->no); break; } } result = ORIENTATION_VERT; } - else if (em->totvertsel > 3) + else if (em->bm->totvertsel > 3) { + BMIter iter; normal[0] = normal[1] = normal[2] = 0; - - for (eve = em->verts.first; eve; eve = eve->next) - { - if ( eve->f & SELECT ) { + + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT)) { VecAddf(normal, normal, eve->no); } } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 9438581409b..575e8f2150a 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -69,6 +69,8 @@ #include "BKE_object.h" #include "BKE_anim.h" /* for duplis */ #include "BKE_context.h" +#include "BKE_tessmesh.h" +#include "BKE_mesh.h" #include "ED_armature.h" #include "ED_image.h" @@ -1109,11 +1111,11 @@ int snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm, float return retval; } -int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, EditMesh *em, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], float *loc, float *no, int *dist, float *depth) +int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], float *loc, float *no, int *dist, float *depth) { int retval = 0; int totvert = dm->getNumVerts(dm); - int totface = dm->getNumFaces(dm); + int totface = dm->getNumTessFaces(dm); if (totvert > 0) { float imat[4][4]; @@ -1148,19 +1150,19 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E case SCE_SNAP_MODE_FACE: { MVert *verts = dm->getVertArray(dm); - MFace *faces = dm->getFaceArray(dm); + MFace *faces = dm->getTessFaceArray(dm); int *index_array = NULL; int index = 0; int i; if (em != NULL) { - index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX); - EM_init_index_arrays(em, 0, 0, 1); + index_array = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + EDBM_init_index_arrays(em, 0, 0, 1); } for( i = 0; i < totface; i++) { - EditFace *efa = NULL; + BMFace *efa = NULL; MFace *f = faces + i; test = 1; /* reset for every face */ @@ -1182,11 +1184,22 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E } else { - efa = EM_get_face_for_index(index); + efa = EDBM_get_face_for_index(em, index); - if (efa && (efa->h || (efa->v1->f & SELECT) || (efa->v2->f & SELECT) || (efa->v3->f & SELECT) || (efa->v4 && efa->v4->f & SELECT))) + if (efa && BM_TestHFlag(efa, BM_HIDDEN)) { test = 0; + } else if (efa) { + BMIter iter; + BMLoop *l; + + l = BMIter_New(&iter, em->bm, BM_LOOPS_OF_FACE, efa); + for ( ; l; l=BMIter_Step(&iter)) { + if (BM_TestHFlag(l->v, BM_SELECT)) { + test = 0; + break; + } + } } } } @@ -1214,7 +1227,7 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E if (em != NULL) { - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } break; } @@ -1228,11 +1241,11 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E if (em != NULL) { index_array = dm->getVertDataArray(dm, CD_ORIGINDEX); - EM_init_index_arrays(em, 1, 0, 0); + EDBM_init_index_arrays(em, 1, 0, 0); } for( i = 0; i < totvert; i++) { - EditVert *eve = NULL; + BMVert *eve = NULL; MVert *v = verts + i; test = 1; /* reset for every vert */ @@ -1254,9 +1267,9 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E } else { - eve = EM_get_vert_for_index(index); + eve = EDBM_get_vert_for_index(em, index); - if (eve && (eve->h || (eve->f & SELECT))) + if (eve && (BM_TestHFlag(eve, BM_HIDDEN) || BM_TestHFlag(eve, BM_SELECT))) { test = 0; } @@ -1272,7 +1285,7 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E if (em != NULL) { - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } break; } @@ -1288,11 +1301,11 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E if (em != NULL) { index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX); - EM_init_index_arrays(em, 0, 1, 0); + EDBM_init_index_arrays(em, 0, 1, 0); } for( i = 0; i < totedge; i++) { - EditEdge *eed = NULL; + BMEdge *eed = NULL; MEdge *e = edges + i; test = 1; /* reset for every vert */ @@ -1314,9 +1327,11 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E } else { - eed = EM_get_edge_for_index(index); + eed = EDBM_get_edge_for_index(em, index); - if (eed && (eed->h || (eed->v1->f & SELECT) || (eed->v2->f & SELECT))) + if (eed && (BM_TestHFlag(eed, BM_HIDDEN) || + BM_TestHFlag(eed->v1, BM_SELECT) || + BM_TestHFlag(eed->v2, BM_SELECT))) { test = 0; } @@ -1332,7 +1347,7 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E if (em != NULL) { - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } break; } @@ -1349,13 +1364,13 @@ int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, float obma int retval = 0; if (ob->type == OB_MESH) { - EditMesh *em; + BMEditMesh *em; DerivedMesh *dm; if (editobject) { - em = ((Mesh *)ob->data)->edit_mesh; - dm = editmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); + em = ((Mesh *)ob->data)->edit_btmesh; + dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); } else { @@ -1491,7 +1506,7 @@ int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta { int retval = 0; int totvert = dm->getNumVerts(dm); - int totface = dm->getNumFaces(dm); + int totface = dm->getNumTessFaces(dm); if (totvert > 0) { float imat[4][4]; @@ -1521,7 +1536,7 @@ int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta if (test == 1) { MVert *verts = dm->getVertArray(dm); - MFace *faces = dm->getFaceArray(dm); + MFace *faces = dm->getTessFaceArray(dm); int i; for( i = 0; i < totface; i++) { @@ -1617,6 +1632,7 @@ int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase Object *ob = dupli_ob->ob; if (ob->type == OB_MESH) { +#if 0 //BMESH_TODO EditMesh *em; DerivedMesh *dm = NULL; int val; @@ -1638,6 +1654,7 @@ int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase retval = retval || val; dm->release(dm); +#endif } } @@ -1645,7 +1662,7 @@ int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase } if (ob->type == OB_MESH) { - EditMesh *em; + BMEditMesh *em; DerivedMesh *dm = NULL; int val; @@ -1657,8 +1674,8 @@ int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase } else { - em = ((Mesh *)ob->data)->edit_mesh; - dm = editmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH); + em = ((Mesh *)ob->data)->edit_btmesh; + dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH); val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels); } diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index ae1e932bb81..93760ab77e3 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -72,10 +72,10 @@ void ED_editors_exit(bContext *C) if(ob) { if(ob->type==OB_MESH) { Mesh *me= ob->data; - if(me->edit_mesh) { - free_editMesh(me->edit_mesh); - MEM_freeN(me->edit_mesh); - me->edit_mesh= NULL; + if(me->edit_btmesh) { + EDBM_FreeEditBMesh(me->edit_btmesh); + MEM_freeN(me->edit_btmesh); + me->edit_btmesh= NULL; } } else if(ob->type==OB_ARMATURE) { diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index a58ee9772e9..0a747c951f5 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -41,6 +41,7 @@ #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_utildefines.h" +#include "BKE_mesh.h" #include "BLI_arithb.h" #include "BLI_editVert.h" @@ -452,7 +453,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) /* first try existing derivedmesh */ if(!draw_uvs_dm_shadow(em->derivedFinal)) { /* create one if it does not exist */ - cagedm = editmesh_get_derived_cage_and_final(scene, obedit, em, &finaldm, CD_MASK_BAREMESH|CD_MASK_MTFACE); + cagedm = editbmesh_get_derived_cage_and_final(scene, obedit, me->edit_btmesh, &finaldm, CD_MASK_BAREMESH|CD_MASK_MTFACE); /* when sync selection is enabled, all faces are drawn (except for hidden) * so if cage is the same as the final, theres no point in drawing this */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 801da08e611..6f8d710ed3e 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -1374,7 +1374,7 @@ static int de_select_all_exec(bContext *C, wmOperator *op) ima= CTX_data_edit_image(C); if(ts->uv_flag & UV_SYNC_SELECTION) { - EM_toggle_select_all(em); + EDBM_toggle_select_all(((Mesh*)obedit->data)->edit_btmesh); } else { sel= 0; @@ -2172,7 +2172,7 @@ static int border_select_exec(bContext *C, wmOperator *op) BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } - + BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } @@ -2706,6 +2706,7 @@ static int hide_exec(bContext *C, wmOperator *op) EM_hide_mesh(em, swap); WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 18c18d9e9dd..98cf7379df9 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -76,7 +76,9 @@ typedef struct CustomData { #define CD_TANGENT 18 #define CD_MDISPS 19 #define CD_WEIGHT_MCOL 20 /* for displaying weightpaint colors */ -#define CD_NUMTYPES 21 +#define CD_MPOLY 21 +#define CD_MLOOP 22 +#define CD_NUMTYPES 23 /* Bits for CustomDataMask */ #define CD_MASK_MVERT (1 << CD_MVERT) @@ -100,6 +102,8 @@ typedef struct CustomData { #define CD_MASK_TANGENT (1 << CD_TANGENT) #define CD_MASK_MDISPS (1 << CD_MDISPS) #define CD_MASK_WEIGHT_MCOL (1 << CD_WEIGHT_MCOL) +#define CD_MASK_MPOLY (1 << CD_MPOLY) +#define CD_MASK_MLOOP (1 << CD_MLOOP) /* derivedmesh wants CustomDataMask for weightpaint too, is not customdata though */ #define CD_MASK_WEIGHTPAINT (1 << CD_WEIGHTPAINT) diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 3ecfe416c79..01c009a7971 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -44,6 +44,11 @@ struct MCol; struct MSticky; struct Mesh; struct OcInfo; +struct MPoly; +struct MTexPoly; +struct MLoop; +struct MLoopUV; +struct MLoopCol; struct Multires; struct PartialVisibility; struct EditMesh; @@ -58,23 +63,35 @@ typedef struct Mesh { struct Ipo *ipo; struct Key *key; struct Material **mat; - - struct MFace *mface; /* array of mesh object mode faces */ - struct MTFace *mtface; /* store face UV's and texture here */ + + /*new face structures*/ + struct MPoly *mpoly; + struct MTexPoly *mtpoly; + struct MLoop *mloop; + struct MLoopUV *mloopuv; + struct MLoopCol *mloopcol; + + /*mface stores the tesselation (triangulation) of the mesh, + real faces are now stored in nface.*/ + struct MFace *mface; /* array of mesh object mode faces for tesselation */ + struct MTFace *mtface; /* store tesselation face UV's and texture here */ struct TFace *tface; /* depecrated, use mtface */ struct MVert *mvert; /* array of verts */ struct MEdge *medge; /* array of edges */ struct MDeformVert *dvert; /* deformgroup vertices */ - struct MCol *mcol; /* array of colors, this must be the number of faces * 4 */ + + /* array of colors for the tesselated faces, must be number of tesselated + faces * 4 in length */ + struct MCol *mcol; struct MSticky *msticky; struct Mesh *texcomesh; struct MSelect *mselect; - struct EditMesh *edit_mesh; /* not saved in file! */ + struct BMEditMesh *edit_btmesh; /* not saved in file! */ - struct CustomData vdata, edata, fdata; + struct CustomData vdata, edata, fdata, pdata, ldata; - int totvert, totedge, totface, totselect; + int totvert, totedge, totface, totpoly, totloop, totselect; /* the last selected vertex/edge/face are used for the active face however * this means the active face must always be selected, this is to keep track diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index d53a7833d0e..94713cf0d76 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -71,7 +71,22 @@ typedef struct MCol { char a, r, g, b; } MCol; -/*bmesh custom data stuff*/ +/*new face structure, replaces MFace, which is now + only used for storing tesselations.*/ +typedef struct MPoly { + /*offset into loop array and number of loops in the face*/ + int loopstart, totloop; + short mat_nr; + short flag; +} MPoly; + +/*the e here is because we want to move away from + relying on edge hashes.*/ +typedef struct MLoop { + int v; /*vertex index*/ + int e; /*edge index*/ +} MLoop; + typedef struct MTexPoly{ struct Image *tpage; char flag, transp; @@ -217,7 +232,9 @@ typedef struct PartialVisibility { /* flag (mface) */ #define ME_SMOOTH 1 #define ME_FACE_SEL 2 - /* flag ME_HIDE==16 is used here too */ +/* flag ME_HIDE==16 is used here too */ +#define ME_DRAW_ACT 4 + /* mselect->type */ #define ME_VSEl 0 #define ME_ESEl 1 diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 2b0ede846af..93980e58f8c 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -116,7 +116,7 @@ typedef struct Object { /* materials */ struct Material **mat; /* material slots */ - char *matbits; /* 1 if material linked to object */ + char *matbits; /* a bitfield, with each bit 1 if corrusponding material linked to object */ int totcol; /* copy of mesh or curve or meta */ int actcol; /* currently selected material in the UI */ diff --git a/source/blender/makesdna/intern/SConscript b/source/blender/makesdna/intern/SConscript index 1c716019e80..29d57f095e7 100644 --- a/source/blender/makesdna/intern/SConscript +++ b/source/blender/makesdna/intern/SConscript @@ -46,21 +46,25 @@ targetdir = normpath(root_build_dir + '/makesdna') if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'): targetdir = '#' + targetdir + #root_build_dir = "#" makesdna = makesdna_tool.Program (target = targetdir, source = source_files, LIBS=['bf_guardedalloc']) dna_dict = dna.Dictionary() dna.Depends ('dna.c', makesdna) dna.Depends ('dna.c', header_files) + +ap = os.path.abspath + if env['OURPLATFORM'] != 'linuxcross': if USE_WINE: - dna.Command ('dna.c', '', 'wine ' + root_build_dir+os.sep+"makesdna $TARGET") + dna.Command ('dna.c', '', 'wine ' + ap(root_build_dir+os.sep+"makesdna $TARGET")) else: if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'): dna.Command ('dna.c', '', "\"" + root_build_dir+os.sep+"makesdna\" $TARGET") else: dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna $TARGET") else: - dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna.exe $TARGET") + dna.Command ('dna.c', '', ap(root_build_dir+os.sep+"makesdna.exe $TARGET")) obj = ['intern/dna.c', 'intern/dna_genfile.c'] Return ('obj') diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript index 89118850b20..2a1ae7be543 100644 --- a/source/blender/makesrna/SConscript +++ b/source/blender/makesrna/SConscript @@ -7,7 +7,7 @@ o = SConscript('intern/SConscript') objs += o incs = '#/intern/guardedalloc ../blenkernel ../blenlib ../makesdna intern .' -incs += ' ../windowmanager ../editors/include ../imbuf' +incs += ' ../windowmanager ../editors/include ../imbuf ../bmesh' defs = [] diff --git a/source/blender/makesrna/intern/Makefile b/source/blender/makesrna/intern/Makefile index 7f9bfbfea67..4a3715fb9a9 100644 --- a/source/blender/makesrna/intern/Makefile +++ b/source/blender/makesrna/intern/Makefile @@ -52,6 +52,7 @@ CPPFLAGS += -I../../imbuf CPPFLAGS += -I../../makesdna CPPFLAGS += -I../../windowmanager CPPFLAGS += -I../../editors/include +CPPFLAGS += -I../../bmesh CPPFLAGS += -I.. CPPFLAGS += -I. diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript index 7cd3fde21be..53243fd97a0 100644 --- a/source/blender/makesrna/intern/SConscript +++ b/source/blender/makesrna/intern/SConscript @@ -29,7 +29,7 @@ makesrna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesrna/\\"" ' defs = [] -incs = '#/intern/guardedalloc ../../blenlib ../../blenkernel' +incs = '#/intern/guardedalloc ../../bmesh ../../blenlib ../../blenkernel' incs += ' ../../imbuf ../../makesdna ../../makesrna' incs += ' ../../windowmanager ../../editors/include' diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c deleted file mode 100644 index 6d56b2b00f9..00000000000 --- a/source/blender/makesrna/intern/rna_main_api.c +++ /dev/null @@ -1,81 +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) 2009 Blender Foundation. - * All rights reserved. - * - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include <stdlib.h> -#include <stdio.h> - -#include "RNA_define.h" -#include "RNA_types.h" - -#ifdef RNA_RUNTIME - -#include "BKE_main.h" -#include "BKE_mesh.h" -#include "BKE_library.h" - -#include "DNA_mesh_types.h" - -Mesh *rna_Main_add_mesh(Main *main, char *name) -{ - Mesh *me= add_mesh(name); - me->id.us--; - return me; -} - -void rna_Main_remove_mesh(Main *main, ReportList *reports, Mesh *me) -{ - if(me->id.us == 0) - free_libblock(&main->mesh, me); - else - BKE_report(reports, RPT_ERROR, "Mesh must have zero users to be removed."); - - /* XXX python now has invalid pointer? */ -} - -#else - -void RNA_api_main(StructRNA *srna) -{ - FunctionRNA *func; - PropertyRNA *prop; - - func= RNA_def_function(srna, "add_mesh", "rna_Main_add_mesh"); - RNA_def_function_ui_description(func, "Add a new mesh."); - prop= RNA_def_string(func, "name", "Mesh", 0, "", "New name for the datablock."); - prop= RNA_def_pointer(func, "mesh", "Mesh", "", "New mesh."); - RNA_def_function_return(func, prop); - - func= RNA_def_function(srna, "remove_mesh", "rna_Main_remove_mesh"); - RNA_def_function_flag(func, FUNC_USE_REPORTS); - RNA_def_function_ui_description(func, "Remove a mesh if it has zero users."); - prop= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove."); - RNA_def_property_flag(prop, PROP_REQUIRED); -} - -#endif - diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 3a7015b65be..0a0d70fa9eb 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -45,6 +45,7 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_utildefines.h" +#include "BKE_tessmesh.h" #include "WM_api.h" #include "WM_types.h" @@ -212,7 +213,7 @@ static void rna_MeshFace_material_index_range(PointerRNA *ptr, int *min, int *ma static CustomData *rna_mesh_fdata(Mesh *me) { - return (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata; + return (me->edit_btmesh)? &me->edit_btmesh->bm->pdata: &me->pdata; } static int rna_CustomDataLayer_length(PointerRNA *ptr, int type) diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c deleted file mode 100644 index c98b3fb7b09..00000000000 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ /dev/null @@ -1,241 +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) 2009 Blender Foundation. - * All rights reserved. - * - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include <stdlib.h> -#include <stdio.h> - -#include "RNA_define.h" -#include "RNA_types.h" - -#ifdef RNA_RUNTIME - -#include "DNA_mesh_types.h" -#include "DNA_scene_types.h" - -#include "BKE_customdata.h" -#include "BKE_depsgraph.h" -#include "BKE_DerivedMesh.h" -#include "BKE_main.h" -#include "BKE_mesh.h" - -#include "BLI_edgehash.h" - -#include "WM_api.h" -#include "WM_types.h" - -static void rna_Mesh_calc_edges(Mesh *mesh) -{ - CustomData edata; - EdgeHashIterator *ehi; - MFace *mf = mesh->mface; - MEdge *med; - EdgeHash *eh = BLI_edgehash_new(); - int i, *index, totedge, totface = mesh->totface; - - for (i = 0; i < totface; i++, mf++) { - if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2)) - BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL); - if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3)) - BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL); - - if (mf->v4) { - if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4)) - BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL); - if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1)) - BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL); - } else { - if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1)) - BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL); - } - } - - totedge = BLI_edgehash_size(eh); - - /* write new edges into a temporary CustomData */ - memset(&edata, 0, sizeof(edata)); - CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); - - ehi = BLI_edgehashIterator_new(eh); - med = CustomData_get_layer(&edata, CD_MEDGE); - for(i = 0; !BLI_edgehashIterator_isDone(ehi); - BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) { - BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2); - - med->flag = ME_EDGEDRAW|ME_EDGERENDER; - } - BLI_edgehashIterator_free(ehi); - - /* free old CustomData and assign new one */ - CustomData_free(&mesh->edata, mesh->totedge); - mesh->edata = edata; - mesh->totedge = totedge; - - mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE); - - BLI_edgehash_free(eh, NULL); -} - -static void rna_Mesh_update(Mesh *mesh, bContext *C) -{ - Main *bmain= CTX_data_main(C); - Object *ob; - - if(mesh->totface && mesh->totedge == 0) - rna_Mesh_calc_edges(mesh); - - mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL); - - for(ob=bmain->object.first; ob; ob=ob->id.next) { - if(ob->data == mesh) { - ob->recalc |= OB_RECALC_DATA; - WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob); - } - } -} - -static void rna_Mesh_add_verts(Mesh *mesh, int len) -{ - CustomData vdata; - MVert *mvert; - int i, totvert; - - if(len == 0) - return; - - totvert= mesh->totvert + len; - CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert); - CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); - - if(!CustomData_has_layer(&vdata, CD_MVERT)) - CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); - - CustomData_free(&mesh->vdata, mesh->totvert); - mesh->vdata= vdata; - mesh_update_customdata_pointers(mesh); - - /* scan the input list and insert the new vertices */ - - mvert= &mesh->mvert[mesh->totvert]; - for(i=0; i<len; i++, mvert++) - mvert->flag |= SELECT; - - /* set final vertex list size */ - mesh->totvert= totvert; -} - -static void rna_Mesh_add_edges(Mesh *mesh, int len) -{ - CustomData edata; - MEdge *medge; - int i, totedge; - - if(len == 0) - return; - - totedge= mesh->totedge+len; - - /* update customdata */ - CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge); - CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); - - if(!CustomData_has_layer(&edata, CD_MEDGE)) - CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); - - CustomData_free(&mesh->edata, mesh->totedge); - mesh->edata= edata; - mesh_update_customdata_pointers(mesh); - - /* set default flags */ - medge= &mesh->medge[mesh->totedge]; - for(i=0; i<len; i++, medge++) - medge->flag= ME_EDGEDRAW|ME_EDGERENDER|SELECT; - - mesh->totedge= totedge; -} - -static void rna_Mesh_add_faces(Mesh *mesh, int len) -{ - CustomData fdata; - MFace *mface; - int i, totface; - - if(len == 0) - return; - - totface= mesh->totface + len; /* new face count */ - - /* update customdata */ - CustomData_copy(&mesh->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface); - CustomData_copy_data(&mesh->fdata, &fdata, 0, 0, mesh->totface); - - if(!CustomData_has_layer(&fdata, CD_MFACE)) - CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface); - - CustomData_free(&mesh->fdata, mesh->totface); - mesh->fdata= fdata; - mesh_update_customdata_pointers(mesh); - - /* set default flags */ - mface= &mesh->mface[mesh->totface]; - for(i=0; i<len; i++, mface++) - mface->flag= SELECT; - - mesh->totface= totface; -} - -static void rna_Mesh_add_geometry(Mesh *mesh, int verts, int edges, int faces) -{ - if(verts) - rna_Mesh_add_verts(mesh, verts); - if(edges) - rna_Mesh_add_edges(mesh, edges); - if(faces) - rna_Mesh_add_faces(mesh, faces); -} - -#else - -void RNA_api_mesh(StructRNA *srna) -{ - FunctionRNA *func; - PropertyRNA *parm; - - func= RNA_def_function(srna, "add_geometry", "rna_Mesh_add_geometry"); - parm= RNA_def_int(func, "verts", 0, 0, INT_MAX, "Number", "Number of vertices to add.", 0, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_int(func, "edges", 0, 0, INT_MAX, "Number", "Number of edges to add.", 0, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_int(func, "faces", 0, 0, INT_MAX, "Number", "Number of faces to add.", 0, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "update", "rna_Mesh_update"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); -} - -#endif - diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c deleted file mode 100644 index bc636af6849..00000000000 --- a/source/blender/makesrna/intern/rna_nla.c +++ /dev/null @@ -1,460 +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): Blender Foundation (2009), Joshua Leung - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include <stdlib.h> - -#include "RNA_define.h" -#include "RNA_types.h" - -#include "rna_internal.h" - -#include "DNA_anim_types.h" -#include "DNA_action_types.h" -#include "DNA_scene_types.h" - -#include "MEM_guardedalloc.h" - -#ifdef RNA_RUNTIME - -#include <stdio.h> -#include <math.h> - -/* needed for some of the validation stuff... */ -#include "BKE_animsys.h" -#include "BKE_nla.h" - -/* temp constant defined for these funcs only... */ -#define NLASTRIP_MIN_LEN_THRESH 0.1f - -void rna_NlaStrip_name_set(PointerRNA *ptr, const char *value) -{ - NlaStrip *data= (NlaStrip *)ptr->data; - - /* copy the name first */ - BLI_strncpy(data->name, value, sizeof(data->name)); - - /* validate if there's enough info to do so */ - if (ptr->id.data) { - AnimData *adt= BKE_animdata_from_id(ptr->id.data); - BKE_nlastrip_validate_name(adt, data); - } -} - - -static void rna_NlaStrip_start_frame_set(PointerRNA *ptr, float value) -{ - NlaStrip *data= (NlaStrip*)ptr->data; - - /* clamp value to lie within valid limits - * - cannot start past the end of the strip + some flexibility threshold - * - cannot start before the previous strip (if present) ends - * -> but if it was a transition, we could go up to the start of the strip + some flexibility threshold - * as long as we re-adjust the transition afterwards - * - minimum frame is -MAXFRAME so that we don't get clipping on frame 0 - */ - if (data->prev) { - if (data->prev->type == NLASTRIP_TYPE_TRANSITION) { - CLAMP(value, data->prev->start+NLASTRIP_MIN_LEN_THRESH, data->end-NLASTRIP_MIN_LEN_THRESH); - - /* readjust the transition to stick to the endpoints of the action-clips */ - data->prev->end= value; - } - else { - CLAMP(value, data->prev->end, data->end-NLASTRIP_MIN_LEN_THRESH); - } - } - else { - CLAMP(value, MINAFRAME, data->end); - } - data->start= value; -} - -static void rna_NlaStrip_end_frame_set(PointerRNA *ptr, float value) -{ - NlaStrip *data= (NlaStrip*)ptr->data; - - /* clamp value to lie within valid limits - * - must not have zero or negative length strip, so cannot start before the first frame - * + some minimum-strip-length threshold - * - cannot end later than the start of the next strip (if present) - * -> but if it was a transition, we could go up to the start of the end - some flexibility threshold - * as long as we re-adjust the transition afterwards - */ - if (data->next) { - if (data->next->type == NLASTRIP_TYPE_TRANSITION) { - CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, data->next->end-NLASTRIP_MIN_LEN_THRESH); - - /* readjust the transition to stick to the endpoints of the action-clips */ - data->next->start= value; - } - else { - CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, data->next->start); - } - } - else { - CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, MAXFRAME); - } - data->end= value; - - - /* calculate the lengths the strip and its action (if applicable) */ - if (data->type == NLASTRIP_TYPE_CLIP) { - float len, actlen; - - len= data->end - data->start; - actlen= data->actend - data->actstart; - if (IS_EQ(actlen, 0.0f)) actlen= 1.0f; - - /* now, adjust the 'scale' setting to reflect this (so that this change can be valid) */ - data->scale= len / ((actlen) * data->repeat); - } -} - -static void rna_NlaStrip_scale_set(PointerRNA *ptr, float value) -{ - NlaStrip *data= (NlaStrip*)ptr->data; - float actlen, mapping; - - /* set scale value */ - CLAMP(value, 0.0001f, 1000.0f); /* NOTE: these need to be synced with the values in the property definition in rna_def_nlastrip() */ - data->scale= value; - - /* calculate existing factors */ - actlen= data->actend - data->actstart; - if (IS_EQ(actlen, 0.0f)) actlen= 1.0f; - mapping= data->scale * data->repeat; - - /* adjust endpoint of strip in response to this */ - if (IS_EQ(mapping, 0.0f) == 0) - data->end = (actlen * mapping) + data->start; - else - printf("NlaStrip Set Scale Error (in RNA): Scale = %0.4f, Repeat = %0.4f \n", data->scale, data->repeat); -} - -static void rna_NlaStrip_repeat_set(PointerRNA *ptr, float value) -{ - NlaStrip *data= (NlaStrip*)ptr->data; - float actlen, mapping; - - /* set scale value */ - CLAMP(value, 0.01f, 1000.0f); /* NOTE: these need to be synced with the values in the property definition in rna_def_nlastrip() */ - data->repeat= value; - - /* calculate existing factors */ - actlen= data->actend - data->actstart; - if (IS_EQ(actlen, 0.0f)) actlen= 1.0f; - mapping= data->scale * data->repeat; - - /* adjust endpoint of strip in response to this */ - if (IS_EQ(mapping, 0.0f) == 0) - data->end = (actlen * mapping) + data->start; - else - printf("NlaStrip Set Repeat Error (in RNA): Scale = %0.4f, Repeat = %0.4f \n", data->scale, data->repeat); -} - -static void rna_NlaStrip_blend_in_set(PointerRNA *ptr, float value) -{ - NlaStrip *data= (NlaStrip*)ptr->data; - float len; - - /* blend-in is limited to the length of the strip, and also cannot overlap with blendout */ - len= (data->end - data->start) - data->blendout; - CLAMP(value, 0, len); - - data->blendin= value; -} - -static void rna_NlaStrip_blend_out_set(PointerRNA *ptr, float value) -{ - NlaStrip *data= (NlaStrip*)ptr->data; - float len; - - /* blend-out is limited to the length of the strip */ - len= (data->end - data->start); - CLAMP(value, 0, len); - - /* it also cannot overlap with blendin */ - if ((len - value) < data->blendin) - value= len - data->blendin; - - data->blendout= value; -} - -static void rna_NlaStrip_action_start_frame_set(PointerRNA *ptr, float value) -{ - NlaStrip *data= (NlaStrip*)ptr->data; - CLAMP(value, MINAFRAME, data->actend); - data->actstart= value; -} - -static void rna_NlaStrip_action_end_frame_set(PointerRNA *ptr, float value) -{ - NlaStrip *data= (NlaStrip*)ptr->data; - CLAMP(value, data->actstart, MAXFRAME); - data->actend= value; -} - -static void rna_NlaStrip_animated_influence_set(PointerRNA *ptr, int value) -{ - NlaStrip *data= (NlaStrip*)ptr->data; - - if (value) { - /* set the flag, then make sure a curve for this exists */ - data->flag |= NLASTRIP_FLAG_USR_INFLUENCE; - BKE_nlastrip_validate_fcurves(data); - } - else - data->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE; -} - -static void rna_NlaStrip_animated_time_set(PointerRNA *ptr, int value) -{ - NlaStrip *data= (NlaStrip*)ptr->data; - - if (value) { - /* set the flag, then make sure a curve for this exists */ - data->flag |= NLASTRIP_FLAG_USR_TIME; - BKE_nlastrip_validate_fcurves(data); - } - else - data->flag &= ~NLASTRIP_FLAG_USR_TIME; -} - -#else - -void rna_def_nlastrip(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - /* enum defs */ - static EnumPropertyItem prop_type_items[] = { - {NLASTRIP_TYPE_CLIP, "CLIP", 0, "Action Clip", "NLA Strip references some Action."}, - {NLASTRIP_TYPE_TRANSITION, "TRANSITION", 0, "Transition", "NLA Strip 'transitions' between adjacent strips."}, - {NLASTRIP_TYPE_META, "META", 0, "Meta", "NLA Strip acts as a container for adjacent strips."}, - {0, NULL, 0, NULL, NULL}}; - static EnumPropertyItem prop_mode_blend_items[] = { - {NLASTRIP_MODE_REPLACE, "REPLACE", 0, "Replace", "Result strip replaces the accumulated results by amount specified by influence."}, - {NLASTRIP_MODE_ADD, "ADD", 0, "Add", "Weighted result of strip is added to the accumlated results."}, - {NLASTRIP_MODE_SUBTRACT, "SUBTRACT", 0, "Subtract", "Weighted result of strip is removed from the accumlated results."}, - {NLASTRIP_MODE_MULTIPLY, "MULITPLY", 0, "Multiply", "Weighted result of strip is multiplied with the accumlated results."}, - {0, NULL, 0, NULL, NULL}}; - static EnumPropertyItem prop_mode_extend_items[] = { - {NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents."}, - {NLASTRIP_EXTEND_HOLD, "HOLD", 0, "Hold", "Hold the first frame if no previous strips in track, and always hold last frame."}, - {NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame."}, - {0, NULL, 0, NULL, NULL}}; - - /* struct definition */ - srna= RNA_def_struct(brna, "NlaStrip", NULL); - RNA_def_struct_ui_text(srna, "NLA Strip", "A container referencing an existing Action."); - RNA_def_struct_ui_icon(srna, ICON_NLA); // XXX - - /* name property */ - prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); - RNA_def_property_ui_text(prop, "Name", ""); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NlaStrip_name_set"); - RNA_def_struct_name_property(srna, prop); - - /* Enums */ - prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "type"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); // XXX for now, not editable, since this is dangerous - RNA_def_property_enum_items(prop, prop_type_items); - RNA_def_property_ui_text(prop, "Type", "Type of NLA Strip."); - - prop= RNA_def_property(srna, "extrapolation", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "extendmode"); - RNA_def_property_enum_items(prop, prop_mode_extend_items); - RNA_def_property_ui_text(prop, "Extrapolation", "Action to take for gaps past the strip extents."); - - prop= RNA_def_property(srna, "blending", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "blendmode"); - RNA_def_property_enum_items(prop, prop_mode_blend_items); - RNA_def_property_ui_text(prop, "Blending", "Method used for combining strip's result with accumulated result."); - - /* Strip extents */ - prop= RNA_def_property(srna, "start_frame", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "start"); - RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_start_frame_set", NULL); - RNA_def_property_ui_text(prop, "Start Frame", ""); - - prop= RNA_def_property(srna, "end_frame", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "end"); - RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_end_frame_set", NULL); - RNA_def_property_ui_text(prop, "End Frame", ""); - - /* Blending */ - prop= RNA_def_property(srna, "blend_in", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "blendin"); - RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_in_set", NULL); - RNA_def_property_ui_text(prop, "Blend In", "Number of frames at start of strip to fade in influence."); - - prop= RNA_def_property(srna, "blend_out", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "blendout"); - RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_out_set", NULL); - RNA_def_property_ui_text(prop, "Blend Out", ""); - - prop= RNA_def_property(srna, "auto_blending", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_AUTO_BLENDS); - RNA_def_property_ui_text(prop, "Auto Blend In/Out", "Number of frames for Blending In/Out is automatically determined from overlapping strips."); - - /* Action */ - prop= RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "act"); - RNA_def_property_ui_text(prop, "Action", "Action referenced by this strip."); - - /* Action extents */ - prop= RNA_def_property(srna, "action_start_frame", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "actstart"); - RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_start_frame_set", NULL); - RNA_def_property_ui_text(prop, "Action Start Frame", ""); - - prop= RNA_def_property(srna, "action_end_frame", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "actend"); - RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_end_frame_set", NULL); - RNA_def_property_ui_text(prop, "Action End Frame", ""); - - /* Action Reuse */ - prop= RNA_def_property(srna, "repeat", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "repeat"); - RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_repeat_set", NULL); - RNA_def_property_range(prop, 0.1f, 1000.0f); /* these limits have currently be chosen arbitarily, but could be extended (minimum should still be > 0 though) if needed... */ - RNA_def_property_ui_text(prop, "Repeat", "Number of times to repeat the action range."); - - prop= RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "scale"); - RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_scale_set", NULL); - RNA_def_property_range(prop, 0.0001f, 1000.0f); /* these limits can be extended, but beyond this, we can get some crazy+annoying bugs due to numeric errors */ - RNA_def_property_ui_text(prop, "Scale", "Scaling factor for action."); - - /* Strip's F-Curves */ - prop= RNA_def_property(srna, "fcurves", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "FCurve"); - RNA_def_property_ui_text(prop, "F-Curves", "F-Curves for controlling the strip's influence and timing."); - - /* Strip's F-Modifiers */ - prop= RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "FModifier"); - RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting all the F-Curves in the referenced Action."); - - /* Strip's Sub-Strips (for Meta-Strips) */ - prop= RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "NlaStrip"); - RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips that this strip acts as a container for (if it is of type Meta)."); - - /* Settings - Values necessary for evaluation */ - prop= RNA_def_property(srna, "influence", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Influence", "Amount the strip contributes to the current result."); - - prop= RNA_def_property(srna, "strip_time", PROP_FLOAT, PROP_NONE); - RNA_def_property_ui_text(prop, "Strip Time", "Frame of referenced Action to evaluate."); - - // TODO: should the animated_influence/time settings be animatable themselves? - prop= RNA_def_property(srna, "animated_influence", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_INFLUENCE); - RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_influence_set"); - RNA_def_property_ui_text(prop, "Animated Influence", "Influence setting is controlled by an F-Curve rather than automatically determined."); - - prop= RNA_def_property(srna, "animated_time", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_TIME); - RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_time_set"); - RNA_def_property_ui_text(prop, "Animated Strip Time", "Strip time is controlled by an F-Curve rather than automatically determined."); - - /* settings */ - prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */ - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_ACTIVE); - RNA_def_property_ui_text(prop, "Active", "NLA Strip is active."); - - prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_SELECT); - RNA_def_property_ui_text(prop, "Selected", "NLA Strip is selected."); - - prop= RNA_def_property(srna, "muted", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_MUTED); - RNA_def_property_ui_text(prop, "Muted", "NLA Strip is not evaluated."); - - prop= RNA_def_property(srna, "reversed", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_REVERSE); - RNA_def_property_ui_text(prop, "Reversed", "NLA Strip is played back in reverse order (only when timing is automatically determined)."); - - // TODO: - // - sync length -} - -void rna_def_nlatrack(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna= RNA_def_struct(brna, "NlaTrack", NULL); - RNA_def_struct_ui_text(srna, "NLA Track", "A animation layer containing Actions referenced as NLA strips."); - RNA_def_struct_ui_icon(srna, ICON_NLA); - - /* strips collection */ - prop= RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "NlaStrip"); - RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips on this NLA-track."); - - /* name property */ - prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); - RNA_def_property_ui_text(prop, "Name", ""); - RNA_def_struct_name_property(srna, prop); - - /* settings */ - prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */ - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_ACTIVE); - RNA_def_property_ui_text(prop, "Active", "NLA Track is active."); - - prop= RNA_def_property(srna, "solo", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */ - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_SOLO); - RNA_def_property_ui_text(prop, "Solo", "NLA Track is evaluated itself (i.e. active Action and all other NLA Tracks in the same AnimData block are disabled)."); - - prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_SELECTED); - RNA_def_property_ui_text(prop, "Selected", "NLA Track is selected."); - - prop= RNA_def_property(srna, "muted", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_MUTED); - RNA_def_property_ui_text(prop, "Muted", "NLA Track is not evaluated."); - - prop= RNA_def_property(srna, "locked", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_PROTECTED); - RNA_def_property_ui_text(prop, "Locked", "NLA Track is locked."); -} - -/* --------- */ - -void RNA_def_nla(BlenderRNA *brna) -{ - rna_def_nlatrack(brna); - rna_def_nlastrip(brna); -} - - -#endif diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c deleted file mode 100644 index 053ab115b3b..00000000000 --- a/source/blender/makesrna/intern/rna_object_api.c +++ /dev/null @@ -1,83 +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) 2009 Blender Foundation. - * All rights reserved. - * - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include <stdlib.h> -#include <stdio.h> - -#include "RNA_define.h" -#include "RNA_types.h" - -#ifdef RNA_RUNTIME - -#include "BKE_customdata.h" -#include "BKE_DerivedMesh.h" - -#include "DNA_mesh_types.h" -#include "DNA_scene_types.h" - -/* copied from init_render_mesh (render code) */ -Mesh *rna_Object_create_render_mesh(Object *ob, Scene *scene) -{ - CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; - DerivedMesh *dm; - Mesh *me; - - /* TODO: other types */ - if(ob->type != OB_MESH) - return NULL; - - dm= mesh_create_derived_render(scene, ob, mask); - - if(!dm) - return NULL; - - me= add_mesh("tmp_render_mesh"); - me->id.us--; /* we don't assign it to anything */ - DM_to_mesh(dm, me); - dm->release(dm); - - return me; -} - -#else - -void RNA_api_object(StructRNA *srna) -{ - FunctionRNA *func; - PropertyRNA *prop; - - func= RNA_def_function(srna, "create_render_mesh", "rna_Object_create_render_mesh"); - RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied."); - prop= RNA_def_pointer(func, "scene", "Scene", "", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object, remove it if it is only used for export."); - RNA_def_function_return(func, prop); -} - -#endif - diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c deleted file mode 100644 index 404befc9bb2..00000000000 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ /dev/null @@ -1,282 +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) 2009 Blender Foundation. - * All rights reserved. - * - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include <stdlib.h> -#include <stdio.h> - -#include "RNA_define.h" -#include "RNA_types.h" - -#include "UI_interface.h" -#include "UI_resources.h" - -#ifdef RNA_RUNTIME - -#else - -#define DEF_ICON(name) {name, #name, 0, #name, ""}, -static EnumPropertyItem icon_items[] = { -#include "UI_icons.h" - {0, NULL, 0, NULL, NULL}}; -#undef DEF_ICON - -static void api_ui_item_common(FunctionRNA *func) -{ - PropertyRNA *prop; - - RNA_def_string(func, "text", "", 0, "", "Override automatic text of the item."); - - prop= RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, icon_items); - RNA_def_property_ui_text(prop, "Icon", "Override automatic icon of the item."); - -} - -static void api_ui_item_op_common(FunctionRNA *func) -{ - PropertyRNA *parm; - - api_ui_item_common(func); - parm= RNA_def_string(func, "operator", "", 0, "", "Identifier of the operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); -} - -static void api_ui_item_rna_common(FunctionRNA *func) -{ - PropertyRNA *parm; - - parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property."); - RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data."); - RNA_def_property_flag(parm, PROP_REQUIRED); -} - -void RNA_api_ui_layout(StructRNA *srna) -{ - FunctionRNA *func; - PropertyRNA *parm; - - static EnumPropertyItem curve_type_items[] = { - {0, "NONE", 0, "None", ""}, - {'v', "VECTOR", 0, "Vector", ""}, - {'c', "COLOR", 0, "Color", ""}, - {0, NULL, 0, NULL, NULL}}; - - /* simple layout specifiers */ - func= RNA_def_function(srna, "row", "uiLayoutRow"); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - RNA_def_boolean(func, "align", 0, "", "Align buttons to each other."); - - func= RNA_def_function(srna, "column", "uiLayoutColumn"); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - RNA_def_boolean(func, "align", 0, "", "Align buttons to each other."); - - func= RNA_def_function(srna, "column_flow", "uiLayoutColumnFlow"); - parm= RNA_def_int(func, "columns", 0, 0, INT_MAX, "", "Number of columns, 0 is automatic.", 0, INT_MAX); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - RNA_def_boolean(func, "align", 0, "", "Align buttons to each other."); - - /* box layout */ - func= RNA_def_function(srna, "box", "uiLayoutBox"); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - - /* split layout */ - func= RNA_def_function(srna, "split", "uiLayoutSplit"); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - RNA_def_float(func, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at.", 0.0f, 1.0f); - - /* items */ - func= RNA_def_function(srna, "itemR", "uiItemR"); - api_ui_item_common(func); - api_ui_item_rna_common(func); - RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail."); - RNA_def_boolean(func, "slider", 0, "", "Use slider widget for numeric values."); - RNA_def_boolean(func, "toggle", 0, "", "Use toggle widget for boolean values."); - - func= RNA_def_function(srna, "items_enumR", "uiItemsEnumR"); - api_ui_item_rna_common(func); - - func= RNA_def_function(srna, "item_menu_enumR", "uiItemMenuEnumR"); - api_ui_item_common(func); - api_ui_item_rna_common(func); - - func= RNA_def_function(srna, "item_enumR", "uiItemEnumR_string"); - api_ui_item_common(func); - api_ui_item_rna_common(func); - parm= RNA_def_string(func, "value", "", 0, "", "Enum property value."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_pointerR", "uiItemPointerR"); - api_ui_item_common(func); - api_ui_item_rna_common(func); - parm= RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in."); - RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); - parm= RNA_def_string(func, "search_property", "", 0, "", "Identifier of search collection property."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "itemO", "uiItemO"); - api_ui_item_op_common(func); - - func= RNA_def_function(srna, "item_enumO", "uiItemEnumO_string"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "value", "", 0, "", "Enum property value."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "items_enumO", "uiItemsEnumO"); - parm= RNA_def_string(func, "operator", "", 0, "", "Identifier of the operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_menu_enumO", "uiItemMenuEnumO"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_booleanO", "uiItemBooleanO"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_boolean(func, "value", 0, "", "Value of the property to call the operator with."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_intO", "uiItemIntO"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_int(func, "value", 0, INT_MIN, INT_MAX, "", "Value of the property to call the operator with.", INT_MIN, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_floatO", "uiItemFloatO"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_float(func, "value", 0, -FLT_MAX, FLT_MAX, "", "Value of the property to call the operator with.", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "item_stringO", "uiItemStringO"); - api_ui_item_op_common(func); - parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_string(func, "value", "", 0, "", "Value of the property to call the operator with."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "itemL", "uiItemL"); - api_ui_item_common(func); - - func= RNA_def_function(srna, "itemM", "uiItemM"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); - api_ui_item_common(func); - parm= RNA_def_string(func, "menu", "", 0, "", "Identifier of the menu."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "itemS", "uiItemS"); - - /* context */ - func= RNA_def_function(srna, "set_context_pointer", "uiLayoutSetContextPointer"); - parm= RNA_def_string(func, "name", "", 0, "Name", "Name of entry in the context."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_pointer(func, "data", "AnyType", "", "Pointer to put in context."); - RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); - - /* templates */ - func= RNA_def_function(srna, "template_header", "uiTemplateHeader"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); - - func= RNA_def_function(srna, "template_ID", "uiTemplateID"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); - api_ui_item_rna_common(func); - RNA_def_string(func, "new", "", 0, "", "Operator identifier to create a new ID block."); - RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block."); - - func= RNA_def_function(srna, "template_modifier", "uiTemplateModifier"); - parm= RNA_def_pointer(func, "data", "Modifier", "", "Modifier data."); - RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - - func= RNA_def_function(srna, "template_constraint", "uiTemplateConstraint"); - parm= RNA_def_pointer(func, "data", "Constraint", "", "Constraint data."); - RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); - parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in."); - RNA_def_function_return(func, parm); - - func= RNA_def_function(srna, "template_preview", "uiTemplatePreview"); - parm= RNA_def_pointer(func, "id", "ID", "", "ID datablock."); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "template_curve_mapping", "uiTemplateCurveMapping"); - parm= RNA_def_pointer(func, "curvemap", "CurveMapping", "", "Curve mapping pointer."); - RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_enum(func, "type", curve_type_items, 0, "Type", "Type of curves to display."); - - func= RNA_def_function(srna, "template_color_ramp", "uiTemplateColorRamp"); - parm= RNA_def_pointer(func, "ramp", "ColorRamp", "", "Color ramp pointer."); - RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail."); - - func= RNA_def_function(srna, "template_layers", "uiTemplateLayers"); - api_ui_item_rna_common(func); - - func= RNA_def_function(srna, "template_image_layers", "uiTemplateImageLayers"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); - parm= RNA_def_pointer(func, "image", "Image", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_pointer(func, "image_user", "ImageUser", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); - - func= RNA_def_function(srna, "template_list", "uiTemplateList"); - api_ui_item_rna_common(func); - parm= RNA_def_pointer(func, "active_data", "AnyType", "", "Data from which to take property for the active element."); - RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR); - parm= RNA_def_string(func, "active_property", "", 0, "", "Identifier of property in data, for the active element."); - RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Number of rows to display.", 0, INT_MAX); - parm= RNA_def_int(func, "columns", 5, 0, INT_MAX, "", "Number of columns to display.", 0, INT_MAX); - parm= RNA_def_boolean(func, "compact", 0, "", "Use compact, single row list template."); - parm= RNA_def_collection(func, "items", 0, "", "Items visible in the list."); - RNA_def_function_return(func, parm); - - func= RNA_def_function(srna, "template_running_jobs", "uiTemplateRunningJobs"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); - - func= RNA_def_function(srna, "template_operator_search", "uiTemplateOperatorSearch"); - - func= RNA_def_function(srna, "template_header_3D", "uiTemplateHeader3D"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); -} - -#endif - diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c deleted file mode 100644 index fd34d7c4d70..00000000000 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ /dev/null @@ -1,56 +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) 2009 Blender Foundation. - * All rights reserved. - * - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include <stdlib.h> -#include <stdio.h> - -#include "RNA_define.h" -#include "RNA_types.h" - -#ifdef RNA_RUNTIME - -#include "BKE_context.h" - -#include "WM_api.h" - -#else - -void RNA_api_wm(StructRNA *srna) -{ - FunctionRNA *func; - PropertyRNA *prop; - - func= RNA_def_function(srna, "add_fileselect", "WM_event_add_fileselect"); - RNA_def_function_flag(func, FUNC_NO_SELF|FUNC_USE_CONTEXT); - RNA_def_function_ui_description(func, "Show up the file selector."); - prop= RNA_def_pointer(func, "operator", "Operator", "", "Operator to call."); - RNA_def_property_flag(prop, PROP_REQUIRED); -} - -#endif - diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_at.c b/source/blender/nodes/intern/TEX_nodes/TEX_at.c deleted file mode 100644 index 80f232ccd0c..00000000000 --- a/source/blender/nodes/intern/TEX_nodes/TEX_at.c +++ /dev/null @@ -1,70 +0,0 @@ -/** - * - * ***** 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) 2005 Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): R Allen - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "../TEX_util.h" - -static bNodeSocketType inputs[]= { - { SOCK_RGBA, 1, "Texture", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f }, - { SOCK_VECTOR, 1, "Coordinates", 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f }, - { -1, 0, "" } -}; -static bNodeSocketType outputs[]= { - { SOCK_RGBA, 0, "Texture", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f }, - { -1, 0, "" } -}; - -static void colorfn(float *out, float *coord, bNode *node, bNodeStack **in, short thread) -{ - float new_coord[3]; - - tex_input_vec(new_coord, in[1], coord, thread); - tex_input_rgba(out, in[0], new_coord, thread); -} - -static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) -{ - tex_output(node, in, out[0], &colorfn); -} - -bNodeType tex_node_at = { - /* *next,*prev */ NULL, NULL, - /* type code */ TEX_NODE_AT, - /* name */ "At", - /* width+range */ 100, 60, 150, - /* class+opts */ NODE_CLASS_DISTORT, 0, - /* input sock */ inputs, - /* output sock */ outputs, - /* storage */ "", - /* execfunc */ exec, - /* butfunc */ NULL, - /* initfunc */ NULL, - /* freestoragefunc */ NULL, - /* copystoragefunc */ NULL, - /* id */ NULL - -}; diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index c6972793372..ff3e89a6e25 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: BPY_extern.h 12334 2007-10-21 23:00:29Z aligorith $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -50,8 +50,6 @@ struct bConstraintTarget; /* DNA_constraint_types.h*/ struct Script; /* DNA_screen_types.h */ struct BPyMenu; struct bContext; -struct ReportList; - #ifdef __cplusplus extern "C" { #endif @@ -99,8 +97,8 @@ extern "C" { int BPY_menu_invoke( struct BPyMenu *pym, short menutype ); /* 2.5 UI Scripts */ - int BPY_run_python_script( struct bContext *C, const char *filename, struct Text *text, struct ReportList *reports ); // 2.5 working - int BPY_run_script_space_draw(const struct bContext *C, struct SpaceScript * sc); // 2.5 working + int BPY_run_python_script( struct bContext *C, const char *filename, struct Text *text ); // 2.5 working + int BPY_run_script_space_draw(struct bContext *C, struct SpaceScript * sc); // 2.5 working void BPY_run_ui_scripts(struct bContext *C, int reload); // int BPY_run_script_space_listener(struct bContext *C, struct SpaceScript * sc, struct ARegion *ar, struct wmNotifier *wmn); // 2.5 working void BPY_update_modules( void ); // XXX - annoying, need this for pointers that get out of date diff --git a/source/blender/python/BPY_menus.c b/source/blender/python/BPY_menus.c new file mode 100644 index 00000000000..b67f1e717da --- /dev/null +++ b/source/blender/python/BPY_menus.c @@ -0,0 +1,1118 @@ +/* + * $Id: BPY_menus.c 12932 2007-12-17 20:21:06Z theeth $ + * + * ***** BEGIN GPL/BL DUAL 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Michael Reimpell + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +/* + *This is the main file responsible for having bpython scripts accessible + * from Blender menus. To know more, please start with its header file. + */ + +#include "BPY_menus.h" + +#include <Python.h> +#ifndef WIN32 + #include <dirent.h> +#else + #include "BLI_winstuff.h" +#endif +#include "BKE_global.h" +#include "BKE_utildefines.h" +#include "BLI_blenlib.h" +#include "MEM_guardedalloc.h" +#include "DNA_userdef_types.h" /* for U.pythondir */ +#include "api2_2x/EXPP_interface.h" /* for bpy_gethome() */ + +#define BPYMENU_DATAFILE "Bpymenus" +#define MAX_DIR_DEPTH 4 /* max depth for traversing scripts dirs */ +#define MAX_DIR_NUMBER 30 /* max number of dirs in scripts dirs trees */ + +static int DEBUG; +static int Dir_Depth; +static int Dirs_Number; + +/* BPyMenuTable holds all registered pymenus, as linked lists for each menu + * where they can appear (see PYMENUHOOKS enum in BPY_menus.h). +*/ +BPyMenu *BPyMenuTable[PYMENU_TOTAL]; + +static int bpymenu_group_atoi( char *str ) +{ + if( !strcmp( str, "Export" ) ) + return PYMENU_EXPORT; + else if( !strcmp( str, "Import" ) ) + return PYMENU_IMPORT; + else if( !strcmp( str, "Help" ) ) + return PYMENU_HELP; + else if( !strcmp( str, "HelpWebsites" ) ) + return PYMENU_HELPWEBSITES; + else if( !strcmp( str, "HelpSystem" ) ) + return PYMENU_HELPSYSTEM; + else if( !strcmp( str, "Render" ) ) + return PYMENU_RENDER; + else if( !strcmp( str, "System" ) ) + return PYMENU_SYSTEM; + else if( !strcmp( str, "Object" ) ) + return PYMENU_OBJECT; + else if( !strcmp( str, "Mesh" ) ) + return PYMENU_MESH; + else if( !strncmp( str, "Theme", 5 ) ) + return PYMENU_THEMES; + else if( !strcmp( str, "Add" ) ) + return PYMENU_ADD; + else if( !strcmp( str, "Wizards" ) ) + return PYMENU_WIZARDS; + else if( !strcmp( str, "Animation" ) ) + return PYMENU_ANIMATION; + else if( !strcmp( str, "Materials" ) ) + return PYMENU_MATERIALS; + else if( !strcmp( str, "UV" ) ) + return PYMENU_UV; + else if( !strcmp( str, "Image" ) ) + return PYMENU_IMAGE; + else if( !strcmp( str, "FaceSelect" ) ) + return PYMENU_FACESELECT; + else if( !strcmp( str, "WeightPaint" ) ) + return PYMENU_WEIGHTPAINT; + else if( !strcmp( str, "VertexPaint" ) ) + return PYMENU_VERTEXPAINT; + else if( !strcmp( str, "UVCalculation" ) ) + return PYMENU_UVCALCULATION; + else if( !strcmp( str, "Armature" ) ) + return PYMENU_ARMATURE; + else if( !strcmp( str, "ScriptTemplate" ) ) + return PYMENU_SCRIPTTEMPLATE; + else if( !strcmp( str, "MeshFaceKey" ) ) + return PYMENU_MESHFACEKEY; + else if( !strcmp( str, "AddMesh" ) ) + return PYMENU_ADDMESH; + /* "Misc" or an inexistent group name: use misc */ + else + return PYMENU_MISC; +} + +char *BPyMenu_group_itoa( short menugroup ) +{ + switch ( menugroup ) { + case PYMENU_EXPORT: + return "Export"; + break; + case PYMENU_IMPORT: + return "Import"; + break; + case PYMENU_ADD: + return "Add"; + break; + case PYMENU_HELP: + return "Help"; + break; + case PYMENU_HELPWEBSITES: + return "HelpWebsites"; + break; + case PYMENU_HELPSYSTEM: + return "HelpSystem"; + break; + case PYMENU_RENDER: + return "Render"; + break; + case PYMENU_SYSTEM: + return "System"; + break; + case PYMENU_OBJECT: + return "Object"; + break; + case PYMENU_MESH: + return "Mesh"; + break; + case PYMENU_THEMES: + return "Themes"; + break; + case PYMENU_WIZARDS: + return "Wizards"; + break; + case PYMENU_ANIMATION: + return "Animation"; + break; + case PYMENU_MATERIALS: + return "Materials"; + break; + case PYMENU_UV: + return "UV"; + break; + case PYMENU_IMAGE: + return "Image"; + break; + case PYMENU_FACESELECT: + return "FaceSelect"; + break; + case PYMENU_WEIGHTPAINT: + return "WeightPaint"; + break; + case PYMENU_VERTEXPAINT: + return "VertexPaint"; + break; + case PYMENU_UVCALCULATION: + return "UVCalculation"; + break; + case PYMENU_ARMATURE: + return "Armature"; + break; + case PYMENU_SCRIPTTEMPLATE: + return "ScriptTemplate"; + break; + case PYMENU_MESHFACEKEY: + return "MeshFaceKey"; + break; + case PYMENU_ADDMESH: + return "AddMesh"; + break; + case PYMENU_MISC: + return "Misc"; + break; + } + return NULL; +} + +/* BPyMenu_CreatePupmenuStr: + * build and return a meaninful string to be used by pupmenu(). The + * string is made of a bpymenu name as title and its submenus as possible + * choices for the user. +*/ +char *BPyMenu_CreatePupmenuStr( BPyMenu * pym, short menugroup ) +{ + BPySubMenu *pysm = pym->submenus; + char str[1024], str2[100]; + int i = 0, rlen; + + if( !pym || !pysm ) + return NULL; + + str[0] = '\0'; + + PyOS_snprintf( str2, sizeof( str2 ), "%s: %s%%t", + BPyMenu_group_itoa( menugroup ), pym->name ); + strcat( str, str2 ); + + while( pysm ) { + PyOS_snprintf( str2, sizeof( str2 ), "|%s%%x%d", pysm->name, + i ); + rlen = sizeof( str ) - strlen( str ); + strncat( str, str2, rlen ); + i++; + pysm = pysm->next; + } + + return BLI_strdup( str ); +} + +static void bpymenu_RemoveAllSubEntries( BPySubMenu * smenu ) +{ + BPySubMenu *tmp; + + while( smenu ) { + tmp = smenu->next; + if( smenu->name ) + MEM_freeN( smenu->name ); + if( smenu->arg ) + MEM_freeN( smenu->arg ); + MEM_freeN( smenu ); + smenu = tmp; + } + return; +} + +void BPyMenu_RemoveAllEntries( void ) +{ + BPyMenu *tmp, *pymenu; + int i; + + for( i = 0; i < PYMENU_TOTAL; i++ ) { + pymenu = BPyMenuTable[i]; + while( pymenu ) { + tmp = pymenu->next; + if( pymenu->name ) + MEM_freeN( pymenu->name ); + if( pymenu->filename ) + MEM_freeN( pymenu->filename ); + if( pymenu->tooltip ) + MEM_freeN( pymenu->tooltip ); + if( pymenu->submenus ) + bpymenu_RemoveAllSubEntries( pymenu-> + submenus ); + MEM_freeN( pymenu ); + pymenu = tmp; + } + BPyMenuTable[i] = NULL; + } + + Dirs_Number = 0; + Dir_Depth = 0; + + return; +} + +static BPyMenu *bpymenu_FindEntry( short group, char *name ) +{ + BPyMenu *pymenu; + + if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) ) + return NULL; + + pymenu = BPyMenuTable[group]; + + while( pymenu ) { + if( !strcmp( pymenu->name, name ) ) + return pymenu; + pymenu = pymenu->next; + } + + return NULL; +} + +/* BPyMenu_GetEntry: + * given a group and a position, return the entry in that position from + * that group. +*/ +BPyMenu *BPyMenu_GetEntry( short group, short pos ) +{ + BPyMenu *pym = NULL; + + if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) ) + return NULL; + + pym = BPyMenuTable[group]; + + while( pos-- ) { + if( pym ) + pym = pym->next; + else + break; + } + + return pym; /* found entry or NULL */ +} + +static void bpymenu_set_tooltip( BPyMenu * pymenu, char *tip ) +{ + if( !pymenu ) + return; + + if( pymenu->tooltip ) + MEM_freeN( pymenu->tooltip ); + pymenu->tooltip = BLI_strdup( tip ); + + return; +} + +/* bpymenu_AddEntry: + * try to find an existing pymenu entry with the given type and name; + * if found, update it with new info, otherwise create a new one and fill it. + */ +static BPyMenu *bpymenu_AddEntry( short group, short version, char *name, + char *fname, int is_userdir, char *tooltip ) +{ + BPyMenu *menu, *next = NULL, **iter; + int nameclash = 0; + + if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) ) + return NULL; + if( !name || !fname ) + return NULL; + + menu = bpymenu_FindEntry( group, name ); /* already exists? */ + + /* if a menu with this name already exists in the same group: + * - if one script is in the default dir and the other in U.pythondir, + * accept and let the new one override the other. + * - otherwise, report the error and return NULL. */ + if( menu ) { + if( menu->dir < is_userdir ) { /* new one is in U.pythondir */ + nameclash = 1; + if( menu->name ) + MEM_freeN( menu->name ); + if( menu->filename ) + MEM_freeN( menu->filename ); + if( menu->tooltip ) + MEM_freeN( menu->tooltip ); + if( menu->submenus ) + bpymenu_RemoveAllSubEntries( menu->submenus ); + next = menu->next; + } else { /* they are in the same dir */ + if (DEBUG) { + fprintf(stderr, "\n\ +Warning: script %s's menu name is already in use.\n\ +Edit the script and change its \n\ +Name: '%s'\n\ +field, please.\n\ +Note: if you really want to have two scripts for the same menu with\n\ +the same name, keep one in the default dir and the other in\n\ +the user defined dir (only the later will be registered).\n", fname, name); + } + return NULL; + } + } else + menu = MEM_mallocN( sizeof( BPyMenu ), "pymenu" ); + + if( !menu ) + return NULL; + + menu->name = BLI_strdup( name ); + menu->version = version; + menu->filename = BLI_strdup( fname ); + menu->tooltip = NULL; + if( tooltip ) + menu->tooltip = BLI_strdup( tooltip ); + menu->dir = is_userdir; + menu->submenus = NULL; + menu->next = next; /* non-NULL if menu already existed */ + + if( nameclash ) + return menu; /* no need to place it, it's already at the list */ + else { /* insert the new entry in its correct position at the table */ + BPyMenu *prev = NULL; + char *s = NULL; + + iter = &BPyMenuTable[group]; + while( *iter ) { + s = ( *iter )->name; + if( s ) + if( strcmp( menu->name, s ) < 0 ) + break; /* sort by names */ + prev = *iter; + iter = &( ( *iter )->next ); + } + + if( *iter ) { /* prepend */ + menu->next = *iter; + if( prev ) + prev->next = menu; + else + BPyMenuTable[group] = menu; /* is first entry */ + } else + *iter = menu; /* append */ + } + + return menu; +} + +/* bpymenu_AddSubEntry: + * add a submenu to an existing python menu. + */ +static int bpymenu_AddSubEntry( BPyMenu * mentry, char *name, char *arg ) +{ + BPySubMenu *smenu, **iter; + + smenu = MEM_mallocN( sizeof( BPySubMenu ), "pysubmenu" ); + if( !smenu ) + return -1; + + smenu->name = BLI_strdup( name ); + smenu->arg = BLI_strdup( arg ); + smenu->next = NULL; + + if( !smenu->name || !smenu->arg ) + return -1; + + iter = &( mentry->submenus ); + while( *iter ) + iter = &( ( *iter )->next ); + + *iter = smenu; + + return 0; +} + +/* bpymenu_CreateFromFile: + * parse the bpymenus data file where Python menu data is stored; + * based on this data, create and fill the pymenu structs. + */ +static int bpymenu_CreateFromFile( void ) +{ + FILE *fp; + char line[255], w1[255], w2[255], tooltip[255], *tip; + char *homedir = NULL; + int parsing, version, is_userdir; + short group; + BPyMenu *pymenu = NULL; + + /* init global bpymenu table (it is a list of pointers to struct BPyMenus + * for each available cathegory: import, export, etc.) */ + for( group = 0; group < PYMENU_TOTAL; group++ ) + BPyMenuTable[group] = NULL; + + /* let's try to open the file with bpymenu data */ + homedir = bpy_gethome(0); + if (!homedir) { + if( DEBUG ) + fprintf(stderr, + "BPyMenus error: couldn't open config file Bpymenus: no home dir.\n"); + return -1; + } + + BLI_make_file_string( "/", line, homedir, BPYMENU_DATAFILE ); + + fp = fopen( line, "rb" ); + + if( !fp ) { + if( DEBUG ) + fprintf(stderr, "BPyMenus error: couldn't open config file %s.\n", line ); + return -1; + } + + fgets( line, 255, fp ); /* header */ + + /* check if the U.pythondir we saved at the file is different from the + * current one. If so, return to force updating from dirs */ + w1[0] = '\0'; + fscanf( fp, "# User defined scripts dir: %[^\n]\n", w1 ); + if( w1 ) { + char upythondir[FILE_MAXDIR]; + + BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR); + BLI_convertstringcode(upythondir, G.sce, 0); + if( strcmp( w1, upythondir ) != 0 ) + return -1; + w1[0] = '\0'; + } + + while( fgets( line, 255, fp ) ) { /* parsing file lines */ + + switch ( line[0] ) { /* check first char */ + case '#': /* comment */ + continue; + break; + case '\n': + continue; + break; + default: + parsing = sscanf( line, "%s {\n", w1 ); /* menu group */ + break; + } + + if( parsing == 1 ) { /* got menu group string */ + group = (short)bpymenu_group_atoi( w1 ); + if( group < 0 && DEBUG ) { /* invalid type */ + fprintf(stderr, + "BPyMenus error parsing config file: wrong group: %s,\n\ +will use 'Misc'.\n", w1 ); + } + } else + continue; + + for(;;) { + tip = NULL; /* optional tooltip */ + fgets( line, 255, fp ); + if( line[0] == '}' ) + break; + else if( line[0] == '\n' ) + continue; + else if( line[0] == '\'' ) { /* menu entry */ + parsing = + sscanf( line, + "'%[^']' %d %s %d '%[^']'\n", + w1, &version, w2, &is_userdir, + tooltip ); + + if( parsing <= 0 ) { /* invalid line, get rid of it */ + fgets( line, 255, fp ); + } else if( parsing == 5 ) + tip = tooltip; /* has tooltip */ + + pymenu = bpymenu_AddEntry( group, + ( short ) version, + w1, w2, is_userdir, + tip ); + if( !pymenu ) { + puts( "BPyMenus error: couldn't create bpymenu entry.\n" ); + fclose( fp ); + return -1; + } + } else if( line[0] == '|' && line[1] == '_' ) { /* menu sub-entry */ + if( !pymenu ) + continue; /* no menu yet, skip this line */ + sscanf( line, "|_%[^:]: %s\n", w1, w2 ); + bpymenu_AddSubEntry( pymenu, w1, w2 ); + } + } + } + + fclose( fp ); + return 0; +} + +/* bpymenu_WriteDataFile: + * writes the registered scripts info to the user's home dir, for faster + * access when the scripts dir hasn't changed. +*/ +static void bpymenu_WriteDataFile( void ) +{ + BPyMenu *pymenu; + BPySubMenu *smenu; + FILE *fp; + char fname[FILE_MAXDIR], *homedir; + int i; + + homedir = bpy_gethome(0); + + if (!homedir) { + if( DEBUG ) + fprintf(stderr, + "BPyMenus error: couldn't write Bpymenus file: no home dir.\n\n"); + return; + } + + BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE ); + + fp = fopen( fname, "w" ); + if( !fp ) { + if( DEBUG ) + fprintf(stderr, "BPyMenus error: couldn't write %s file.\n\n", + fname ); + return; + } + + fprintf( fp, + "# Blender: registered menu entries for bpython scripts\n" ); + + if (U.pythondir[0] != '\0' && + strcmp(U.pythondir, "/") != 0 && strcmp(U.pythondir, "//") != 0) + { + char upythondir[FILE_MAXDIR]; + + BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR); + BLI_convertstringcode(upythondir, G.sce, 0); + fprintf( fp, "# User defined scripts dir: %s\n", upythondir ); + } + + for( i = 0; i < PYMENU_TOTAL; i++ ) { + pymenu = BPyMenuTable[i]; + if( !pymenu ) + continue; + fprintf( fp, "\n%s {\n", BPyMenu_group_itoa( (short)i ) ); + while( pymenu ) { + fprintf( fp, "'%s' %d %s %d", pymenu->name, + pymenu->version, pymenu->filename, + pymenu->dir ); + if( pymenu->tooltip ) + fprintf( fp, " '%s'\n", pymenu->tooltip ); + else + fprintf( fp, "\n" ); + smenu = pymenu->submenus; + while( smenu ) { + fprintf( fp, "|_%s: %s\n", smenu->name, + smenu->arg ); + smenu = smenu->next; + } + pymenu = pymenu->next; + } + fprintf( fp, "}\n" ); + } + + fclose( fp ); + return; +} + +/* BPyMenu_PrintAllEntries: + * useful for debugging. + */ +void BPyMenu_PrintAllEntries( void ) +{ + BPyMenu *pymenu; + BPySubMenu *smenu; + int i; + + printf( "# Blender: registered menu entries for bpython scripts\n" ); + + for( i = 0; i < PYMENU_TOTAL; i++ ) { + pymenu = BPyMenuTable[i]; + printf( "\n%s {\n", BPyMenu_group_itoa( (short)i ) ); + while( pymenu ) { + printf( "'%s' %d %s %d", pymenu->name, pymenu->version, + pymenu->filename, pymenu->dir ); + if( pymenu->tooltip ) + printf( " '%s'\n", pymenu->tooltip ); + else + printf( "\n" ); + smenu = pymenu->submenus; + while( smenu ) { + printf( "|_%s: %s\n", smenu->name, + smenu->arg ); + smenu = smenu->next; + } + pymenu = pymenu->next; + } + printf( "}\n" ); + } +} + +/* bpymenu_ParseFile: + * recursively scans folders looking for scripts to register. + * + * This function scans the scripts directory looking for .py files with the + * right header and menu info, using that to fill the bpymenu structs. + * is_userdir defines if the script is in the default scripts dir or the + * user defined one (U.pythondir: is_userdir == 1). + * Speed is important. + * + * The first line of the script must be '#!BPY'. + * The header registration lines must appear between the first pair of + * '\"\"\"' and follow this order (the single-quotes are part of + * the format): + * + * # \"\"\"<br> + * # Name: 'script name for the menu' + * # Blender: <code>short int</code> (minimal Blender version) + * # Group: 'group name' (defines menu) + * # Submenu: 'submenu name' related_1word_arg + * # Tooltip: 'tooltip for the menu' + * # \"\"\" + * + * Notes: + * + * - Commenting out header lines with "#" is optional, but recommended. + * - There may be more than one submenu line, or none: + * submenus and the tooltip are optional; + * - The Blender version is the same number reported by + * Blender.Get('version') in BPython or G.version in C; + * - Line length must be less than 99. + */ +static int bpymenu_ParseFile(FILE *file, char *fname, int is_userdir) +{ + char line[100]; + char head[100]; + char middle[100]; + char tail[100]; + int matches; + int parser_state; + + char script_name[100]; + int script_version = 1; + int script_group; + + BPyMenu *scriptMenu = NULL; + + if (file != NULL) { + parser_state = 1; /* state of parser, 0 to terminate */ + + while ((parser_state != 0) && (fgets(line, 100, file) != NULL)) { + + switch (parser_state) { + + case 1: /* !BPY */ + if (strncmp(line, "#!BPY", 5) == 0) { + parser_state++; + } else { + parser_state = 0; + } + break; + + case 2: /* \"\"\" */ + if ((strstr(line, "\"\"\""))) { + parser_state++; + } + break; + + case 3: /* Name: 'script name for the menu' */ + matches = sscanf(line, "%[^']'%[^']'%c", head, script_name, tail); + if ((matches == 3) && (strstr(head, "Name:") != NULL)) { + parser_state++; + } else { + if (DEBUG) + fprintf(stderr, "BPyMenus error: Wrong 'Name' line: %s\n", fname); + parser_state = 0; + } + break; + + case 4: /* Blender: <short int> */ + matches = sscanf(line, "%[^1234567890]%i%c", head, &script_version, + tail); + if (matches == 3) { + parser_state++; + } else { + if (DEBUG) + fprintf(stderr,"BPyMenus error: Wrong 'Blender' line: %s\n",fname); + parser_state = 0; + } + break; + + case 5: /* Group: 'group name' */ + matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail); + if ((matches == 3) && (strstr(head, "Group:") != NULL)) { + script_group = bpymenu_group_atoi(middle); + if (script_group < 0) { + if (DEBUG) + fprintf(stderr, "BPyMenus error: Unknown group \"%s\": %s\n", + middle, fname); + parser_state = 0; + } + + else { /* register script */ + scriptMenu = bpymenu_AddEntry((short)script_group, + (short int)script_version, script_name, fname, is_userdir,NULL); + if (scriptMenu == NULL) { + if (DEBUG) + fprintf(stderr, + "BPyMenus error: Couldn't create entry for: %s\n", fname); + parser_state = 0; + } else { + parser_state++; + } + } + + } else { + if (DEBUG) + fprintf(stderr, "BPyMenus error: Wrong 'Group' line: %s\n",fname); + parser_state = 0; + } + break; + + case 6: /* optional elements */ + /* Submenu: 'submenu name' related_1word_arg */ + matches = sscanf(line, "%[^']'%[^']'%s\n", head, middle, tail); + if ((matches == 3) && (strstr(head, "Submenu:") != NULL)) { + bpymenu_AddSubEntry(scriptMenu, middle, tail); + } else { + /* Tooltip: 'tooltip for the menu */ + matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail); + if ((matches == 3) && ((strstr(head, "Tooltip:") != NULL) || + (strstr(head, "Tip:") != NULL))) { + bpymenu_set_tooltip(scriptMenu, middle); + } + parser_state = 0; + } + break; + + default: + parser_state = 0; + break; + } + } + } + + else { /* shouldn't happen, it's checked in bpymenus_ParseDir */ + if (DEBUG) + fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", fname); + return -1; + } + + return 0; +} + +/* bpymenu_ParseDir: + * recursively scans folders looking for scripts to register. + * + * This function scans the scripts directory looking for .py files with the + * right header and menu info. + * - is_userdir defines if the script is in the default scripts dir or the + * user defined one (U.pythondir: is_userdir == 1); + * - parentdir is the parent dir name to store as part of the script filename, + * if we're down a subdir. + * Speed is important. + */ +static int bpymenu_ParseDir(char *dirname, char *parentdir, int is_userdir ) +{ + DIR *dir; + FILE *file = NULL; + struct dirent *de; + struct stat status; + char *file_extension; + char path[FILE_MAX]; + char subdir[FILE_MAX]; + char *s = NULL; + + dir = opendir(dirname); + + if (dir != NULL) { + while ((de = readdir(dir)) != NULL) { + + /* skip files and dirs starting with '.' or 'bpy' */ + if ((de->d_name[0] == '.') || !strncmp(de->d_name, "bpy", 3)) { + continue; + } + + BLI_make_file_string("/", path, dirname, de->d_name); + + if (stat(path, &status) != 0) { + if (DEBUG) + fprintf(stderr, "stat %s failed: %s\n", path, strerror(errno)); + } + + if (S_ISREG(status.st_mode)) { /* is file */ + + file_extension = strstr(de->d_name, ".py"); + + if (file_extension && *(file_extension + 3) == '\0') { + file = fopen(path, "rb"); + + if (file) { + s = de->d_name; + if (parentdir) { + /* Join parentdir and de->d_name */ + BLI_join_dirfile(subdir, parentdir, de->d_name); + + s = subdir; + } + bpymenu_ParseFile(file, s, is_userdir); + fclose(file); + } + + else { + if (DEBUG) + fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", path); + } + } + } + + else if (S_ISDIR(status.st_mode)) { /* is subdir */ + Dirs_Number++; + Dir_Depth++; + if (Dirs_Number > MAX_DIR_NUMBER) { + if (DEBUG) { + fprintf(stderr, "BPyMenus error: too many subdirs.\n"); + } + closedir(dir); + return -1; + } + else if (Dir_Depth > MAX_DIR_DEPTH) { + if (DEBUG) + fprintf(stderr, + "BPyMenus error: max depth reached traversing dir tree.\n"); + closedir(dir); + return -1; + } + s = de->d_name; + if (parentdir) { + /* Join parentdir and de->d_name */ + BLI_join_dirfile(subdir, parentdir, de->d_name); + s = subdir; + } + if (bpymenu_ParseDir(path, s, is_userdir) == -1) { + closedir(dir); + return -1; + } + Dir_Depth--; + } + + } + closedir(dir); + } + + else { /* open directory stream failed */ + if (DEBUG) + fprintf(stderr, "opendir %s failed: %s\n", dirname, strerror(errno)); + return -1; + } + + return 0; +} + +static int bpymenu_GetStatMTime( char *name, int is_file, time_t * mtime ) +{ + struct stat st; + int result; + + result = stat( name, &st ); + + if( result == -1 ) + return -1; + + if( is_file ) { + if( !S_ISREG( st.st_mode ) ) + return -2; + } else if( !S_ISDIR( st.st_mode ) ) + return -2; + + *mtime = st.st_mtime; + + return 0; +} + +/* BPyMenu_Init: + * import the bpython menus data to Blender, either from: + * - the BPYMENU_DATAFILE file (?/.blender/Bpymenus) or + * - the scripts dir(s), case newer than the datafile (then update the file). + * then fill the bpymenu table with this data. + * if param usedir != 0, then the data is recreated from the dir(s) anyway. +*/ +int BPyMenu_Init( int usedir ) +{ + char fname[FILE_MAXDIR]; + char dirname[FILE_MAXDIR]; + char upythondir[FILE_MAXDIR]; + char *upydir = U.pythondir, *sdir = NULL; + time_t time_dir1 = 0, time_dir2 = 0, time_file = 0; + int stat_dir1 = 0, stat_dir2 = 0, stat_file = 0; + int i; + + DEBUG = G.f & G_DEBUG; /* is Blender in debug mode (started with -d) ? */ + + /* init global bpymenu table (it is a list of pointers to struct BPyMenus + * for each available group: import, export, etc.) */ + for( i = 0; i < PYMENU_TOTAL; i++ ) + BPyMenuTable[i] = NULL; + + if( DEBUG ) + fprintf(stdout, "\nRegistering scripts in Blender menus ...\n\n" ); + + if( U.pythondir[0] == '\0') { + upydir = NULL; + } + else if (strcmp(U.pythondir, "/") == 0 || strcmp(U.pythondir, "//") == 0) { + /* these are not accepted to prevent possible slight slowdowns on startup; + * they should not be used as user defined scripts dir, anyway, also from + * speed considerations, since they'd not be dedicated scripts dirs */ + if (DEBUG) fprintf(stderr, + "BPyMenus: invalid user defined Python scripts dir: \"/\" or \"//\".\n"); + upydir = NULL; + } + else { + BLI_strncpy(upythondir, upydir, FILE_MAXDIR); + BLI_convertstringcode(upythondir, G.sce, 0); + } + + sdir = bpy_gethome(1); + + if (sdir) { + BLI_strncpy(dirname, sdir, FILE_MAXDIR); + stat_dir1 = bpymenu_GetStatMTime( dirname, 0, &time_dir1 ); + + if( stat_dir1 < 0 ) { + time_dir1 = 0; + if( DEBUG ) { + fprintf(stderr, + "\nDefault scripts dir: %s:\n%s\n", dirname, strerror(errno)); + if( upydir ) + fprintf(stdout, + "Getting scripts menu data from user defined dir: %s.\n", + upythondir ); + } + } + } + else stat_dir1 = -1; + + if( upydir ) { + stat_dir2 = bpymenu_GetStatMTime( upythondir, 0, &time_dir2 ); + + if( stat_dir2 < 0 ) { + time_dir2 = 0; + upydir = NULL; + if( DEBUG ) + fprintf(stderr, "\nUser defined scripts dir: %s:\n%s.\n", + upythondir, strerror( errno ) ); + if( stat_dir1 < 0 ) { + if( DEBUG ) + fprintf(stderr, "\ +To have scripts in menus, please add them to the default scripts dir:\n\ +%s\n\ +and / or go to 'Info window -> File Paths tab' and set a valid path for\n\ +the user defined Python scripts dir.\n", dirname ); + return -1; + } + } + } + else stat_dir2 = -1; + + if( ( stat_dir1 < 0 ) && ( stat_dir2 < 0 ) ) { + if( DEBUG ) { + fprintf(stderr, "\nCannot register scripts in menus, no scripts dir" + " available.\nExpected default dir at: %s \n", dirname ); + } + return -1; + } + + if (usedir) stat_file = -1; + else { /* if we're not forced to use the dir */ + char *homedir = bpy_gethome(0); + + if (homedir) { + BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE ); + stat_file = bpymenu_GetStatMTime( fname, 1, &time_file ); + if( stat_file < 0 ) + time_file = 0; + + /* comparing dates */ + + if((stat_file == 0) + && (time_file > time_dir1) && (time_file > time_dir2)) + { /* file is newer */ + stat_file = bpymenu_CreateFromFile( ); /* -1 if an error occurred */ + if( !stat_file && DEBUG ) + fprintf(stdout, + "Getting menu data for scripts from file:\n%s\n\n", fname ); + } + else stat_file = -1; + } + else stat_file = -1; /* -1 to use dirs: didn't use file or it was corrupted */ + } + + if( stat_file == -1 ) { /* use dirs */ + if( DEBUG ) { + fprintf(stdout, + "Getting menu data for scripts from dir(s):\ndefault: %s\n", dirname ); + if( upydir ) + fprintf(stdout, "user defined: %s\n", upythondir ); + fprintf(stdout, "\n"); + } + if( stat_dir1 == 0 ) { + i = bpymenu_ParseDir( dirname, NULL, 0 ); + if (i == -1 && DEBUG) + fprintf(stderr, "Default scripts dir does not seem valid.\n\n"); + } + if( stat_dir2 == 0 ) { + BLI_strncpy(dirname, U.pythondir, FILE_MAXDIR); + BLI_convertstringcode(dirname, G.sce, 0); + i = bpymenu_ParseDir( dirname, NULL, 1 ); + if (i == -1 && DEBUG) + fprintf(stderr, "User defined scripts dir does not seem valid.\n\n"); + } + + /* check if we got any data */ + for( i = 0; i < PYMENU_TOTAL; i++ ) + if( BPyMenuTable[i] ) + break; + + /* if we got, recreate the file */ + if( i < PYMENU_TOTAL ) + bpymenu_WriteDataFile( ); + else if( DEBUG ) { + fprintf(stderr, "\n\ +Warning: Registering scripts in menus -- no info found.\n\ +Either your scripts dirs have no .py scripts or the scripts\n\ +don't have a header with registration data.\n\ +Default scripts dir is:\n\ +%s\n", dirname ); + if( upydir ) + fprintf(stderr, "User defined scripts dir is: %s\n", + upythondir ); + } + } + + return 0; +} diff --git a/source/blender/python/BPY_menus.h b/source/blender/python/BPY_menus.h new file mode 100644 index 00000000000..6cdea608b10 --- /dev/null +++ b/source/blender/python/BPY_menus.h @@ -0,0 +1,128 @@ +/* + * $Id: BPY_menus.h 12931 2007-12-17 18:20:48Z theeth $ + * + * ***** BEGIN GPL/BL DUAL 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano, Matt Ebb + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** +*/ + +#ifndef BPY_MENUS_H +#define BPY_MENUS_H + +/* This header exposes BPyMenu related public declarations. The implementation + * adds 'dynamic' menus to Blender, letting scripts register themselves in any + * of a few pre-defined (trivial to upgrade) places in menus. These places or + * slots are called groups here (Import, Export, etc). This is how it works: + * - scripts at dirs user pref U.pythondir and .blender/scripts/ are scanned + * for registration info. + * - this data is also saved to a Bpymenus file at the user's .blender/ dir and + * only re-created when the scripts folder gets modified. + * - on start-up Blender uses this info to fill a table, which is used to + * create the menu entries when they are needed (see header_info.c or + * header_script.c, under source/blender/src/, for examples). +*/ + +/* These two structs hold py menu/submenu info. + * BPyMenu holds a script's name (as should appear in the menu) and filename, + * plus an optional list of submenus. Each submenu is related to a string + * (arg) that the script can get from the __script__ pydict, to know which + * submenu was chosen. */ + +typedef struct BPySubMenu { + char *name; + char *arg; + struct BPySubMenu *next; +} BPySubMenu; + +typedef struct BPyMenu { + char *name; + char *filename; + char *tooltip; + short version; /* Blender version */ + int dir; /* 0: default, 1: U.pythondir */ + struct BPySubMenu *submenus; + struct BPyMenu *next; +} BPyMenu; + +/* Scripts can be added to only a few pre-defined places in menus, like + * File->Import, File->Export, etc. (for speed and better control). + * To make a new menu 'slot' available for scripts: + * - add an entry to the enum below, before PYMENU_TOTAL, of course; + * - update the bpymenu_group_atoi() and BPyMenu_group_itoa() functions in + * BPY_menus.c; + * - add the necessary code to the header_***.c file in + * source/blender/src/, like done in header_info.c for import/export; +*/ +typedef enum { + PYMENU_ADD,/* creates new objects */ + PYMENU_ANIMATION, + PYMENU_EXPORT, + PYMENU_IMPORT, + PYMENU_MATERIALS, + PYMENU_MESH, + PYMENU_MISC, + PYMENU_OBJECT, + PYMENU_RENDER,/* exporters to external renderers */ + PYMENU_SYSTEM, + PYMENU_THEMES, + PYMENU_UV,/* UV editing tools, to go in UV/Image editor space, 'UV' menu */ + PYMENU_IMAGE,/* Image editing tools, to go in UV/Image editor space, 'Image' menu */ + PYMENU_WIZARDS,/* complex 'app' scripts */ + + /* entries put after Wizards don't appear at the Scripts win->Scripts menu; + * see define right below */ + + PYMENU_FACESELECT, + PYMENU_WEIGHTPAINT, + PYMENU_VERTEXPAINT, + PYMENU_UVCALCULATION, + PYMENU_ARMATURE, + PYMENU_SCRIPTTEMPLATE, + PYMENU_HELP,/*Main Help menu items - prob best to leave for 'official' ones*/ + PYMENU_HELPSYSTEM,/* Resources, troubleshooting, system tools */ + PYMENU_HELPWEBSITES,/* Help -> Websites submenu */ + PYMENU_MESHFACEKEY, /* face key in mesh editmode */ + PYMENU_ADDMESH, /* adds mesh */ + PYMENU_TOTAL +} PYMENUHOOKS; + +#define PYMENU_SCRIPTS_MENU_TOTAL (PYMENU_WIZARDS + 1) + +/* BPyMenuTable holds all registered pymenus, as linked lists for each menu + * where they can appear (see PYMENUHOOKS enum above). +*/ +extern BPyMenu *BPyMenuTable[]; /* defined in BPY_menus.c */ + +/* public functions: */ +int BPyMenu_Init( int usedir ); +void BPyMenu_RemoveAllEntries( void ); +void BPyMenu_PrintAllEntries( void ); +char *BPyMenu_CreatePupmenuStr( BPyMenu * pym, short group ); +char *BPyMenu_group_itoa( short group ); +struct BPyMenu *BPyMenu_GetEntry( short group, short pos ); + +#endif /* BPY_MENUS_H */ diff --git a/source/blender/python/CMakeLists.txt b/source/blender/python/CMakeLists.txt index 7700e6bc2aa..d15970e1df4 100644 --- a/source/blender/python/CMakeLists.txt +++ b/source/blender/python/CMakeLists.txt @@ -24,12 +24,10 @@ # ***** END GPL LICENSE BLOCK ***** FILE(GLOB SRC intern/*.c) -FILE(GLOB GENSRC generic/*.c) SET(INC . ../../../intern/guardedalloc ../blenlib ../makesdna ../makesrna ../blenkernel ../editors/include ../windowmanager ${PYTHON_INC} - ../../../extern/glew/include ) IF(WITH_OPENEXR) @@ -49,5 +47,3 @@ ENDIF(WITH_FFMPEG) ADD_DEFINITIONS(-DWITH_CCGSUBSURF) BLENDERLIB(bf_python "${SRC}" "${INC}") -BLENDERLIB(bf_gen_python "${GENSRC}" "${INC}") - diff --git a/source/blender/python/Makefile b/source/blender/python/Makefile index 8e2a04b8449..c830fbb3ccf 100644 --- a/source/blender/python/Makefile +++ b/source/blender/python/Makefile @@ -1,5 +1,5 @@ # -# $Id$ +# $Id: Makefile 14444 2008-04-16 22:40:48Z hos $ # # ***** BEGIN GPL LICENSE BLOCK ***** # @@ -29,6 +29,6 @@ # Bounces make to subdirectories. SOURCEDIR = source/blender/python -DIRS = intern generic +DIRS = intern include nan_subdirs.mk diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript index 73dc171fc3e..9d7fcf6a9cf 100644 --- a/source/blender/python/SConscript +++ b/source/blender/python/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('intern/*.c') incs = '. ../editors/include ../makesdna ../makesrna ../blenlib ../blenkernel ../nodes' incs += ' ../imbuf ../blenloader ../render/extern/include ../windowmanager' -incs += ' #intern/guardedalloc #intern/memutil #extern/glew/include' +incs += ' #intern/guardedalloc #intern/memutil' incs += ' ' + env['BF_PYTHON_INC'] defs = [] @@ -15,7 +15,3 @@ if env['OURPLATFORM'] in ('win32-mingw', 'win32-vc') and env['BF_DEBUG']: env.BlenderLib( libname = 'bf_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core'], priority = [140]) - -# generic -sources = env.Glob('generic/*.c') -env.BlenderLib( libname = 'bf_gen_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core'], priority = [361]) # ketsji is 360 diff --git a/source/blender/python/generic/BGL.c b/source/blender/python/generic/BGL.c deleted file mode 100644 index de82781cf3a..00000000000 --- a/source/blender/python/generic/BGL.c +++ /dev/null @@ -1,1610 +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. - * - * This is a new part of Blender. - * - * Contributor(s): Willian P. Germano - * - * ***** END GPL LICENSE BLOCK ***** -*/ - -/* This file is the Blender.BGL part of opy_draw.c, from the old - * bpython/intern dir, with minor changes to adapt it to the new Python - * implementation. The BGL submodule "wraps" OpenGL functions and constants, - * allowing script writers to make OpenGL calls in their Python scripts. */ - -#include "BGL.h" /*This must come first */ - -#include "MEM_guardedalloc.h" - -static int type_size( int type ); -static Buffer *make_buffer( int type, int ndimensions, int *dimensions ); - -static char Method_Buffer_doc[] = - "(type, dimensions, [template]) - Create a new Buffer object\n\n\ -(type) - The format to store data in\n\ -(dimensions) - An int or sequence specifying the dimensions of the buffer\n\ -[template] - A sequence of matching dimensions to the buffer to be created\n\ - which will be used to initialize the Buffer.\n\n\ -If a template is not passed in all fields will be initialized to 0.\n\n\ -The type should be one of GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, or GL_DOUBLE.\n\ -If the dimensions are specified as an int a linear buffer will be\n\ -created. If a sequence is passed for the dimensions the buffer\n\ -will have len(sequence) dimensions, where the size for each dimension\n\ -is determined by the value in the sequence at that index.\n\n\ -For example, passing [100, 100] will create a 2 dimensional\n\ -square buffer. Passing [16, 16, 32] will create a 3 dimensional\n\ -buffer which is twice as deep as it is wide or high."; - -static PyObject *Method_Buffer( PyObject * self, PyObject * args ); - -/* Buffer sequence methods */ - -static int Buffer_len( PyObject * self ); -static PyObject *Buffer_item( PyObject * self, int i ); -static PyObject *Buffer_slice( PyObject * self, int begin, int end ); -static int Buffer_ass_item( PyObject * self, int i, PyObject * v ); -static int Buffer_ass_slice( PyObject * self, int begin, int end, - PyObject * seq ); - -static PySequenceMethods Buffer_SeqMethods = { - ( inquiry ) Buffer_len, /*sq_length */ - ( binaryfunc ) 0, /*sq_concat */ - ( ssizeargfunc ) 0, /*sq_repeat */ - ( ssizeargfunc ) Buffer_item, /*sq_item */ - ( ssizessizeargfunc ) Buffer_slice, /*sq_slice */ - ( ssizeobjargproc ) Buffer_ass_item, /*sq_ass_item */ - ( ssizessizeobjargproc ) Buffer_ass_slice, /*sq_ass_slice */ -}; - -static void Buffer_dealloc( PyObject * self ); -static PyObject *Buffer_tolist( PyObject * self ); -static PyObject *Buffer_dimensions( PyObject * self ); -static PyObject *Buffer_getattr( PyObject * self, char *name ); -static PyObject *Buffer_repr( PyObject * self ); - -PyTypeObject buffer_Type = { -#if (PY_VERSION_HEX >= 0x02060000) - PyVarObject_HEAD_INIT(NULL, 0) -#else - /* python 2.5 and below */ - PyObject_HEAD_INIT( NULL ) /* required py macro */ - 0, /* ob_size */ -#endif - "buffer", /*tp_name */ - sizeof( Buffer ), /*tp_basicsize */ - 0, /*tp_itemsize */ - ( destructor ) Buffer_dealloc, /*tp_dealloc */ - ( printfunc ) 0, /*tp_print */ - ( getattrfunc ) Buffer_getattr, /*tp_getattr */ - ( setattrfunc ) 0, /*tp_setattr */ - 0, /*tp_compare */ - ( reprfunc ) Buffer_repr, /*tp_repr */ - 0, /*tp_as_number */ - &Buffer_SeqMethods, /*tp_as_sequence */ -}; - -/* #ifndef __APPLE__ */ - -#define BGL_Wrap(nargs, funcname, ret, arg_list) \ -static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\ - arg_def##nargs arg_list; \ - ret_def_##ret; \ - if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\ - ret_set_##ret gl##funcname (arg_var##nargs arg_list);\ - ret_ret_##ret; \ -} - -#define BGLU_Wrap(nargs, funcname, ret, arg_list) \ -static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\ - arg_def##nargs arg_list; \ - ret_def_##ret; \ - if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\ - ret_set_##ret glu##funcname (arg_var##nargs arg_list);\ - ret_ret_##ret; \ -} - -/* #endif */ - -/********/ -static int type_size(int type) -{ - switch (type) { - case GL_BYTE: - return sizeof(char); - case GL_SHORT: - return sizeof(short); - case GL_INT: - return sizeof(int); - case GL_FLOAT: - return sizeof(float); - case GL_DOUBLE: - return sizeof(double); - } - return -1; -} - -static Buffer *make_buffer(int type, int ndimensions, int *dimensions) -{ - Buffer *buffer; - void *buf= NULL; - int i, size, length; - - length= 1; - for (i=0; i<ndimensions; i++) - length*= dimensions[i]; - - size= type_size(type); - - buf= MEM_mallocN(length*size, "Buffer buffer"); - - buffer= (Buffer *) PyObject_NEW(Buffer, &buffer_Type); - buffer->parent= NULL; - buffer->ndimensions= ndimensions; - buffer->dimensions= dimensions; - buffer->type= type; - buffer->buf.asvoid= buf; - - for (i= 0; i<length; i++) { - if (type==GL_BYTE) - buffer->buf.asbyte[i]= 0; - else if (type==GL_SHORT) - buffer->buf.asshort[i]= 0; - else if (type==GL_INT) - buffer->buf.asint[i]= 0; - else if (type==GL_FLOAT) - buffer->buf.asfloat[i]= 0.0f; - else if (type==GL_DOUBLE) - buffer->buf.asdouble[i]= 0.0; - } - return buffer; -} - -static PyObject *Method_Buffer (PyObject *self, PyObject *args) -{ - PyObject *length_ob= NULL, *template= NULL; - Buffer *buffer; - - int i, type; - int *dimensions = 0, ndimensions = 0; - - if (!PyArg_ParseTuple(args, "iO|O", &type, &length_ob, &template)) { - PyErr_SetString(PyExc_AttributeError, "expected an int and one or two PyObjects"); - return NULL; - } - if (type!=GL_BYTE && type!=GL_SHORT && type!=GL_INT && type!=GL_FLOAT && type!=GL_DOUBLE) { - PyErr_SetString(PyExc_AttributeError, "invalid first argument type, should be one of GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT or GL_DOUBLE"); - return NULL; - } - - if (PyNumber_Check(length_ob)) { - ndimensions= 1; - dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions"); - dimensions[0]= PyLong_AsLong(length_ob); - } else if (PySequence_Check(length_ob)) { - ndimensions= PySequence_Length(length_ob); - dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions"); - for (i=0; i<ndimensions; i++) { - PyObject *ob= PySequence_GetItem(length_ob, i); - - if (!PyNumber_Check(ob)) dimensions[i]= 1; - else dimensions[i]= PyLong_AsLong(ob); - Py_DECREF(ob); - } - } - - buffer= make_buffer(type, ndimensions, dimensions); - if (template && ndimensions) { - if (Buffer_ass_slice((PyObject *) buffer, 0, dimensions[0], template)) { - Py_DECREF(buffer); - return NULL; - } - } - - return (PyObject *) buffer; -} - -/*@ Buffer sequence methods */ - -static int Buffer_len(PyObject *self) -{ - Buffer *buf= (Buffer *) self; - return buf->dimensions[0]; -} - -static PyObject *Buffer_item(PyObject *self, int i) -{ - Buffer *buf= (Buffer *) self; - - if (i >= buf->dimensions[0]) { - PyErr_SetString(PyExc_IndexError, "array index out of range"); - return NULL; - } - - if (buf->ndimensions==1) { - switch (buf->type) { - case GL_BYTE: return Py_BuildValue("b", buf->buf.asbyte[i]); - case GL_SHORT: return Py_BuildValue("h", buf->buf.asshort[i]); - case GL_INT: return Py_BuildValue("i", buf->buf.asint[i]); - case GL_FLOAT: return PyFloat_FromDouble(buf->buf.asfloat[i]); - case GL_DOUBLE: return Py_BuildValue("d", buf->buf.asdouble[i]); - } - } else { - Buffer *newbuf; - int j, length, size; - - length= 1; - for (j=1; j<buf->ndimensions; j++) { - length*= buf->dimensions[j]; - } - size= type_size(buf->type); - - newbuf= (Buffer *) PyObject_NEW(Buffer, &buffer_Type); - - Py_INCREF(self); - newbuf->parent= self; - - newbuf->ndimensions= buf->ndimensions-1; - newbuf->type= buf->type; - newbuf->buf.asvoid= buf->buf.asbyte + i*length*size; - newbuf->dimensions= MEM_mallocN(newbuf->ndimensions*sizeof(int), - "Buffer dimensions"); - memcpy(newbuf->dimensions, buf->dimensions+1, - newbuf->ndimensions*sizeof(int)); - - return (PyObject *) newbuf; - } - - return NULL; -} - -static PyObject *Buffer_slice(PyObject *self, int begin, int end) -{ - Buffer *buf= (Buffer *) self; - PyObject *list; - int count; - - if (begin<0) begin= 0; - if (end>buf->dimensions[0]) - end= buf->dimensions[0]; - if (begin>end) begin= end; - - list= PyList_New(end-begin); - - for (count= begin; count<end; count++) - PyList_SetItem(list, count-begin, Buffer_item(self, count)); - - return list; -} - -static int Buffer_ass_item(PyObject *self, int i, PyObject *v) -{ - Buffer *buf= (Buffer *) self; - - if (i >= buf->dimensions[0]) { - PyErr_SetString(PyExc_IndexError, "array assignment index out of range"); - return -1; - } - - if (buf->ndimensions!=1) { - PyObject *row= Buffer_item(self, i); - int ret; - - if (!row) return -1; - ret= Buffer_ass_slice(row, 0, buf->dimensions[1], v); - Py_DECREF(row); - return ret; - } - - if (buf->type==GL_BYTE) { - if (!PyArg_Parse(v, "b;Coordinates must be ints", &buf->buf.asbyte[i])) - return -1; - } else if (buf->type==GL_SHORT) { - if (!PyArg_Parse(v, "h;Coordinates must be ints", &buf->buf.asshort[i])) - return -1; - - } else if (buf->type==GL_INT) { - if (!PyArg_Parse(v, "i;Coordinates must be ints", &buf->buf.asint[i])) - return -1; - } else if (buf->type==GL_FLOAT) { - if (!PyArg_Parse(v, "f;Coordinates must be floats", &buf->buf.asfloat[i])) - return -1; - } else if (buf->type==GL_DOUBLE) { - if (!PyArg_Parse(v, "d;Coordinates must be floats", &buf->buf.asdouble[i])) - return -1; - } - return 0; -} - -static int Buffer_ass_slice(PyObject *self, int begin, int end, PyObject *seq) -{ - Buffer *buf= (Buffer *) self; - PyObject *item; - int count, err=0; - - if (begin<0) begin= 0; - if (end>buf->dimensions[0]) end= buf->dimensions[0]; - if (begin>end) begin= end; - - if (!PySequence_Check(seq)) { - PyErr_SetString(PyExc_TypeError, - "illegal argument type for built-in operation"); - return -1; - } - - if (PySequence_Length(seq)!=(end-begin)) { - PyErr_SetString(PyExc_TypeError, "size mismatch in assignment"); - return -1; - } - - for (count= begin; count<end; count++) { - item= PySequence_GetItem(seq, count-begin); - err= Buffer_ass_item(self, count, item); - Py_DECREF(item); - if (err) break; - } - return err; -} - -static void Buffer_dealloc(PyObject *self) -{ - Buffer *buf = (Buffer *)self; - - if (buf->parent) Py_DECREF (buf->parent); - else MEM_freeN (buf->buf.asvoid); - - MEM_freeN (buf->dimensions); - - PyObject_DEL (self); -} - -static PyObject *Buffer_tolist(PyObject *self) -{ - int i, len= ((Buffer *)self)->dimensions[0]; - PyObject *list= PyList_New(len); - - for (i=0; i<len; i++) { - PyList_SetItem(list, i, Buffer_item(self, i)); - } - - return list; -} - -static PyObject *Buffer_dimensions(PyObject *self) -{ - Buffer *buffer= (Buffer *) self; - PyObject *list= PyList_New(buffer->ndimensions); - int i; - - for (i= 0; i<buffer->ndimensions; i++) { - PyList_SetItem(list, i, PyLong_FromLong(buffer->dimensions[i])); - } - - return list; -} - -static PyObject *Buffer_getattr(PyObject *self, char *name) -{ - if (strcmp(name, "list")==0) return Buffer_tolist(self); - else if (strcmp(name, "dimensions")==0) return Buffer_dimensions(self); - - PyErr_SetString(PyExc_AttributeError, name); - return NULL; -} - -static PyObject *Buffer_repr(PyObject *self) -{ - PyObject *list= Buffer_tolist(self); - PyObject *repr= PyObject_Repr(list); - Py_DECREF(list); - - return repr; -} - - -BGL_Wrap(2, Accum, void, (GLenum, GLfloat)) -BGL_Wrap(2, AlphaFunc, void, (GLenum, GLclampf)) -BGL_Wrap(3, AreTexturesResident, GLboolean, (GLsizei, GLuintP, GLbooleanP)) -BGL_Wrap(1, Begin, void, (GLenum)) -BGL_Wrap(2, BindTexture, void, (GLenum, GLuint)) -BGL_Wrap(7, Bitmap, void, (GLsizei, GLsizei, GLfloat, - GLfloat, GLfloat, GLfloat, GLubyteP)) -BGL_Wrap(2, BlendFunc, void, (GLenum, GLenum)) -BGL_Wrap(1, CallList, void, (GLuint)) -BGL_Wrap(3, CallLists, void, (GLsizei, GLenum, GLvoidP)) -BGL_Wrap(1, Clear, void, (GLbitfield)) -BGL_Wrap(4, ClearAccum, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(4, ClearColor, void, (GLclampf, GLclampf, GLclampf, GLclampf)) -BGL_Wrap(1, ClearDepth, void, (GLclampd)) -BGL_Wrap(1, ClearIndex, void, (GLfloat)) -BGL_Wrap(1, ClearStencil, void, (GLint)) -BGL_Wrap(2, ClipPlane, void, (GLenum, GLdoubleP)) -BGL_Wrap(3, Color3b, void, (GLbyte, GLbyte, GLbyte)) -BGL_Wrap(1, Color3bv, void, (GLbyteP)) -BGL_Wrap(3, Color3d, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(1, Color3dv, void, (GLdoubleP)) -BGL_Wrap(3, Color3f, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(1, Color3fv, void, (GLfloatP)) -BGL_Wrap(3, Color3i, void, (GLint, GLint, GLint)) -BGL_Wrap(1, Color3iv, void, (GLintP)) -BGL_Wrap(3, Color3s, void, (GLshort, GLshort, GLshort)) -BGL_Wrap(1, Color3sv, void, (GLshortP)) -BGL_Wrap(3, Color3ub, void, (GLubyte, GLubyte, GLubyte)) -BGL_Wrap(1, Color3ubv, void, (GLubyteP)) -BGL_Wrap(3, Color3ui, void, (GLuint, GLuint, GLuint)) -BGL_Wrap(1, Color3uiv, void, (GLuintP)) -BGL_Wrap(3, Color3us, void, (GLushort, GLushort, GLushort)) -BGL_Wrap(1, Color3usv, void, (GLushortP)) -BGL_Wrap(4, Color4b, void, (GLbyte, GLbyte, GLbyte, GLbyte)) -BGL_Wrap(1, Color4bv, void, (GLbyteP)) -BGL_Wrap(4, Color4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(1, Color4dv, void, (GLdoubleP)) -BGL_Wrap(4, Color4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(1, Color4fv, void, (GLfloatP)) -BGL_Wrap(4, Color4i, void, (GLint, GLint, GLint, GLint)) -BGL_Wrap(1, Color4iv, void, (GLintP)) -BGL_Wrap(4, Color4s, void, (GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(1, Color4sv, void, (GLshortP)) -BGL_Wrap(4, Color4ub, void, (GLubyte, GLubyte, GLubyte, GLubyte)) -BGL_Wrap(1, Color4ubv, void, (GLubyteP)) -BGL_Wrap(4, Color4ui, void, (GLuint, GLuint, GLuint, GLuint)) -BGL_Wrap(1, Color4uiv, void, (GLuintP)) -BGL_Wrap(4, Color4us, void, (GLushort, GLushort, GLushort, GLushort)) -BGL_Wrap(1, Color4usv, void, (GLushortP)) -BGL_Wrap(4, ColorMask, void, (GLboolean, GLboolean, GLboolean, GLboolean)) -BGL_Wrap(2, ColorMaterial, void, (GLenum, GLenum)) -BGL_Wrap(5, CopyPixels, void, (GLint, GLint, GLsizei, GLsizei, GLenum)) -BGL_Wrap(1, CullFace, void, (GLenum)) -BGL_Wrap(2, DeleteLists, void, (GLuint, GLsizei)) -BGL_Wrap(2, DeleteTextures, void, (GLsizei, GLuintP)) -BGL_Wrap(1, DepthFunc, void, (GLenum)) -BGL_Wrap(1, DepthMask, void, (GLboolean)) -BGL_Wrap(2, DepthRange, void, (GLclampd, GLclampd)) -BGL_Wrap(1, Disable, void, (GLenum)) -BGL_Wrap(1, DrawBuffer, void, (GLenum)) -BGL_Wrap(5, DrawPixels, void, (GLsizei, GLsizei, GLenum, GLenum, GLvoidP)) -BGL_Wrap(1, EdgeFlag, void, (GLboolean)) -BGL_Wrap(1, EdgeFlagv, void, (GLbooleanP)) -BGL_Wrap(1, Enable, void, (GLenum)) -BGL_Wrap(1, End, void, (void)) -BGL_Wrap(1, EndList, void, (void)) -BGL_Wrap(1, EvalCoord1d, void, (GLdouble)) -BGL_Wrap(1, EvalCoord1dv, void, (GLdoubleP)) -BGL_Wrap(1, EvalCoord1f, void, (GLfloat)) -BGL_Wrap(1, EvalCoord1fv, void, (GLfloatP)) -BGL_Wrap(2, EvalCoord2d, void, (GLdouble, GLdouble)) -BGL_Wrap(1, EvalCoord2dv, void, (GLdoubleP)) -BGL_Wrap(2, EvalCoord2f, void, (GLfloat, GLfloat)) -BGL_Wrap(1, EvalCoord2fv, void, (GLfloatP)) -BGL_Wrap(3, EvalMesh1, void, (GLenum, GLint, GLint)) -BGL_Wrap(5, EvalMesh2, void, (GLenum, GLint, GLint, GLint, GLint)) -BGL_Wrap(1, EvalPoint1, void, (GLint)) -BGL_Wrap(2, EvalPoint2, void, (GLint, GLint)) -BGL_Wrap(3, FeedbackBuffer, void, (GLsizei, GLenum, GLfloatP)) -BGL_Wrap(1, Finish, void, (void)) -BGL_Wrap(1, Flush, void, (void)) -BGL_Wrap(2, Fogf, void, (GLenum, GLfloat)) -BGL_Wrap(2, Fogfv, void, (GLenum, GLfloatP)) -BGL_Wrap(2, Fogi, void, (GLenum, GLint)) -BGL_Wrap(2, Fogiv, void, (GLenum, GLintP)) -BGL_Wrap(1, FrontFace, void, (GLenum)) -BGL_Wrap(6, Frustum, void, (GLdouble, GLdouble, - GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(1, GenLists, GLuint, (GLsizei)) -BGL_Wrap(2, GenTextures, void, (GLsizei, GLuintP)) -BGL_Wrap(2, GetBooleanv, void, (GLenum, GLbooleanP)) -BGL_Wrap(2, GetClipPlane, void, (GLenum, GLdoubleP)) -BGL_Wrap(2, GetDoublev, void, (GLenum, GLdoubleP)) -BGL_Wrap(1, GetError, GLenum, (void)) -BGL_Wrap(2, GetFloatv, void, (GLenum, GLfloatP)) -BGL_Wrap(2, GetIntegerv, void, (GLenum, GLintP)) -BGL_Wrap(3, GetLightfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(3, GetLightiv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(3, GetMapdv, void, (GLenum, GLenum, GLdoubleP)) -BGL_Wrap(3, GetMapfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(3, GetMapiv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(3, GetMaterialfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(3, GetMaterialiv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(2, GetPixelMapfv, void, (GLenum, GLfloatP)) -BGL_Wrap(2, GetPixelMapuiv, void, (GLenum, GLuintP)) -BGL_Wrap(2, GetPixelMapusv, void, (GLenum, GLushortP)) -BGL_Wrap(1, GetPolygonStipple,void, (GLubyteP)) -BGL_Wrap(1, GetString, GLstring, (GLenum)) -BGL_Wrap(3, GetTexEnvfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(3, GetTexEnviv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(3, GetTexGendv, void, (GLenum, GLenum, GLdoubleP)) -BGL_Wrap(3, GetTexGenfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(3, GetTexGeniv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(5, GetTexImage, void, (GLenum, GLint, GLenum, GLenum, GLvoidP)) -BGL_Wrap(4, GetTexLevelParameterfv, void, (GLenum, GLint, GLenum, GLfloatP)) -BGL_Wrap(4, GetTexLevelParameteriv, void, (GLenum, GLint, GLenum, GLintP)) -BGL_Wrap(3, GetTexParameterfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(3, GetTexParameteriv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(2, Hint, void, (GLenum, GLenum)) -BGL_Wrap(1, IndexMask, void, (GLuint)) -BGL_Wrap(1, Indexd, void, (GLdouble)) -BGL_Wrap(1, Indexdv, void, (GLdoubleP)) -BGL_Wrap(1, Indexf, void, (GLfloat)) -BGL_Wrap(1, Indexfv, void, (GLfloatP)) -BGL_Wrap(1, Indexi, void, (GLint)) -BGL_Wrap(1, Indexiv, void, (GLintP)) -BGL_Wrap(1, Indexs, void, (GLshort)) -BGL_Wrap(1, Indexsv, void, (GLshortP)) -BGL_Wrap(1, InitNames, void, (void)) -BGL_Wrap(1, IsEnabled, GLboolean, (GLenum)) -BGL_Wrap(1, IsList, GLboolean, (GLuint)) -BGL_Wrap(1, IsTexture, GLboolean, (GLuint)) -BGL_Wrap(2, LightModelf, void, (GLenum, GLfloat)) -BGL_Wrap(2, LightModelfv, void, (GLenum, GLfloatP)) -BGL_Wrap(2, LightModeli, void, (GLenum, GLint)) -BGL_Wrap(2, LightModeliv, void, (GLenum, GLintP)) -BGL_Wrap(3, Lightf, void, (GLenum, GLenum, GLfloat)) -BGL_Wrap(3, Lightfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(3, Lighti, void, (GLenum, GLenum, GLint)) -BGL_Wrap(3, Lightiv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(2, LineStipple, void, (GLint, GLushort)) -BGL_Wrap(1, LineWidth, void, (GLfloat)) -BGL_Wrap(1, ListBase, void, (GLuint)) -BGL_Wrap(1, LoadIdentity, void, (void)) -BGL_Wrap(1, LoadMatrixd, void, (GLdoubleP)) -BGL_Wrap(1, LoadMatrixf, void, (GLfloatP)) -BGL_Wrap(1, LoadName, void, (GLuint)) -BGL_Wrap(1, LogicOp, void, (GLenum)) -BGL_Wrap(6, Map1d, void, (GLenum, GLdouble, GLdouble, - GLint, GLint, GLdoubleP)) -BGL_Wrap(6, Map1f, void, (GLenum, GLfloat, GLfloat, - GLint, GLint, GLfloatP)) -BGL_Wrap(10, Map2d, void, (GLenum, GLdouble, GLdouble, - GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdoubleP)) -BGL_Wrap(10, Map2f, void, (GLenum, GLfloat, GLfloat, - GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloatP)) -BGL_Wrap(3, MapGrid1d, void, (GLint, GLdouble, GLdouble)) -BGL_Wrap(3, MapGrid1f, void, (GLint, GLfloat, GLfloat)) -BGL_Wrap(6, MapGrid2d, void, (GLint, GLdouble, GLdouble, - GLint, GLdouble, GLdouble)) -BGL_Wrap(6, MapGrid2f, void, (GLint, GLfloat, GLfloat, - GLint, GLfloat, GLfloat)) -BGL_Wrap(3, Materialf, void, (GLenum, GLenum, GLfloat)) -BGL_Wrap(3, Materialfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(3, Materiali, void, (GLenum, GLenum, GLint)) -BGL_Wrap(3, Materialiv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(1, MatrixMode, void, (GLenum)) -BGL_Wrap(1, MultMatrixd, void, (GLdoubleP)) -BGL_Wrap(1, MultMatrixf, void, (GLfloatP)) -BGL_Wrap(2, NewList, void, (GLuint, GLenum)) -BGL_Wrap(3, Normal3b, void, (GLbyte, GLbyte, GLbyte)) -BGL_Wrap(1, Normal3bv, void, (GLbyteP)) -BGL_Wrap(3, Normal3d, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(1, Normal3dv, void, (GLdoubleP)) -BGL_Wrap(3, Normal3f, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(1, Normal3fv, void, (GLfloatP)) -BGL_Wrap(3, Normal3i, void, (GLint, GLint, GLint)) -BGL_Wrap(1, Normal3iv, void, (GLintP)) -BGL_Wrap(3, Normal3s, void, (GLshort, GLshort, GLshort)) -BGL_Wrap(1, Normal3sv, void, (GLshortP)) -BGL_Wrap(6, Ortho, void, (GLdouble, GLdouble, - GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(1, PassThrough, void, (GLfloat)) -BGL_Wrap(3, PixelMapfv, void, (GLenum, GLint, GLfloatP)) -BGL_Wrap(3, PixelMapuiv, void, (GLenum, GLint, GLuintP)) -BGL_Wrap(3, PixelMapusv, void, (GLenum, GLint, GLushortP)) -BGL_Wrap(2, PixelStoref, void, (GLenum, GLfloat)) -BGL_Wrap(2, PixelStorei, void, (GLenum, GLint)) -BGL_Wrap(2, PixelTransferf, void, (GLenum, GLfloat)) -BGL_Wrap(2, PixelTransferi, void, (GLenum, GLint)) -BGL_Wrap(2, PixelZoom, void, (GLfloat, GLfloat)) -BGL_Wrap(1, PointSize, void, (GLfloat)) -BGL_Wrap(2, PolygonMode, void, (GLenum, GLenum)) -BGL_Wrap(2, PolygonOffset, void, (GLfloat, GLfloat)) -BGL_Wrap(1, PolygonStipple, void, (GLubyteP)) -BGL_Wrap(1, PopAttrib, void, (void)) -BGL_Wrap(1, PopClientAttrib, void, (void)) -BGL_Wrap(1, PopMatrix, void, (void)) -BGL_Wrap(1, PopName, void, (void)) -BGL_Wrap(3, PrioritizeTextures, void, (GLsizei, GLuintP, GLclampfP)) -BGL_Wrap(1, PushAttrib, void, (GLbitfield)) -BGL_Wrap(1, PushClientAttrib, void, (GLbitfield)) -BGL_Wrap(1, PushMatrix, void, (void)) -BGL_Wrap(1, PushName, void, (GLuint)) -BGL_Wrap(2, RasterPos2d, void, (GLdouble, GLdouble)) -BGL_Wrap(1, RasterPos2dv, void, (GLdoubleP)) -BGL_Wrap(2, RasterPos2f, void, (GLfloat, GLfloat)) -BGL_Wrap(1, RasterPos2fv, void, (GLfloatP)) -BGL_Wrap(2, RasterPos2i, void, (GLint, GLint)) -BGL_Wrap(1, RasterPos2iv, void, (GLintP)) -BGL_Wrap(2, RasterPos2s, void, (GLshort, GLshort)) -BGL_Wrap(1, RasterPos2sv, void, (GLshortP)) -BGL_Wrap(3, RasterPos3d, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(1, RasterPos3dv, void, (GLdoubleP)) -BGL_Wrap(3, RasterPos3f, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(1, RasterPos3fv, void, (GLfloatP)) -BGL_Wrap(3, RasterPos3i, void, (GLint, GLint, GLint)) -BGL_Wrap(1, RasterPos3iv, void, (GLintP)) -BGL_Wrap(3, RasterPos3s, void, (GLshort, GLshort, GLshort)) -BGL_Wrap(1, RasterPos3sv, void, (GLshortP)) -BGL_Wrap(4, RasterPos4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(1, RasterPos4dv, void, (GLdoubleP)) -BGL_Wrap(4, RasterPos4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(1, RasterPos4fv, void, (GLfloatP)) -BGL_Wrap(4, RasterPos4i, void, (GLint, GLint, GLint, GLint)) -BGL_Wrap(1, RasterPos4iv, void, (GLintP)) -BGL_Wrap(4, RasterPos4s, void, (GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(1, RasterPos4sv, void, (GLshortP)) -BGL_Wrap(1, ReadBuffer, void, (GLenum)) -BGL_Wrap(7, ReadPixels, void, (GLint, GLint, GLsizei, - GLsizei, GLenum, GLenum, GLvoidP)) -BGL_Wrap(4, Rectd, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(2, Rectdv, void, (GLdoubleP, GLdoubleP)) -BGL_Wrap(4, Rectf, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(2, Rectfv, void, (GLfloatP, GLfloatP)) -BGL_Wrap(4, Recti, void, (GLint, GLint, GLint, GLint)) -BGL_Wrap(2, Rectiv, void, (GLintP, GLintP)) -BGL_Wrap(4, Rects, void, (GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(2, Rectsv, void, (GLshortP, GLshortP)) -BGL_Wrap(1, RenderMode, GLint, (GLenum)) -BGL_Wrap(4, Rotated, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(4, Rotatef, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(3, Scaled, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(3, Scalef, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(4, Scissor, void, (GLint, GLint, GLsizei, GLsizei)) -BGL_Wrap(2, SelectBuffer, void, (GLsizei, GLuintP)) -BGL_Wrap(1, ShadeModel, void, (GLenum)) -BGL_Wrap(3, StencilFunc, void, (GLenum, GLint, GLuint)) -BGL_Wrap(1, StencilMask, void, (GLuint)) -BGL_Wrap(3, StencilOp, void, (GLenum, GLenum, GLenum)) -BGL_Wrap(1, TexCoord1d, void, (GLdouble)) -BGL_Wrap(1, TexCoord1dv, void, (GLdoubleP)) -BGL_Wrap(1, TexCoord1f, void, (GLfloat)) -BGL_Wrap(1, TexCoord1fv, void, (GLfloatP)) -BGL_Wrap(1, TexCoord1i, void, (GLint)) -BGL_Wrap(1, TexCoord1iv, void, (GLintP)) -BGL_Wrap(1, TexCoord1s, void, (GLshort)) -BGL_Wrap(1, TexCoord1sv, void, (GLshortP)) -BGL_Wrap(2, TexCoord2d, void, (GLdouble, GLdouble)) -BGL_Wrap(1, TexCoord2dv, void, (GLdoubleP)) -BGL_Wrap(2, TexCoord2f, void, (GLfloat, GLfloat)) -BGL_Wrap(1, TexCoord2fv, void, (GLfloatP)) -BGL_Wrap(2, TexCoord2i, void, (GLint, GLint)) -BGL_Wrap(1, TexCoord2iv, void, (GLintP)) -BGL_Wrap(2, TexCoord2s, void, (GLshort, GLshort)) -BGL_Wrap(1, TexCoord2sv, void, (GLshortP)) -BGL_Wrap(3, TexCoord3d, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(1, TexCoord3dv, void, (GLdoubleP)) -BGL_Wrap(3, TexCoord3f, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(1, TexCoord3fv, void, (GLfloatP)) -BGL_Wrap(3, TexCoord3i, void, (GLint, GLint, GLint)) -BGL_Wrap(1, TexCoord3iv, void, (GLintP)) -BGL_Wrap(3, TexCoord3s, void, (GLshort, GLshort, GLshort)) -BGL_Wrap(1, TexCoord3sv, void, (GLshortP)) -BGL_Wrap(4, TexCoord4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(1, TexCoord4dv, void, (GLdoubleP)) -BGL_Wrap(4, TexCoord4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(1, TexCoord4fv, void, (GLfloatP)) -BGL_Wrap(4, TexCoord4i, void, (GLint, GLint, GLint, GLint)) -BGL_Wrap(1, TexCoord4iv, void, (GLintP)) -BGL_Wrap(4, TexCoord4s, void, (GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(1, TexCoord4sv, void, (GLshortP)) -BGL_Wrap(3, TexEnvf, void, (GLenum, GLenum, GLfloat)) -BGL_Wrap(3, TexEnvfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(3, TexEnvi, void, (GLenum, GLenum, GLint)) -BGL_Wrap(3, TexEnviv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(3, TexGend, void, (GLenum, GLenum, GLdouble)) -BGL_Wrap(3, TexGendv, void, (GLenum, GLenum, GLdoubleP)) -BGL_Wrap(3, TexGenf, void, (GLenum, GLenum, GLfloat)) -BGL_Wrap(3, TexGenfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(3, TexGeni, void, (GLenum, GLenum, GLint)) -BGL_Wrap(3, TexGeniv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(8, TexImage1D, void, (GLenum, GLint, GLint, - GLsizei, GLint, GLenum, GLenum, GLvoidP)) -BGL_Wrap(9, TexImage2D, void, (GLenum, GLint, GLint, - GLsizei, GLsizei, GLint, GLenum, GLenum, GLvoidP)) -BGL_Wrap(3, TexParameterf, void, (GLenum, GLenum, GLfloat)) -BGL_Wrap(3, TexParameterfv, void, (GLenum, GLenum, GLfloatP)) -BGL_Wrap(3, TexParameteri, void, (GLenum, GLenum, GLint)) -BGL_Wrap(3, TexParameteriv, void, (GLenum, GLenum, GLintP)) -BGL_Wrap(3, Translated, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(3, Translatef, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(2, Vertex2d, void, (GLdouble, GLdouble)) -BGL_Wrap(1, Vertex2dv, void, (GLdoubleP)) -BGL_Wrap(2, Vertex2f, void, (GLfloat, GLfloat)) -BGL_Wrap(1, Vertex2fv, void, (GLfloatP)) -BGL_Wrap(2, Vertex2i, void, (GLint, GLint)) -BGL_Wrap(1, Vertex2iv, void, (GLintP)) -BGL_Wrap(2, Vertex2s, void, (GLshort, GLshort)) -BGL_Wrap(1, Vertex2sv, void, (GLshortP)) -BGL_Wrap(3, Vertex3d, void, (GLdouble, GLdouble, GLdouble)) -BGL_Wrap(1, Vertex3dv, void, (GLdoubleP)) -BGL_Wrap(3, Vertex3f, void, (GLfloat, GLfloat, GLfloat)) -BGL_Wrap(1, Vertex3fv, void, (GLfloatP)) -BGL_Wrap(3, Vertex3i, void, (GLint, GLint, GLint)) -BGL_Wrap(1, Vertex3iv, void, (GLintP)) -BGL_Wrap(3, Vertex3s, void, (GLshort, GLshort, GLshort)) -BGL_Wrap(1, Vertex3sv, void, (GLshortP)) -BGL_Wrap(4, Vertex4d, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGL_Wrap(1, Vertex4dv, void, (GLdoubleP)) -BGL_Wrap(4, Vertex4f, void, (GLfloat, GLfloat, GLfloat, GLfloat)) -BGL_Wrap(1, Vertex4fv, void, (GLfloatP)) -BGL_Wrap(4, Vertex4i, void, (GLint, GLint, GLint, GLint)) -BGL_Wrap(1, Vertex4iv, void, (GLintP)) -BGL_Wrap(4, Vertex4s, void, (GLshort, GLshort, GLshort, GLshort)) -BGL_Wrap(1, Vertex4sv, void, (GLshortP)) -BGL_Wrap(4, Viewport, void, (GLint, GLint, GLsizei, GLsizei)) -BGLU_Wrap(4, Perspective, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGLU_Wrap(9, LookAt, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble)) -BGLU_Wrap(4, Ortho2D, void, (GLdouble, GLdouble, GLdouble, GLdouble)) -BGLU_Wrap(5, PickMatrix, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLintP)) -BGLU_Wrap(9, Project, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP)) -BGLU_Wrap(9, UnProject, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP)) - -#undef MethodDef -#define MethodDef(func) {"gl"#func, Method_##func, METH_VARARGS, "no string"} -#define MethodDefu(func) {"glu"#func, Method_##func, METH_VARARGS, "no string"} -/* So that MethodDef(Accum) becomes: - * {"glAccum", Method_Accumfunc, METH_VARARGS} */ - -static struct PyMethodDef BGL_methods[] = { - {"Buffer", Method_Buffer, METH_VARARGS, Method_Buffer_doc}, - -/* #ifndef __APPLE__ */ - MethodDef(Accum), - MethodDef(AlphaFunc), - MethodDef(AreTexturesResident), - MethodDef(Begin), - MethodDef(BindTexture), - MethodDef(Bitmap), - MethodDef(BlendFunc), - MethodDef(CallList), - MethodDef(CallLists), - MethodDef(Clear), - MethodDef(ClearAccum), - MethodDef(ClearColor), - MethodDef(ClearDepth), - MethodDef(ClearIndex), - MethodDef(ClearStencil), - MethodDef(ClipPlane), - MethodDef(Color3b), - MethodDef(Color3bv), - MethodDef(Color3d), - MethodDef(Color3dv), - MethodDef(Color3f), - MethodDef(Color3fv), - MethodDef(Color3i), - MethodDef(Color3iv), - MethodDef(Color3s), - MethodDef(Color3sv), - MethodDef(Color3ub), - MethodDef(Color3ubv), - MethodDef(Color3ui), - MethodDef(Color3uiv), - MethodDef(Color3us), - MethodDef(Color3usv), - MethodDef(Color4b), - MethodDef(Color4bv), - MethodDef(Color4d), - MethodDef(Color4dv), - MethodDef(Color4f), - MethodDef(Color4fv), - MethodDef(Color4i), - MethodDef(Color4iv), - MethodDef(Color4s), - MethodDef(Color4sv), - MethodDef(Color4ub), - MethodDef(Color4ubv), - MethodDef(Color4ui), - MethodDef(Color4uiv), - MethodDef(Color4us), - MethodDef(Color4usv), - MethodDef(ColorMask), - MethodDef(ColorMaterial), - MethodDef(CopyPixels), - MethodDef(CullFace), - MethodDef(DeleteLists), - MethodDef(DeleteTextures), - MethodDef(DepthFunc), - MethodDef(DepthMask), - MethodDef(DepthRange), - MethodDef(Disable), - MethodDef(DrawBuffer), - MethodDef(DrawPixels), - MethodDef(EdgeFlag), - MethodDef(EdgeFlagv), - MethodDef(Enable), - MethodDef(End), - MethodDef(EndList), - MethodDef(EvalCoord1d), - MethodDef(EvalCoord1dv), - MethodDef(EvalCoord1f), - MethodDef(EvalCoord1fv), - MethodDef(EvalCoord2d), - MethodDef(EvalCoord2dv), - MethodDef(EvalCoord2f), - MethodDef(EvalCoord2fv), - MethodDef(EvalMesh1), - MethodDef(EvalMesh2), - MethodDef(EvalPoint1), - MethodDef(EvalPoint2), - MethodDef(FeedbackBuffer), - MethodDef(Finish), - MethodDef(Flush), - MethodDef(Fogf), - MethodDef(Fogfv), - MethodDef(Fogi), - MethodDef(Fogiv), - MethodDef(FrontFace), - MethodDef(Frustum), - MethodDef(GenLists), - MethodDef(GenTextures), - MethodDef(GetBooleanv), - MethodDef(GetClipPlane), - MethodDef(GetDoublev), - MethodDef(GetError), - MethodDef(GetFloatv), - MethodDef(GetIntegerv), - MethodDef(GetLightfv), - MethodDef(GetLightiv), - MethodDef(GetMapdv), - MethodDef(GetMapfv), - MethodDef(GetMapiv), - MethodDef(GetMaterialfv), - MethodDef(GetMaterialiv), - MethodDef(GetPixelMapfv), - MethodDef(GetPixelMapuiv), - MethodDef(GetPixelMapusv), - MethodDef(GetPolygonStipple), - MethodDef(GetString), - MethodDef(GetTexEnvfv), - MethodDef(GetTexEnviv), - MethodDef(GetTexGendv), - MethodDef(GetTexGenfv), - MethodDef(GetTexGeniv), - MethodDef(GetTexImage), - MethodDef(GetTexLevelParameterfv), - MethodDef(GetTexLevelParameteriv), - MethodDef(GetTexParameterfv), - MethodDef(GetTexParameteriv), - MethodDef(Hint), - MethodDef(IndexMask), - MethodDef(Indexd), - MethodDef(Indexdv), - MethodDef(Indexf), - MethodDef(Indexfv), - MethodDef(Indexi), - MethodDef(Indexiv), - MethodDef(Indexs), - MethodDef(Indexsv), - MethodDef(InitNames), - MethodDef(IsEnabled), - MethodDef(IsList), - MethodDef(IsTexture), - MethodDef(LightModelf), - MethodDef(LightModelfv), - MethodDef(LightModeli), - MethodDef(LightModeliv), - MethodDef(Lightf), - MethodDef(Lightfv), - MethodDef(Lighti), - MethodDef(Lightiv), - MethodDef(LineStipple), - MethodDef(LineWidth), - MethodDef(ListBase), - MethodDef(LoadIdentity), - MethodDef(LoadMatrixd), - MethodDef(LoadMatrixf), - MethodDef(LoadName), - MethodDef(LogicOp), - MethodDef(Map1d), - MethodDef(Map1f), - MethodDef(Map2d), - MethodDef(Map2f), - MethodDef(MapGrid1d), - MethodDef(MapGrid1f), - MethodDef(MapGrid2d), - MethodDef(MapGrid2f), - MethodDef(Materialf), - MethodDef(Materialfv), - MethodDef(Materiali), - MethodDef(Materialiv), - MethodDef(MatrixMode), - MethodDef(MultMatrixd), - MethodDef(MultMatrixf), - MethodDef(NewList), - MethodDef(Normal3b), - MethodDef(Normal3bv), - MethodDef(Normal3d), - MethodDef(Normal3dv), - MethodDef(Normal3f), - MethodDef(Normal3fv), - MethodDef(Normal3i), - MethodDef(Normal3iv), - MethodDef(Normal3s), - MethodDef(Normal3sv), - MethodDef(Ortho), - MethodDef(PassThrough), - MethodDef(PixelMapfv), - MethodDef(PixelMapuiv), - MethodDef(PixelMapusv), - MethodDef(PixelStoref), - MethodDef(PixelStorei), - MethodDef(PixelTransferf), - MethodDef(PixelTransferi), - MethodDef(PixelZoom), - MethodDef(PointSize), - MethodDef(PolygonMode), - MethodDef(PolygonOffset), - MethodDef(PolygonStipple), - MethodDef(PopAttrib), - MethodDef(PopClientAttrib), - MethodDef(PopMatrix), - MethodDef(PopName), - MethodDef(PrioritizeTextures), - MethodDef(PushAttrib), - MethodDef(PushClientAttrib), - MethodDef(PushMatrix), - MethodDef(PushName), - MethodDef(RasterPos2d), - MethodDef(RasterPos2dv), - MethodDef(RasterPos2f), - MethodDef(RasterPos2fv), - MethodDef(RasterPos2i), - MethodDef(RasterPos2iv), - MethodDef(RasterPos2s), - MethodDef(RasterPos2sv), - MethodDef(RasterPos3d), - MethodDef(RasterPos3dv), - MethodDef(RasterPos3f), - MethodDef(RasterPos3fv), - MethodDef(RasterPos3i), - MethodDef(RasterPos3iv), - MethodDef(RasterPos3s), - MethodDef(RasterPos3sv), - MethodDef(RasterPos4d), - MethodDef(RasterPos4dv), - MethodDef(RasterPos4f), - MethodDef(RasterPos4fv), - MethodDef(RasterPos4i), - MethodDef(RasterPos4iv), - MethodDef(RasterPos4s), - MethodDef(RasterPos4sv), - MethodDef(ReadBuffer), - MethodDef(ReadPixels), - MethodDef(Rectd), - MethodDef(Rectdv), - MethodDef(Rectf), - MethodDef(Rectfv), - MethodDef(Recti), - MethodDef(Rectiv), - MethodDef(Rects), - MethodDef(Rectsv), - MethodDef(RenderMode), - MethodDef(Rotated), - MethodDef(Rotatef), - MethodDef(Scaled), - MethodDef(Scalef), - MethodDef(Scissor), - MethodDef(SelectBuffer), - MethodDef(ShadeModel), - MethodDef(StencilFunc), - MethodDef(StencilMask), - MethodDef(StencilOp), - MethodDef(TexCoord1d), - MethodDef(TexCoord1dv), - MethodDef(TexCoord1f), - MethodDef(TexCoord1fv), - MethodDef(TexCoord1i), - MethodDef(TexCoord1iv), - MethodDef(TexCoord1s), - MethodDef(TexCoord1sv), - MethodDef(TexCoord2d), - MethodDef(TexCoord2dv), - MethodDef(TexCoord2f), - MethodDef(TexCoord2fv), - MethodDef(TexCoord2i), - MethodDef(TexCoord2iv), - MethodDef(TexCoord2s), - MethodDef(TexCoord2sv), - MethodDef(TexCoord3d), - MethodDef(TexCoord3dv), - MethodDef(TexCoord3f), - MethodDef(TexCoord3fv), - MethodDef(TexCoord3i), - MethodDef(TexCoord3iv), - MethodDef(TexCoord3s), - MethodDef(TexCoord3sv), - MethodDef(TexCoord4d), - MethodDef(TexCoord4dv), - MethodDef(TexCoord4f), - MethodDef(TexCoord4fv), - MethodDef(TexCoord4i), - MethodDef(TexCoord4iv), - MethodDef(TexCoord4s), - MethodDef(TexCoord4sv), - MethodDef(TexEnvf), - MethodDef(TexEnvfv), - MethodDef(TexEnvi), - MethodDef(TexEnviv), - MethodDef(TexGend), - MethodDef(TexGendv), - MethodDef(TexGenf), - MethodDef(TexGenfv), - MethodDef(TexGeni), - MethodDef(TexGeniv), - MethodDef(TexImage1D), - MethodDef(TexImage2D), - MethodDef(TexParameterf), - MethodDef(TexParameterfv), - MethodDef(TexParameteri), - MethodDef(TexParameteriv), - MethodDef(Translated), - MethodDef(Translatef), - MethodDef(Vertex2d), - MethodDef(Vertex2dv), - MethodDef(Vertex2f), - MethodDef(Vertex2fv), - MethodDef(Vertex2i), - MethodDef(Vertex2iv), - MethodDef(Vertex2s), - MethodDef(Vertex2sv), - MethodDef(Vertex3d), - MethodDef(Vertex3dv), - MethodDef(Vertex3f), - MethodDef(Vertex3fv), - MethodDef(Vertex3i), - MethodDef(Vertex3iv), - MethodDef(Vertex3s), - MethodDef(Vertex3sv), - MethodDef(Vertex4d), - MethodDef(Vertex4dv), - MethodDef(Vertex4f), - MethodDef(Vertex4fv), - MethodDef(Vertex4i), - MethodDef(Vertex4iv), - MethodDef(Vertex4s), - MethodDef(Vertex4sv), - MethodDef(Viewport), - MethodDefu(Perspective), - MethodDefu(LookAt), - MethodDefu(Ortho2D), - MethodDefu(PickMatrix), - MethodDefu(Project), - MethodDefu(UnProject), -/* #endif */ - {NULL, NULL, 0, NULL} -}; - -#if (PY_VERSION_HEX >= 0x03000000) -static struct PyModuleDef BGL_module_def = { - PyModuleDef_HEAD_INIT, - "BGL", /* m_name */ - 0, /* m_doc */ - 0, /* m_size */ - BGL_methods, /* m_methods */ - 0, /* m_reload */ - 0, /* m_traverse */ - 0, /* m_clear */ - 0, /* m_free */ -}; -#endif - -PyObject *BGL_Init(const char *from) -{ - PyObject *mod, *dict, *item; -#if (PY_VERSION_HEX >= 0x03000000) - mod = PyModule_Create(&BGL_module_def); - PyDict_SetItemString(PySys_GetObject("modules"), BGL_module_def.m_name, mod); -#else - mod= Py_InitModule(from, BGL_methods); -#endif - dict= PyModule_GetDict(mod); - - if( PyType_Ready( &buffer_Type) < 0) - return NULL; /* should never happen */ - -#define EXPP_ADDCONST(x) PyDict_SetItemString(dict, #x, item=PyLong_FromLong((int)x)); Py_DECREF(item) - -/* So, for example: - * EXPP_ADDCONST(GL_CURRENT_BIT) becomes - * PyDict_SetItemString(dict, "GL_CURRENT_BIT", item=PyLong_FromLong(GL_CURRENT_BIT)); Py_DECREF(item) */ - - EXPP_ADDCONST(GL_CURRENT_BIT); - EXPP_ADDCONST(GL_POINT_BIT); - EXPP_ADDCONST(GL_LINE_BIT); - EXPP_ADDCONST(GL_POLYGON_BIT); - EXPP_ADDCONST(GL_POLYGON_STIPPLE_BIT); - EXPP_ADDCONST(GL_PIXEL_MODE_BIT); - EXPP_ADDCONST(GL_LIGHTING_BIT); - EXPP_ADDCONST(GL_FOG_BIT); - EXPP_ADDCONST(GL_DEPTH_BUFFER_BIT); - EXPP_ADDCONST(GL_ACCUM_BUFFER_BIT); - EXPP_ADDCONST(GL_STENCIL_BUFFER_BIT); - EXPP_ADDCONST(GL_VIEWPORT_BIT); - EXPP_ADDCONST(GL_TRANSFORM_BIT); - EXPP_ADDCONST(GL_ENABLE_BIT); - EXPP_ADDCONST(GL_COLOR_BUFFER_BIT); - EXPP_ADDCONST(GL_HINT_BIT); - EXPP_ADDCONST(GL_EVAL_BIT); - EXPP_ADDCONST(GL_LIST_BIT); - EXPP_ADDCONST(GL_TEXTURE_BIT); - EXPP_ADDCONST(GL_SCISSOR_BIT); - EXPP_ADDCONST(GL_ALL_ATTRIB_BITS); - EXPP_ADDCONST(GL_CLIENT_ALL_ATTRIB_BITS); - - EXPP_ADDCONST(GL_FALSE); - EXPP_ADDCONST(GL_TRUE); - - EXPP_ADDCONST(GL_POINTS); - EXPP_ADDCONST(GL_LINES); - EXPP_ADDCONST(GL_LINE_LOOP); - EXPP_ADDCONST(GL_LINE_STRIP); - EXPP_ADDCONST(GL_TRIANGLES); - EXPP_ADDCONST(GL_TRIANGLE_STRIP); - EXPP_ADDCONST(GL_TRIANGLE_FAN); - EXPP_ADDCONST(GL_QUADS); - EXPP_ADDCONST(GL_QUAD_STRIP); - EXPP_ADDCONST(GL_POLYGON); - - EXPP_ADDCONST(GL_ACCUM); - EXPP_ADDCONST(GL_LOAD); - EXPP_ADDCONST(GL_RETURN); - EXPP_ADDCONST(GL_MULT); - EXPP_ADDCONST(GL_ADD); - - EXPP_ADDCONST(GL_NEVER); - EXPP_ADDCONST(GL_LESS); - EXPP_ADDCONST(GL_EQUAL); - EXPP_ADDCONST(GL_LEQUAL); - EXPP_ADDCONST(GL_GREATER); - EXPP_ADDCONST(GL_NOTEQUAL); - EXPP_ADDCONST(GL_GEQUAL); - EXPP_ADDCONST(GL_ALWAYS); - - EXPP_ADDCONST(GL_ZERO); - EXPP_ADDCONST(GL_ONE); - EXPP_ADDCONST(GL_SRC_COLOR); - EXPP_ADDCONST(GL_ONE_MINUS_SRC_COLOR); - EXPP_ADDCONST(GL_SRC_ALPHA); - EXPP_ADDCONST(GL_ONE_MINUS_SRC_ALPHA); - EXPP_ADDCONST(GL_DST_ALPHA); - EXPP_ADDCONST(GL_ONE_MINUS_DST_ALPHA); - - EXPP_ADDCONST(GL_DST_COLOR); - EXPP_ADDCONST(GL_ONE_MINUS_DST_COLOR); - EXPP_ADDCONST(GL_SRC_ALPHA_SATURATE); - - EXPP_ADDCONST(GL_NONE); - EXPP_ADDCONST(GL_FRONT_LEFT); - EXPP_ADDCONST(GL_FRONT_RIGHT); - EXPP_ADDCONST(GL_BACK_LEFT); - EXPP_ADDCONST(GL_BACK_RIGHT); - EXPP_ADDCONST(GL_FRONT); - EXPP_ADDCONST(GL_BACK); - EXPP_ADDCONST(GL_LEFT); - EXPP_ADDCONST(GL_RIGHT); - EXPP_ADDCONST(GL_FRONT_AND_BACK); - EXPP_ADDCONST(GL_AUX0); - EXPP_ADDCONST(GL_AUX1); - EXPP_ADDCONST(GL_AUX2); - EXPP_ADDCONST(GL_AUX3); - - EXPP_ADDCONST(GL_NO_ERROR); - EXPP_ADDCONST(GL_INVALID_ENUM); - EXPP_ADDCONST(GL_INVALID_VALUE); - EXPP_ADDCONST(GL_INVALID_OPERATION); - EXPP_ADDCONST(GL_STACK_OVERFLOW); - EXPP_ADDCONST(GL_STACK_UNDERFLOW); - EXPP_ADDCONST(GL_OUT_OF_MEMORY); - - EXPP_ADDCONST(GL_2D); - EXPP_ADDCONST(GL_3D); - EXPP_ADDCONST(GL_3D_COLOR); - EXPP_ADDCONST(GL_3D_COLOR_TEXTURE); - EXPP_ADDCONST(GL_4D_COLOR_TEXTURE); - - EXPP_ADDCONST(GL_PASS_THROUGH_TOKEN); - EXPP_ADDCONST(GL_POINT_TOKEN); - EXPP_ADDCONST(GL_LINE_TOKEN); - EXPP_ADDCONST(GL_POLYGON_TOKEN); - EXPP_ADDCONST(GL_BITMAP_TOKEN); - EXPP_ADDCONST(GL_DRAW_PIXEL_TOKEN); - EXPP_ADDCONST(GL_COPY_PIXEL_TOKEN); - EXPP_ADDCONST(GL_LINE_RESET_TOKEN); - - EXPP_ADDCONST(GL_EXP); - EXPP_ADDCONST(GL_EXP2); - - EXPP_ADDCONST(GL_CW); - EXPP_ADDCONST(GL_CCW); - - EXPP_ADDCONST(GL_COEFF); - EXPP_ADDCONST(GL_ORDER); - EXPP_ADDCONST(GL_DOMAIN); - - EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_I); - EXPP_ADDCONST(GL_PIXEL_MAP_S_TO_S); - EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_R); - EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_G); - EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_B); - EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_A); - EXPP_ADDCONST(GL_PIXEL_MAP_R_TO_R); - EXPP_ADDCONST(GL_PIXEL_MAP_G_TO_G); - EXPP_ADDCONST(GL_PIXEL_MAP_B_TO_B); - EXPP_ADDCONST(GL_PIXEL_MAP_A_TO_A); - - EXPP_ADDCONST(GL_CURRENT_COLOR); - EXPP_ADDCONST(GL_CURRENT_INDEX); - EXPP_ADDCONST(GL_CURRENT_NORMAL); - EXPP_ADDCONST(GL_CURRENT_TEXTURE_COORDS); - EXPP_ADDCONST(GL_CURRENT_RASTER_COLOR); - EXPP_ADDCONST(GL_CURRENT_RASTER_INDEX); - EXPP_ADDCONST(GL_CURRENT_RASTER_TEXTURE_COORDS); - EXPP_ADDCONST(GL_CURRENT_RASTER_POSITION); - EXPP_ADDCONST(GL_CURRENT_RASTER_POSITION_VALID); - EXPP_ADDCONST(GL_CURRENT_RASTER_DISTANCE); - EXPP_ADDCONST(GL_POINT_SMOOTH); - EXPP_ADDCONST(GL_POINT_SIZE); - EXPP_ADDCONST(GL_POINT_SIZE_RANGE); - EXPP_ADDCONST(GL_POINT_SIZE_GRANULARITY); - EXPP_ADDCONST(GL_LINE_SMOOTH); - EXPP_ADDCONST(GL_LINE_WIDTH); - EXPP_ADDCONST(GL_LINE_WIDTH_RANGE); - EXPP_ADDCONST(GL_LINE_WIDTH_GRANULARITY); - EXPP_ADDCONST(GL_LINE_STIPPLE); - EXPP_ADDCONST(GL_LINE_STIPPLE_PATTERN); - EXPP_ADDCONST(GL_LINE_STIPPLE_REPEAT); - EXPP_ADDCONST(GL_LIST_MODE); - EXPP_ADDCONST(GL_MAX_LIST_NESTING); - EXPP_ADDCONST(GL_LIST_BASE); - EXPP_ADDCONST(GL_LIST_INDEX); - EXPP_ADDCONST(GL_POLYGON_MODE); - EXPP_ADDCONST(GL_POLYGON_SMOOTH); - EXPP_ADDCONST(GL_POLYGON_STIPPLE); - EXPP_ADDCONST(GL_EDGE_FLAG); - EXPP_ADDCONST(GL_CULL_FACE); - EXPP_ADDCONST(GL_CULL_FACE_MODE); - EXPP_ADDCONST(GL_FRONT_FACE); - EXPP_ADDCONST(GL_LIGHTING); - EXPP_ADDCONST(GL_LIGHT_MODEL_LOCAL_VIEWER); - EXPP_ADDCONST(GL_LIGHT_MODEL_TWO_SIDE); - EXPP_ADDCONST(GL_LIGHT_MODEL_AMBIENT); - EXPP_ADDCONST(GL_SHADE_MODEL); - EXPP_ADDCONST(GL_COLOR_MATERIAL_FACE); - EXPP_ADDCONST(GL_COLOR_MATERIAL_PARAMETER); - EXPP_ADDCONST(GL_COLOR_MATERIAL); - EXPP_ADDCONST(GL_FOG); - EXPP_ADDCONST(GL_FOG_INDEX); - EXPP_ADDCONST(GL_FOG_DENSITY); - EXPP_ADDCONST(GL_FOG_START); - EXPP_ADDCONST(GL_FOG_END); - EXPP_ADDCONST(GL_FOG_MODE); - EXPP_ADDCONST(GL_FOG_COLOR); - EXPP_ADDCONST(GL_DEPTH_RANGE); - EXPP_ADDCONST(GL_DEPTH_TEST); - EXPP_ADDCONST(GL_DEPTH_WRITEMASK); - EXPP_ADDCONST(GL_DEPTH_CLEAR_VALUE); - EXPP_ADDCONST(GL_DEPTH_FUNC); - EXPP_ADDCONST(GL_ACCUM_CLEAR_VALUE); - EXPP_ADDCONST(GL_STENCIL_TEST); - EXPP_ADDCONST(GL_STENCIL_CLEAR_VALUE); - EXPP_ADDCONST(GL_STENCIL_FUNC); - EXPP_ADDCONST(GL_STENCIL_VALUE_MASK); - EXPP_ADDCONST(GL_STENCIL_FAIL); - EXPP_ADDCONST(GL_STENCIL_PASS_DEPTH_FAIL); - EXPP_ADDCONST(GL_STENCIL_PASS_DEPTH_PASS); - EXPP_ADDCONST(GL_STENCIL_REF); - EXPP_ADDCONST(GL_STENCIL_WRITEMASK); - EXPP_ADDCONST(GL_MATRIX_MODE); - EXPP_ADDCONST(GL_NORMALIZE); - EXPP_ADDCONST(GL_VIEWPORT); - EXPP_ADDCONST(GL_MODELVIEW_STACK_DEPTH); - EXPP_ADDCONST(GL_PROJECTION_STACK_DEPTH); - EXPP_ADDCONST(GL_TEXTURE_STACK_DEPTH); - EXPP_ADDCONST(GL_MODELVIEW_MATRIX); - EXPP_ADDCONST(GL_PROJECTION_MATRIX); - EXPP_ADDCONST(GL_TEXTURE_MATRIX); - EXPP_ADDCONST(GL_ATTRIB_STACK_DEPTH); - EXPP_ADDCONST(GL_ALPHA_TEST); - EXPP_ADDCONST(GL_ALPHA_TEST_FUNC); - EXPP_ADDCONST(GL_ALPHA_TEST_REF); - EXPP_ADDCONST(GL_DITHER); - EXPP_ADDCONST(GL_BLEND_DST); - EXPP_ADDCONST(GL_BLEND_SRC); - EXPP_ADDCONST(GL_BLEND); - EXPP_ADDCONST(GL_LOGIC_OP_MODE); - EXPP_ADDCONST(GL_LOGIC_OP); - EXPP_ADDCONST(GL_AUX_BUFFERS); - EXPP_ADDCONST(GL_DRAW_BUFFER); - EXPP_ADDCONST(GL_READ_BUFFER); - EXPP_ADDCONST(GL_SCISSOR_BOX); - EXPP_ADDCONST(GL_SCISSOR_TEST); - EXPP_ADDCONST(GL_INDEX_CLEAR_VALUE); - EXPP_ADDCONST(GL_INDEX_WRITEMASK); - EXPP_ADDCONST(GL_COLOR_CLEAR_VALUE); - EXPP_ADDCONST(GL_COLOR_WRITEMASK); - EXPP_ADDCONST(GL_INDEX_MODE); - EXPP_ADDCONST(GL_RGBA_MODE); - EXPP_ADDCONST(GL_DOUBLEBUFFER); - EXPP_ADDCONST(GL_STEREO); - EXPP_ADDCONST(GL_RENDER_MODE); - EXPP_ADDCONST(GL_PERSPECTIVE_CORRECTION_HINT); - EXPP_ADDCONST(GL_POINT_SMOOTH_HINT); - EXPP_ADDCONST(GL_LINE_SMOOTH_HINT); - EXPP_ADDCONST(GL_POLYGON_SMOOTH_HINT); - EXPP_ADDCONST(GL_FOG_HINT); - EXPP_ADDCONST(GL_TEXTURE_GEN_S); - EXPP_ADDCONST(GL_TEXTURE_GEN_T); - EXPP_ADDCONST(GL_TEXTURE_GEN_R); - EXPP_ADDCONST(GL_TEXTURE_GEN_Q); - EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_I_SIZE); - EXPP_ADDCONST(GL_PIXEL_MAP_S_TO_S_SIZE); - EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_R_SIZE); - EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_G_SIZE); - EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_B_SIZE); - EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_A_SIZE); - EXPP_ADDCONST(GL_PIXEL_MAP_R_TO_R_SIZE); - EXPP_ADDCONST(GL_PIXEL_MAP_G_TO_G_SIZE); - EXPP_ADDCONST(GL_PIXEL_MAP_B_TO_B_SIZE); - EXPP_ADDCONST(GL_PIXEL_MAP_A_TO_A_SIZE); - EXPP_ADDCONST(GL_UNPACK_SWAP_BYTES); - EXPP_ADDCONST(GL_UNPACK_LSB_FIRST); - EXPP_ADDCONST(GL_UNPACK_ROW_LENGTH); - EXPP_ADDCONST(GL_UNPACK_SKIP_ROWS); - EXPP_ADDCONST(GL_UNPACK_SKIP_PIXELS); - EXPP_ADDCONST(GL_UNPACK_ALIGNMENT); - EXPP_ADDCONST(GL_PACK_SWAP_BYTES); - EXPP_ADDCONST(GL_PACK_LSB_FIRST); - EXPP_ADDCONST(GL_PACK_ROW_LENGTH); - EXPP_ADDCONST(GL_PACK_SKIP_ROWS); - EXPP_ADDCONST(GL_PACK_SKIP_PIXELS); - EXPP_ADDCONST(GL_PACK_ALIGNMENT); - EXPP_ADDCONST(GL_MAP_COLOR); - EXPP_ADDCONST(GL_MAP_STENCIL); - EXPP_ADDCONST(GL_INDEX_SHIFT); - EXPP_ADDCONST(GL_INDEX_OFFSET); - EXPP_ADDCONST(GL_RED_SCALE); - EXPP_ADDCONST(GL_RED_BIAS); - EXPP_ADDCONST(GL_ZOOM_X); - EXPP_ADDCONST(GL_ZOOM_Y); - EXPP_ADDCONST(GL_GREEN_SCALE); - EXPP_ADDCONST(GL_GREEN_BIAS); - EXPP_ADDCONST(GL_BLUE_SCALE); - EXPP_ADDCONST(GL_BLUE_BIAS); - EXPP_ADDCONST(GL_ALPHA_SCALE); - EXPP_ADDCONST(GL_ALPHA_BIAS); - EXPP_ADDCONST(GL_DEPTH_SCALE); - EXPP_ADDCONST(GL_DEPTH_BIAS); - EXPP_ADDCONST(GL_MAX_EVAL_ORDER); - EXPP_ADDCONST(GL_MAX_LIGHTS); - EXPP_ADDCONST(GL_MAX_CLIP_PLANES); - EXPP_ADDCONST(GL_MAX_TEXTURE_SIZE); - EXPP_ADDCONST(GL_MAX_PIXEL_MAP_TABLE); - EXPP_ADDCONST(GL_MAX_ATTRIB_STACK_DEPTH); - EXPP_ADDCONST(GL_MAX_MODELVIEW_STACK_DEPTH); - EXPP_ADDCONST(GL_MAX_NAME_STACK_DEPTH); - EXPP_ADDCONST(GL_MAX_PROJECTION_STACK_DEPTH); - EXPP_ADDCONST(GL_MAX_TEXTURE_STACK_DEPTH); - EXPP_ADDCONST(GL_MAX_VIEWPORT_DIMS); - EXPP_ADDCONST(GL_SUBPIXEL_BITS); - EXPP_ADDCONST(GL_INDEX_BITS); - EXPP_ADDCONST(GL_RED_BITS); - EXPP_ADDCONST(GL_GREEN_BITS); - EXPP_ADDCONST(GL_BLUE_BITS); - EXPP_ADDCONST(GL_ALPHA_BITS); - EXPP_ADDCONST(GL_DEPTH_BITS); - EXPP_ADDCONST(GL_STENCIL_BITS); - EXPP_ADDCONST(GL_ACCUM_RED_BITS); - EXPP_ADDCONST(GL_ACCUM_GREEN_BITS); - EXPP_ADDCONST(GL_ACCUM_BLUE_BITS); - EXPP_ADDCONST(GL_ACCUM_ALPHA_BITS); - EXPP_ADDCONST(GL_NAME_STACK_DEPTH); - EXPP_ADDCONST(GL_AUTO_NORMAL); - EXPP_ADDCONST(GL_MAP1_COLOR_4); - EXPP_ADDCONST(GL_MAP1_INDEX); - EXPP_ADDCONST(GL_MAP1_NORMAL); - EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_1); - EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_2); - EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_3); - EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_4); - EXPP_ADDCONST(GL_MAP1_VERTEX_3); - EXPP_ADDCONST(GL_MAP1_VERTEX_4); - EXPP_ADDCONST(GL_MAP2_COLOR_4); - EXPP_ADDCONST(GL_MAP2_INDEX); - EXPP_ADDCONST(GL_MAP2_NORMAL); - EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_1); - EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_2); - EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_3); - EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_4); - EXPP_ADDCONST(GL_MAP2_VERTEX_3); - EXPP_ADDCONST(GL_MAP2_VERTEX_4); - EXPP_ADDCONST(GL_MAP1_GRID_DOMAIN); - EXPP_ADDCONST(GL_MAP1_GRID_SEGMENTS); - EXPP_ADDCONST(GL_MAP2_GRID_DOMAIN); - EXPP_ADDCONST(GL_MAP2_GRID_SEGMENTS); - EXPP_ADDCONST(GL_TEXTURE_1D); - EXPP_ADDCONST(GL_TEXTURE_2D); - - EXPP_ADDCONST(GL_TEXTURE_WIDTH); - EXPP_ADDCONST(GL_TEXTURE_HEIGHT); - EXPP_ADDCONST(GL_TEXTURE_COMPONENTS); - EXPP_ADDCONST(GL_TEXTURE_BORDER_COLOR); - EXPP_ADDCONST(GL_TEXTURE_BORDER); - - EXPP_ADDCONST(GL_DONT_CARE); - EXPP_ADDCONST(GL_FASTEST); - EXPP_ADDCONST(GL_NICEST); - - EXPP_ADDCONST(GL_AMBIENT); - EXPP_ADDCONST(GL_DIFFUSE); - EXPP_ADDCONST(GL_SPECULAR); - EXPP_ADDCONST(GL_POSITION); - EXPP_ADDCONST(GL_SPOT_DIRECTION); - EXPP_ADDCONST(GL_SPOT_EXPONENT); - EXPP_ADDCONST(GL_SPOT_CUTOFF); - EXPP_ADDCONST(GL_CONSTANT_ATTENUATION); - EXPP_ADDCONST(GL_LINEAR_ATTENUATION); - EXPP_ADDCONST(GL_QUADRATIC_ATTENUATION); - - EXPP_ADDCONST(GL_COMPILE); - EXPP_ADDCONST(GL_COMPILE_AND_EXECUTE); - - EXPP_ADDCONST(GL_BYTE); - EXPP_ADDCONST(GL_UNSIGNED_BYTE); - EXPP_ADDCONST(GL_SHORT); - EXPP_ADDCONST(GL_UNSIGNED_SHORT); - EXPP_ADDCONST(GL_INT); - EXPP_ADDCONST(GL_UNSIGNED_INT); - EXPP_ADDCONST(GL_FLOAT); - EXPP_ADDCONST(GL_DOUBLE); - EXPP_ADDCONST(GL_2_BYTES); - EXPP_ADDCONST(GL_3_BYTES); - EXPP_ADDCONST(GL_4_BYTES); - - EXPP_ADDCONST(GL_CLEAR); - EXPP_ADDCONST(GL_AND); - EXPP_ADDCONST(GL_AND_REVERSE); - EXPP_ADDCONST(GL_COPY); - EXPP_ADDCONST(GL_AND_INVERTED); - EXPP_ADDCONST(GL_NOOP); - EXPP_ADDCONST(GL_XOR); - EXPP_ADDCONST(GL_OR); - EXPP_ADDCONST(GL_NOR); - EXPP_ADDCONST(GL_EQUIV); - EXPP_ADDCONST(GL_INVERT); - EXPP_ADDCONST(GL_OR_REVERSE); - EXPP_ADDCONST(GL_COPY_INVERTED); - EXPP_ADDCONST(GL_OR_INVERTED); - EXPP_ADDCONST(GL_NAND); - EXPP_ADDCONST(GL_SET); - - EXPP_ADDCONST(GL_EMISSION); - EXPP_ADDCONST(GL_SHININESS); - EXPP_ADDCONST(GL_AMBIENT_AND_DIFFUSE); - EXPP_ADDCONST(GL_COLOR_INDEXES); - - EXPP_ADDCONST(GL_MODELVIEW); - EXPP_ADDCONST(GL_PROJECTION); - EXPP_ADDCONST(GL_TEXTURE); - - EXPP_ADDCONST(GL_COLOR); - EXPP_ADDCONST(GL_DEPTH); - EXPP_ADDCONST(GL_STENCIL); - - EXPP_ADDCONST(GL_COLOR_INDEX); - EXPP_ADDCONST(GL_STENCIL_INDEX); - EXPP_ADDCONST(GL_DEPTH_COMPONENT); - EXPP_ADDCONST(GL_RED); - EXPP_ADDCONST(GL_GREEN); - EXPP_ADDCONST(GL_BLUE); - EXPP_ADDCONST(GL_ALPHA); - EXPP_ADDCONST(GL_RGB); - EXPP_ADDCONST(GL_RGBA); - EXPP_ADDCONST(GL_LUMINANCE); - EXPP_ADDCONST(GL_LUMINANCE_ALPHA); - - EXPP_ADDCONST(GL_BITMAP); - - EXPP_ADDCONST(GL_POINT); - EXPP_ADDCONST(GL_LINE); - EXPP_ADDCONST(GL_FILL); - - EXPP_ADDCONST(GL_RENDER); - EXPP_ADDCONST(GL_FEEDBACK); - EXPP_ADDCONST(GL_SELECT); - - EXPP_ADDCONST(GL_FLAT); - EXPP_ADDCONST(GL_SMOOTH); - - EXPP_ADDCONST(GL_KEEP); - EXPP_ADDCONST(GL_REPLACE); - EXPP_ADDCONST(GL_INCR); - EXPP_ADDCONST(GL_DECR); - - EXPP_ADDCONST(GL_VENDOR); - EXPP_ADDCONST(GL_RENDERER); - EXPP_ADDCONST(GL_VERSION); - EXPP_ADDCONST(GL_EXTENSIONS); - - EXPP_ADDCONST(GL_S); - EXPP_ADDCONST(GL_T); - EXPP_ADDCONST(GL_R); - EXPP_ADDCONST(GL_Q); - - EXPP_ADDCONST(GL_MODULATE); - EXPP_ADDCONST(GL_DECAL); - - EXPP_ADDCONST(GL_TEXTURE_ENV_MODE); - EXPP_ADDCONST(GL_TEXTURE_ENV_COLOR); - - EXPP_ADDCONST(GL_TEXTURE_ENV); - - EXPP_ADDCONST(GL_EYE_LINEAR); - EXPP_ADDCONST(GL_OBJECT_LINEAR); - EXPP_ADDCONST(GL_SPHERE_MAP); - - EXPP_ADDCONST(GL_TEXTURE_GEN_MODE); - EXPP_ADDCONST(GL_OBJECT_PLANE); - EXPP_ADDCONST(GL_EYE_PLANE); - - EXPP_ADDCONST(GL_NEAREST); - EXPP_ADDCONST(GL_LINEAR); - - EXPP_ADDCONST(GL_NEAREST_MIPMAP_NEAREST); - EXPP_ADDCONST(GL_LINEAR_MIPMAP_NEAREST); - EXPP_ADDCONST(GL_NEAREST_MIPMAP_LINEAR); - EXPP_ADDCONST(GL_LINEAR_MIPMAP_LINEAR); - - EXPP_ADDCONST(GL_TEXTURE_MAG_FILTER); - EXPP_ADDCONST(GL_TEXTURE_MIN_FILTER); - EXPP_ADDCONST(GL_TEXTURE_WRAP_S); - EXPP_ADDCONST(GL_TEXTURE_WRAP_T); - - EXPP_ADDCONST(GL_CLAMP); - EXPP_ADDCONST(GL_REPEAT); - - EXPP_ADDCONST(GL_CLIP_PLANE0); - EXPP_ADDCONST(GL_CLIP_PLANE1); - EXPP_ADDCONST(GL_CLIP_PLANE2); - EXPP_ADDCONST(GL_CLIP_PLANE3); - EXPP_ADDCONST(GL_CLIP_PLANE4); - EXPP_ADDCONST(GL_CLIP_PLANE5); - - EXPP_ADDCONST(GL_LIGHT0); - EXPP_ADDCONST(GL_LIGHT1); - EXPP_ADDCONST(GL_LIGHT2); - EXPP_ADDCONST(GL_LIGHT3); - EXPP_ADDCONST(GL_LIGHT4); - EXPP_ADDCONST(GL_LIGHT5); - EXPP_ADDCONST(GL_LIGHT6); - EXPP_ADDCONST(GL_LIGHT7); - - EXPP_ADDCONST(GL_POLYGON_OFFSET_UNITS); - EXPP_ADDCONST(GL_POLYGON_OFFSET_POINT); - EXPP_ADDCONST(GL_POLYGON_OFFSET_LINE); - EXPP_ADDCONST(GL_POLYGON_OFFSET_FILL); - EXPP_ADDCONST(GL_POLYGON_OFFSET_FACTOR); - - EXPP_ADDCONST(GL_TEXTURE_PRIORITY); - EXPP_ADDCONST(GL_TEXTURE_RESIDENT); - EXPP_ADDCONST(GL_TEXTURE_BINDING_1D); - EXPP_ADDCONST(GL_TEXTURE_BINDING_2D); - - return mod; -} - diff --git a/source/blender/python/generic/BGL.h b/source/blender/python/generic/BGL.h deleted file mode 100755 index 938c916bcea..00000000000 --- a/source/blender/python/generic/BGL.h +++ /dev/null @@ -1,338 +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. - * - * This is a new part of Blender. - * - * Contributor(s): Willian P. Germano - * - * ***** END GPL LICENSE BLOCK ***** -*/ - -/* This is the Blender.BGL part of opy_draw.c, from the old bpython/intern - * dir, with minor changes to adapt it to the new Python implementation. - * The BGL submodule "wraps" OpenGL functions and constants, allowing script - * writers to make OpenGL calls in their Python scripts for Blender. The - * more important original comments are marked with an @ symbol. */ - -#ifndef EXPP_BGL_H -#define EXPP_BGL_H - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <Python.h> -#include <GL/glew.h> -#include "../intern/bpy_compat.h" - -PyObject *BGL_Init( const char *from ); - -/*@ Buffer Object */ -/*@ For Python access to OpenGL functions requiring a pointer. */ - -typedef struct _Buffer { - PyObject_VAR_HEAD - PyObject * parent; - - int type; /* GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT */ - int ndimensions; - int *dimensions; - - union { - char *asbyte; - short *asshort; - int *asint; - float *asfloat; - double *asdouble; - - void *asvoid; - } buf; -} Buffer; - - -/*@ By golly George! It looks like fancy pants macro time!!! */ - -/* -#define int_str "i" -#define int_var(number) bgl_int##number -#define int_ref(number) &bgl_int##number -#define int_def(number) int int_var(number) - -#define float_str "f" -#define float_var(number) bgl_float##number -#define float_ref(number) &bgl_float##number -#define float_def(number) float float_var(number) -*/ - -/* TYPE_str is the string to pass to Py_ArgParse (for the format) */ -/* TYPE_var is the name to pass to the GL function */ -/* TYPE_ref is the pointer to pass to Py_ArgParse (to store in) */ -/* TYPE_def is the C initialization of the variable */ - -#define void_str "" -#define void_var(num) -#define void_ref(num) &bgl_var##num -#define void_def(num) char bgl_var##num - -#define buffer_str "O!" -#define buffer_var(number) (bgl_buffer##number)->buf.asvoid -#define buffer_ref(number) &buffer_Type, &bgl_buffer##number -#define buffer_def(number) Buffer *bgl_buffer##number - -/* GL Pointer fields, handled by buffer type */ -/* GLdoubleP, GLfloatP, GLintP, GLuintP, GLshortP */ - -#define GLbooleanP_str "O!" -#define GLbooleanP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLbooleanP_ref(number) &buffer_Type, &bgl_buffer##number -#define GLbooleanP_def(number) Buffer *bgl_buffer##number - -#define GLbyteP_str "O!" -#define GLbyteP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLbyteP_ref(number) &buffer_Type, &bgl_buffer##number -#define GLbyteP_def(number) Buffer *bgl_buffer##number - -#define GLubyteP_str "O!" -#define GLubyteP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLubyteP_ref(number) &buffer_Type, &bgl_buffer##number -#define GLubyteP_def(number) Buffer *bgl_buffer##number - -#define GLintP_str "O!" -#define GLintP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLintP_ref(number) &buffer_Type, &bgl_buffer##number -#define GLintP_def(number) Buffer *bgl_buffer##number - -#define GLuintP_str "O!" -#define GLuintP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLuintP_ref(number) &buffer_Type, &bgl_buffer##number -#define GLuintP_def(number) Buffer *bgl_buffer##number - -#define GLshortP_str "O!" -#define GLshortP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLshortP_ref(number) &buffer_Type, &bgl_buffer##number -#define GLshortP_def(number) Buffer *bgl_buffer##number - -#define GLushortP_str "O!" -#define GLushortP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLushortP_ref(number) &buffer_Type, &bgl_buffer##number -#define GLushortP_def(number) Buffer *bgl_buffer##number - -#define GLfloatP_str "O!" -#define GLfloatP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLfloatP_ref(number) &buffer_Type, &bgl_buffer##number -#define GLfloatP_def(number) Buffer *bgl_buffer##number - -#define GLdoubleP_str "O!" -#define GLdoubleP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLdoubleP_ref(number) &buffer_Type, &bgl_buffer##number -#define GLdoubleP_def(number) Buffer *bgl_buffer##number - -#define GLclampfP_str "O!" -#define GLclampfP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLclampfP_ref(number) &buffer_Type, &bgl_buffer##number -#define GLclampfP_def(number) Buffer *bgl_buffer##number - -#define GLvoidP_str "O!" -#define GLvoidP_var(number) (bgl_buffer##number)->buf.asvoid -#define GLvoidP_ref(number) &buffer_Type, &bgl_buffer##number -#define GLvoidP_def(number) Buffer *bgl_buffer##number - -#define buffer_str "O!" -#define buffer_var(number) (bgl_buffer##number)->buf.asvoid -#define buffer_ref(number) &buffer_Type, &bgl_buffer##number -#define buffer_def(number) Buffer *bgl_buffer##number - -/*@The standard GL typedefs are used as prototypes, we can't - * use the GL type directly because Py_ArgParse expects normal - * C types. - * - * Py_ArgParse doesn't grok writing into unsigned variables, - * so we use signed everything (even stuff that should be unsigned. - */ - -/* typedef unsigned int GLenum; */ -#define GLenum_str "i" -#define GLenum_var(num) bgl_var##num -#define GLenum_ref(num) &bgl_var##num -#define GLenum_def(num) /* unsigned */ int GLenum_var(num) - -/* typedef unsigned int GLboolean; */ -#define GLboolean_str "b" -#define GLboolean_var(num) bgl_var##num -#define GLboolean_ref(num) &bgl_var##num -#define GLboolean_def(num) /* unsigned */ char GLboolean_var(num) - -/* typedef unsigned int GLbitfield; */ -#define GLbitfield_str "i" -#define GLbitfield_var(num) bgl_var##num -#define GLbitfield_ref(num) &bgl_var##num -#define GLbitfield_def(num) /* unsigned */ int GLbitfield_var(num) - -/* typedef signed char GLbyte; */ -#define GLbyte_str "b" -#define GLbyte_var(num) bgl_var##num -#define GLbyte_ref(num) &bgl_var##num -#define GLbyte_def(num) signed char GLbyte_var(num) - -/* typedef short GLshort; */ -#define GLshort_str "h" -#define GLshort_var(num) bgl_var##num -#define GLshort_ref(num) &bgl_var##num -#define GLshort_def(num) short GLshort_var(num) - -/* typedef int GLint; */ -#define GLint_str "i" -#define GLint_var(num) bgl_var##num -#define GLint_ref(num) &bgl_var##num -#define GLint_def(num) int GLint_var(num) - -/* typedef int GLsizei; */ -#define GLsizei_str "i" -#define GLsizei_var(num) bgl_var##num -#define GLsizei_ref(num) &bgl_var##num -#define GLsizei_def(num) int GLsizei_var(num) - -/* typedef unsigned char GLubyte; */ -#define GLubyte_str "b" -#define GLubyte_var(num) bgl_var##num -#define GLubyte_ref(num) &bgl_var##num -#define GLubyte_def(num) /* unsigned */ char GLubyte_var(num) - -/* typedef unsigned short GLushort; */ -#define GLushort_str "h" -#define GLushort_var(num) bgl_var##num -#define GLushort_ref(num) &bgl_var##num -#define GLushort_def(num) /* unsigned */ short GLushort_var(num) - -/* typedef unsigned int GLuint; */ -#define GLuint_str "i" -#define GLuint_var(num) bgl_var##num -#define GLuint_ref(num) &bgl_var##num -#define GLuint_def(num) /* unsigned */ int GLuint_var(num) - -/* typedef float GLfloat; */ -#define GLfloat_str "f" -#define GLfloat_var(num) bgl_var##num -#define GLfloat_ref(num) &bgl_var##num -#define GLfloat_def(num) float GLfloat_var(num) - -/* typedef float GLclampf; */ -#define GLclampf_str "f" -#define GLclampf_var(num) bgl_var##num -#define GLclampf_ref(num) &bgl_var##num -#define GLclampf_def(num) float GLclampf_var(num) - -/* typedef double GLdouble; */ -#define GLdouble_str "d" -#define GLdouble_var(num) bgl_var##num -#define GLdouble_ref(num) &bgl_var##num -#define GLdouble_def(num) double GLdouble_var(num) - -/* typedef double GLclampd; */ -#define GLclampd_str "d" -#define GLclampd_var(num) bgl_var##num -#define GLclampd_ref(num) &bgl_var##num -#define GLclampd_def(num) double GLclampd_var(num) - -/* typedef void GLvoid; */ -/* #define GLvoid_str "" */ -/* #define GLvoid_var(num) bgl_var##num */ -/* #define GLvoid_ref(num) &bgl_var##num */ -/* #define GLvoid_def(num) char bgl_var##num */ - -#define arg_def1(a1) a1##_def(1) -#define arg_def2(a1, a2) arg_def1(a1); a2##_def(2) -#define arg_def3(a1, a2, a3) arg_def2(a1, a2); a3##_def(3) -#define arg_def4(a1, a2, a3, a4) arg_def3(a1, a2, a3); a4##_def(4) -#define arg_def5(a1, a2, a3, a4, a5) arg_def4(a1, a2, a3, a4); a5##_def(5) -#define arg_def6(a1, a2, a3, a4, a5, a6)arg_def5(a1, a2, a3, a4, a5); a6##_def(6) -#define arg_def7(a1, a2, a3, a4, a5, a6, a7)arg_def6(a1, a2, a3, a4, a5, a6); a7##_def(7) -#define arg_def8(a1, a2, a3, a4, a5, a6, a7, a8)arg_def7(a1, a2, a3, a4, a5, a6, a7); a8##_def(8) -#define arg_def9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_def8(a1, a2, a3, a4, a5, a6, a7, a8); a9##_def(9) -#define arg_def10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_def9(a1, a2, a3, a4, a5, a6, a7, a8, a9); a10##_def(10) - -#define arg_var1(a1) a1##_var(1) -#define arg_var2(a1, a2) arg_var1(a1), a2##_var(2) -#define arg_var3(a1, a2, a3) arg_var2(a1, a2), a3##_var(3) -#define arg_var4(a1, a2, a3, a4) arg_var3(a1, a2, a3), a4##_var(4) -#define arg_var5(a1, a2, a3, a4, a5) arg_var4(a1, a2, a3, a4), a5##_var(5) -#define arg_var6(a1, a2, a3, a4, a5, a6)arg_var5(a1, a2, a3, a4, a5), a6##_var(6) -#define arg_var7(a1, a2, a3, a4, a5, a6, a7)arg_var6(a1, a2, a3, a4, a5, a6), a7##_var(7) -#define arg_var8(a1, a2, a3, a4, a5, a6, a7, a8)arg_var7(a1, a2, a3, a4, a5, a6, a7), a8##_var(8) -#define arg_var9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_var8(a1, a2, a3, a4, a5, a6, a7, a8), a9##_var(9) -#define arg_var10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_var9(a1, a2, a3, a4, a5, a6, a7, a8, a9), a10##_var(10) - -#define arg_ref1(a1) a1##_ref(1) -#define arg_ref2(a1, a2) arg_ref1(a1), a2##_ref(2) -#define arg_ref3(a1, a2, a3) arg_ref2(a1, a2), a3##_ref(3) -#define arg_ref4(a1, a2, a3, a4) arg_ref3(a1, a2, a3), a4##_ref(4) -#define arg_ref5(a1, a2, a3, a4, a5) arg_ref4(a1, a2, a3, a4), a5##_ref(5) -#define arg_ref6(a1, a2, a3, a4, a5, a6)arg_ref5(a1, a2, a3, a4, a5), a6##_ref(6) -#define arg_ref7(a1, a2, a3, a4, a5, a6, a7)arg_ref6(a1, a2, a3, a4, a5, a6), a7##_ref(7) -#define arg_ref8(a1, a2, a3, a4, a5, a6, a7, a8)arg_ref7(a1, a2, a3, a4, a5, a6, a7), a8##_ref(8) -#define arg_ref9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_ref8(a1, a2, a3, a4, a5, a6, a7, a8), a9##_ref(9) -#define arg_ref10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_ref9(a1, a2, a3, a4, a5, a6, a7, a8, a9), a10##_ref(10) - -#define arg_str1(a1) a1##_str -#define arg_str2(a1, a2) arg_str1(a1) a2##_str -#define arg_str3(a1, a2, a3) arg_str2(a1, a2) a3##_str -#define arg_str4(a1, a2, a3, a4) arg_str3(a1, a2, a3) a4##_str -#define arg_str5(a1, a2, a3, a4, a5) arg_str4(a1, a2, a3, a4) a5##_str -#define arg_str6(a1, a2, a3, a4, a5, a6)arg_str5(a1, a2, a3, a4, a5) a6##_str -#define arg_str7(a1, a2, a3, a4, a5, a6, a7)arg_str6(a1, a2, a3, a4, a5, a6) a7##_str -#define arg_str8(a1, a2, a3, a4, a5, a6, a7, a8)arg_str7(a1, a2, a3, a4, a5, a6, a7) a8##_str -#define arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_str8(a1, a2, a3, a4, a5, a6, a7, a8) a9##_str -#define arg_str10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9) a10##_str - -#define ret_def_void -#define ret_set_void -/* would use Py_RETURN_NONE - except for py 2.3 doesnt have it */ -#define ret_ret_void { Py_INCREF(Py_None); return Py_None; } - -#define ret_def_GLint int ret_int -#define ret_set_GLint ret_int= -#define ret_ret_GLint return PyLong_FromLong(ret_int); - -#define ret_def_GLuint unsigned int ret_uint -#define ret_set_GLuint ret_uint= -#define ret_ret_GLuint return PyLong_FromLong((long) ret_uint); - -#define ret_def_GLenum unsigned int ret_uint -#define ret_set_GLenum ret_uint= -#define ret_ret_GLenum return PyLong_FromLong((long) ret_uint); - -#define ret_def_GLboolean unsigned char ret_bool -#define ret_set_GLboolean ret_bool= -#define ret_ret_GLboolean return PyLong_FromLong((long) ret_bool); - -#define ret_def_GLstring const unsigned char *ret_str; -#define ret_set_GLstring ret_str= - -#define ret_ret_GLstring \ - if (ret_str) {\ - return PyUnicode_FromString(ret_str);\ - } else {\ - PyErr_SetString(PyExc_AttributeError, "could not get opengl string");\ - return NULL;\ - } - -#endif /* EXPP_BGL_H */ diff --git a/source/blender/python/generic/Geometry.c b/source/blender/python/generic/Geometry.c deleted file mode 100644 index b4a34d30051..00000000000 --- a/source/blender/python/generic/Geometry.c +++ /dev/null @@ -1,542 +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. - * - * This is a new part of Blender. - * - * Contributor(s): Joseph Gilbert, Campbell Barton - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "Geometry.h" - -/* - Not needed for now though other geometry functions will probably need them -#include "BLI_arithb.h" -#include "BKE_utildefines.h" -*/ - -/* Used for PolyFill */ -#include "BKE_displist.h" -#include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" - -#include "BKE_utildefines.h" -#include "BKE_curve.h" -#include "BLI_boxpack2d.h" -#include "BLI_arithb.h" - -#define SWAP_FLOAT(a,b,tmp) tmp=a; a=b; b=tmp -#define eul 0.000001 - -/*-- forward declarations -- */ -static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq ); -static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args ); -static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args ); -static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args ); -static PyObject *M_Geometry_PointInQuad2D( PyObject * self, PyObject * args ); -static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * args ); -static PyObject *M_Geometry_BezierInterp( PyObject * self, PyObject * args ); - - -/*-------------------------DOC STRINGS ---------------------------*/ -static char M_Geometry_doc[] = "The Blender Geometry module\n\n"; -static char M_Geometry_PolyFill_doc[] = "(veclist_list) - takes a list of polylines (each point a vector) and returns the point indicies for a polyline filled with triangles"; -static char M_Geometry_LineIntersect2D_doc[] = "(lineA_p1, lineA_p2, lineB_p1, lineB_p2) - takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None"; -static char M_Geometry_ClosestPointOnLine_doc[] = "(pt, line_p1, line_p2) - takes a point and a line and returns a (Vector, float) for the point on the line, and the bool so you can know if the point was between the 2 points"; -static char M_Geometry_PointInTriangle2D_doc[] = "(pt, tri_p1, tri_p2, tri_p3) - takes 4 vectors, one is the point and the next 3 define the triangle, only the x and y are used from the vectors"; -static char M_Geometry_PointInQuad2D_doc[] = "(pt, quad_p1, quad_p2, quad_p3, quad_p4) - takes 5 vectors, one is the point and the next 4 define the quad, only the x and y are used from the vectors"; -static char M_Geometry_BoxPack2D_doc[] = ""; -static char M_Geometry_BezierInterp_doc[] = ""; -/*-----------------------METHOD DEFINITIONS ----------------------*/ -struct PyMethodDef M_Geometry_methods[] = { - {"PolyFill", ( PyCFunction ) M_Geometry_PolyFill, METH_O, M_Geometry_PolyFill_doc}, - {"LineIntersect2D", ( PyCFunction ) M_Geometry_LineIntersect2D, METH_VARARGS, M_Geometry_LineIntersect2D_doc}, - {"ClosestPointOnLine", ( PyCFunction ) M_Geometry_ClosestPointOnLine, METH_VARARGS, M_Geometry_ClosestPointOnLine_doc}, - {"PointInTriangle2D", ( PyCFunction ) M_Geometry_PointInTriangle2D, METH_VARARGS, M_Geometry_PointInTriangle2D_doc}, - {"PointInQuad2D", ( PyCFunction ) M_Geometry_PointInQuad2D, METH_VARARGS, M_Geometry_PointInQuad2D_doc}, - {"BoxPack2D", ( PyCFunction ) M_Geometry_BoxPack2D, METH_O, M_Geometry_BoxPack2D_doc}, - {"BezierInterp", ( PyCFunction ) M_Geometry_BezierInterp, METH_VARARGS, M_Geometry_BezierInterp_doc}, - {NULL, NULL, 0, NULL} -}; - -#if (PY_VERSION_HEX >= 0x03000000) -static struct PyModuleDef M_Geometry_module_def = { - PyModuleDef_HEAD_INIT, - "Geometry", /* m_name */ - M_Geometry_doc, /* m_doc */ - 0, /* m_size */ - M_Geometry_methods, /* m_methods */ - 0, /* m_reload */ - 0, /* m_traverse */ - 0, /* m_clear */ - 0, /* m_free */ -}; -#endif - -/*----------------------------MODULE INIT-------------------------*/ -PyObject *Geometry_Init(const char *from) -{ - PyObject *submodule; - -#if (PY_VERSION_HEX >= 0x03000000) - submodule = PyModule_Create(&M_Geometry_module_def); - PyDict_SetItemString(PySys_GetObject("modules"), M_Geometry_module_def.m_name, submodule); -#else - submodule = Py_InitModule3(from, M_Geometry_methods, M_Geometry_doc); -#endif - - return (submodule); -} - -/*----------------------------------Geometry.PolyFill() -------------------*/ -/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */ -static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq ) -{ - PyObject *tri_list; /*return this list of tri's */ - PyObject *polyLine, *polyVec; - int i, len_polylines, len_polypoints, ls_error = 0; - - /* display listbase */ - ListBase dispbase={NULL, NULL}; - DispList *dl; - float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */ - int index, *dl_face, totpoints=0; - - - dispbase.first= dispbase.last= NULL; - - - if(!PySequence_Check(polyLineSeq)) { - PyErr_SetString( PyExc_TypeError, "expected a sequence of poly lines" ); - return NULL; - } - - len_polylines = PySequence_Size( polyLineSeq ); - - for( i = 0; i < len_polylines; ++i ) { - polyLine= PySequence_GetItem( polyLineSeq, i ); - if (!PySequence_Check(polyLine)) { - freedisplist(&dispbase); - Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/ - PyErr_SetString( PyExc_TypeError, "One or more of the polylines is not a sequence of Mathutils.Vector's" ); - return NULL; - } - - len_polypoints= PySequence_Size( polyLine ); - if (len_polypoints>0) { /* dont bother adding edges as polylines */ -#if 0 - if (EXPP_check_sequence_consistency( polyLine, &vector_Type ) != 1) { - freedisplist(&dispbase); - Py_DECREF(polyLine); - PyErr_SetString( PyExc_TypeError, "A point in one of the polylines is not a Mathutils.Vector type" ); - return NULL; - } -#endif - dl= MEM_callocN(sizeof(DispList), "poly disp"); - BLI_addtail(&dispbase, dl); - dl->type= DL_INDEX3; - dl->nr= len_polypoints; - dl->type= DL_POLY; - dl->parts= 1; /* no faces, 1 edge loop */ - dl->col= 0; /* no material */ - dl->verts= fp= MEM_callocN( sizeof(float)*3*len_polypoints, "dl verts"); - dl->index= MEM_callocN(sizeof(int)*3*len_polypoints, "dl index"); - - for( index = 0; index<len_polypoints; ++index, fp+=3) { - polyVec= PySequence_GetItem( polyLine, index ); - if(VectorObject_Check(polyVec)) { - - if(!BaseMath_ReadCallback((VectorObject *)polyVec)) - ls_error= 1; - - fp[0] = ((VectorObject *)polyVec)->vec[0]; - fp[1] = ((VectorObject *)polyVec)->vec[1]; - if( ((VectorObject *)polyVec)->size > 2 ) - fp[2] = ((VectorObject *)polyVec)->vec[2]; - else - fp[2]= 0.0f; /* if its a 2d vector then set the z to be zero */ - } - else { - ls_error= 1; - } - - totpoints++; - Py_DECREF(polyVec); - } - } - Py_DECREF(polyLine); - } - - if(ls_error) { - freedisplist(&dispbase); /* possible some dl was allocated */ - PyErr_SetString( PyExc_TypeError, "A point in one of the polylines is not a Mathutils.Vector type" ); - return NULL; - } - else if (totpoints) { - /* now make the list to return */ - filldisplist(&dispbase, &dispbase); - - /* The faces are stored in a new DisplayList - thats added to the head of the listbase */ - dl= dispbase.first; - - tri_list= PyList_New(dl->parts); - if( !tri_list ) { - freedisplist(&dispbase); - PyErr_SetString( PyExc_RuntimeError, "Geometry.PolyFill failed to make a new list" ); - return NULL; - } - - index= 0; - dl_face= dl->index; - while(index < dl->parts) { - PyList_SetItem(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2]) ); - dl_face+= 3; - index++; - } - freedisplist(&dispbase); - } else { - /* no points, do this so scripts dont barf */ - freedisplist(&dispbase); /* possible some dl was allocated */ - tri_list= PyList_New(0); - } - - return tri_list; -} - - -static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args ) -{ - VectorObject *line_a1, *line_a2, *line_b1, *line_b2; - float a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, xi, yi, a1,a2,b1,b2, newvec[2]; - if( !PyArg_ParseTuple ( args, "O!O!O!O!", - &vector_Type, &line_a1, - &vector_Type, &line_a2, - &vector_Type, &line_b1, - &vector_Type, &line_b2) - ) { - PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(line_a1) || !BaseMath_ReadCallback(line_a2) || !BaseMath_ReadCallback(line_b1) || !BaseMath_ReadCallback(line_b2)) - return NULL; - - a1x= line_a1->vec[0]; - a1y= line_a1->vec[1]; - a2x= line_a2->vec[0]; - a2y= line_a2->vec[1]; - - b1x= line_b1->vec[0]; - b1y= line_b1->vec[1]; - b2x= line_b2->vec[0]; - b2y= line_b2->vec[1]; - - if((MIN2(a1x, a2x) > MAX2(b1x, b2x)) || - (MAX2(a1x, a2x) < MIN2(b1x, b2x)) || - (MIN2(a1y, a2y) > MAX2(b1y, b2y)) || - (MAX2(a1y, a2y) < MIN2(b1y, b2y)) ) { - Py_RETURN_NONE; - } - /* Make sure the hoz/vert line comes first. */ - if (fabs(b1x - b2x) < eul || fabs(b1y - b2y) < eul) { - SWAP_FLOAT(a1x, b1x, xi); /*abuse xi*/ - SWAP_FLOAT(a1y, b1y, xi); - SWAP_FLOAT(a2x, b2x, xi); - SWAP_FLOAT(a2y, b2y, xi); - } - - if (fabs(a1x-a2x) < eul) { /* verticle line */ - if (fabs(b1x-b2x) < eul){ /*verticle second line */ - Py_RETURN_NONE; /* 2 verticle lines dont intersect. */ - } - else if (fabs(b1y-b2y) < eul) { - /*X of vert, Y of hoz. no calculation needed */ - newvec[0]= a1x; - newvec[1]= b1y; - return newVectorObject(newvec, 2, Py_NEW, NULL); - } - - yi = (float)(((b1y / fabs(b1x - b2x)) * fabs(b2x - a1x)) + ((b2y / fabs(b1x - b2x)) * fabs(b1x - a1x))); - - if (yi > MAX2(a1y, a2y)) {/* New point above seg1's vert line */ - Py_RETURN_NONE; - } else if (yi < MIN2(a1y, a2y)) { /* New point below seg1's vert line */ - Py_RETURN_NONE; - } - newvec[0]= a1x; - newvec[1]= yi; - return newVectorObject(newvec, 2, Py_NEW, NULL); - } else if (fabs(a2y-a1y) < eul) { /* hoz line1 */ - if (fabs(b2y-b1y) < eul) { /*hoz line2*/ - Py_RETURN_NONE; /*2 hoz lines dont intersect*/ - } - - /* Can skip vert line check for seg 2 since its covered above. */ - xi = (float)(((b1x / fabs(b1y - b2y)) * fabs(b2y - a1y)) + ((b2x / fabs(b1y - b2y)) * fabs(b1y - a1y))); - if (xi > MAX2(a1x, a2x)) { /* New point right of hoz line1's */ - Py_RETURN_NONE; - } else if (xi < MIN2(a1x, a2x)) { /*New point left of seg1's hoz line */ - Py_RETURN_NONE; - } - newvec[0]= xi; - newvec[1]= a1y; - return newVectorObject(newvec, 2, Py_NEW, NULL); - } - - b1 = (a2y-a1y)/(a2x-a1x); - b2 = (b2y-b1y)/(b2x-b1x); - a1 = a1y-b1*a1x; - a2 = b1y-b2*b1x; - - if (b1 - b2 == 0.0) { - Py_RETURN_NONE; - } - - xi = - (a1-a2)/(b1-b2); - yi = a1+b1*xi; - if ((a1x-xi)*(xi-a2x) >= 0 && (b1x-xi)*(xi-b2x) >= 0 && (a1y-yi)*(yi-a2y) >= 0 && (b1y-yi)*(yi-b2y)>=0) { - newvec[0]= xi; - newvec[1]= yi; - return newVectorObject(newvec, 2, Py_NEW, NULL); - } - Py_RETURN_NONE; -} - -static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args ) -{ - VectorObject *pt, *line_1, *line_2; - float pt_in[3], pt_out[3], l1[3], l2[3]; - float lambda; - PyObject *ret; - - if( !PyArg_ParseTuple ( args, "O!O!O!", - &vector_Type, &pt, - &vector_Type, &line_1, - &vector_Type, &line_2) - ) { - PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(pt) || !BaseMath_ReadCallback(line_1) || !BaseMath_ReadCallback(line_2)) - return NULL; - - /* accept 2d verts */ - if (pt->size==3) { VECCOPY(pt_in, pt->vec);} - else { pt_in[2]=0.0; VECCOPY2D(pt_in, pt->vec) } - - if (line_1->size==3) { VECCOPY(l1, line_1->vec);} - else { l1[2]=0.0; VECCOPY2D(l1, line_1->vec) } - - if (line_2->size==3) { VECCOPY(l2, line_2->vec);} - else { l2[2]=0.0; VECCOPY2D(l2, line_2->vec) } - - /* do the calculation */ - lambda = lambda_cp_line_ex(pt_in, l1, l2, pt_out); - - ret = PyTuple_New(2); - PyTuple_SET_ITEM( ret, 0, newVectorObject(pt_out, 3, Py_NEW, NULL) ); - PyTuple_SET_ITEM( ret, 1, PyFloat_FromDouble(lambda) ); - return ret; -} - -static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args ) -{ - VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3; - - if( !PyArg_ParseTuple ( args, "O!O!O!O!", - &vector_Type, &pt_vec, - &vector_Type, &tri_p1, - &vector_Type, &tri_p2, - &vector_Type, &tri_p3) - ) { - PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(pt_vec) || !BaseMath_ReadCallback(tri_p1) || !BaseMath_ReadCallback(tri_p2) || !BaseMath_ReadCallback(tri_p3)) - return NULL; - - return PyLong_FromLong(IsectPT2Df(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec)); -} - -static PyObject *M_Geometry_PointInQuad2D( PyObject * self, PyObject * args ) -{ - VectorObject *pt_vec, *quad_p1, *quad_p2, *quad_p3, *quad_p4; - - if( !PyArg_ParseTuple ( args, "O!O!O!O!O!", - &vector_Type, &pt_vec, - &vector_Type, &quad_p1, - &vector_Type, &quad_p2, - &vector_Type, &quad_p3, - &vector_Type, &quad_p4) - ) { - PyErr_SetString( PyExc_TypeError, "expected 5 vector types\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(pt_vec) || !BaseMath_ReadCallback(quad_p1) || !BaseMath_ReadCallback(quad_p2) || !BaseMath_ReadCallback(quad_p3) || !BaseMath_ReadCallback(quad_p4)) - return NULL; - - return PyLong_FromLong(IsectPQ2Df(pt_vec->vec, quad_p1->vec, quad_p2->vec, quad_p3->vec, quad_p4->vec)); -} - -static int boxPack_FromPyObject(PyObject * value, boxPack **boxarray ) -{ - int len, i; - PyObject *list_item, *item_1, *item_2; - boxPack *box; - - - /* Error checking must alredy be done */ - if( !PyList_Check( value ) ) { - PyErr_SetString( PyExc_TypeError, "can only back a list of [x,y,x,w]" ); - return -1; - } - - len = PyList_Size( value ); - - (*boxarray) = MEM_mallocN( len*sizeof(boxPack), "boxPack box"); - - - for( i = 0; i < len; i++ ) { - list_item = PyList_GET_ITEM( value, i ); - if( !PyList_Check( list_item ) || PyList_Size( list_item ) < 4 ) { - MEM_freeN(*boxarray); - PyErr_SetString( PyExc_TypeError, "can only back a list of [x,y,x,w]" ); - return -1; - } - - box = (*boxarray)+i; - - item_1 = PyList_GET_ITEM(list_item, 2); - item_2 = PyList_GET_ITEM(list_item, 3); - - if (!PyNumber_Check(item_1) || !PyNumber_Check(item_2)) { - MEM_freeN(*boxarray); - PyErr_SetString( PyExc_TypeError, "can only back a list of 2d boxes [x,y,x,w]" ); - return -1; - } - - box->w = (float)PyFloat_AsDouble( item_1 ); - box->h = (float)PyFloat_AsDouble( item_2 ); - box->index = i; - /* verts will be added later */ - } - return 0; -} - -static void boxPack_ToPyObject(PyObject * value, boxPack **boxarray) -{ - int len, i; - PyObject *list_item; - boxPack *box; - - len = PyList_Size( value ); - - for( i = 0; i < len; i++ ) { - box = (*boxarray)+i; - list_item = PyList_GET_ITEM( value, box->index ); - PyList_SET_ITEM( list_item, 0, PyFloat_FromDouble( box->x )); - PyList_SET_ITEM( list_item, 1, PyFloat_FromDouble( box->y )); - } - MEM_freeN(*boxarray); -} - - -static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * boxlist ) -{ - boxPack *boxarray = NULL; - float tot_width, tot_height; - int len; - int error; - - if(!PyList_Check(boxlist)) { - PyErr_SetString( PyExc_TypeError, "expected a sequence of boxes [[x,y,w,h], ... ]" ); - return NULL; - } - - len = PyList_Size( boxlist ); - - if (!len) - return Py_BuildValue( "ff", 0.0, 0.0); - - error = boxPack_FromPyObject(boxlist, &boxarray); - if (error!=0) return NULL; - - /* Non Python function */ - boxPack2D(boxarray, len, &tot_width, &tot_height); - - boxPack_ToPyObject(boxlist, &boxarray); - - return Py_BuildValue( "ff", tot_width, tot_height); -} - -static PyObject *M_Geometry_BezierInterp( PyObject * self, PyObject * args ) -{ - VectorObject *vec_k1, *vec_h1, *vec_k2, *vec_h2; - int resolu; - int dims; - int i; - float *coord_array, *fp; - PyObject *list; - - float k1[4] = {0.0, 0.0, 0.0, 0.0}; - float h1[4] = {0.0, 0.0, 0.0, 0.0}; - float k2[4] = {0.0, 0.0, 0.0, 0.0}; - float h2[4] = {0.0, 0.0, 0.0, 0.0}; - - - if( !PyArg_ParseTuple ( args, "O!O!O!O!i", - &vector_Type, &vec_k1, - &vector_Type, &vec_h1, - &vector_Type, &vec_h2, - &vector_Type, &vec_k2, &resolu) || (resolu<=1) - ) { - PyErr_SetString( PyExc_TypeError, "expected 4 vector types and an int greater then 1\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(vec_k1) || !BaseMath_ReadCallback(vec_h1) || !BaseMath_ReadCallback(vec_k2) || !BaseMath_ReadCallback(vec_h2)) - return NULL; - - dims= MAX4(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size); - - for(i=0; i < vec_k1->size; i++) k1[i]= vec_k1->vec[i]; - for(i=0; i < vec_h1->size; i++) h1[i]= vec_h1->vec[i]; - for(i=0; i < vec_k2->size; i++) k2[i]= vec_k2->vec[i]; - for(i=0; i < vec_h2->size; i++) h2[i]= vec_h2->vec[i]; - - coord_array = MEM_callocN(dims * (resolu) * sizeof(float), "BezierInterp"); - for(i=0; i<dims; i++) { - forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array+i, resolu-1, dims); - } - - list= PyList_New(resolu); - fp= coord_array; - for(i=0; i<resolu; i++, fp= fp+dims) { - PyList_SET_ITEM(list, i, newVectorObject(fp, dims, Py_NEW, NULL)); - } - MEM_freeN(coord_array); - return list; -} diff --git a/source/blender/python/generic/Geometry.h b/source/blender/python/generic/Geometry.h deleted file mode 100644 index ebfb054c54a..00000000000 --- a/source/blender/python/generic/Geometry.h +++ /dev/null @@ -1,39 +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. - * - * This is a new part of Blender. - * - * Contributor(s): Joseph Gilbert - * - * ***** END GPL LICENSE BLOCK ***** -*/ -/*Include this file for access to vector, quat, matrix, euler, etc...*/ - -#ifndef EXPP_Geometry_H -#define EXPP_Geometry_H - -#include <Python.h> -#include "Mathutils.h" - -PyObject *Geometry_Init( const char *from ); - -#endif /* EXPP_Geometry_H */ diff --git a/source/blender/python/generic/Makefile b/source/blender/python/generic/Makefile deleted file mode 100644 index 0dbfbd1d102..00000000000 --- a/source/blender/python/generic/Makefile +++ /dev/null @@ -1,66 +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 = gen_python -DIR = $(OCGDIR)/blender/$(LIBNAME) - -include nan_compile.mk - -CFLAGS += $(LEVEL_1_C_WARNINGS) - -# OpenGL and Python -CPPFLAGS += -I$(NAN_GLEW)/include -CPPFLAGS += $(OGL_CPPFLAGS) -CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) - -# PreProcessor stuff - -CPPFLAGS += -I$(NAN_GHOST)/include -CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include $(NAN_SDLCFLAGS) - -# modules -CPPFLAGS += -I../../editors/include -CPPFLAGS += -I../../python -CPPFLAGS += -I../../makesdna -CPPFLAGS += -I../../makesrna -CPPFLAGS += -I../../blenlib -CPPFLAGS += -I../../blenkernel -CPPFLAGS += -I../../nodes -CPPFLAGS += -I../../imbuf -CPPFLAGS += -I../../blenloader -CPPFLAGS += -I../../windowmanager -CPPFLAGS += -I../../render/extern/include - -# path to the guarded memory allocator -CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include -CPPFLAGS += -I$(NAN_MEMUTIL)/include - -# path to our own headerfiles -CPPFLAGS += -I.. diff --git a/source/blender/python/generic/Mathutils.c b/source/blender/python/generic/Mathutils.c deleted file mode 100644 index 53077659655..00000000000 --- a/source/blender/python/generic/Mathutils.c +++ /dev/null @@ -1,1266 +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. - * - * This is a new part of Blender. - * - * Contributor(s): Joseph Gilbert, Campbell Barton - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "Mathutils.h" - -#include "BLI_arithb.h" -#include "PIL_time.h" -#include "BLI_rand.h" -#include "BKE_utildefines.h" - -//-------------------------DOC STRINGS --------------------------- -static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n"; -static char M_Mathutils_Rand_doc[] = "() - return a random number"; -static char M_Mathutils_AngleBetweenVecs_doc[] = "() - returns the angle between two vectors in degrees"; -static char M_Mathutils_MidpointVecs_doc[] = "() - return the vector to the midpoint between two vectors"; -static char M_Mathutils_ProjectVecs_doc[] = "() - returns the projection vector from the projection of vecA onto vecB"; -static char M_Mathutils_RotationMatrix_doc[] = "() - construct a rotation matrix from an angle and axis of rotation"; -static char M_Mathutils_ScaleMatrix_doc[] = "() - construct a scaling matrix from a scaling factor"; -static char M_Mathutils_OrthoProjectionMatrix_doc[] = "() - construct a orthographic projection matrix from a selected plane"; -static char M_Mathutils_ShearMatrix_doc[] = "() - construct a shearing matrix from a plane of shear and a shear factor"; -static char M_Mathutils_TranslationMatrix_doc[] = "(vec) - create a translation matrix from a vector"; -static char M_Mathutils_Slerp_doc[] = "() - returns the interpolation between two quaternions"; -static char M_Mathutils_DifferenceQuats_doc[] = "() - return the angular displacment difference between two quats"; -static char M_Mathutils_Intersect_doc[] = "(v1, v2, v3, ray, orig, clip=1) - returns the intersection between a ray and a triangle, if possible, returns None otherwise"; -static char M_Mathutils_TriangleArea_doc[] = "(v1, v2, v3) - returns the area size of the 2D or 3D triangle defined"; -static char M_Mathutils_TriangleNormal_doc[] = "(v1, v2, v3) - returns the normal of the 3D triangle defined"; -static char M_Mathutils_QuadNormal_doc[] = "(v1, v2, v3, v4) - returns the normal of the 3D quad defined"; -static char M_Mathutils_LineIntersect_doc[] = "(v1, v2, v3, v4) - returns a tuple with the points on each line respectively closest to the other"; -//-----------------------METHOD DEFINITIONS ---------------------- - -static PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * value); -static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args); -static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args ); -static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args ); -static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args ); -static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args ); -static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args ); - -struct PyMethodDef M_Mathutils_methods[] = { - {"Rand", (PyCFunction) M_Mathutils_Rand, METH_VARARGS, M_Mathutils_Rand_doc}, - {"AngleBetweenVecs", (PyCFunction) M_Mathutils_AngleBetweenVecs, METH_VARARGS, M_Mathutils_AngleBetweenVecs_doc}, - {"MidpointVecs", (PyCFunction) M_Mathutils_MidpointVecs, METH_VARARGS, M_Mathutils_MidpointVecs_doc}, - {"ProjectVecs", (PyCFunction) M_Mathutils_ProjectVecs, METH_VARARGS, M_Mathutils_ProjectVecs_doc}, - {"RotationMatrix", (PyCFunction) M_Mathutils_RotationMatrix, METH_VARARGS, M_Mathutils_RotationMatrix_doc}, - {"ScaleMatrix", (PyCFunction) M_Mathutils_ScaleMatrix, METH_VARARGS, M_Mathutils_ScaleMatrix_doc}, - {"ShearMatrix", (PyCFunction) M_Mathutils_ShearMatrix, METH_VARARGS, M_Mathutils_ShearMatrix_doc}, - {"TranslationMatrix", (PyCFunction) M_Mathutils_TranslationMatrix, METH_O, M_Mathutils_TranslationMatrix_doc}, - {"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc}, - {"DifferenceQuats", (PyCFunction) M_Mathutils_DifferenceQuats, METH_VARARGS,M_Mathutils_DifferenceQuats_doc}, - {"Slerp", (PyCFunction) M_Mathutils_Slerp, METH_VARARGS, M_Mathutils_Slerp_doc}, - {"Intersect", ( PyCFunction ) M_Mathutils_Intersect, METH_VARARGS, M_Mathutils_Intersect_doc}, - {"TriangleArea", ( PyCFunction ) M_Mathutils_TriangleArea, METH_VARARGS, M_Mathutils_TriangleArea_doc}, - {"TriangleNormal", ( PyCFunction ) M_Mathutils_TriangleNormal, METH_VARARGS, M_Mathutils_TriangleNormal_doc}, - {"QuadNormal", ( PyCFunction ) M_Mathutils_QuadNormal, METH_VARARGS, M_Mathutils_QuadNormal_doc}, - {"LineIntersect", ( PyCFunction ) M_Mathutils_LineIntersect, METH_VARARGS, M_Mathutils_LineIntersect_doc}, - {NULL, NULL, 0, NULL} -}; - -/*----------------------------MODULE INIT-------------------------*/ -/* from can be Blender.Mathutils or GameLogic.Mathutils for the BGE */ - -#if (PY_VERSION_HEX >= 0x03000000) -static struct PyModuleDef M_Mathutils_module_def = { - PyModuleDef_HEAD_INIT, - "Mathutils", /* m_name */ - M_Mathutils_doc, /* m_doc */ - 0, /* m_size */ - M_Mathutils_methods, /* m_methods */ - 0, /* m_reload */ - 0, /* m_traverse */ - 0, /* m_clear */ - 0, /* m_free */ -}; -#endif - -PyObject *Mathutils_Init(const char *from) -{ - PyObject *submodule; - - //seed the generator for the rand function - BLI_srand((unsigned int) (PIL_check_seconds_timer() * 0x7FFFFFFF)); - -#if (PY_VERSION_HEX < 0x03000000) - vector_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES; - matrix_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES; - euler_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES; - quaternion_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES; -#endif - - if( PyType_Ready( &vector_Type ) < 0 ) - return NULL; - if( PyType_Ready( &matrix_Type ) < 0 ) - return NULL; - if( PyType_Ready( &euler_Type ) < 0 ) - return NULL; - if( PyType_Ready( &quaternion_Type ) < 0 ) - return NULL; - -#if (PY_VERSION_HEX >= 0x03000000) - submodule = PyModule_Create(&M_Mathutils_module_def); - PyDict_SetItemString(PySys_GetObject("modules"), M_Mathutils_module_def.m_name, submodule); -#else - submodule = Py_InitModule3(from, M_Mathutils_methods, M_Mathutils_doc); -#endif - - /* each type has its own new() function */ - PyModule_AddObject( submodule, "Vector", (PyObject *)&vector_Type ); - PyModule_AddObject( submodule, "Matrix", (PyObject *)&matrix_Type ); - PyModule_AddObject( submodule, "Euler", (PyObject *)&euler_Type ); - PyModule_AddObject( submodule, "Quaternion", (PyObject *)&quaternion_Type ); - - mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb); - - return (submodule); -} - -//-----------------------------METHODS---------------------------- -//-----------------quat_rotation (internal)----------- -//This function multiplies a vector/point * quat or vice versa -//to rotate the point/vector by the quaternion -//arguments should all be 3D -PyObject *quat_rotation(PyObject *arg1, PyObject *arg2) -{ - float rot[3]; - QuaternionObject *quat = NULL; - VectorObject *vec = NULL; - - if(QuaternionObject_Check(arg1)){ - quat = (QuaternionObject*)arg1; - if(!BaseMath_ReadCallback(quat)) - return NULL; - - if(VectorObject_Check(arg2)){ - vec = (VectorObject*)arg2; - - if(!BaseMath_ReadCallback(vec)) - return NULL; - - rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] - - 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] + - 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] - - quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0]; - rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] + - 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] - - quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] - - 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1]; - rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] + - quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] - - quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] - - quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2]; - return newVectorObject(rot, 3, Py_NEW, NULL); - } - }else if(VectorObject_Check(arg1)){ - vec = (VectorObject*)arg1; - - if(!BaseMath_ReadCallback(vec)) - return NULL; - - if(QuaternionObject_Check(arg2)){ - quat = (QuaternionObject*)arg2; - if(!BaseMath_ReadCallback(quat)) - return NULL; - - rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] - - 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] + - 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] - - quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0]; - rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] + - 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] - - quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] - - 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1]; - rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] + - quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] - - quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] - - quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2]; - return newVectorObject(rot, 3, Py_NEW, NULL); - } - } - - PyErr_SetString(PyExc_RuntimeError, "quat_rotation(internal): internal problem rotating vector/point\n"); - return NULL; - -} - -//----------------------------------Mathutils.Rand() -------------------- -//returns a random number between a high and low value -static PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args) -{ - float high, low, range; - double drand; - //initializers - high = 1.0; - low = 0.0; - - if(!PyArg_ParseTuple(args, "|ff", &low, &high)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.Rand(): expected nothing or optional (float, float)\n"); - return NULL; - } - - if((high < low) || (high < 0 && low > 0)) { - PyErr_SetString(PyExc_ValueError, "Mathutils.Rand(): high value should be larger than low value\n"); - return NULL; - } - //get the random number 0 - 1 - drand = BLI_drand(); - - //set it to range - range = high - low; - drand = drand * range; - drand = drand + low; - - return PyFloat_FromDouble(drand); -} -//----------------------------------VECTOR FUNCTIONS--------------------- -//----------------------------------Mathutils.AngleBetweenVecs() --------- -//calculates the angle between 2 vectors -static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args) -{ - VectorObject *vec1 = NULL, *vec2 = NULL; - double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f; - int x, size; - - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) - goto AttributeError1; //not vectors - if(vec1->size != vec2->size) - goto AttributeError1; //bad sizes - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) - return NULL; - - //since size is the same.... - size = vec1->size; - - for(x = 0; x < size; x++) { - test_v1 += vec1->vec[x] * vec1->vec[x]; - test_v2 += vec2->vec[x] * vec2->vec[x]; - } - if (!test_v1 || !test_v2){ - goto AttributeError2; //zero-length vector - } - - //dot product - for(x = 0; x < size; x++) { - dot += vec1->vec[x] * vec2->vec[x]; - } - dot /= (sqrt(test_v1) * sqrt(test_v2)); - - angleRads = (double)saacos(dot); - -#ifdef USE_MATHUTILS_DEG - return PyFloat_FromDouble(angleRads * (180/ Py_PI)); -#else - return PyFloat_FromDouble(angleRads); -#endif -AttributeError1: - PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): expects (2) VECTOR objects of the same size\n"); - return NULL; - -AttributeError2: - PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): zero length vectors are not acceptable arguments\n"); - return NULL; -} -//----------------------------------Mathutils.MidpointVecs() ------------- -//calculates the midpoint between 2 vectors -static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args) -{ - VectorObject *vec1 = NULL, *vec2 = NULL; - float vec[4]; - int x; - - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n"); - return NULL; - } - if(vec1->size != vec2->size) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) - return NULL; - - for(x = 0; x < vec1->size; x++) { - vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]); - } - return newVectorObject(vec, vec1->size, Py_NEW, NULL); -} -//----------------------------------Mathutils.ProjectVecs() ------------- -//projects vector 1 onto vector 2 -static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args) -{ - VectorObject *vec1 = NULL, *vec2 = NULL; - float vec[4]; - double dot = 0.0f, dot2 = 0.0f; - int x, size; - - if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n"); - return NULL; - } - if(vec1->size != vec2->size) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) - return NULL; - - - //since they are the same size... - size = vec1->size; - - //get dot products - for(x = 0; x < size; x++) { - dot += vec1->vec[x] * vec2->vec[x]; - dot2 += vec2->vec[x] * vec2->vec[x]; - } - //projection - dot /= dot2; - for(x = 0; x < size; x++) { - vec[x] = (float)(dot * vec2->vec[x]); - } - return newVectorObject(vec, size, Py_NEW, NULL); -} -//----------------------------------MATRIX FUNCTIONS-------------------- -//----------------------------------Mathutils.RotationMatrix() ---------- -//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. -//creates a rotation matrix -static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args) -{ - VectorObject *vec = NULL; - char *axis = NULL; - int matSize; - float angle = 0.0f, norm = 0.0f, cosAngle = 0.0f, sinAngle = 0.0f; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - - if(!PyArg_ParseTuple(args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.RotationMatrix(): expected float int and optional string and vector\n"); - return NULL; - } - -#ifdef USE_MATHUTILS_DEG - /* Clamp to -360:360 */ - while (angle<-360.0f) - angle+=360.0; - while (angle>360.0f) - angle-=360.0; -#else - while (angle<-(Py_PI*2)) - angle+=(Py_PI*2); - while (angle>(Py_PI*2)) - angle-=(Py_PI*2); -#endif - - if(matSize != 2 && matSize != 3 && matSize != 4) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); - return NULL; - } - if(matSize == 2 && (axis != NULL || vec != NULL)) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): cannot create a 2x2 rotation matrix around arbitrary axis\n"); - return NULL; - } - if((matSize == 3 || matSize == 4) && axis == NULL) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices\n"); - return NULL; - } - if(axis) { - if(((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) && vec == NULL) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please define the arbitrary axis of rotation\n"); - return NULL; - } - } - if(vec) { - if(vec->size != 3) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(vec)) - return NULL; - - } -#ifdef USE_MATHUTILS_DEG - //convert to radians - angle = angle * (float) (Py_PI / 180); -#endif - - if(axis == NULL && matSize == 2) { - //2D rotation matrix - mat[0] = (float) cos (angle); - mat[1] = (float) sin (angle); - mat[2] = -((float) sin(angle)); - mat[3] = (float) cos(angle); - } else if((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0)) { - //rotation around X - mat[0] = 1.0f; - mat[4] = (float) cos(angle); - mat[5] = (float) sin(angle); - mat[7] = -((float) sin(angle)); - mat[8] = (float) cos(angle); - } else if((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0)) { - //rotation around Y - mat[0] = (float) cos(angle); - mat[2] = -((float) sin(angle)); - mat[4] = 1.0f; - mat[6] = (float) sin(angle); - mat[8] = (float) cos(angle); - } else if((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0)) { - //rotation around Z - mat[0] = (float) cos(angle); - mat[1] = (float) sin(angle); - mat[3] = -((float) sin(angle)); - mat[4] = (float) cos(angle); - mat[8] = 1.0f; - } else if((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) { - //arbitrary rotation - //normalize arbitrary axis - norm = (float) sqrt(vec->vec[0] * vec->vec[0] + - vec->vec[1] * vec->vec[1] + - vec->vec[2] * vec->vec[2]); - vec->vec[0] /= norm; - vec->vec[1] /= norm; - vec->vec[2] /= norm; - - if (isnan(vec->vec[0]) || isnan(vec->vec[1]) || isnan(vec->vec[2])) { - /* zero length vector, return an identity matrix, could also return an error */ - mat[0]= mat[4] = mat[8] = 1.0f; - } else { - /* create matrix */ - cosAngle = (float) cos(angle); - sinAngle = (float) sin(angle); - mat[0] = ((vec->vec[0] * vec->vec[0]) * (1 - cosAngle)) + - cosAngle; - mat[1] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) + - (vec->vec[2] * sinAngle); - mat[2] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) - - (vec->vec[1] * sinAngle); - mat[3] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) - - (vec->vec[2] * sinAngle); - mat[4] = ((vec->vec[1] * vec->vec[1]) * (1 - cosAngle)) + - cosAngle; - mat[5] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) + - (vec->vec[0] * sinAngle); - mat[6] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) + - (vec->vec[1] * sinAngle); - mat[7] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) - - (vec->vec[0] * sinAngle); - mat[8] = ((vec->vec[2] * vec->vec[2]) * (1 - cosAngle)) + - cosAngle; - } - } else { - PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n"); - return NULL; - } - if(matSize == 4) { - //resize matrix - mat[10] = mat[8]; - mat[9] = mat[7]; - mat[8] = mat[6]; - mat[7] = 0.0f; - mat[6] = mat[5]; - mat[5] = mat[4]; - mat[4] = mat[3]; - mat[3] = 0.0f; - } - //pass to matrix creation - return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL); -} -//----------------------------------Mathutils.TranslationMatrix() ------- -//creates a translation matrix -static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * vec) -{ - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - - if(!VectorObject_Check(vec)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.TranslationMatrix(): expected vector\n"); - return NULL; - } - if(vec->size != 3 && vec->size != 4) { - PyErr_SetString(PyExc_TypeError, "Mathutils.TranslationMatrix(): vector must be 3D or 4D\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(vec)) - return NULL; - - //create a identity matrix and add translation - Mat4One((float(*)[4]) mat); - mat[12] = vec->vec[0]; - mat[13] = vec->vec[1]; - mat[14] = vec->vec[2]; - - return newMatrixObject(mat, 4, 4, Py_NEW, NULL); -} -//----------------------------------Mathutils.ScaleMatrix() ------------- -//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. -//creates a scaling matrix -static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args) -{ - VectorObject *vec = NULL; - float norm = 0.0f, factor; - int matSize, x; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - - if(!PyArg_ParseTuple(args, "fi|O!", &factor, &matSize, &vector_Type, &vec)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.ScaleMatrix(): expected float int and optional vector\n"); - return NULL; - } - if(matSize != 2 && matSize != 3 && matSize != 4) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.ScaleMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); - return NULL; - } - if(vec) { - if(vec->size > 2 && matSize == 2) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.ScaleMatrix(): please use 2D vectors when scaling in 2D\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(vec)) - return NULL; - - } - if(vec == NULL) { //scaling along axis - if(matSize == 2) { - mat[0] = factor; - mat[3] = factor; - } else { - mat[0] = factor; - mat[4] = factor; - mat[8] = factor; - } - } else { //scaling in arbitrary direction - //normalize arbitrary axis - for(x = 0; x < vec->size; x++) { - norm += vec->vec[x] * vec->vec[x]; - } - norm = (float) sqrt(norm); - for(x = 0; x < vec->size; x++) { - vec->vec[x] /= norm; - } - if(matSize == 2) { - mat[0] = 1 +((factor - 1) *(vec->vec[0] * vec->vec[0])); - mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1])); - mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[1])); - mat[3] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1])); - } else { - mat[0] = 1 + ((factor - 1) *(vec->vec[0] * vec->vec[0])); - mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1])); - mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[2])); - mat[3] =((factor - 1) *(vec->vec[0] * vec->vec[1])); - mat[4] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1])); - mat[5] =((factor - 1) *(vec->vec[1] * vec->vec[2])); - mat[6] =((factor - 1) *(vec->vec[0] * vec->vec[2])); - mat[7] =((factor - 1) *(vec->vec[1] * vec->vec[2])); - mat[8] = 1 + ((factor - 1) *(vec->vec[2] * vec->vec[2])); - } - } - if(matSize == 4) { - //resize matrix - mat[10] = mat[8]; - mat[9] = mat[7]; - mat[8] = mat[6]; - mat[7] = 0.0f; - mat[6] = mat[5]; - mat[5] = mat[4]; - mat[4] = mat[3]; - mat[3] = 0.0f; - } - //pass to matrix creation - return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL); -} -//----------------------------------Mathutils.OrthoProjectionMatrix() --- -//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. -//creates an ortho projection matrix -static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args) -{ - VectorObject *vec = NULL; - char *plane; - int matSize, x; - float norm = 0.0f; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - - if(!PyArg_ParseTuple(args, "si|O!", &plane, &matSize, &vector_Type, &vec)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.OrthoProjectionMatrix(): expected string and int and optional vector\n"); - return NULL; - } - if(matSize != 2 && matSize != 3 && matSize != 4) { - PyErr_SetString(PyExc_AttributeError,"Mathutils.OrthoProjectionMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); - return NULL; - } - if(vec) { - if(vec->size > 2 && matSize == 2) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): please use 2D vectors when scaling in 2D\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(vec)) - return NULL; - - } - if(vec == NULL) { //ortho projection onto cardinal plane - if(((strcmp(plane, "x") == 0) - || (strcmp(plane, "X") == 0)) && matSize == 2) { - mat[0] = 1.0f; - } else if(((strcmp(plane, "y") == 0) - || (strcmp(plane, "Y") == 0)) - && matSize == 2) { - mat[3] = 1.0f; - } else if(((strcmp(plane, "xy") == 0) - || (strcmp(plane, "XY") == 0)) - && matSize > 2) { - mat[0] = 1.0f; - mat[4] = 1.0f; - } else if(((strcmp(plane, "xz") == 0) - || (strcmp(plane, "XZ") == 0)) - && matSize > 2) { - mat[0] = 1.0f; - mat[8] = 1.0f; - } else if(((strcmp(plane, "yz") == 0) - || (strcmp(plane, "YZ") == 0)) - && matSize > 2) { - mat[4] = 1.0f; - mat[8] = 1.0f; - } else { - PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: x, y, xy, xz, yz\n"); - return NULL; - } - } else { //arbitrary plane - //normalize arbitrary axis - for(x = 0; x < vec->size; x++) { - norm += vec->vec[x] * vec->vec[x]; - } - norm = (float) sqrt(norm); - for(x = 0; x < vec->size; x++) { - vec->vec[x] /= norm; - } - if(((strcmp(plane, "r") == 0) - || (strcmp(plane, "R") == 0)) && matSize == 2) { - mat[0] = 1 - (vec->vec[0] * vec->vec[0]); - mat[1] = -(vec->vec[0] * vec->vec[1]); - mat[2] = -(vec->vec[0] * vec->vec[1]); - mat[3] = 1 - (vec->vec[1] * vec->vec[1]); - } else if(((strcmp(plane, "r") == 0) - || (strcmp(plane, "R") == 0)) - && matSize > 2) { - mat[0] = 1 - (vec->vec[0] * vec->vec[0]); - mat[1] = -(vec->vec[0] * vec->vec[1]); - mat[2] = -(vec->vec[0] * vec->vec[2]); - mat[3] = -(vec->vec[0] * vec->vec[1]); - mat[4] = 1 - (vec->vec[1] * vec->vec[1]); - mat[5] = -(vec->vec[1] * vec->vec[2]); - mat[6] = -(vec->vec[0] * vec->vec[2]); - mat[7] = -(vec->vec[1] * vec->vec[2]); - mat[8] = 1 - (vec->vec[2] * vec->vec[2]); - } else { - PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: 'r' expected for axis designation\n"); - return NULL; - } - } - if(matSize == 4) { - //resize matrix - mat[10] = mat[8]; - mat[9] = mat[7]; - mat[8] = mat[6]; - mat[7] = 0.0f; - mat[6] = mat[5]; - mat[5] = mat[4]; - mat[4] = mat[3]; - mat[3] = 0.0f; - } - //pass to matrix creation - return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL); -} -//----------------------------------Mathutils.ShearMatrix() ------------- -//creates a shear matrix -static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args) -{ - int matSize; - char *plane; - float factor; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - - if(!PyArg_ParseTuple(args, "sfi", &plane, &factor, &matSize)) { - PyErr_SetString(PyExc_TypeError,"Mathutils.ShearMatrix(): expected string float and int\n"); - return NULL; - } - if(matSize != 2 && matSize != 3 && matSize != 4) { - PyErr_SetString(PyExc_AttributeError,"Mathutils.ShearMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n"); - return NULL; - } - - if(((strcmp(plane, "x") == 0) || (strcmp(plane, "X") == 0)) - && matSize == 2) { - mat[0] = 1.0f; - mat[2] = factor; - mat[3] = 1.0f; - } else if(((strcmp(plane, "y") == 0) - || (strcmp(plane, "Y") == 0)) && matSize == 2) { - mat[0] = 1.0f; - mat[1] = factor; - mat[3] = 1.0f; - } else if(((strcmp(plane, "xy") == 0) - || (strcmp(plane, "XY") == 0)) && matSize > 2) { - mat[0] = 1.0f; - mat[4] = 1.0f; - mat[6] = factor; - mat[7] = factor; - } else if(((strcmp(plane, "xz") == 0) - || (strcmp(plane, "XZ") == 0)) && matSize > 2) { - mat[0] = 1.0f; - mat[3] = factor; - mat[4] = 1.0f; - mat[5] = factor; - mat[8] = 1.0f; - } else if(((strcmp(plane, "yz") == 0) - || (strcmp(plane, "YZ") == 0)) && matSize > 2) { - mat[0] = 1.0f; - mat[1] = factor; - mat[2] = factor; - mat[4] = 1.0f; - mat[8] = 1.0f; - } else { - PyErr_SetString(PyExc_AttributeError, "Mathutils.ShearMatrix(): expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n"); - return NULL; - } - if(matSize == 4) { - //resize matrix - mat[10] = mat[8]; - mat[9] = mat[7]; - mat[8] = mat[6]; - mat[7] = 0.0f; - mat[6] = mat[5]; - mat[5] = mat[4]; - mat[4] = mat[3]; - mat[3] = 0.0f; - } - //pass to matrix creation - return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL); -} -//----------------------------------QUATERNION FUNCTIONS----------------- - -//----------------------------------Mathutils.DifferenceQuats() --------- -//returns the difference between 2 quaternions -static PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args) -{ - QuaternionObject *quatU = NULL, *quatV = NULL; - float quat[4], tempQuat[4]; - double dot = 0.0f; - int x; - - if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU, &quaternion_Type, &quatV)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.DifferenceQuats(): expected Quaternion types"); - return NULL; - } - - if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV)) - return NULL; - - tempQuat[0] = quatU->quat[0]; - tempQuat[1] = -quatU->quat[1]; - tempQuat[2] = -quatU->quat[2]; - tempQuat[3] = -quatU->quat[3]; - - dot = sqrt(tempQuat[0] * tempQuat[0] + tempQuat[1] * tempQuat[1] + - tempQuat[2] * tempQuat[2] + tempQuat[3] * tempQuat[3]); - - for(x = 0; x < 4; x++) { - tempQuat[x] /= (float)(dot * dot); - } - QuatMul(quat, tempQuat, quatV->quat); - return newQuaternionObject(quat, Py_NEW, NULL); -} -//----------------------------------Mathutils.Slerp() ------------------ -//attemps to interpolate 2 quaternions and return the result -static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args) -{ - QuaternionObject *quatU = NULL, *quatV = NULL; - float quat[4], quat_u[4], quat_v[4], param; - double x, y, dot, sinT, angle, IsinT; - int z; - - if(!PyArg_ParseTuple(args, "O!O!f", &quaternion_Type, &quatU, &quaternion_Type, &quatV, ¶m)) { - PyErr_SetString(PyExc_TypeError, "Mathutils.Slerp(): expected Quaternion types and float"); - return NULL; - } - - if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV)) - return NULL; - - if(param > 1.0f || param < 0.0f) { - PyErr_SetString(PyExc_AttributeError, "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0"); - return NULL; - } - - //copy quats - for(z = 0; z < 4; z++){ - quat_u[z] = quatU->quat[z]; - quat_v[z] = quatV->quat[z]; - } - - //dot product - dot = quat_u[0] * quat_v[0] + quat_u[1] * quat_v[1] + - quat_u[2] * quat_v[2] + quat_u[3] * quat_v[3]; - - //if negative negate a quat (shortest arc) - if(dot < 0.0f) { - quat_v[0] = -quat_v[0]; - quat_v[1] = -quat_v[1]; - quat_v[2] = -quat_v[2]; - quat_v[3] = -quat_v[3]; - dot = -dot; - } - if(dot > .99999f) { //very close - x = 1.0f - param; - y = param; - } else { - //calculate sin of angle - sinT = sqrt(1.0f - (dot * dot)); - //calculate angle - angle = atan2(sinT, dot); - //caluculate inverse of sin(theta) - IsinT = 1.0f / sinT; - x = sin((1.0f - param) * angle) * IsinT; - y = sin(param * angle) * IsinT; - } - //interpolate - quat[0] = (float)(quat_u[0] * x + quat_v[0] * y); - quat[1] = (float)(quat_u[1] * x + quat_v[1] * y); - quat[2] = (float)(quat_u[2] * x + quat_v[2] * y); - quat[3] = (float)(quat_u[3] * x + quat_v[3] * y); - - return newQuaternionObject(quat, Py_NEW, NULL); -} -//----------------------------------EULER FUNCTIONS---------------------- -//---------------------------------INTERSECTION FUNCTIONS-------------------- -//----------------------------------Mathutils.Intersect() ------------------- -static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args ) -{ - VectorObject *ray, *ray_off, *vec1, *vec2, *vec3; - float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3]; - float det, inv_det, u, v, t; - int clip = 1; - - if(!PyArg_ParseTuple(args, "O!O!O!O!O!|i", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off , &clip)) { - PyErr_SetString( PyExc_TypeError, "expected 5 vector types\n" ); - return NULL; - } - if(vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) { - PyErr_SetString( PyExc_TypeError, "only 3D vectors for all parameters\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(ray) || !BaseMath_ReadCallback(ray_off)) - return NULL; - - VECCOPY(v1, vec1->vec); - VECCOPY(v2, vec2->vec); - VECCOPY(v3, vec3->vec); - - VECCOPY(dir, ray->vec); - Normalize(dir); - - VECCOPY(orig, ray_off->vec); - - /* find vectors for two edges sharing v1 */ - VecSubf(e1, v2, v1); - VecSubf(e2, v3, v1); - - /* begin calculating determinant - also used to calculated U parameter */ - Crossf(pvec, dir, e2); - - /* if determinant is near zero, ray lies in plane of triangle */ - det = Inpf(e1, pvec); - - if (det > -0.000001 && det < 0.000001) { - Py_RETURN_NONE; - } - - inv_det = 1.0f / det; - - /* calculate distance from v1 to ray origin */ - VecSubf(tvec, orig, v1); - - /* calculate U parameter and test bounds */ - u = Inpf(tvec, pvec) * inv_det; - if (clip && (u < 0.0f || u > 1.0f)) { - Py_RETURN_NONE; - } - - /* prepare to test the V parameter */ - Crossf(qvec, tvec, e1); - - /* calculate V parameter and test bounds */ - v = Inpf(dir, qvec) * inv_det; - - if (clip && (v < 0.0f || u + v > 1.0f)) { - Py_RETURN_NONE; - } - - /* calculate t, ray intersects triangle */ - t = Inpf(e2, qvec) * inv_det; - - VecMulf(dir, t); - VecAddf(pvec, orig, dir); - - return newVectorObject(pvec, 3, Py_NEW, NULL); -} -//----------------------------------Mathutils.LineIntersect() ------------------- -/* Line-Line intersection using algorithm from mathworld.wolfram.com */ -static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args ) -{ - PyObject * tuple; - VectorObject *vec1, *vec2, *vec3, *vec4; - float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3]; - - if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) { - PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" ); - return NULL; - } - if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec2->size) { - PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4)) - return NULL; - - if( vec1->size == 3 || vec1->size == 2) { - int result; - - if (vec1->size == 3) { - VECCOPY(v1, vec1->vec); - VECCOPY(v2, vec2->vec); - VECCOPY(v3, vec3->vec); - VECCOPY(v4, vec4->vec); - } - else { - v1[0] = vec1->vec[0]; - v1[1] = vec1->vec[1]; - v1[2] = 0.0f; - - v2[0] = vec2->vec[0]; - v2[1] = vec2->vec[1]; - v2[2] = 0.0f; - - v3[0] = vec3->vec[0]; - v3[1] = vec3->vec[1]; - v3[2] = 0.0f; - - v4[0] = vec4->vec[0]; - v4[1] = vec4->vec[1]; - v4[2] = 0.0f; - } - - result = LineIntersectLine(v1, v2, v3, v4, i1, i2); - - if (result == 0) { - /* colinear */ - Py_RETURN_NONE; - } - else { - tuple = PyTuple_New( 2 ); - PyTuple_SetItem( tuple, 0, newVectorObject(i1, vec1->size, Py_NEW, NULL) ); - PyTuple_SetItem( tuple, 1, newVectorObject(i2, vec1->size, Py_NEW, NULL) ); - return tuple; - } - } - else { - PyErr_SetString( PyExc_TypeError, "2D/3D vectors only\n" ); - return NULL; - } -} - - - -//---------------------------------NORMALS FUNCTIONS-------------------- -//----------------------------------Mathutils.QuadNormal() ------------------- -static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args ) -{ - VectorObject *vec1; - VectorObject *vec2; - VectorObject *vec3; - VectorObject *vec4; - float v1[3], v2[3], v3[3], v4[3], e1[3], e2[3], n1[3], n2[3]; - - if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) { - PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" ); - return NULL; - } - if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) { - PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" ); - return NULL; - } - if( vec1->size != 3 ) { - PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4)) - return NULL; - - VECCOPY(v1, vec1->vec); - VECCOPY(v2, vec2->vec); - VECCOPY(v3, vec3->vec); - VECCOPY(v4, vec4->vec); - - /* find vectors for two edges sharing v2 */ - VecSubf(e1, v1, v2); - VecSubf(e2, v3, v2); - - Crossf(n1, e2, e1); - Normalize(n1); - - /* find vectors for two edges sharing v4 */ - VecSubf(e1, v3, v4); - VecSubf(e2, v1, v4); - - Crossf(n2, e2, e1); - Normalize(n2); - - /* adding and averaging the normals of both triangles */ - VecAddf(n1, n2, n1); - Normalize(n1); - - return newVectorObject(n1, 3, Py_NEW, NULL); -} - -//----------------------------Mathutils.TriangleNormal() ------------------- -static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args ) -{ - VectorObject *vec1, *vec2, *vec3; - float v1[3], v2[3], v3[3], e1[3], e2[3], n[3]; - - if( !PyArg_ParseTuple( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3 ) ) { - PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" ); - return NULL; - } - if( vec1->size != vec2->size || vec1->size != vec3->size ) { - PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" ); - return NULL; - } - if( vec1->size != 3 ) { - PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3)) - return NULL; - - VECCOPY(v1, vec1->vec); - VECCOPY(v2, vec2->vec); - VECCOPY(v3, vec3->vec); - - /* find vectors for two edges sharing v2 */ - VecSubf(e1, v1, v2); - VecSubf(e2, v3, v2); - - Crossf(n, e2, e1); - Normalize(n); - - return newVectorObject(n, 3, Py_NEW, NULL); -} - -//--------------------------------- AREA FUNCTIONS-------------------- -//----------------------------------Mathutils.TriangleArea() ------------------- -static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args ) -{ - VectorObject *vec1, *vec2, *vec3; - float v1[3], v2[3], v3[3]; - - if( !PyArg_ParseTuple - ( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2 - , &vector_Type, &vec3 ) ) { - PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n"); - return NULL; - } - if( vec1->size != vec2->size || vec1->size != vec3->size ) { - PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3)) - return NULL; - - if (vec1->size == 3) { - VECCOPY(v1, vec1->vec); - VECCOPY(v2, vec2->vec); - VECCOPY(v3, vec3->vec); - - return PyFloat_FromDouble( AreaT3Dfl(v1, v2, v3) ); - } - else if (vec1->size == 2) { - v1[0] = vec1->vec[0]; - v1[1] = vec1->vec[1]; - - v2[0] = vec2->vec[0]; - v2[1] = vec2->vec[1]; - - v3[0] = vec3->vec[0]; - v3[1] = vec3->vec[1]; - - return PyFloat_FromDouble( AreaF2Dfl(v1, v2, v3) ); - } - else { - PyErr_SetString( PyExc_TypeError, "only 2D,3D vectors are supported\n" ); - return NULL; - } -} - -/* Utility functions */ - -/*---------------------- EXPP_FloatsAreEqual ------------------------- - Floating point comparisons - floatStep = number of representable floats allowable in between - float A and float B to be considered equal. */ -int EXPP_FloatsAreEqual(float A, float B, int floatSteps) -{ - int a, b, delta; - assert(floatSteps > 0 && floatSteps < (4 * 1024 * 1024)); - a = *(int*)&A; - if (a < 0) - a = 0x80000000 - a; - b = *(int*)&B; - if (b < 0) - b = 0x80000000 - b; - delta = abs(a - b); - if (delta <= floatSteps) - return 1; - return 0; -} -/*---------------------- EXPP_VectorsAreEqual ------------------------- - Builds on EXPP_FloatsAreEqual to test vectors */ -int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps) -{ - int x; - for (x=0; x< size; x++){ - if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0) - return 0; - } - return 1; -} - - -/* Mathutils Callbacks */ - -/* for mathutils internal use only, eventually should re-alloc but to start with we only have a few users */ -Mathutils_Callback *mathutils_callbacks[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; - -int Mathutils_RegisterCallback(Mathutils_Callback *cb) -{ - int i; - - /* find the first free slot */ - for(i= 0; mathutils_callbacks[i]; i++) { - if(mathutils_callbacks[i]==cb) /* alredy registered? */ - return i; - } - - mathutils_callbacks[i] = cb; - return i; -} - -/* use macros to check for NULL */ -int _BaseMathObject_ReadCallback(BaseMathObject *self) -{ - Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; - if(cb->get(self->cb_user, self->cb_subtype, self->data)) - return 1; - - PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name); - return 0; -} - -int _BaseMathObject_WriteCallback(BaseMathObject *self) -{ - Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; - if(cb->set(self->cb_user, self->cb_subtype, self->data)) - return 1; - - PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name); - return 0; -} - -int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index) -{ - Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; - if(cb->get_index(self->cb_user, self->cb_subtype, self->data, index)) - return 1; - - PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name); - return 0; -} - -int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index) -{ - Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; - if(cb->set_index(self->cb_user, self->cb_subtype, self->data, index)) - return 1; - - PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name); - return 0; -} - -/* BaseMathObject generic functions for all mathutils types */ -PyObject *BaseMathObject_getOwner( BaseMathObject * self, void *type ) -{ - PyObject *ret= self->cb_user ? self->cb_user : Py_None; - Py_INCREF(ret); - return ret; -} - -PyObject *BaseMathObject_getWrapped( BaseMathObject *self, void *type ) -{ - return PyBool_FromLong((self->wrapped == Py_WRAP) ? 1:0); -} - -void BaseMathObject_dealloc(BaseMathObject * self) -{ - /* only free non wrapped */ - if(self->wrapped != Py_WRAP) - PyMem_Free(self->data); - - Py_XDECREF(self->cb_user); - Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); // breaks subtypes -} - diff --git a/source/blender/python/generic/Mathutils.h b/source/blender/python/generic/Mathutils.h deleted file mode 100644 index 5bdd9d9cfe0..00000000000 --- a/source/blender/python/generic/Mathutils.h +++ /dev/null @@ -1,116 +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. - * - * This is a new part of Blender. - * - * Contributor(s): Joseph Gilbert - * - * ***** END GPL LICENSE BLOCK ***** -*/ -//Include this file for access to vector, quat, matrix, euler, etc... - -#ifndef EXPP_Mathutils_H -#define EXPP_Mathutils_H - -#include <Python.h> -#include "../intern/bpy_compat.h" -#include "vector.h" -#include "matrix.h" -#include "quat.h" -#include "euler.h" - -/* #define USE_MATHUTILS_DEG - for backwards compat */ - -/* Can cast different mathutils types to this, use for generic funcs */ - -typedef struct { - PyObject_VAR_HEAD - float *data; /*array of data (alias), wrapped status depends on wrapped status */ - PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */ - unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ - unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */ - unsigned char wrapped; /* wrapped data type? */ -} BaseMathObject; - -PyObject *BaseMathObject_getOwner( BaseMathObject * self, void * ); -PyObject *BaseMathObject_getWrapped( BaseMathObject *self, void * ); -void BaseMathObject_dealloc(BaseMathObject * self); - - - - -PyObject *Mathutils_Init( const char * from ); - -PyObject *quat_rotation(PyObject *arg1, PyObject *arg2); - -int EXPP_FloatsAreEqual(float A, float B, int floatSteps); -int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps); - - -#define Py_PI 3.14159265358979323846 - -#define Py_NEW 1 -#define Py_WRAP 2 - - -/* Mathutils is used by the BGE and Blender so have to define - * some things here for luddite mac users of py2.3 */ -#ifndef Py_RETURN_NONE -#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None -#endif -#ifndef Py_RETURN_FALSE -#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False -#endif -#ifndef Py_RETURN_TRUE -#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True -#endif - -typedef struct Mathutils_Callback Mathutils_Callback; - -typedef int (*BaseMathCheckFunc)(PyObject *); -typedef int (*BaseMathGetFunc)(PyObject *, int, float *); -typedef int (*BaseMathSetFunc)(PyObject *, int, float *); -typedef int (*BaseMathGetIndexFunc)(PyObject *, int, float *, int); -typedef int (*BaseMathSetIndexFunc)(PyObject *, int, float *, int); - -struct Mathutils_Callback { - int (*check)(PyObject *user); /* checks the user is still valid */ - int (*get)(PyObject *user, int subtype, float *from); /* gets the vector from the user */ - int (*set)(PyObject *user, int subtype, float *to); /* sets the users vector values once the vector is modified */ - int (*get_index)(PyObject *user, int subtype, float *from,int index); /* same as above but only for an index */ - int (*set_index)(PyObject *user, int subtype, float *to, int index); /* same as above but only for an index */ -}; - -int Mathutils_RegisterCallback(Mathutils_Callback *cb); - -int _BaseMathObject_ReadCallback(BaseMathObject *self); -int _BaseMathObject_WriteCallback(BaseMathObject *self); -int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index); -int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index); - -/* since this is called so often avoid where possible */ -#define BaseMath_ReadCallback(_self) (((_self)->cb_user ? _BaseMathObject_ReadCallback((BaseMathObject *)_self):1)) -#define BaseMath_WriteCallback(_self) (((_self)->cb_user ?_BaseMathObject_WriteCallback((BaseMathObject *)_self):1)) -#define BaseMath_ReadIndexCallback(_self, _index) (((_self)->cb_user ? _BaseMathObject_ReadIndexCallback((BaseMathObject *)_self, _index):1)) -#define BaseMath_WriteIndexCallback(_self, _index) (((_self)->cb_user ? _BaseMathObject_WriteIndexCallback((BaseMathObject *)_self, _index):1)) - -#endif /* EXPP_Mathutils_H */ diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c deleted file mode 100644 index c41ea386c0e..00000000000 --- a/source/blender/python/generic/bpy_internal_import.c +++ /dev/null @@ -1,341 +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. - * - * This is a new part of Blender. - * - * Contributor(s): Willian P. Germano - * - * ***** END GPL LICENSE BLOCK ***** -*/ - -#include "bpy_internal_import.h" -#include "DNA_text_types.h" -#include "DNA_ID.h" - -#include "MEM_guardedalloc.h" -#include "BKE_text.h" /* txt_to_buf */ -#include "BKE_main.h" - -static Main *bpy_import_main= NULL; - -static void free_compiled_text(Text *text) -{ - if(text->compiled) { - Py_DECREF(( PyObject * )text->compiled); - } - text->compiled= NULL; -} - -struct Main *bpy_import_main_get(void) -{ - return bpy_import_main; -} - -void bpy_import_main_set(struct Main *maggie) -{ - bpy_import_main= maggie; -} - - -PyObject *bpy_text_import( char *name, int *found ) -{ - Text *text; - char txtname[22]; /* 21+NULL */ - char *buf = NULL; - int namelen = strlen( name ); -//XXX Main *maggie= bpy_import_main ? bpy_import_main:G.main; - Main *maggie= bpy_import_main; - - *found= 0; - - if (namelen>21-3) return NULL; /* we know this cant be importable, the name is too long for blender! */ - - memcpy( txtname, name, namelen ); - memcpy( &txtname[namelen], ".py", 4 ); - - for(text = maggie->text.first; text; text = text->id.next) { - if( !strcmp( txtname, text->id.name+2 ) ) - break; - } - - if( !text ) - return NULL; - else - *found = 1; - - if( !text->compiled ) { - buf = txt_to_buf( text ); - text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input ); - MEM_freeN( buf ); - - if( PyErr_Occurred( ) ) { - PyErr_Print( ); - PyErr_Clear( ); - PySys_SetObject("last_traceback", NULL); - free_compiled_text( text ); - return NULL; - } - } - - return PyImport_ExecCodeModule( name, text->compiled ); -} - - -/* - * find in-memory module and recompile - */ - -PyObject *bpy_text_reimport( PyObject *module, int *found ) -{ - Text *text; - char *txtname; - char *name; - char *buf = NULL; -//XXX Main *maggie= bpy_import_main ? bpy_import_main:G.main; - Main *maggie= bpy_import_main; - - *found= 0; - - /* get name, filename from the module itself */ - - txtname = PyModule_GetFilename( module ); - name = PyModule_GetName( module ); - if( !txtname || !name) - return NULL; - - /* look up the text object */ - text = ( Text * ) & ( maggie->text.first ); - while( text ) { - if( !strcmp( txtname, text->id.name+2 ) ) - break; - text = text->id.next; - } - - /* uh-oh.... didn't find it */ - if( !text ) - return NULL; - else - *found = 1; - - /* if previously compiled, free the object */ - /* (can't see how could be NULL, but check just in case) */ - if( text->compiled ){ - Py_DECREF( (PyObject *)text->compiled ); - } - - /* compile the buffer */ - buf = txt_to_buf( text ); - text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input ); - MEM_freeN( buf ); - - /* if compile failed.... return this error */ - if( PyErr_Occurred( ) ) { - PyErr_Print( ); - PyErr_Clear( ); - PySys_SetObject("last_traceback", NULL); - free_compiled_text( text ); - return NULL; - } - - /* make into a module */ - return PyImport_ExecCodeModule( name, text->compiled ); -} - - -static PyObject *blender_import( PyObject * self, PyObject * args, PyObject * kw) -{ - PyObject *exception, *err, *tb; - char *name; - int found= 0; - PyObject *globals = NULL, *locals = NULL, *fromlist = NULL; - PyObject *newmodule; - - //PyObject_Print(args, stderr, 0); -#if (PY_VERSION_HEX >= 0x02060000) - int dummy_val; /* what does this do?*/ - static char *kwlist[] = {"name", "globals", "locals", "fromlist", "level", 0}; - - if( !PyArg_ParseTupleAndKeywords( args, kw, "s|OOOi:bpy_import_meth", kwlist, - &name, &globals, &locals, &fromlist, &dummy_val) ) - return NULL; -#else - static char *kwlist[] = {"name", "globals", "locals", "fromlist", 0}; - - if( !PyArg_ParseTupleAndKeywords( args, kw, "s|OOO:bpy_import_meth", kwlist, - &name, &globals, &locals, &fromlist ) ) - return NULL; -#endif - - /* import existing builtin modules or modules that have been imported alredy */ - newmodule = PyImport_ImportModuleEx( name, globals, locals, fromlist ); - - if(newmodule) - return newmodule; - - PyErr_Fetch( &exception, &err, &tb ); /* get the python error incase we cant import as blender text either */ - - /* importing from existing modules failed, see if we have this module as blender text */ - newmodule = bpy_text_import( name, &found ); - - if( newmodule ) {/* found module as blender text, ignore above exception */ - PyErr_Clear( ); - Py_XDECREF( exception ); - Py_XDECREF( err ); - Py_XDECREF( tb ); - /* printf( "imported from text buffer...\n" ); */ - } - else if (found==1) { /* blender text module failed to execute but was found, use its error message */ - Py_XDECREF( exception ); - Py_XDECREF( err ); - Py_XDECREF( tb ); - return NULL; - } - else { - /* no blender text was found that could import the module - * rause the original error from PyImport_ImportModuleEx */ - PyErr_Restore( exception, err, tb ); - } - return newmodule; -} - - -/* - * our reload() module, to handle reloading in-memory scripts - */ - -static PyObject *blender_reload( PyObject * self, PyObject * args ) -{ - PyObject *exception, *err, *tb; - PyObject *module = NULL; - PyObject *newmodule = NULL; - int found= 0; - - /* check for a module arg */ - if( !PyArg_ParseTuple( args, "O:bpy_reload_meth", &module ) ) - return NULL; - - /* try reimporting from file */ - newmodule = PyImport_ReloadModule( module ); - if( newmodule ) - return newmodule; - - /* no file, try importing from memory */ - PyErr_Fetch( &exception, &err, &tb ); /*restore for probable later use */ - - newmodule = bpy_text_reimport( module, &found ); - if( newmodule ) {/* found module as blender text, ignore above exception */ - PyErr_Clear( ); - Py_XDECREF( exception ); - Py_XDECREF( err ); - Py_XDECREF( tb ); - /* printf( "imported from text buffer...\n" ); */ - } - else if (found==1) { /* blender text module failed to execute but was found, use its error message */ - Py_XDECREF( exception ); - Py_XDECREF( err ); - Py_XDECREF( tb ); - return NULL; - } - else { - /* no blender text was found that could import the module - * rause the original error from PyImport_ImportModuleEx */ - PyErr_Restore( exception, err, tb ); - } - - return newmodule; -} - -PyMethodDef bpy_import_meth[] = { {"bpy_import_meth", blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"} }; -PyMethodDef bpy_reload_meth[] = { {"bpy_reload_meth", blender_reload, METH_VARARGS, "blenders reload"} }; - - -/* Clear user modules. - * This is to clear any modules that could be defined from running scripts in blender. - * - * Its also needed for the BGE Python api so imported scripts are not used between levels - * - * This clears every modules that has a __file__ attribute (is not a builtin) - * - * Note that clearing external python modules is important for the BGE otherwise - * it wont reload scripts between loading different blend files or while making the game. - * - use 'clear_all' arg in this case. - * - * Since pythons bultins include a full path even for win32. - * even if we remove a python module a reimport will bring it back again. - */ - -#if 0 // not used anymore but may still come in handy later - -#if defined(WIN32) || defined(WIN64) -#define SEPSTR "\\" -#else -#define SEPSTR "/" -#endif - - -void bpy_text_clear_modules(int clear_all) -{ - PyObject *modules= PySys_GetObject("modules"); - - char *fname; - char *file_extension; - - /* looping over the dict */ - PyObject *key, *value; - int pos = 0; - - /* new list */ - PyObject *list; - - if (modules==NULL) - return; /* should never happen but just incase */ - - list= PyList_New(0); - - /* go over sys.modules and remove anything with a - * sys.modukes[x].__file__ thats ends with a .py and has no path - */ - while (PyDict_Next(modules, &pos, &key, &value)) { - fname= PyModule_GetFilename(value); - if(fname) { - if (clear_all || ((strstr(fname, SEPSTR))==0)) { /* no path ? */ - file_extension = strstr(fname, ".py"); - if(file_extension && (*(file_extension + 3) == '\0' || *(file_extension + 4) == '\0')) { /* .py or pyc extension? */ - /* now we can be fairly sure its a python import from the blendfile */ - PyList_Append(list, key); /* free'd with the list */ - } - } - } - else { - PyErr_Clear(); - } - } - - /* remove all our modules */ - for(pos=0; pos < PyList_Size(list); pos++) { - /* PyObject_Print(key, stderr, 0); */ - key= PyList_GET_ITEM(list, pos); - PyDict_DelItem(modules, key); - } - - Py_DECREF(list); /* removes all references from append */ -} -#endif diff --git a/source/blender/python/generic/bpy_internal_import.h b/source/blender/python/generic/bpy_internal_import.h deleted file mode 100644 index aeeafb7c1c4..00000000000 --- a/source/blender/python/generic/bpy_internal_import.h +++ /dev/null @@ -1,50 +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. - * - * This is a new part of Blender. - * - * Contributor(s): Willian P. Germano, Campbell Barton - * - * ***** END GPL LICENSE BLOCK ***** -*/ - -/* Note, the BGE needs to use this too, keep it minimal */ - -#ifndef EXPP_bpy_import_h -#define EXPP_bpy_import_h - -#include <Python.h> -#include "../intern/bpy_compat.h" -#include "compile.h" /* for the PyCodeObject */ -#include "eval.h" /* for PyEval_EvalCode */ - -PyObject* bpy_text_import( char *name, int *found ); -PyObject* bpy_text_reimport( PyObject *module, int *found ); -/* void bpy_text_clear_modules( int clear_all );*/ /* Clear user modules */ -extern PyMethodDef bpy_import_meth[]; -extern PyMethodDef bpy_reload_meth[]; - -/* The game engine has its own Main struct, if this is set search this rather then G.main */ -struct Main *bpy_import_main_get(void); -void bpy_import_main_set(struct Main *maggie); - - -#endif /* EXPP_bpy_import_h */ diff --git a/source/blender/python/generic/euler.c b/source/blender/python/generic/euler.c deleted file mode 100644 index 69373b1aa36..00000000000 --- a/source/blender/python/generic/euler.c +++ /dev/null @@ -1,651 +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. - * - * - * Contributor(s): Joseph Gilbert - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "Mathutils.h" - -#include "BLI_arithb.h" -#include "BKE_utildefines.h" -#include "BLI_blenlib.h" - - -//-------------------------DOC STRINGS --------------------------- - -static PyObject *Euler_Zero( EulerObject * self ); -static PyObject *Euler_Unique( EulerObject * self ); -static PyObject *Euler_ToMatrix( EulerObject * self ); -static PyObject *Euler_ToQuat( EulerObject * self ); -static PyObject *Euler_Rotate( EulerObject * self, PyObject *args ); -static PyObject *Euler_MakeCompatible( EulerObject * self, EulerObject *value ); -static PyObject *Euler_copy( EulerObject * self, PyObject *args ); - -//-----------------------METHOD DEFINITIONS ---------------------- -static struct PyMethodDef Euler_methods[] = { - {"zero", (PyCFunction) Euler_Zero, METH_NOARGS, NULL}, - {"unique", (PyCFunction) Euler_Unique, METH_NOARGS, NULL}, - {"toMatrix", (PyCFunction) Euler_ToMatrix, METH_NOARGS, NULL}, - {"toQuat", (PyCFunction) Euler_ToQuat, METH_NOARGS, NULL}, - {"rotate", (PyCFunction) Euler_Rotate, METH_VARARGS, NULL}, - {"makeCompatible", (PyCFunction) Euler_MakeCompatible, METH_O, NULL}, - {"__copy__", (PyCFunction) Euler_copy, METH_VARARGS, NULL}, - {"copy", (PyCFunction) Euler_copy, METH_VARARGS, NULL}, - {NULL, NULL, 0, NULL} -}; - -//----------------------------------Mathutils.Euler() ------------------- -//makes a new euler for you to play with -static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwargs) -{ - PyObject *listObject = NULL; - int size, i; - float eul[3]; - PyObject *e; - - size = PyTuple_GET_SIZE(args); - if (size == 1) { - listObject = PyTuple_GET_ITEM(args, 0); - if (PySequence_Check(listObject)) { - size = PySequence_Length(listObject); - } else { // Single argument was not a sequence - PyErr_SetString(PyExc_TypeError, "Mathutils.Euler(): 3d numeric sequence expected\n"); - return NULL; - } - } else if (size == 0) { - //returns a new empty 3d euler - return newEulerObject(NULL, Py_NEW, NULL); - } else { - listObject = args; - } - - if (size != 3) { // Invalid euler size - PyErr_SetString(PyExc_AttributeError, "Mathutils.Euler(): 3d numeric sequence expected\n"); - return NULL; - } - - for (i=0; i<size; i++) { - e = PySequence_GetItem(listObject, i); - if (e == NULL) { // Failed to read sequence - Py_DECREF(listObject); - PyErr_SetString(PyExc_RuntimeError, "Mathutils.Euler(): 3d numeric sequence expected\n"); - return NULL; - } - - eul[i]= (float)PyFloat_AsDouble(e); - Py_DECREF(e); - - if(eul[i]==-1 && PyErr_Occurred()) { // parsed item is not a number - PyErr_SetString(PyExc_TypeError, "Mathutils.Euler(): 3d numeric sequence expected\n"); - return NULL; - } - } - return newEulerObject(eul, Py_NEW, NULL); -} - -//-----------------------------METHODS---------------------------- -//----------------------------Euler.toQuat()---------------------- -//return a quaternion representation of the euler -static PyObject *Euler_ToQuat(EulerObject * self) -{ - float quat[4]; -#ifdef USE_MATHUTILS_DEG - float eul[3]; - int x; -#endif - - if(!BaseMath_ReadCallback(self)) - return NULL; - -#ifdef USE_MATHUTILS_DEG - for(x = 0; x < 3; x++) { - eul[x] = self->eul[x] * ((float)Py_PI / 180); - } - EulToQuat(eul, quat); -#else - EulToQuat(self->eul, quat); -#endif - - return newQuaternionObject(quat, Py_NEW, NULL); -} -//----------------------------Euler.toMatrix()--------------------- -//return a matrix representation of the euler -static PyObject *Euler_ToMatrix(EulerObject * self) -{ - float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; - - if(!BaseMath_ReadCallback(self)) - return NULL; - -#ifdef USE_MATHUTILS_DEG - { - float eul[3]; - int x; - - for(x = 0; x < 3; x++) { - eul[x] = self->eul[x] * ((float)Py_PI / 180); - } - EulToMat3(eul, (float (*)[3]) mat); - } -#else - EulToMat3(self->eul, (float (*)[3]) mat); -#endif - return newMatrixObject(mat, 3, 3 , Py_NEW, NULL); -} -//----------------------------Euler.unique()----------------------- -//sets the x,y,z values to a unique euler rotation -static PyObject *Euler_Unique(EulerObject * self) -{ -#define PI_2 (Py_PI * 2.0) -#define PI_HALF (Py_PI / 2.0) -#define PI_INV (1.0 / Py_PI) - - double heading, pitch, bank; - - if(!BaseMath_ReadCallback(self)) - return NULL; - -#ifdef USE_MATHUTILS_DEG - //radians - heading = self->eul[0] * (float)Py_PI / 180; - pitch = self->eul[1] * (float)Py_PI / 180; - bank = self->eul[2] * (float)Py_PI / 180; -#else - heading = self->eul[0]; - pitch = self->eul[1]; - bank = self->eul[2]; -#endif - - //wrap heading in +180 / -180 - pitch += Py_PI; - pitch -= floor(pitch * PI_INV) * PI_2; - pitch -= Py_PI; - - - if(pitch < -PI_HALF) { - pitch = -Py_PI - pitch; - heading += Py_PI; - bank += Py_PI; - } else if(pitch > PI_HALF) { - pitch = Py_PI - pitch; - heading += Py_PI; - bank += Py_PI; - } - //gimbal lock test - if(fabs(pitch) > PI_HALF - 1e-4) { - heading += bank; - bank = 0.0f; - } else { - bank += Py_PI; - bank -= (floor(bank * PI_INV)) * PI_2; - bank -= Py_PI; - } - - heading += Py_PI; - heading -= (floor(heading * PI_INV)) * PI_2; - heading -= Py_PI; - -#ifdef USE_MATHUTILS_DEG - //back to degrees - self->eul[0] = (float)(heading * 180 / (float)Py_PI); - self->eul[1] = (float)(pitch * 180 / (float)Py_PI); - self->eul[2] = (float)(bank * 180 / (float)Py_PI); -#endif - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject *)self; -} -//----------------------------Euler.zero()------------------------- -//sets the euler to 0,0,0 -static PyObject *Euler_Zero(EulerObject * self) -{ - self->eul[0] = 0.0; - self->eul[1] = 0.0; - self->eul[2] = 0.0; - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject *)self; -} -//----------------------------Euler.rotate()----------------------- -//rotates a euler a certain amount and returns the result -//should return a unique euler rotation (i.e. no 720 degree pitches :) -static PyObject *Euler_Rotate(EulerObject * self, PyObject *args) -{ - float angle = 0.0f; - char *axis; - - if(!PyArg_ParseTuple(args, "fs", &angle, &axis)){ - PyErr_SetString(PyExc_TypeError, "euler.rotate():expected angle (float) and axis (x,y,z)"); - return NULL; - } - if(!STREQ3(axis,"x","y","z")){ - PyErr_SetString(PyExc_TypeError, "euler.rotate(): expected axis to be 'x', 'y' or 'z'"); - return NULL; - } - - if(!BaseMath_ReadCallback(self)) - return NULL; - -#ifdef USE_MATHUTILS_DEG - { - int x; - - //covert to radians - angle *= ((float)Py_PI / 180); - for(x = 0; x < 3; x++) { - self->eul[x] *= ((float)Py_PI / 180); - } - } -#endif - euler_rot(self->eul, angle, *axis); - -#ifdef USE_MATHUTILS_DEG - { - int x; - //convert back from radians - for(x = 0; x < 3; x++) { - self->eul[x] *= (180 / (float)Py_PI); - } - } -#endif - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject *)self; -} - -static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value) -{ -#ifdef USE_MATHUTILS_DEG - float eul_from_rad[3]; - int x; -#endif - - if(!EulerObject_Check(value)) { - PyErr_SetString(PyExc_TypeError, "euler.makeCompatible(euler):expected a single euler argument."); - return NULL; - } - - if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) - return NULL; - -#ifdef USE_MATHUTILS_DEG - //covert to radians - for(x = 0; x < 3; x++) { - self->eul[x] = self->eul[x] * ((float)Py_PI / 180); - eul_from_rad[x] = value->eul[x] * ((float)Py_PI / 180); - } - compatible_eul(self->eul, eul_from_rad); -#else - compatible_eul(self->eul, value->eul); -#endif - -#ifdef USE_MATHUTILS_DEG - //convert back from radians - for(x = 0; x < 3; x++) { - self->eul[x] *= (180 / (float)Py_PI); - } -#endif - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject *)self; -} - -//----------------------------Euler.rotate()----------------------- -// return a copy of the euler -static PyObject *Euler_copy(EulerObject * self, PyObject *args) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - return newEulerObject(self->eul, Py_NEW, Py_TYPE(self)); -} - -//----------------------------print object (internal)-------------- -//print the object to screen -static PyObject *Euler_repr(EulerObject * self) -{ - char str[64]; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - sprintf(str, "[%.6f, %.6f, %.6f](euler)", self->eul[0], self->eul[1], self->eul[2]); - return PyUnicode_FromString(str); -} -//------------------------tp_richcmpr -//returns -1 execption, 0 false, 1 true -static PyObject* Euler_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type) -{ - EulerObject *eulA = NULL, *eulB = NULL; - int result = 0; - - if(EulerObject_Check(objectA)) { - eulA = (EulerObject*)objectA; - if(!BaseMath_ReadCallback(eulA)) - return NULL; - } - if(EulerObject_Check(objectB)) { - eulB = (EulerObject*)objectB; - if(!BaseMath_ReadCallback(eulB)) - return NULL; - } - - if (!eulA || !eulB){ - if (comparison_type == Py_NE){ - Py_RETURN_TRUE; - }else{ - Py_RETURN_FALSE; - } - } - eulA = (EulerObject*)objectA; - eulB = (EulerObject*)objectB; - - switch (comparison_type){ - case Py_EQ: - result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1); - break; - case Py_NE: - result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1); - if (result == 0){ - result = 1; - }else{ - result = 0; - } - break; - default: - printf("The result of the comparison could not be evaluated"); - break; - } - if (result == 1){ - Py_RETURN_TRUE; - }else{ - Py_RETURN_FALSE; - } -} - -//---------------------SEQUENCE PROTOCOLS------------------------ -//----------------------------len(object)------------------------ -//sequence length -static int Euler_len(EulerObject * self) -{ - return 3; -} -//----------------------------object[]--------------------------- -//sequence accessor (get) -static PyObject *Euler_item(EulerObject * self, int i) -{ - if(i<0) i= 3-i; - - if(i < 0 || i >= 3) { - PyErr_SetString(PyExc_IndexError, "euler[attribute]: array index out of range"); - return NULL; - } - - if(!BaseMath_ReadIndexCallback(self, i)) - return NULL; - - return PyFloat_FromDouble(self->eul[i]); - -} -//----------------------------object[]------------------------- -//sequence accessor (set) -static int Euler_ass_item(EulerObject * self, int i, PyObject * value) -{ - float f = PyFloat_AsDouble(value); - - if(f == -1 && PyErr_Occurred()) { // parsed item not a number - PyErr_SetString(PyExc_TypeError, "euler[attribute] = x: argument not a number"); - return -1; - } - - if(i<0) i= 3-i; - - if(i < 0 || i >= 3){ - PyErr_SetString(PyExc_IndexError, "euler[attribute] = x: array assignment index out of range\n"); - return -1; - } - - self->eul[i] = f; - - if(!BaseMath_WriteIndexCallback(self, i)) - return -1; - - return 0; -} -//----------------------------object[z:y]------------------------ -//sequence slice (get) -static PyObject *Euler_slice(EulerObject * self, int begin, int end) -{ - PyObject *list = NULL; - int count; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - CLAMP(begin, 0, 3); - if (end<0) end= 4+end; - CLAMP(end, 0, 3); - begin = MIN2(begin,end); - - list = PyList_New(end - begin); - for(count = begin; count < end; count++) { - PyList_SetItem(list, count - begin, - PyFloat_FromDouble(self->eul[count])); - } - - return list; -} -//----------------------------object[z:y]------------------------ -//sequence slice (set) -static int Euler_ass_slice(EulerObject * self, int begin, int end, - PyObject * seq) -{ - int i, y, size = 0; - float eul[3]; - PyObject *e; - - if(!BaseMath_ReadCallback(self)) - return -1; - - CLAMP(begin, 0, 3); - if (end<0) end= 4+end; - CLAMP(end, 0, 3); - begin = MIN2(begin,end); - - size = PySequence_Length(seq); - if(size != (end - begin)){ - PyErr_SetString(PyExc_TypeError, "euler[begin:end] = []: size mismatch in slice assignment"); - return -1; - } - - for (i = 0; i < size; i++) { - e = PySequence_GetItem(seq, i); - if (e == NULL) { // Failed to read sequence - PyErr_SetString(PyExc_RuntimeError, "euler[begin:end] = []: unable to read sequence"); - return -1; - } - - eul[i] = (float)PyFloat_AsDouble(e); - Py_DECREF(e); - - if(eul[i]==-1 && PyErr_Occurred()) { // parsed item not a number - PyErr_SetString(PyExc_TypeError, "euler[begin:end] = []: sequence argument not a number"); - return -1; - } - } - //parsed well - now set in vector - for(y = 0; y < 3; y++){ - self->eul[begin + y] = eul[y]; - } - - BaseMath_WriteCallback(self); - return 0; -} -//-----------------PROTCOL DECLARATIONS-------------------------- -static PySequenceMethods Euler_SeqMethods = { - (inquiry) Euler_len, /* sq_length */ - (binaryfunc) 0, /* sq_concat */ - (ssizeargfunc) 0, /* sq_repeat */ - (ssizeargfunc) Euler_item, /* sq_item */ - (ssizessizeargfunc) Euler_slice, /* sq_slice */ - (ssizeobjargproc) Euler_ass_item, /* sq_ass_item */ - (ssizessizeobjargproc) Euler_ass_slice, /* sq_ass_slice */ -}; - - -/* - * vector axis, vector.x/y/z/w - */ - -static PyObject *Euler_getAxis( EulerObject * self, void *type ) -{ - return Euler_item(self, GET_INT_FROM_POINTER(type)); -} - -static int Euler_setAxis( EulerObject * self, PyObject * value, void * type ) -{ - return Euler_ass_item(self, GET_INT_FROM_POINTER(type), value); -} - -/*****************************************************************************/ -/* Python attributes get/set structure: */ -/*****************************************************************************/ -static PyGetSetDef Euler_getseters[] = { - {"x", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler X axis", (void *)0}, - {"y", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler Y axis", (void *)1}, - {"z", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler Z axis", (void *)2}, - - {"wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, "True when this wraps blenders internal data", NULL}, - {"__owner__", (getter)BaseMathObject_getOwner, (setter)NULL, "Read only owner for vectors that depend on another object", NULL}, - {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ -}; - -//------------------PY_OBECT DEFINITION-------------------------- -PyTypeObject euler_Type = { -#if (PY_VERSION_HEX >= 0x02060000) - PyVarObject_HEAD_INIT(NULL, 0) -#else - /* python 2.5 and below */ - PyObject_HEAD_INIT( NULL ) /* required py macro */ - 0, /* ob_size */ -#endif - "euler", //tp_name - sizeof(EulerObject), //tp_basicsize - 0, //tp_itemsize - (destructor)BaseMathObject_dealloc, //tp_dealloc - 0, //tp_print - 0, //tp_getattr - 0, //tp_setattr - 0, //tp_compare - (reprfunc) Euler_repr, //tp_repr - 0, //tp_as_number - &Euler_SeqMethods, //tp_as_sequence - 0, //tp_as_mapping - 0, //tp_hash - 0, //tp_call - 0, //tp_str - 0, //tp_getattro - 0, //tp_setattro - 0, //tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags - 0, //tp_doc - 0, //tp_traverse - 0, //tp_clear - (richcmpfunc)Euler_richcmpr, //tp_richcompare - 0, //tp_weaklistoffset - 0, //tp_iter - 0, //tp_iternext - Euler_methods, //tp_methods - 0, //tp_members - Euler_getseters, //tp_getset - 0, //tp_base - 0, //tp_dict - 0, //tp_descr_get - 0, //tp_descr_set - 0, //tp_dictoffset - 0, //tp_init - 0, //tp_alloc - Euler_new, //tp_new - 0, //tp_free - 0, //tp_is_gc - 0, //tp_bases - 0, //tp_mro - 0, //tp_cache - 0, //tp_subclasses - 0, //tp_weaklist - 0 //tp_del -}; -//------------------------newEulerObject (internal)------------- -//creates a new euler object -/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - (i.e. it was allocated elsewhere by MEM_mallocN()) - pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *newEulerObject(float *eul, int type, PyTypeObject *base_type) -{ - EulerObject *self; - int x; - - if(base_type) self = (EulerObject *)base_type->tp_alloc(base_type, 0); - else self = PyObject_NEW(EulerObject, &euler_Type); - - /* init callbacks as NULL */ - self->cb_user= NULL; - self->cb_type= self->cb_subtype= 0; - - if(type == Py_WRAP){ - self->eul = eul; - self->wrapped = Py_WRAP; - }else if (type == Py_NEW){ - self->eul = PyMem_Malloc(3 * sizeof(float)); - if(!eul) { //new empty - for(x = 0; x < 3; x++) { - self->eul[x] = 0.0f; - } - }else{ - VECCOPY(self->eul, eul); - } - self->wrapped = Py_NEW; - }else{ //bad type - return NULL; - } - return (PyObject *)self; -} - -PyObject *newEulerObject_cb(PyObject *cb_user, int cb_type, int cb_subtype) -{ - EulerObject *self= (EulerObject *)newEulerObject(NULL, Py_NEW, NULL); - if(self) { - Py_INCREF(cb_user); - self->cb_user= cb_user; - self->cb_type= (unsigned char)cb_type; - self->cb_subtype= (unsigned char)cb_subtype; - } - - return (PyObject *)self; -} diff --git a/source/blender/python/generic/euler.h b/source/blender/python/generic/euler.h deleted file mode 100644 index a3706d53756..00000000000 --- a/source/blender/python/generic/euler.h +++ /dev/null @@ -1,60 +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): Joseph Gilbert - * - * ***** END GPL LICENSE BLOCK ***** - * - */ - -#ifndef EXPP_euler_h -#define EXPP_euler_h - -#include <Python.h> -#include "../intern/bpy_compat.h" - -extern PyTypeObject euler_Type; -#define EulerObject_Check(_v) PyObject_TypeCheck((_v), &euler_Type) - -typedef struct { - PyObject_VAR_HEAD - float *eul; /*1D array of data */ - PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */ - unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ - unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */ - unsigned char wrapped; /* wrapped data type? */ - /* end BaseMathObject */ - -} EulerObject; - -/*struct data contains a pointer to the actual data that the -object uses. It can use either PyMem allocated data (which will -be stored in py_data) or be a wrapper for data allocated through -blender (stored in blend_data). This is an either/or struct not both*/ - -//prototypes -PyObject *newEulerObject( float *eul, int type, PyTypeObject *base_type); -PyObject *newEulerObject_cb(PyObject *cb_user, int cb_type, int cb_subtype); - -#endif /* EXPP_euler_h */ diff --git a/source/blender/python/generic/matrix.c b/source/blender/python/generic/matrix.c deleted file mode 100644 index 5bdbf804618..00000000000 --- a/source/blender/python/generic/matrix.c +++ /dev/null @@ -1,1358 +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. - * - * Contributor(s): Michel Selten & Joseph Gilbert - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "Mathutils.h" - -#include "BKE_utildefines.h" -#include "BLI_arithb.h" -#include "BLI_blenlib.h" - -static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec); /* utility func */ - - -/* matrix vector callbacks */ -int mathutils_matrix_vector_cb_index= -1; - -static int mathutils_matrix_vector_check(MatrixObject *self) -{ - return BaseMath_ReadCallback(self); -} - -static int mathutils_matrix_vector_get(MatrixObject *self, int subtype, float *vec_from) -{ - int i; - if(!BaseMath_ReadCallback(self)) - return 0; - - for(i=0; i<self->colSize; i++) - vec_from[i]= self->matrix[subtype][i]; - - return 1; -} - -static int mathutils_matrix_vector_set(MatrixObject *self, int subtype, float *vec_to) -{ - int i; - if(!BaseMath_ReadCallback(self)) - return 0; - - for(i=0; i<self->colSize; i++) - self->matrix[subtype][i]= vec_to[i]; - - BaseMath_WriteCallback(self); - return 1; -} - -static int mathutils_matrix_vector_get_index(MatrixObject *self, int subtype, float *vec_from, int index) -{ - if(!BaseMath_ReadCallback(self)) - return 0; - - vec_from[index]= self->matrix[subtype][index]; - return 1; -} - -static int mathutils_matrix_vector_set_index(MatrixObject *self, int subtype, float *vec_to, int index) -{ - if(!BaseMath_ReadCallback(self)) - return 0; - - self->matrix[subtype][index]= vec_to[index]; - - BaseMath_WriteCallback(self); - return 1; -} - -Mathutils_Callback mathutils_matrix_vector_cb = { - mathutils_matrix_vector_check, - mathutils_matrix_vector_get, - mathutils_matrix_vector_set, - mathutils_matrix_vector_get_index, - mathutils_matrix_vector_set_index -}; -/* matrix vector callbacks, this is so you can do matrix[i][j] = val */ - -/*-------------------------DOC STRINGS ---------------------------*/ - -static PyObject *Matrix_Zero( MatrixObject * self ); -static PyObject *Matrix_Identity( MatrixObject * self ); -static PyObject *Matrix_Transpose( MatrixObject * self ); -static PyObject *Matrix_Determinant( MatrixObject * self ); -static PyObject *Matrix_Invert( MatrixObject * self ); -static PyObject *Matrix_TranslationPart( MatrixObject * self ); -static PyObject *Matrix_RotationPart( MatrixObject * self ); -static PyObject *Matrix_scalePart( MatrixObject * self ); -static PyObject *Matrix_Resize4x4( MatrixObject * self ); -static PyObject *Matrix_toEuler( MatrixObject * self, PyObject *args ); -static PyObject *Matrix_toQuat( MatrixObject * self ); -static PyObject *Matrix_copy( MatrixObject * self ); - -/*-----------------------METHOD DEFINITIONS ----------------------*/ -static struct PyMethodDef Matrix_methods[] = { - {"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, NULL}, - {"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, NULL}, - {"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, NULL}, - {"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, NULL}, - {"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, NULL}, - {"translationPart", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, NULL}, - {"rotationPart", (PyCFunction) Matrix_RotationPart, METH_NOARGS, NULL}, - {"scalePart", (PyCFunction) Matrix_scalePart, METH_NOARGS, NULL}, - {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, NULL}, - {"toEuler", (PyCFunction) Matrix_toEuler, METH_VARARGS, NULL}, - {"toQuat", (PyCFunction) Matrix_toQuat, METH_NOARGS, NULL}, - {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, NULL}, - {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, NULL}, - {NULL, NULL, 0, NULL} -}; - -//----------------------------------Mathutils.Matrix() ----------------- -//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc. -//create a new matrix type -static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *argObject, *m, *s; - MatrixObject *mat; - int argSize, seqSize = 0, i, j; - float matrix[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - float scalar; - - argSize = PyTuple_GET_SIZE(args); - if(argSize > 4){ //bad arg nums - PyErr_SetString(PyExc_AttributeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); - return NULL; - } else if (argSize == 0) { //return empty 4D matrix - return (PyObject *) newMatrixObject(NULL, 4, 4, Py_NEW, NULL); - }else if (argSize == 1){ - //copy constructor for matrix objects - argObject = PyTuple_GET_ITEM(args, 0); - if(MatrixObject_Check(argObject)){ - mat = (MatrixObject*)argObject; - if(!BaseMath_ReadCallback(mat)) - return NULL; - - memcpy(matrix, mat->contigPtr, sizeof(float) * mat->rowSize * mat->colSize); - } - }else{ //2-4 arguments (all seqs? all same size?) - for(i =0; i < argSize; i++){ - argObject = PyTuple_GET_ITEM(args, i); - if (PySequence_Check(argObject)) { //seq? - if(seqSize){ //0 at first - if(PySequence_Length(argObject) != seqSize){ //seq size not same - PyErr_SetString(PyExc_AttributeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); - return NULL; - } - } - seqSize = PySequence_Length(argObject); - }else{ //arg not a sequence - PyErr_SetString(PyExc_TypeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); - return NULL; - } - } - //all is well... let's continue parsing - for (i = 0; i < argSize; i++){ - m = PyTuple_GET_ITEM(args, i); - if (m == NULL) { // Failed to read sequence - PyErr_SetString(PyExc_RuntimeError, "Mathutils.Matrix(): failed to parse arguments...\n"); - return NULL; - } - - for (j = 0; j < seqSize; j++) { - s = PySequence_GetItem(m, j); - if (s == NULL) { // Failed to read sequence - PyErr_SetString(PyExc_RuntimeError, "Mathutils.Matrix(): failed to parse arguments...\n"); - return NULL; - } - - scalar= (float)PyFloat_AsDouble(s); - Py_DECREF(s); - - if(scalar==-1 && PyErr_Occurred()) { // parsed item is not a number - PyErr_SetString(PyExc_AttributeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n"); - return NULL; - } - - matrix[(seqSize*i)+j]= scalar; - } - } - } - return newMatrixObject(matrix, argSize, seqSize, Py_NEW, NULL); -} - -/*-----------------------------METHODS----------------------------*/ -/*---------------------------Matrix.toQuat() ---------------------*/ -static PyObject *Matrix_toQuat(MatrixObject * self) -{ - float quat[4]; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - /*must be 3-4 cols, 3-4 rows, square matrix*/ - if(self->colSize < 3 || self->rowSize < 3 || (self->colSize != self->rowSize)) { - PyErr_SetString(PyExc_AttributeError, "Matrix.toQuat(): inappropriate matrix size - expects 3x3 or 4x4 matrix"); - return NULL; - } - if(self->colSize == 3){ - Mat3ToQuat((float (*)[3])*self->matrix, quat); - }else{ - Mat4ToQuat((float (*)[4])*self->matrix, quat); - } - - return newQuaternionObject(quat, Py_NEW, NULL); -} -/*---------------------------Matrix.toEuler() --------------------*/ -PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args) -{ - float eul[3], eul_compatf[3]; - EulerObject *eul_compat = NULL; -#ifdef USE_MATHUTILS_DEG - int x; -#endif - - if(!BaseMath_ReadCallback(self)) - return NULL; - - if(!PyArg_ParseTuple(args, "|O!:toEuler", &euler_Type, &eul_compat)) - return NULL; - - if(eul_compat) { - if(!BaseMath_ReadCallback(eul_compat)) - return NULL; - -#ifdef USE_MATHUTILS_DEG - for(x = 0; x < 3; x++) { - eul_compatf[x] = eul_compat->eul[x] * ((float)Py_PI / 180); - } -#else - VECCOPY(eul_compatf, eul_compat->eul); -#endif - } - - /*must be 3-4 cols, 3-4 rows, square matrix*/ - if(self->colSize ==3 && self->rowSize ==3) { - if(eul_compat) Mat3ToCompatibleEul((float (*)[3])*self->matrix, eul, eul_compatf); - else Mat3ToEul((float (*)[3])*self->matrix, eul); - }else if (self->colSize ==4 && self->rowSize ==4) { - float tempmat3[3][3]; - Mat3CpyMat4(tempmat3, (float (*)[4])*self->matrix); - Mat3ToEul(tempmat3, eul); - if(eul_compat) Mat3ToCompatibleEul(tempmat3, eul, eul_compatf); - else Mat3ToEul(tempmat3, eul); - - }else { - PyErr_SetString(PyExc_AttributeError, "Matrix.toEuler(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n"); - return NULL; - } -#ifdef USE_MATHUTILS_DEG - /*have to convert to degrees*/ - for(x = 0; x < 3; x++) { - eul[x] *= (float) (180 / Py_PI); - } -#endif - return newEulerObject(eul, Py_NEW, NULL); -} -/*---------------------------Matrix.resize4x4() ------------------*/ -PyObject *Matrix_Resize4x4(MatrixObject * self) -{ - int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index; - - if(self->wrapped==Py_WRAP){ - PyErr_SetString(PyExc_TypeError, "cannot resize wrapped data - make a copy and resize that"); - return NULL; - } - if(self->cb_user){ - PyErr_SetString(PyExc_TypeError, "cannot resize owned data - make a copy and resize that"); - return NULL; - } - - self->contigPtr = PyMem_Realloc(self->contigPtr, (sizeof(float) * 16)); - if(self->contigPtr == NULL) { - PyErr_SetString(PyExc_MemoryError, "matrix.resize4x4(): problem allocating pointer space"); - return NULL; - } - self->matrix = PyMem_Realloc(self->matrix, (sizeof(float *) * 4)); - if(self->matrix == NULL) { - PyErr_SetString(PyExc_MemoryError, "matrix.resize4x4(): problem allocating pointer space"); - return NULL; - } - /*set row pointers*/ - for(x = 0; x < 4; x++) { - self->matrix[x] = self->contigPtr + (x * 4); - } - /*move data to new spot in array + clean*/ - for(blank_rows = (4 - self->rowSize); blank_rows > 0; blank_rows--){ - for(x = 0; x < 4; x++){ - index = (4 * (self->rowSize + (blank_rows - 1))) + x; - if (index == 10 || index == 15){ - self->contigPtr[index] = 1.0f; - }else{ - self->contigPtr[index] = 0.0f; - } - } - } - for(x = 1; x <= self->rowSize; x++){ - first_row_elem = (self->colSize * (self->rowSize - x)); - curr_pos = (first_row_elem + (self->colSize -1)); - new_pos = (4 * (self->rowSize - x )) + (curr_pos - first_row_elem); - for(blank_columns = (4 - self->colSize); blank_columns > 0; blank_columns--){ - self->contigPtr[new_pos + blank_columns] = 0.0f; - } - for(curr_pos = curr_pos; curr_pos >= first_row_elem; curr_pos--){ - self->contigPtr[new_pos] = self->contigPtr[curr_pos]; - new_pos--; - } - } - self->rowSize = 4; - self->colSize = 4; - - Py_INCREF(self); - return (PyObject *)self; -} -/*---------------------------Matrix.translationPart() ------------*/ -PyObject *Matrix_TranslationPart(MatrixObject * self) -{ - float vec[4]; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - if(self->colSize < 3 || self->rowSize < 4){ - PyErr_SetString(PyExc_AttributeError, "Matrix.translationPart: inappropriate matrix size"); - return NULL; - } - - vec[0] = self->matrix[3][0]; - vec[1] = self->matrix[3][1]; - vec[2] = self->matrix[3][2]; - - return newVectorObject(vec, 3, Py_NEW, NULL); -} -/*---------------------------Matrix.rotationPart() ---------------*/ -PyObject *Matrix_RotationPart(MatrixObject * self) -{ - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - if(self->colSize < 3 || self->rowSize < 3){ - PyErr_SetString(PyExc_AttributeError, "Matrix.rotationPart: inappropriate matrix size\n"); - return NULL; - } - - mat[0] = self->matrix[0][0]; - mat[1] = self->matrix[0][1]; - mat[2] = self->matrix[0][2]; - mat[3] = self->matrix[1][0]; - mat[4] = self->matrix[1][1]; - mat[5] = self->matrix[1][2]; - mat[6] = self->matrix[2][0]; - mat[7] = self->matrix[2][1]; - mat[8] = self->matrix[2][2]; - - return newMatrixObject(mat, 3, 3, Py_NEW, Py_TYPE(self)); -} -/*---------------------------Matrix.scalePart() --------------------*/ -PyObject *Matrix_scalePart(MatrixObject * self) -{ - float scale[3], rot[3]; - float mat[3][3], imat[3][3], tmat[3][3]; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - /*must be 3-4 cols, 3-4 rows, square matrix*/ - if(self->colSize == 4 && self->rowSize == 4) - Mat3CpyMat4(mat, (float (*)[4])*self->matrix); - else if(self->colSize == 3 && self->rowSize == 3) - Mat3CpyMat3(mat, (float (*)[3])*self->matrix); - else { - PyErr_SetString(PyExc_AttributeError, "Matrix.scalePart(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n"); - return NULL; - } - /* functionality copied from editobject.c apply_obmat */ - Mat3ToEul(mat, rot); - EulToMat3(rot, tmat); - Mat3Inv(imat, tmat); - Mat3MulMat3(tmat, imat, mat); - - scale[0]= tmat[0][0]; - scale[1]= tmat[1][1]; - scale[2]= tmat[2][2]; - return newVectorObject(scale, 3, Py_NEW, NULL); -} -/*---------------------------Matrix.invert() ---------------------*/ -PyObject *Matrix_Invert(MatrixObject * self) -{ - - int x, y, z = 0; - float det = 0.0f; - PyObject *f = NULL; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - if(self->rowSize != self->colSize){ - PyErr_SetString(PyExc_AttributeError, "Matrix.invert(ed): only square matrices are supported"); - return NULL; - } - - /*calculate the determinant*/ - f = Matrix_Determinant(self); - det = (float)PyFloat_AS_DOUBLE(f); /*Increfs, so we need to decref*/ - Py_DECREF(f); - - if(det != 0) { - /*calculate the classical adjoint*/ - if(self->rowSize == 2) { - mat[0] = self->matrix[1][1]; - mat[1] = -self->matrix[0][1]; - mat[2] = -self->matrix[1][0]; - mat[3] = self->matrix[0][0]; - } else if(self->rowSize == 3) { - Mat3Adj((float (*)[3]) mat,(float (*)[3]) *self->matrix); - } else if(self->rowSize == 4) { - Mat4Adj((float (*)[4]) mat, (float (*)[4]) *self->matrix); - } - /*divide by determinate*/ - for(x = 0; x < (self->rowSize * self->colSize); x++) { - mat[x] /= det; - } - /*set values*/ - for(x = 0; x < self->rowSize; x++) { - for(y = 0; y < self->colSize; y++) { - self->matrix[x][y] = mat[z]; - z++; - } - } - /*transpose - Matrix_Transpose(self);*/ - } else { - PyErr_SetString(PyExc_ValueError, "matrix does not have an inverse"); - return NULL; - } - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject *)self; -} - - -/*---------------------------Matrix.determinant() ----------------*/ -PyObject *Matrix_Determinant(MatrixObject * self) -{ - float det = 0.0f; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - if(self->rowSize != self->colSize){ - PyErr_SetString(PyExc_AttributeError, "Matrix.determinant: only square matrices are supported"); - return NULL; - } - - if(self->rowSize == 2) { - det = Det2x2(self->matrix[0][0], self->matrix[0][1], - self->matrix[1][0], self->matrix[1][1]); - } else if(self->rowSize == 3) { - det = Det3x3(self->matrix[0][0], self->matrix[0][1], - self->matrix[0][2], self->matrix[1][0], - self->matrix[1][1], self->matrix[1][2], - self->matrix[2][0], self->matrix[2][1], - self->matrix[2][2]); - } else { - det = Det4x4((float (*)[4]) *self->matrix); - } - - return PyFloat_FromDouble( (double) det ); -} -/*---------------------------Matrix.transpose() ------------------*/ -PyObject *Matrix_Transpose(MatrixObject * self) -{ - float t = 0.0f; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - if(self->rowSize != self->colSize){ - PyErr_SetString(PyExc_AttributeError, "Matrix.transpose(d): only square matrices are supported"); - return NULL; - } - - if(self->rowSize == 2) { - t = self->matrix[1][0]; - self->matrix[1][0] = self->matrix[0][1]; - self->matrix[0][1] = t; - } else if(self->rowSize == 3) { - Mat3Transp((float (*)[3])*self->matrix); - } else { - Mat4Transp((float (*)[4])*self->matrix); - } - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject *)self; -} - - -/*---------------------------Matrix.zero() -----------------------*/ -PyObject *Matrix_Zero(MatrixObject * self) -{ - int row, col; - - for(row = 0; row < self->rowSize; row++) { - for(col = 0; col < self->colSize; col++) { - self->matrix[row][col] = 0.0f; - } - } - - if(!BaseMath_WriteCallback(self)) - return NULL; - - Py_INCREF(self); - return (PyObject *)self; -} -/*---------------------------Matrix.identity(() ------------------*/ -PyObject *Matrix_Identity(MatrixObject * self) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - if(self->rowSize != self->colSize){ - PyErr_SetString(PyExc_AttributeError, "Matrix.identity: only square matrices are supported\n"); - return NULL; - } - - if(self->rowSize == 2) { - self->matrix[0][0] = 1.0f; - self->matrix[0][1] = 0.0f; - self->matrix[1][0] = 0.0f; - self->matrix[1][1] = 1.0f; - } else if(self->rowSize == 3) { - Mat3One((float (*)[3]) *self->matrix); - } else { - Mat4One((float (*)[4]) *self->matrix); - } - - if(!BaseMath_WriteCallback(self)) - return NULL; - - Py_INCREF(self); - return (PyObject *)self; -} - -/*---------------------------Matrix.inverted() ------------------*/ -PyObject *Matrix_copy(MatrixObject * self) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - return (PyObject*)newMatrixObject((float (*))*self->matrix, self->rowSize, self->colSize, Py_NEW, Py_TYPE(self)); -} - -/*----------------------------print object (internal)-------------*/ -/*print the object to screen*/ -static PyObject *Matrix_repr(MatrixObject * self) -{ - int x, y; - char buffer[48], str[1024]; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - BLI_strncpy(str,"",1024); - for(x = 0; x < self->rowSize; x++){ - sprintf(buffer, "["); - strcat(str,buffer); - for(y = 0; y < (self->colSize - 1); y++) { - sprintf(buffer, "%.6f, ", self->matrix[x][y]); - strcat(str,buffer); - } - if(x < (self->rowSize-1)){ - sprintf(buffer, "%.6f](matrix [row %d])\n", self->matrix[x][y], x); - strcat(str,buffer); - }else{ - sprintf(buffer, "%.6f](matrix [row %d])", self->matrix[x][y], x); - strcat(str,buffer); - } - } - - return PyUnicode_FromString(str); -} -/*------------------------tp_richcmpr*/ -/*returns -1 execption, 0 false, 1 true*/ -static PyObject* Matrix_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type) -{ - MatrixObject *matA = NULL, *matB = NULL; - int result = 0; - - if (!MatrixObject_Check(objectA) || !MatrixObject_Check(objectB)){ - if (comparison_type == Py_NE){ - Py_RETURN_TRUE; - }else{ - Py_RETURN_FALSE; - } - } - matA = (MatrixObject*)objectA; - matB = (MatrixObject*)objectB; - - if(!BaseMath_ReadCallback(matA) || !BaseMath_ReadCallback(matB)) - return NULL; - - if (matA->colSize != matB->colSize || matA->rowSize != matB->rowSize){ - if (comparison_type == Py_NE){ - Py_RETURN_TRUE; - }else{ - Py_RETURN_FALSE; - } - } - - switch (comparison_type){ - case Py_EQ: - /*contigPtr is basically a really long vector*/ - result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr, - (matA->rowSize * matA->colSize), 1); - break; - case Py_NE: - result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr, - (matA->rowSize * matA->colSize), 1); - if (result == 0){ - result = 1; - }else{ - result = 0; - } - break; - default: - printf("The result of the comparison could not be evaluated"); - break; - } - if (result == 1){ - Py_RETURN_TRUE; - }else{ - Py_RETURN_FALSE; - } -} - -/*---------------------SEQUENCE PROTOCOLS------------------------ - ----------------------------len(object)------------------------ - sequence length*/ -static int Matrix_len(MatrixObject * self) -{ - return (self->rowSize); -} -/*----------------------------object[]--------------------------- - sequence accessor (get) - the wrapped vector gives direct access to the matrix data*/ -static PyObject *Matrix_item(MatrixObject * self, int i) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - if(i < 0 || i >= self->rowSize) { - PyErr_SetString(PyExc_IndexError, "matrix[attribute]: array index out of range"); - return NULL; - } - return newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, i); -} -/*----------------------------object[]------------------------- - sequence accessor (set)*/ -static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob) -{ - int y, x, size = 0; - float vec[4]; - PyObject *m, *f; - - if(!BaseMath_ReadCallback(self)) - return -1; - - if(i >= self->rowSize || i < 0){ - PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad row\n"); - return -1; - } - - if(PySequence_Check(ob)){ - size = PySequence_Length(ob); - if(size != self->colSize){ - PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad sequence size\n"); - return -1; - } - for (x = 0; x < size; x++) { - m = PySequence_GetItem(ob, x); - if (m == NULL) { /*Failed to read sequence*/ - PyErr_SetString(PyExc_RuntimeError, "matrix[attribute] = x: unable to read sequence\n"); - return -1; - } - - f = PyNumber_Float(m); - if(f == NULL) { /*parsed item not a number*/ - Py_DECREF(m); - PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: sequence argument not a number\n"); - return -1; - } - - vec[x] = (float)PyFloat_AS_DOUBLE(f); - Py_DECREF(m); - Py_DECREF(f); - } - /*parsed well - now set in matrix*/ - for(y = 0; y < size; y++){ - self->matrix[i][y] = vec[y]; - } - - BaseMath_WriteCallback(self); - return 0; - }else{ - PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: expects a sequence of column size\n"); - return -1; - } -} -/*----------------------------object[z:y]------------------------ - sequence slice (get)*/ -static PyObject *Matrix_slice(MatrixObject * self, int begin, int end) -{ - - PyObject *list = NULL; - int count; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - CLAMP(begin, 0, self->rowSize); - CLAMP(end, 0, self->rowSize); - begin = MIN2(begin,end); - - list = PyList_New(end - begin); - for(count = begin; count < end; count++) { - PyList_SetItem(list, count - begin, - newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, count)); - - } - - return list; -} -/*----------------------------object[z:y]------------------------ - sequence slice (set)*/ -static int Matrix_ass_slice(MatrixObject * self, int begin, int end, PyObject * seq) -{ - int i, x, y, size, sub_size = 0; - float mat[16], f; - PyObject *subseq; - PyObject *m; - - if(!BaseMath_ReadCallback(self)) - return -1; - - CLAMP(begin, 0, self->rowSize); - CLAMP(end, 0, self->rowSize); - begin = MIN2(begin,end); - - if(PySequence_Check(seq)){ - size = PySequence_Length(seq); - if(size != (end - begin)){ - PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment\n"); - return -1; - } - /*parse sub items*/ - for (i = 0; i < size; i++) { - /*parse each sub sequence*/ - subseq = PySequence_GetItem(seq, i); - if (subseq == NULL) { /*Failed to read sequence*/ - PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence"); - return -1; - } - - if(PySequence_Check(subseq)){ - /*subsequence is also a sequence*/ - sub_size = PySequence_Length(subseq); - if(sub_size != self->colSize){ - Py_DECREF(subseq); - PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment\n"); - return -1; - } - for (y = 0; y < sub_size; y++) { - m = PySequence_GetItem(subseq, y); - if (m == NULL) { /*Failed to read sequence*/ - Py_DECREF(subseq); - PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence\n"); - return -1; - } - - f = PyFloat_AsDouble(m); /* faster to assume a float and raise an error after */ - if(f == -1 && PyErr_Occurred()) { /*parsed item not a number*/ - Py_DECREF(m); - Py_DECREF(subseq); - PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: sequence argument not a number\n"); - return -1; - } - - mat[(i * self->colSize) + y] = f; - Py_DECREF(m); - } - }else{ - Py_DECREF(subseq); - PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation\n"); - return -1; - } - Py_DECREF(subseq); - } - /*parsed well - now set in matrix*/ - for(x = 0; x < (size * sub_size); x++){ - self->matrix[begin + (int)floor(x / self->colSize)][x % self->colSize] = mat[x]; - } - - BaseMath_WriteCallback(self); - return 0; - }else{ - PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation\n"); - return -1; - } -} -/*------------------------NUMERIC PROTOCOLS---------------------- - ------------------------obj + obj------------------------------*/ -static PyObject *Matrix_add(PyObject * m1, PyObject * m2) -{ - int x, y; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - MatrixObject *mat1 = NULL, *mat2 = NULL; - - mat1 = (MatrixObject*)m1; - mat2 = (MatrixObject*)m2; - - if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) { - PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation...."); - return NULL; - } - - if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2)) - return NULL; - - if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){ - PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation"); - return NULL; - } - - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat1->colSize; y++) { - mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] + mat2->matrix[x][y]; - } - } - - return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL); -} -/*------------------------obj - obj------------------------------ - subtraction*/ -static PyObject *Matrix_sub(PyObject * m1, PyObject * m2) -{ - int x, y; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - MatrixObject *mat1 = NULL, *mat2 = NULL; - - mat1 = (MatrixObject*)m1; - mat2 = (MatrixObject*)m2; - - if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) { - PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation...."); - return NULL; - } - - if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2)) - return NULL; - - if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){ - PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation"); - return NULL; - } - - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat1->colSize; y++) { - mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] - mat2->matrix[x][y]; - } - } - - return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL); -} -/*------------------------obj * obj------------------------------ - mulplication*/ -static PyObject *Matrix_mul(PyObject * m1, PyObject * m2) -{ - int x, y, z; - float scalar; - float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - double dot = 0.0f; - MatrixObject *mat1 = NULL, *mat2 = NULL; - - if(MatrixObject_Check(m1)) { - mat1 = (MatrixObject*)m1; - if(!BaseMath_ReadCallback(mat1)) - return NULL; - } - if(MatrixObject_Check(m2)) { - mat2 = (MatrixObject*)m2; - if(!BaseMath_ReadCallback(mat2)) - return NULL; - } - - if(mat1 && mat2) { /*MATRIX * MATRIX*/ - if(mat1->colSize != mat2->rowSize){ - PyErr_SetString(PyExc_AttributeError,"Matrix multiplication: matrix A rowsize must equal matrix B colsize"); - return NULL; - } - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat2->colSize; y++) { - for(z = 0; z < mat1->colSize; z++) { - dot += (mat1->matrix[x][z] * mat2->matrix[z][y]); - } - mat[((x * mat1->rowSize) + y)] = (float)dot; - dot = 0.0f; - } - } - - return newMatrixObject(mat, mat1->rowSize, mat2->colSize, Py_NEW, NULL); - } - - if(mat1==NULL){ - scalar=PyFloat_AsDouble(m1); // may not be a float... - if ((scalar == -1.0 && PyErr_Occurred())==0) { /*FLOAT/INT * MATRIX, this line annoys theeth, lets see if he finds it */ - for(x = 0; x < mat2->rowSize; x++) { - for(y = 0; y < mat2->colSize; y++) { - mat[((x * mat2->colSize) + y)] = scalar * mat2->matrix[x][y]; - } - } - return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW, NULL); - } - - PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation"); - return NULL; - } - else /* if(mat1) { */ { - - if(VectorObject_Check(m2)) { /* MATRIX*VECTOR */ - return column_vector_multiplication(mat1, (VectorObject *)m2); /* vector update done inside the function */ - } - else { - scalar= PyFloat_AsDouble(m2); - if ((scalar == -1.0 && PyErr_Occurred())==0) { /* MATRIX*FLOAT/INT */ - for(x = 0; x < mat1->rowSize; x++) { - for(y = 0; y < mat1->colSize; y++) { - mat[((x * mat1->colSize) + y)] = scalar * mat1->matrix[x][y]; - } - } - return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL); - } - } - PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation"); - return NULL; - } - - PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation\n"); - return NULL; -} -static PyObject* Matrix_inv(MatrixObject *self) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - return Matrix_Invert(self); -} - -/*-----------------PROTOCOL DECLARATIONS--------------------------*/ -static PySequenceMethods Matrix_SeqMethods = { - (inquiry) Matrix_len, /* sq_length */ - (binaryfunc) 0, /* sq_concat */ - (ssizeargfunc) 0, /* sq_repeat */ - (ssizeargfunc) Matrix_item, /* sq_item */ - (ssizessizeargfunc) Matrix_slice, /* sq_slice */ - (ssizeobjargproc) Matrix_ass_item, /* sq_ass_item */ - (ssizessizeobjargproc) Matrix_ass_slice, /* sq_ass_slice */ -}; - - - -#if (PY_VERSION_HEX >= 0x03000000) -static PyObject *Matrix_subscript(MatrixObject* self, PyObject* item) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i; - i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - if (i < 0) - i += self->rowSize; - return Matrix_item(self, i); - } else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0) - return NULL; - - if (slicelength <= 0) { - return PyList_New(0); - } - else if (step == 1) { - return Matrix_slice(self, start, stop); - } - else { - PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies"); - return NULL; - } - } - else { - PyErr_Format(PyExc_TypeError, - "vector indices must be integers, not %.200s", - item->ob_type->tp_name); - return NULL; - } -} - -static int Matrix_ass_subscript(MatrixObject* self, PyObject* item, PyObject* value) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return -1; - if (i < 0) - i += self->rowSize; - return Matrix_ass_item(self, i, value); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0) - return -1; - - if (step == 1) - return Matrix_ass_slice(self, start, stop, value); - else { - PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies"); - return -1; - } - } - else { - PyErr_Format(PyExc_TypeError, - "matrix indices must be integers, not %.200s", - item->ob_type->tp_name); - return -1; - } -} - -static PyMappingMethods Matrix_AsMapping = { - (lenfunc)Matrix_len, - (binaryfunc)Matrix_subscript, - (objobjargproc)Matrix_ass_subscript -}; -#endif /* (PY_VERSION_HEX >= 0x03000000) */ - - - -#if (PY_VERSION_HEX >= 0x03000000) -static PyNumberMethods Matrix_NumMethods = { - (binaryfunc) Matrix_add, /*nb_add*/ - (binaryfunc) Matrix_sub, /*nb_subtract*/ - (binaryfunc) Matrix_mul, /*nb_multiply*/ - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - (unaryfunc) 0, /*nb_negative*/ - (unaryfunc) 0, /*tp_positive*/ - (unaryfunc) 0, /*tp_absolute*/ - (inquiry) 0, /*tp_bool*/ - (unaryfunc) Matrix_inv, /*nb_invert*/ - 0, /*nb_lshift*/ - (binaryfunc)0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - 0, /*nb_int*/ - 0, /*nb_reserved*/ - 0, /*nb_float*/ - 0, /* nb_inplace_add */ - 0, /* nb_inplace_subtract */ - 0, /* nb_inplace_multiply */ - 0, /* nb_inplace_remainder */ - 0, /* nb_inplace_power */ - 0, /* nb_inplace_lshift */ - 0, /* nb_inplace_rshift */ - 0, /* nb_inplace_and */ - 0, /* nb_inplace_xor */ - 0, /* nb_inplace_or */ - 0, /* nb_floor_divide */ - 0, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ - 0, /* nb_index */ -}; -#else -static PyNumberMethods Matrix_NumMethods = { - (binaryfunc) Matrix_add, /* __add__ */ - (binaryfunc) Matrix_sub, /* __sub__ */ - (binaryfunc) Matrix_mul, /* __mul__ */ - (binaryfunc) 0, /* __div__ */ - (binaryfunc) 0, /* __mod__ */ - (binaryfunc) 0, /* __divmod__ */ - (ternaryfunc) 0, /* __pow__ */ - (unaryfunc) 0, /* __neg__ */ - (unaryfunc) 0, /* __pos__ */ - (unaryfunc) 0, /* __abs__ */ - (inquiry) 0, /* __nonzero__ */ - (unaryfunc) Matrix_inv, /* __invert__ */ - (binaryfunc) 0, /* __lshift__ */ - (binaryfunc) 0, /* __rshift__ */ - (binaryfunc) 0, /* __and__ */ - (binaryfunc) 0, /* __xor__ */ - (binaryfunc) 0, /* __or__ */ - /*(coercion)*/ 0, /* __coerce__ */ - (unaryfunc) 0, /* __int__ */ - (unaryfunc) 0, /* __long__ */ - (unaryfunc) 0, /* __float__ */ - (unaryfunc) 0, /* __oct__ */ - (unaryfunc) 0, /* __hex__ */ -}; -#endif - -static PyObject *Matrix_getRowSize( MatrixObject * self, void *type ) -{ - return PyLong_FromLong((long) self->rowSize); -} - -static PyObject *Matrix_getColSize( MatrixObject * self, void *type ) -{ - return PyLong_FromLong((long) self->colSize); -} - -/*****************************************************************************/ -/* Python attributes get/set structure: */ -/*****************************************************************************/ -static PyGetSetDef Matrix_getseters[] = { - {"rowSize", (getter)Matrix_getRowSize, (setter)NULL, "", NULL}, - {"colSize", (getter)Matrix_getColSize, (setter)NULL, "", NULL}, - {"wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, "", NULL}, - {"__owner__",(getter)BaseMathObject_getOwner, (setter)NULL, "", - NULL}, - {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ -}; - -/*------------------PY_OBECT DEFINITION--------------------------*/ -PyTypeObject matrix_Type = { -#if (PY_VERSION_HEX >= 0x02060000) - PyVarObject_HEAD_INIT(NULL, 0) -#else - /* python 2.5 and below */ - PyObject_HEAD_INIT( NULL ) /* required py macro */ - 0, /* ob_size */ -#endif - "matrix", /*tp_name*/ - sizeof(MatrixObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)BaseMathObject_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc) Matrix_repr, /*tp_repr*/ - &Matrix_NumMethods, /*tp_as_number*/ - &Matrix_SeqMethods, /*tp_as_sequence*/ -#if (PY_VERSION_HEX >= 0x03000000) - &Matrix_AsMapping, /*tp_as_mapping*/ -#else - 0, -#endif - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - (richcmpfunc)Matrix_richcmpr, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - Matrix_methods, /*tp_methods*/ - 0, /*tp_members*/ - Matrix_getseters, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - 0, /*tp_init*/ - 0, /*tp_alloc*/ - Matrix_new, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ - 0 /*tp_del*/ -}; - -/*------------------------newMatrixObject (internal)------------- -creates a new matrix object -self->matrix self->contiguous_ptr (reference to data.xxx) - [0]------------->[0] - [1] - [2] - [1]------------->[3] - [4] - [5] - .... -self->matrix[1][1] = self->contigPtr[4] */ - -/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - (i.e. it was allocated elsewhere by MEM_mallocN()) - pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type, PyTypeObject *base_type) -{ - MatrixObject *self; - int x, row, col; - - /*matrix objects can be any 2-4row x 2-4col matrix*/ - if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4){ - PyErr_SetString(PyExc_RuntimeError, "matrix(): row and column sizes must be between 2 and 4"); - return NULL; - } - - if(base_type) self = (MatrixObject *)base_type->tp_alloc(base_type, 0); - else self = PyObject_NEW(MatrixObject, &matrix_Type); - - self->rowSize = rowSize; - self->colSize = colSize; - - /* init callbacks as NULL */ - self->cb_user= NULL; - self->cb_type= self->cb_subtype= 0; - - if(type == Py_WRAP){ - self->contigPtr = mat; - /*create pointer array*/ - self->matrix = PyMem_Malloc(rowSize * sizeof(float *)); - if(self->matrix == NULL) { /*allocation failure*/ - PyErr_SetString( PyExc_MemoryError, "matrix(): problem allocating pointer space"); - return NULL; - } - /*pointer array points to contigous memory*/ - for(x = 0; x < rowSize; x++) { - self->matrix[x] = self->contigPtr + (x * colSize); - } - self->wrapped = Py_WRAP; - }else if (type == Py_NEW){ - self->contigPtr = PyMem_Malloc(rowSize * colSize * sizeof(float)); - if(self->contigPtr == NULL) { /*allocation failure*/ - PyErr_SetString( PyExc_MemoryError, "matrix(): problem allocating pointer space\n"); - return NULL; - } - /*create pointer array*/ - self->matrix = PyMem_Malloc(rowSize * sizeof(float *)); - if(self->matrix == NULL) { /*allocation failure*/ - PyMem_Free(self->contigPtr); - PyErr_SetString( PyExc_MemoryError, "matrix(): problem allocating pointer space"); - return NULL; - } - /*pointer array points to contigous memory*/ - for(x = 0; x < rowSize; x++) { - self->matrix[x] = self->contigPtr + (x * colSize); - } - /*parse*/ - if(mat) { /*if a float array passed*/ - for(row = 0; row < rowSize; row++) { - for(col = 0; col < colSize; col++) { - self->matrix[row][col] = mat[(row * colSize) + col]; - } - } - } else if (rowSize == colSize ) { /*or if no arguments are passed return identity matrix for square matrices */ - Matrix_Identity(self); - Py_DECREF(self); - } - self->wrapped = Py_NEW; - }else{ /*bad type*/ - return NULL; - } - return (PyObject *) self; -} - -PyObject *newMatrixObject_cb(PyObject *cb_user, int rowSize, int colSize, int cb_type, int cb_subtype) -{ - MatrixObject *self= (MatrixObject *)newMatrixObject(NULL, rowSize, colSize, Py_NEW, NULL); - if(self) { - Py_INCREF(cb_user); - self->cb_user= cb_user; - self->cb_type= (unsigned char)cb_type; - self->cb_subtype= (unsigned char)cb_subtype; - } - return (PyObject *) self; -} - -//----------------column_vector_multiplication (internal)--------- -//COLUMN VECTOR Multiplication (Matrix X Vector) -// [1][2][3] [a] -// [4][5][6] * [b] -// [7][8][9] [c] -//vector/matrix multiplication IS NOT COMMUTATIVE!!!! -static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec) -{ - float vecNew[4], vecCopy[4]; - double dot = 0.0f; - int x, y, z = 0; - - if(!BaseMath_ReadCallback(mat) || !BaseMath_ReadCallback(vec)) - return NULL; - - if(mat->rowSize != vec->size){ - if(mat->rowSize == 4 && vec->size != 3){ - PyErr_SetString(PyExc_AttributeError, "matrix * vector: matrix row size and vector size must be the same"); - return NULL; - }else{ - vecCopy[3] = 1.0f; - } - } - - for(x = 0; x < vec->size; x++){ - vecCopy[x] = vec->vec[x]; - } - - for(x = 0; x < mat->rowSize; x++) { - for(y = 0; y < mat->colSize; y++) { - dot += mat->matrix[x][y] * vecCopy[y]; - } - vecNew[z++] = (float)dot; - dot = 0.0f; - } - return newVectorObject(vecNew, vec->size, Py_NEW, NULL); -} diff --git a/source/blender/python/generic/matrix.h b/source/blender/python/generic/matrix.h deleted file mode 100644 index 856c711c4ef..00000000000 --- a/source/blender/python/generic/matrix.h +++ /dev/null @@ -1,66 +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): Joseph Gilbert - * - * ***** END GPL LICENSE BLOCK ***** - * - */ - -#ifndef EXPP_matrix_h -#define EXPP_matrix_h - -#include <Python.h> - -extern PyTypeObject matrix_Type; -#define MatrixObject_Check(_v) PyObject_TypeCheck((_v), &matrix_Type) - -typedef float **ptRow; -typedef struct _Matrix { /* keep aligned with BaseMathObject in Mathutils.h */ - PyObject_VAR_HEAD - float *contigPtr; /*1D array of data (alias)*/ - PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */ - unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ - unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */ - unsigned char wrapped; /*is wrapped data?*/ - /* end BaseMathObject */ - - unsigned char rowSize; - unsigned int colSize; - ptRow matrix; /*ptr to the contigPtr (accessor)*/ - -} MatrixObject; - -/*struct data contains a pointer to the actual data that the -object uses. It can use either PyMem allocated data (which will -be stored in py_data) or be a wrapper for data allocated through -blender (stored in blend_data). This is an either/or struct not both*/ - -/*prototypes*/ -PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type, PyTypeObject *base_type); -PyObject *newMatrixObject_cb(PyObject *user, int rowSize, int colSize, int cb_type, int cb_subtype); - -extern int mathutils_matrix_vector_cb_index; -extern struct Mathutils_Callback mathutils_matrix_vector_cb; - -#endif /* EXPP_matrix_H */ diff --git a/source/blender/python/generic/quat.c b/source/blender/python/generic/quat.c deleted file mode 100644 index a353f73c854..00000000000 --- a/source/blender/python/generic/quat.c +++ /dev/null @@ -1,879 +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. - * - * - * Contributor(s): Joseph Gilbert - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "Mathutils.h" - -#include "BLI_arithb.h" -#include "BKE_utildefines.h" -#include "BLI_blenlib.h" - - -//-------------------------DOC STRINGS --------------------------- - -static PyObject *Quaternion_Identity( QuaternionObject * self ); -static PyObject *Quaternion_Negate( QuaternionObject * self ); -static PyObject *Quaternion_Conjugate( QuaternionObject * self ); -static PyObject *Quaternion_Inverse( QuaternionObject * self ); -static PyObject *Quaternion_Normalize( QuaternionObject * self ); -static PyObject *Quaternion_ToEuler( QuaternionObject * self, PyObject *args ); -static PyObject *Quaternion_ToMatrix( QuaternionObject * self ); -static PyObject *Quaternion_Cross( QuaternionObject * self, QuaternionObject * value ); -static PyObject *Quaternion_Dot( QuaternionObject * self, QuaternionObject * value ); -static PyObject *Quaternion_copy( QuaternionObject * self ); - -//-----------------------METHOD DEFINITIONS ---------------------- -static struct PyMethodDef Quaternion_methods[] = { - {"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, NULL}, - {"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, NULL}, - {"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, NULL}, - {"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, NULL}, - {"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, NULL}, - {"toEuler", (PyCFunction) Quaternion_ToEuler, METH_VARARGS, NULL}, - {"toMatrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, NULL}, - {"cross", (PyCFunction) Quaternion_Cross, METH_O, NULL}, - {"dot", (PyCFunction) Quaternion_Dot, METH_O, NULL}, - {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, NULL}, - {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, NULL}, - {NULL, NULL, 0, NULL} -}; - -//----------------------------------Mathutils.Quaternion() -------------- -static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *listObject = NULL, *n, *q; - int size, i; - float quat[4]; - double angle = 0.0f; - - size = PyTuple_GET_SIZE(args); - if (size == 1 || size == 2) { //seq? - listObject = PyTuple_GET_ITEM(args, 0); - if (PySequence_Check(listObject)) { - size = PySequence_Length(listObject); - if ((size == 4 && PySequence_Length(args) !=1) || - (size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) { - // invalid args/size - PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - if(size == 3){ //get angle in axis/angle - n = PySequence_GetItem(args, 1); - if(n == NULL) { // parsed item not a number or getItem fail - PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - - angle = PyFloat_AsDouble(n); - Py_DECREF(n); - - if (angle==-1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - } - }else{ - listObject = PyTuple_GET_ITEM(args, 1); - if (size>1 && PySequence_Check(listObject)) { - size = PySequence_Length(listObject); - if (size != 3) { - // invalid args/size - PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - angle = PyFloat_AsDouble(PyTuple_GET_ITEM(args, 0)); - - if (angle==-1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - } else { // argument was not a sequence - PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - } - } else if (size == 0) { //returns a new empty quat - return newQuaternionObject(NULL, Py_NEW, NULL); - } else { - listObject = args; - } - - if (size == 3) { // invalid quat size - if(PySequence_Length(args) != 2){ - PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - }else{ - if(size != 4){ - PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - } - - for (i=0; i<size; i++) { //parse - q = PySequence_GetItem(listObject, i); - if (q == NULL) { // Failed to read sequence - PyErr_SetString(PyExc_RuntimeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - - quat[i] = PyFloat_AsDouble(q); - Py_DECREF(q); - - if (quat[i]==-1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n"); - return NULL; - } - } - - if(size == 3) //calculate the quat based on axis/angle -#ifdef USE_MATHUTILS_DEG - AxisAngleToQuat(quat, quat, angle * (Py_PI / 180)); -#else - AxisAngleToQuat(quat, quat, angle); -#endif - - return newQuaternionObject(quat, Py_NEW, NULL); -} - -//-----------------------------METHODS------------------------------ -//----------------------------Quaternion.toEuler()------------------ -//return the quat as a euler -static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args) -{ - float eul[3]; - EulerObject *eul_compat = NULL; - - if(!PyArg_ParseTuple(args, "|O!:toEuler", &euler_Type, &eul_compat)) - return NULL; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - if(eul_compat) { - float mat[3][3]; - - if(!BaseMath_ReadCallback(eul_compat)) - return NULL; - - QuatToMat3(self->quat, mat); - -#ifdef USE_MATHUTILS_DEG - { - float eul_compatf[3]; - int x; - - for(x = 0; x < 3; x++) { - eul_compatf[x] = eul_compat->eul[x] * ((float)Py_PI / 180); - } - Mat3ToCompatibleEul(mat, eul, eul_compatf); - } -#else - Mat3ToCompatibleEul(mat, eul, eul_compat->eul); -#endif - } - else { - QuatToEul(self->quat, eul); - } - -#ifdef USE_MATHUTILS_DEG - { - int x; - - for(x = 0; x < 3; x++) { - eul[x] *= (180 / (float)Py_PI); - } - } -#endif - return newEulerObject(eul, Py_NEW, NULL); -} -//----------------------------Quaternion.toMatrix()------------------ -//return the quat as a matrix -static PyObject *Quaternion_ToMatrix(QuaternionObject * self) -{ - float mat[9]; /* all values are set */ - - if(!BaseMath_ReadCallback(self)) - return NULL; - - QuatToMat3(self->quat, (float (*)[3]) mat); - return newMatrixObject(mat, 3, 3, Py_NEW, NULL); -} - -//----------------------------Quaternion.cross(other)------------------ -//return the cross quat -static PyObject *Quaternion_Cross(QuaternionObject * self, QuaternionObject * value) -{ - float quat[4]; - - if (!QuaternionObject_Check(value)) { - PyErr_SetString( PyExc_TypeError, "quat.cross(value): expected a quaternion argument" ); - return NULL; - } - - if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) - return NULL; - - QuatMul(quat, self->quat, value->quat); - return newQuaternionObject(quat, Py_NEW, NULL); -} - -//----------------------------Quaternion.dot(other)------------------ -//return the dot quat -static PyObject *Quaternion_Dot(QuaternionObject * self, QuaternionObject * value) -{ - if (!QuaternionObject_Check(value)) { - PyErr_SetString( PyExc_TypeError, "quat.dot(value): expected a quaternion argument" ); - return NULL; - } - - if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) - return NULL; - - return PyFloat_FromDouble(QuatDot(self->quat, value->quat)); -} - -//----------------------------Quaternion.normalize()---------------- -//normalize the axis of rotation of [theta,vector] -static PyObject *Quaternion_Normalize(QuaternionObject * self) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - NormalQuat(self->quat); - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject*)self; -} -//----------------------------Quaternion.inverse()------------------ -//invert the quat -static PyObject *Quaternion_Inverse(QuaternionObject * self) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - QuatInv(self->quat); - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject*)self; -} -//----------------------------Quaternion.identity()----------------- -//generate the identity quaternion -static PyObject *Quaternion_Identity(QuaternionObject * self) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - QuatOne(self->quat); - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject*)self; -} -//----------------------------Quaternion.negate()------------------- -//negate the quat -static PyObject *Quaternion_Negate(QuaternionObject * self) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - QuatMulf(self->quat, -1.0f); - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject*)self; -} -//----------------------------Quaternion.conjugate()---------------- -//negate the vector part -static PyObject *Quaternion_Conjugate(QuaternionObject * self) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - QuatConj(self->quat); - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject*)self; -} -//----------------------------Quaternion.copy()---------------- -//return a copy of the quat -static PyObject *Quaternion_copy(QuaternionObject * self) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - return newQuaternionObject(self->quat, Py_NEW, Py_TYPE(self)); -} - -//----------------------------print object (internal)-------------- -//print the object to screen -static PyObject *Quaternion_repr(QuaternionObject * self) -{ - char str[64]; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - sprintf(str, "[%.6f, %.6f, %.6f, %.6f](quaternion)", self->quat[0], self->quat[1], self->quat[2], self->quat[3]); - return PyUnicode_FromString(str); -} -//------------------------tp_richcmpr -//returns -1 execption, 0 false, 1 true -static PyObject* Quaternion_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type) -{ - QuaternionObject *quatA = NULL, *quatB = NULL; - int result = 0; - - if(QuaternionObject_Check(objectA)) { - quatA = (QuaternionObject*)objectA; - if(!BaseMath_ReadCallback(quatA)) - return NULL; - } - if(QuaternionObject_Check(objectB)) { - quatB = (QuaternionObject*)objectB; - if(!BaseMath_ReadCallback(quatB)) - return NULL; - } - - if (!quatA || !quatB){ - if (comparison_type == Py_NE){ - Py_RETURN_TRUE; - }else{ - Py_RETURN_FALSE; - } - } - - switch (comparison_type){ - case Py_EQ: - result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, 4, 1); - break; - case Py_NE: - result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, 4, 1); - if (result == 0){ - result = 1; - }else{ - result = 0; - } - break; - default: - printf("The result of the comparison could not be evaluated"); - break; - } - if (result == 1){ - Py_RETURN_TRUE; - }else{ - Py_RETURN_FALSE; - } -} - -//---------------------SEQUENCE PROTOCOLS------------------------ -//----------------------------len(object)------------------------ -//sequence length -static int Quaternion_len(QuaternionObject * self) -{ - return 4; -} -//----------------------------object[]--------------------------- -//sequence accessor (get) -static PyObject *Quaternion_item(QuaternionObject * self, int i) -{ - if(i<0) i= 4-i; - - if(i < 0 || i >= 4) { - PyErr_SetString(PyExc_IndexError, "quaternion[attribute]: array index out of range\n"); - return NULL; - } - - if(!BaseMath_ReadIndexCallback(self, i)) - return NULL; - - return PyFloat_FromDouble(self->quat[i]); - -} -//----------------------------object[]------------------------- -//sequence accessor (set) -static int Quaternion_ass_item(QuaternionObject * self, int i, PyObject * ob) -{ - float scalar= (float)PyFloat_AsDouble(ob); - if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ - PyErr_SetString(PyExc_TypeError, "quaternion[index] = x: index argument not a number\n"); - return -1; - } - - if(i<0) i= 4-i; - - if(i < 0 || i >= 4){ - PyErr_SetString(PyExc_IndexError, "quaternion[attribute] = x: array assignment index out of range\n"); - return -1; - } - self->quat[i] = scalar; - - if(!BaseMath_WriteIndexCallback(self, i)) - return -1; - - return 0; -} -//----------------------------object[z:y]------------------------ -//sequence slice (get) -static PyObject *Quaternion_slice(QuaternionObject * self, int begin, int end) -{ - PyObject *list = NULL; - int count; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - CLAMP(begin, 0, 4); - if (end<0) end= 5+end; - CLAMP(end, 0, 4); - begin = MIN2(begin,end); - - list = PyList_New(end - begin); - for(count = begin; count < end; count++) { - PyList_SetItem(list, count - begin, - PyFloat_FromDouble(self->quat[count])); - } - - return list; -} -//----------------------------object[z:y]------------------------ -//sequence slice (set) -static int Quaternion_ass_slice(QuaternionObject * self, int begin, int end, PyObject * seq) -{ - int i, y, size = 0; - float quat[4]; - PyObject *q; - - if(!BaseMath_ReadCallback(self)) - return -1; - - CLAMP(begin, 0, 4); - if (end<0) end= 5+end; - CLAMP(end, 0, 4); - begin = MIN2(begin,end); - - size = PySequence_Length(seq); - if(size != (end - begin)){ - PyErr_SetString(PyExc_TypeError, "quaternion[begin:end] = []: size mismatch in slice assignment\n"); - return -1; - } - - for (i = 0; i < size; i++) { - q = PySequence_GetItem(seq, i); - if (q == NULL) { // Failed to read sequence - PyErr_SetString(PyExc_RuntimeError, "quaternion[begin:end] = []: unable to read sequence\n"); - return -1; - } - - quat[i]= (float)PyFloat_AsDouble(q); - Py_DECREF(q); - - if(quat[i]==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ - PyErr_SetString(PyExc_TypeError, "quaternion[begin:end] = []: sequence argument not a number\n"); - return -1; - } - } - //parsed well - now set in vector - for(y = 0; y < size; y++) - self->quat[begin + y] = quat[y]; - - BaseMath_WriteCallback(self); - return 0; -} -//------------------------NUMERIC PROTOCOLS---------------------- -//------------------------obj + obj------------------------------ -//addition -static PyObject *Quaternion_add(PyObject * q1, PyObject * q2) -{ - float quat[4]; - QuaternionObject *quat1 = NULL, *quat2 = NULL; - - if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) { - PyErr_SetString(PyExc_AttributeError, "Quaternion addition: arguments not valid for this operation....\n"); - return NULL; - } - quat1 = (QuaternionObject*)q1; - quat2 = (QuaternionObject*)q2; - - if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2)) - return NULL; - - QuatAdd(quat, quat1->quat, quat2->quat, 1.0f); - return newQuaternionObject(quat, Py_NEW, NULL); -} -//------------------------obj - obj------------------------------ -//subtraction -static PyObject *Quaternion_sub(PyObject * q1, PyObject * q2) -{ - int x; - float quat[4]; - QuaternionObject *quat1 = NULL, *quat2 = NULL; - - if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) { - PyErr_SetString(PyExc_AttributeError, "Quaternion addition: arguments not valid for this operation....\n"); - return NULL; - } - - quat1 = (QuaternionObject*)q1; - quat2 = (QuaternionObject*)q2; - - if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2)) - return NULL; - - for(x = 0; x < 4; x++) { - quat[x] = quat1->quat[x] - quat2->quat[x]; - } - - return newQuaternionObject(quat, Py_NEW, NULL); -} -//------------------------obj * obj------------------------------ -//mulplication -static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2) -{ - float quat[4], scalar; - QuaternionObject *quat1 = NULL, *quat2 = NULL; - VectorObject *vec = NULL; - - if(QuaternionObject_Check(q1)) { - quat1 = (QuaternionObject*)q1; - if(!BaseMath_ReadCallback(quat1)) - return NULL; - } - if(QuaternionObject_Check(q2)) { - quat2 = (QuaternionObject*)q2; - if(!BaseMath_ReadCallback(quat2)) - return NULL; - } - - if(quat1 && quat2) { /* QUAT*QUAT (dot product) */ - return PyFloat_FromDouble(QuatDot(quat1->quat, quat2->quat)); - } - - /* the only case this can happen (for a supported type is "FLOAT*QUAT" ) */ - if(!QuaternionObject_Check(q1)) { - scalar= PyFloat_AsDouble(q1); - if ((scalar == -1.0 && PyErr_Occurred())==0) { /* FLOAT*QUAT */ - QUATCOPY(quat, quat2->quat); - QuatMulf(quat, scalar); - return newQuaternionObject(quat, Py_NEW, NULL); - } - PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: val * quat, val is not an acceptable type"); - return NULL; - } - else { /* QUAT*SOMETHING */ - if(VectorObject_Check(q2)){ /* QUAT*VEC */ - vec = (VectorObject*)q2; - if(vec->size != 3){ - PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: only 3D vector rotations currently supported\n"); - return NULL; - } - return quat_rotation((PyObject*)quat1, (PyObject*)vec); /* vector updating done inside the func */ - } - - scalar= PyFloat_AsDouble(q2); - if ((scalar == -1.0 && PyErr_Occurred())==0) { /* QUAT*FLOAT */ - QUATCOPY(quat, quat1->quat); - QuatMulf(quat, scalar); - return newQuaternionObject(quat, Py_NEW, NULL); - } - } - - PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: arguments not acceptable for this operation\n"); - return NULL; -} - -//-----------------PROTOCOL DECLARATIONS-------------------------- -static PySequenceMethods Quaternion_SeqMethods = { - (inquiry) Quaternion_len, /* sq_length */ - (binaryfunc) 0, /* sq_concat */ - (ssizeargfunc) 0, /* sq_repeat */ - (ssizeargfunc) Quaternion_item, /* sq_item */ - (ssizessizeargfunc) Quaternion_slice, /* sq_slice */ - (ssizeobjargproc) Quaternion_ass_item, /* sq_ass_item */ - (ssizessizeobjargproc) Quaternion_ass_slice, /* sq_ass_slice */ -}; - -#if (PY_VERSION_HEX >= 0x03000000) -static PyNumberMethods Quaternion_NumMethods = { - (binaryfunc) Quaternion_add, /*nb_add*/ - (binaryfunc) Quaternion_sub, /*nb_subtract*/ - (binaryfunc) Quaternion_mul, /*nb_multiply*/ - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - (unaryfunc) 0, /*nb_negative*/ - (unaryfunc) 0, /*tp_positive*/ - (unaryfunc) 0, /*tp_absolute*/ - (inquiry) 0, /*tp_bool*/ - (unaryfunc) 0, /*nb_invert*/ - 0, /*nb_lshift*/ - (binaryfunc)0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - 0, /*nb_int*/ - 0, /*nb_reserved*/ - 0, /*nb_float*/ - 0, /* nb_inplace_add */ - 0, /* nb_inplace_subtract */ - 0, /* nb_inplace_multiply */ - 0, /* nb_inplace_remainder */ - 0, /* nb_inplace_power */ - 0, /* nb_inplace_lshift */ - 0, /* nb_inplace_rshift */ - 0, /* nb_inplace_and */ - 0, /* nb_inplace_xor */ - 0, /* nb_inplace_or */ - 0, /* nb_floor_divide */ - 0, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ - 0, /* nb_index */ -}; -#else -static PyNumberMethods Quaternion_NumMethods = { - (binaryfunc) Quaternion_add, /* __add__ */ - (binaryfunc) Quaternion_sub, /* __sub__ */ - (binaryfunc) Quaternion_mul, /* __mul__ */ - (binaryfunc) 0, /* __div__ */ - (binaryfunc) 0, /* __mod__ */ - (binaryfunc) 0, /* __divmod__ */ - (ternaryfunc) 0, /* __pow__ */ - (unaryfunc) 0, /* __neg__ */ - (unaryfunc) 0, /* __pos__ */ - (unaryfunc) 0, /* __abs__ */ - (inquiry) 0, /* __nonzero__ */ - (unaryfunc) 0, /* __invert__ */ - (binaryfunc) 0, /* __lshift__ */ - (binaryfunc) 0, /* __rshift__ */ - (binaryfunc) 0, /* __and__ */ - (binaryfunc) 0, /* __xor__ */ - (binaryfunc) 0, /* __or__ */ - /*(coercion)*/ 0, /* __coerce__ */ - (unaryfunc) 0, /* __int__ */ - (unaryfunc) 0, /* __long__ */ - (unaryfunc) 0, /* __float__ */ - (unaryfunc) 0, /* __oct__ */ - (unaryfunc) 0, /* __hex__ */ -}; -#endif - -static PyObject *Quaternion_getAxis( QuaternionObject * self, void *type ) -{ - return Quaternion_item(self, GET_INT_FROM_POINTER(type)); -} - -static int Quaternion_setAxis( QuaternionObject * self, PyObject * value, void * type ) -{ - return Quaternion_ass_item(self, GET_INT_FROM_POINTER(type), value); -} - -static PyObject *Quaternion_getMagnitude( QuaternionObject * self, void *type ) -{ - return PyFloat_FromDouble(sqrt(QuatDot(self->quat, self->quat))); -} - -static PyObject *Quaternion_getAngle( QuaternionObject * self, void *type ) -{ - double ang = self->quat[0]; - ang = 2 * (saacos(ang)); -#ifdef USE_MATHUTILS_DEG - ang *= (180 / Py_PI); -#endif - return PyFloat_FromDouble(ang); -} - -static PyObject *Quaternion_getAxisVec( QuaternionObject * self, void *type ) -{ - int i; - float vec[3]; - double mag = self->quat[0] * (Py_PI / 180); - mag = 2 * (saacos(mag)); - mag = sin(mag / 2); - for(i = 0; i < 3; i++) - vec[i] = (float)(self->quat[i + 1] / mag); - - Normalize(vec); - //If the axis of rotation is 0,0,0 set it to 1,0,0 - for zero-degree rotations - if( EXPP_FloatsAreEqual(vec[0], 0.0f, 10) && - EXPP_FloatsAreEqual(vec[1], 0.0f, 10) && - EXPP_FloatsAreEqual(vec[2], 0.0f, 10) ){ - vec[0] = 1.0f; - } - return (PyObject *) newVectorObject(vec, 3, Py_NEW, NULL); -} - - -/*****************************************************************************/ -/* Python attributes get/set structure: */ -/*****************************************************************************/ -static PyGetSetDef Quaternion_getseters[] = { - {"w", - (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, - "Quaternion W value", - (void *)0}, - {"x", - (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, - "Quaternion X axis", - (void *)1}, - {"y", - (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, - "Quaternion Y axis", - (void *)2}, - {"z", - (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, - "Quaternion Z axis", - (void *)3}, - {"magnitude", - (getter)Quaternion_getMagnitude, (setter)NULL, - "Size of the quaternion", - NULL}, - {"angle", - (getter)Quaternion_getAngle, (setter)NULL, - "angle of the quaternion", - NULL}, - {"axis", - (getter)Quaternion_getAxisVec, (setter)NULL, - "quaternion axis as a vector", - NULL}, - {"wrapped", - (getter)BaseMathObject_getWrapped, (setter)NULL, - "True when this wraps blenders internal data", - NULL}, - {"__owner__", - (getter)BaseMathObject_getOwner, (setter)NULL, - "Read only owner for vectors that depend on another object", - NULL}, - - {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ -}; - - -//------------------PY_OBECT DEFINITION-------------------------- -PyTypeObject quaternion_Type = { -#if (PY_VERSION_HEX >= 0x02060000) - PyVarObject_HEAD_INIT(NULL, 0) -#else - /* python 2.5 and below */ - PyObject_HEAD_INIT( NULL ) /* required py macro */ - 0, /* ob_size */ -#endif - "quaternion", //tp_name - sizeof(QuaternionObject), //tp_basicsize - 0, //tp_itemsize - (destructor)BaseMathObject_dealloc, //tp_dealloc - 0, //tp_print - 0, //tp_getattr - 0, //tp_setattr - 0, //tp_compare - (reprfunc) Quaternion_repr, //tp_repr - &Quaternion_NumMethods, //tp_as_number - &Quaternion_SeqMethods, //tp_as_sequence - 0, //tp_as_mapping - 0, //tp_hash - 0, //tp_call - 0, //tp_str - 0, //tp_getattro - 0, //tp_setattro - 0, //tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags - 0, //tp_doc - 0, //tp_traverse - 0, //tp_clear - (richcmpfunc)Quaternion_richcmpr, //tp_richcompare - 0, //tp_weaklistoffset - 0, //tp_iter - 0, //tp_iternext - Quaternion_methods, //tp_methods - 0, //tp_members - Quaternion_getseters, //tp_getset - 0, //tp_base - 0, //tp_dict - 0, //tp_descr_get - 0, //tp_descr_set - 0, //tp_dictoffset - 0, //tp_init - 0, //tp_alloc - Quaternion_new, //tp_new - 0, //tp_free - 0, //tp_is_gc - 0, //tp_bases - 0, //tp_mro - 0, //tp_cache - 0, //tp_subclasses - 0, //tp_weaklist - 0 //tp_del -}; -//------------------------newQuaternionObject (internal)------------- -//creates a new quaternion object -/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - (i.e. it was allocated elsewhere by MEM_mallocN()) - pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *newQuaternionObject(float *quat, int type, PyTypeObject *base_type) -{ - QuaternionObject *self; - - if(base_type) self = (QuaternionObject *)base_type->tp_alloc(base_type, 0); - else self = PyObject_NEW(QuaternionObject, &quaternion_Type); - - /* init callbacks as NULL */ - self->cb_user= NULL; - self->cb_type= self->cb_subtype= 0; - - if(type == Py_WRAP){ - self->quat = quat; - self->wrapped = Py_WRAP; - }else if (type == Py_NEW){ - self->quat = PyMem_Malloc(4 * sizeof(float)); - if(!quat) { //new empty - QuatOne(self->quat); - }else{ - QUATCOPY(self->quat, quat); - } - self->wrapped = Py_NEW; - }else{ //bad type - return NULL; - } - return (PyObject *) self; -} - -PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype) -{ - QuaternionObject *self= (QuaternionObject *)newQuaternionObject(NULL, Py_NEW, NULL); - if(self) { - Py_INCREF(cb_user); - self->cb_user= cb_user; - self->cb_type= (unsigned char)cb_type; - self->cb_subtype= (unsigned char)cb_subtype; - } - - return (PyObject *)self; -} diff --git a/source/blender/python/generic/quat.h b/source/blender/python/generic/quat.h deleted file mode 100644 index a7cfb7898b1..00000000000 --- a/source/blender/python/generic/quat.h +++ /dev/null @@ -1,60 +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): Joseph Gilbert - * - * ***** END GPL LICENSE BLOCK ***** - * - */ - -#ifndef EXPP_quat_h -#define EXPP_quat_h - -#include <Python.h> -#include "../intern/bpy_compat.h" - -extern PyTypeObject quaternion_Type; -#define QuaternionObject_Check(_v) PyObject_TypeCheck((_v), &quaternion_Type) - -typedef struct { /* keep aligned with BaseMathObject in Mathutils.h */ - PyObject_VAR_HEAD - float *quat; /* 1D array of data (alias) */ - PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */ - unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ - unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */ - unsigned char wrapped; /* wrapped data type? */ - /* end BaseMathObject */ - -} QuaternionObject; - -/*struct data contains a pointer to the actual data that the -object uses. It can use either PyMem allocated data (which will -be stored in py_data) or be a wrapper for data allocated through -blender (stored in blend_data). This is an either/or struct not both*/ - -//prototypes -PyObject *newQuaternionObject( float *quat, int type, PyTypeObject *base_type); -PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype); - -#endif /* EXPP_quat_h */ diff --git a/source/blender/python/generic/vector.c b/source/blender/python/generic/vector.c deleted file mode 100644 index cf2396b30d4..00000000000 --- a/source/blender/python/generic/vector.c +++ /dev/null @@ -1,2078 +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. - * - * - * Contributor(s): Willian P. Germano, Joseph Gilbert, Ken Hughes, Alex Fraser, Campbell Barton - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "Mathutils.h" - -#include "BLI_blenlib.h" -#include "BKE_utildefines.h" -#include "BLI_arithb.h" - -#define MAX_DIMENSIONS 4 -/* Swizzle axes get packed into a single value that is used as a closure. Each - axis uses SWIZZLE_BITS_PER_AXIS bits. The first bit (SWIZZLE_VALID_AXIS) is - used as a sentinel: if it is unset, the axis is not valid. */ -#define SWIZZLE_BITS_PER_AXIS 3 -#define SWIZZLE_VALID_AXIS 0x4 -#define SWIZZLE_AXIS 0x3 - -static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat); /* utility func */ - -/*-----------------------METHOD DEFINITIONS ----------------------*/ -static PyObject *Vector_Zero( VectorObject * self ); -static PyObject *Vector_Normalize( VectorObject * self ); -static PyObject *Vector_Negate( VectorObject * self ); -static PyObject *Vector_Resize2D( VectorObject * self ); -static PyObject *Vector_Resize3D( VectorObject * self ); -static PyObject *Vector_Resize4D( VectorObject * self ); -static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ); -static PyObject *Vector_Reflect( VectorObject *self, VectorObject *value ); -static PyObject *Vector_Cross( VectorObject * self, VectorObject * value ); -static PyObject *Vector_Dot( VectorObject * self, VectorObject * value ); -static PyObject *Vector_copy( VectorObject * self ); - -static struct PyMethodDef Vector_methods[] = { - {"zero", (PyCFunction) Vector_Zero, METH_NOARGS, NULL}, - {"normalize", (PyCFunction) Vector_Normalize, METH_NOARGS, NULL}, - {"negate", (PyCFunction) Vector_Negate, METH_NOARGS, NULL}, - {"resize2D", (PyCFunction) Vector_Resize2D, METH_NOARGS, NULL}, - {"resize3D", (PyCFunction) Vector_Resize3D, METH_NOARGS, NULL}, - {"resize4D", (PyCFunction) Vector_Resize4D, METH_NOARGS, NULL}, - {"toTrackQuat", ( PyCFunction ) Vector_ToTrackQuat, METH_VARARGS, NULL}, - {"reflect", ( PyCFunction ) Vector_Reflect, METH_O, NULL}, - {"cross", ( PyCFunction ) Vector_Cross, METH_O, NULL}, - {"dot", ( PyCFunction ) Vector_Dot, METH_O, NULL}, - {"copy", (PyCFunction) Vector_copy, METH_NOARGS, NULL}, - {"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL}, - {NULL, NULL, 0, NULL} -}; - -//----------------------------------Mathutils.Vector() ------------------ -// Supports 2D, 3D, and 4D vector objects both int and float values -// accepted. Mixed float and int values accepted. Ints are parsed to float -static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *listObject = NULL; - int size, i; - float vec[4], f; - PyObject *v; - - size = PyTuple_GET_SIZE(args); /* we know its a tuple because its an arg */ - if (size == 1) { - listObject = PyTuple_GET_ITEM(args, 0); - if (PySequence_Check(listObject)) { - size = PySequence_Length(listObject); - } else { // Single argument was not a sequence - PyErr_SetString(PyExc_TypeError, "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n"); - return NULL; - } - } else if (size == 0) { - //returns a new empty 3d vector - return newVectorObject(NULL, 3, Py_NEW, type); - } else { - listObject = args; - } - - if (size<2 || size>4) { // Invalid vector size - PyErr_SetString(PyExc_AttributeError, "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n"); - return NULL; - } - - for (i=0; i<size; i++) { - v=PySequence_GetItem(listObject, i); - if (v==NULL) { // Failed to read sequence - PyErr_SetString(PyExc_RuntimeError, "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n"); - return NULL; - } - - f= PyFloat_AsDouble(v); - if(f==-1 && PyErr_Occurred()) { // parsed item not a number - Py_DECREF(v); - PyErr_SetString(PyExc_TypeError, "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n"); - return NULL; - } - - vec[i]= f; - Py_DECREF(v); - } - return newVectorObject(vec, size, Py_NEW, type); -} - -/*-----------------------------METHODS---------------------------- */ -/*----------------------------Vector.zero() ---------------------- - set the vector data to 0,0,0 */ -static PyObject *Vector_Zero(VectorObject * self) -{ - int i; - for(i = 0; i < self->size; i++) { - self->vec[i] = 0.0f; - } - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject*)self; -} -/*----------------------------Vector.normalize() ----------------- - normalize the vector data to a unit vector */ -static PyObject *Vector_Normalize(VectorObject * self) -{ - int i; - float norm = 0.0f; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - for(i = 0; i < self->size; i++) { - norm += self->vec[i] * self->vec[i]; - } - norm = (float) sqrt(norm); - for(i = 0; i < self->size; i++) { - self->vec[i] /= norm; - } - - BaseMath_WriteCallback(self); - Py_INCREF(self); - return (PyObject*)self; -} - - -/*----------------------------Vector.resize2D() ------------------ - resize the vector to x,y */ -static PyObject *Vector_Resize2D(VectorObject * self) -{ - if(self->wrapped==Py_WRAP) { - PyErr_SetString(PyExc_TypeError, "vector.resize2d(): cannot resize wrapped data - only python vectors\n"); - return NULL; - } - if(self->cb_user) { - PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner"); - return NULL; - } - - self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 2)); - if(self->vec == NULL) { - PyErr_SetString(PyExc_MemoryError, "vector.resize2d(): problem allocating pointer space\n\n"); - return NULL; - } - - self->size = 2; - Py_INCREF(self); - return (PyObject*)self; -} -/*----------------------------Vector.resize3D() ------------------ - resize the vector to x,y,z */ -static PyObject *Vector_Resize3D(VectorObject * self) -{ - if (self->wrapped==Py_WRAP) { - PyErr_SetString(PyExc_TypeError, "vector.resize3d(): cannot resize wrapped data - only python vectors\n"); - return NULL; - } - if(self->cb_user) { - PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner"); - return NULL; - } - - self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 3)); - if(self->vec == NULL) { - PyErr_SetString(PyExc_MemoryError, "vector.resize3d(): problem allocating pointer space\n\n"); - return NULL; - } - - if(self->size == 2) - self->vec[2] = 0.0f; - - self->size = 3; - Py_INCREF(self); - return (PyObject*)self; -} -/*----------------------------Vector.resize4D() ------------------ - resize the vector to x,y,z,w */ -static PyObject *Vector_Resize4D(VectorObject * self) -{ - if(self->wrapped==Py_WRAP) { - PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize wrapped data - only python vectors"); - return NULL; - } - if(self->cb_user) { - PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner"); - return NULL; - } - - self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 4)); - if(self->vec == NULL) { - PyErr_SetString(PyExc_MemoryError, "vector.resize4d(): problem allocating pointer space\n\n"); - return NULL; - } - if(self->size == 2){ - self->vec[2] = 0.0f; - self->vec[3] = 1.0f; - }else if(self->size == 3){ - self->vec[3] = 1.0f; - } - self->size = 4; - Py_INCREF(self); - return (PyObject*)self; -} -/*----------------------------Vector.toTrackQuat(track, up) ---------------------- - extract a quaternion from the vector and the track and up axis */ -static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args ) -{ - float vec[3], quat[4]; - char *strack, *sup; - short track = 2, up = 1; - - if( !PyArg_ParseTuple ( args, "|ss", &strack, &sup ) ) { - PyErr_SetString( PyExc_TypeError, "expected optional two strings\n" ); - return NULL; - } - if (self->size != 3) { - PyErr_SetString( PyExc_TypeError, "only for 3D vectors\n" ); - return NULL; - } - - if(!BaseMath_ReadCallback(self)) - return NULL; - - if (strack) { - if (strlen(strack) == 2) { - if (strack[0] == '-') { - switch(strack[1]) { - case 'X': - case 'x': - track = 3; - break; - case 'Y': - case 'y': - track = 4; - break; - case 'z': - case 'Z': - track = 5; - break; - default: - PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" ); - return NULL; - } - } - else { - PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" ); - return NULL; - } - } - else if (strlen(strack) == 1) { - switch(strack[0]) { - case '-': - case 'X': - case 'x': - track = 0; - break; - case 'Y': - case 'y': - track = 1; - break; - case 'z': - case 'Z': - track = 2; - break; - default: - PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" ); - return NULL; - } - } - else { - PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" ); - return NULL; - } - } - - if (sup) { - if (strlen(sup) == 1) { - switch(*sup) { - case 'X': - case 'x': - up = 0; - break; - case 'Y': - case 'y': - up = 1; - break; - case 'z': - case 'Z': - up = 2; - break; - default: - PyErr_SetString( PyExc_ValueError, "only X, Y or Z for up axis\n" ); - return NULL; - } - } - else { - PyErr_SetString( PyExc_ValueError, "only X, Y or Z for up axis\n" ); - return NULL; - } - } - - if (track == up) { - PyErr_SetString( PyExc_ValueError, "Can't have the same axis for track and up\n" ); - return NULL; - } - - /* - flip vector around, since vectoquat expect a vector from target to tracking object - and the python function expects the inverse (a vector to the target). - */ - vec[0] = -self->vec[0]; - vec[1] = -self->vec[1]; - vec[2] = -self->vec[2]; - - vectoquat(vec, track, up, quat); - - return newQuaternionObject(quat, Py_NEW, NULL); -} - -/*----------------------------Vector.reflect(mirror) ---------------------- - return a reflected vector on the mirror normal - ((2 * DotVecs(vec, mirror)) * mirror) - vec - using arithb.c would be nice here */ -static PyObject *Vector_Reflect( VectorObject * self, VectorObject * value ) -{ - float mirror[3]; - float vec[3]; - float reflect[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - float dot2; - - /* for normalizing */ - int i; - float norm = 0.0f; - - if (!VectorObject_Check(value)) { - PyErr_SetString( PyExc_TypeError, "vec.reflect(value): expected a vector argument" ); - return NULL; - } - - if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) - return NULL; - - mirror[0] = value->vec[0]; - mirror[1] = value->vec[1]; - if (value->size > 2) mirror[2] = value->vec[2]; - else mirror[2] = 0.0; - - /* normalize, whos idea was it not to use arithb.c? :-/ */ - for(i = 0; i < 3; i++) { - norm += mirror[i] * mirror[i]; - } - norm = (float) sqrt(norm); - for(i = 0; i < 3; i++) { - mirror[i] /= norm; - } - /* done */ - - vec[0] = self->vec[0]; - vec[1] = self->vec[1]; - if (self->size > 2) vec[2] = self->vec[2]; - else vec[2] = 0.0; - - dot2 = 2 * vec[0]*mirror[0]+vec[1]*mirror[1]+vec[2]*mirror[2]; - - reflect[0] = (dot2 * mirror[0]) - vec[0]; - reflect[1] = (dot2 * mirror[1]) - vec[1]; - reflect[2] = (dot2 * mirror[2]) - vec[2]; - - return newVectorObject(reflect, self->size, Py_NEW, NULL); -} - -static PyObject *Vector_Cross( VectorObject * self, VectorObject * value ) -{ - VectorObject *vecCross = NULL; - - if (!VectorObject_Check(value)) { - PyErr_SetString( PyExc_TypeError, "vec.cross(value): expected a vector argument" ); - return NULL; - } - - if(self->size != 3 || value->size != 3) { - PyErr_SetString(PyExc_AttributeError, "vec.cross(value): expects both vectors to be 3D\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) - return NULL; - - vecCross = (VectorObject *)newVectorObject(NULL, 3, Py_NEW, NULL); - Crossf(vecCross->vec, self->vec, value->vec); - return (PyObject *)vecCross; -} - -static PyObject *Vector_Dot( VectorObject * self, VectorObject * value ) -{ - double dot = 0.0; - int x; - - if (!VectorObject_Check(value)) { - PyErr_SetString( PyExc_TypeError, "vec.cross(value): expected a vector argument" ); - return NULL; - } - - if(self->size != value->size) { - PyErr_SetString(PyExc_AttributeError, "vec.dot(value): expects both vectors to have the same size\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value)) - return NULL; - - for(x = 0; x < self->size; x++) { - dot += self->vec[x] * value->vec[x]; - } - return PyFloat_FromDouble(dot); -} - -/*----------------------------Vector.copy() -------------------------------------- - return a copy of the vector */ -static PyObject *Vector_copy(VectorObject * self) -{ - if(!BaseMath_ReadCallback(self)) - return NULL; - - return newVectorObject(self->vec, self->size, Py_NEW, Py_TYPE(self)); -} - -/*----------------------------print object (internal)------------- - print the object to screen */ -static PyObject *Vector_repr(VectorObject * self) -{ - int i; - char buffer[48], str[1024]; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - BLI_strncpy(str,"[",1024); - for(i = 0; i < self->size; i++){ - if(i < (self->size - 1)){ - sprintf(buffer, "%.6f, ", self->vec[i]); - strcat(str,buffer); - }else{ - sprintf(buffer, "%.6f", self->vec[i]); - strcat(str,buffer); - } - } - strcat(str, "](vector)"); - - return PyUnicode_FromString(str); -} -/*---------------------SEQUENCE PROTOCOLS------------------------ - ----------------------------len(object)------------------------ - sequence length*/ -static int Vector_len(VectorObject * self) -{ - return self->size; -} -/*----------------------------object[]--------------------------- - sequence accessor (get)*/ -static PyObject *Vector_item(VectorObject * self, int i) -{ - if(i<0) i= self->size-i; - - if(i < 0 || i >= self->size) { - PyErr_SetString(PyExc_IndexError,"vector[index]: out of range\n"); - return NULL; - } - - if(!BaseMath_ReadIndexCallback(self, i)) - return NULL; - - return PyFloat_FromDouble(self->vec[i]); - -} -/*----------------------------object[]------------------------- - sequence accessor (set)*/ -static int Vector_ass_item(VectorObject * self, int i, PyObject * ob) -{ - float scalar= (float)PyFloat_AsDouble(ob); - if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ - PyErr_SetString(PyExc_TypeError, "vector[index] = x: index argument not a number\n"); - return -1; - } - - if(i<0) i= self->size-i; - - if(i < 0 || i >= self->size){ - PyErr_SetString(PyExc_IndexError, "vector[index] = x: assignment index out of range\n"); - return -1; - } - self->vec[i] = scalar; - - if(!BaseMath_WriteIndexCallback(self, i)) - return -1; - return 0; -} - -/*----------------------------object[z:y]------------------------ - sequence slice (get) */ -static PyObject *Vector_slice(VectorObject * self, int begin, int end) -{ - PyObject *list = NULL; - int count; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - CLAMP(begin, 0, self->size); - if (end<0) end= self->size+end+1; - CLAMP(end, 0, self->size); - begin = MIN2(begin,end); - - list = PyList_New(end - begin); - for(count = begin; count < end; count++) { - PyList_SetItem(list, count - begin, - PyFloat_FromDouble(self->vec[count])); - } - - return list; -} -/*----------------------------object[z:y]------------------------ - sequence slice (set) */ -static int Vector_ass_slice(VectorObject * self, int begin, int end, - PyObject * seq) -{ - int i, y, size = 0; - float vec[4], scalar; - PyObject *v; - - if(!BaseMath_ReadCallback(self)) - return -1; - - CLAMP(begin, 0, self->size); - if (end<0) end= self->size+end+1; - CLAMP(end, 0, self->size); - begin = MIN2(begin,end); - - size = PySequence_Length(seq); - if(size != (end - begin)){ - PyErr_SetString(PyExc_TypeError, "vector[begin:end] = []: size mismatch in slice assignment\n"); - return -1; - } - - for (i = 0; i < size; i++) { - v = PySequence_GetItem(seq, i); - if (v == NULL) { /* Failed to read sequence */ - PyErr_SetString(PyExc_RuntimeError, "vector[begin:end] = []: unable to read sequence\n"); - return -1; - } - - scalar= (float)PyFloat_AsDouble(v); - if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ - Py_DECREF(v); - PyErr_SetString(PyExc_TypeError, "vector[begin:end] = []: sequence argument not a number\n"); - return -1; - } - - vec[i] = scalar; - Py_DECREF(v); - } - /*parsed well - now set in vector*/ - for(y = 0; y < size; y++){ - self->vec[begin + y] = vec[y]; - } - - if(!BaseMath_WriteCallback(self)) - return -1; - - return 0; -} -/*------------------------NUMERIC PROTOCOLS---------------------- - ------------------------obj + obj------------------------------ - addition*/ -static PyObject *Vector_add(PyObject * v1, PyObject * v2) -{ - int i; - float vec[4]; - - VectorObject *vec1 = NULL, *vec2 = NULL; - - if VectorObject_Check(v1) - vec1= (VectorObject *)v1; - - if VectorObject_Check(v2) - vec2= (VectorObject *)v2; - - /* make sure v1 is always the vector */ - if (vec1 && vec2 ) { - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) - return NULL; - - /*VECTOR + VECTOR*/ - if(vec1->size != vec2->size) { - PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation\n"); - return NULL; - } - for(i = 0; i < vec1->size; i++) { - vec[i] = vec1->vec[i] + vec2->vec[i]; - } - return newVectorObject(vec, vec1->size, Py_NEW, NULL); - } - - PyErr_SetString(PyExc_AttributeError, "Vector addition: arguments not valid for this operation....\n"); - return NULL; -} - -/* ------------------------obj += obj------------------------------ - addition in place */ -static PyObject *Vector_iadd(PyObject * v1, PyObject * v2) -{ - int i; - - VectorObject *vec1 = NULL, *vec2 = NULL; - - if VectorObject_Check(v1) - vec1= (VectorObject *)v1; - - if VectorObject_Check(v2) - vec2= (VectorObject *)v2; - - /* make sure v1 is always the vector */ - if (vec1 && vec2 ) { - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) - return NULL; - - /*VECTOR + VECTOR*/ - if(vec1->size != vec2->size) { - PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation\n"); - return NULL; - } - for(i = 0; i < vec1->size; i++) { - vec1->vec[i] += vec2->vec[i]; - } - Py_INCREF( v1 ); - return v1; - } - - BaseMath_WriteCallback(vec1); - PyErr_SetString(PyExc_AttributeError, "Vector addition: arguments not valid for this operation....\n"); - return NULL; -} - -/*------------------------obj - obj------------------------------ - subtraction*/ -static PyObject *Vector_sub(PyObject * v1, PyObject * v2) -{ - int i; - float vec[4]; - VectorObject *vec1 = NULL, *vec2 = NULL; - - if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) { - PyErr_SetString(PyExc_AttributeError, "Vector subtraction: arguments not valid for this operation....\n"); - return NULL; - } - vec1 = (VectorObject*)v1; - vec2 = (VectorObject*)v2; - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) - return NULL; - - if(vec1->size != vec2->size) { - PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation\n"); - return NULL; - } - for(i = 0; i < vec1->size; i++) { - vec[i] = vec1->vec[i] - vec2->vec[i]; - } - - return newVectorObject(vec, vec1->size, Py_NEW, NULL); -} - -/*------------------------obj -= obj------------------------------ - subtraction*/ -static PyObject *Vector_isub(PyObject * v1, PyObject * v2) -{ - int i; - VectorObject *vec1 = NULL, *vec2 = NULL; - - if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) { - PyErr_SetString(PyExc_AttributeError, "Vector subtraction: arguments not valid for this operation....\n"); - return NULL; - } - vec1 = (VectorObject*)v1; - vec2 = (VectorObject*)v2; - - if(vec1->size != vec2->size) { - PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation\n"); - return NULL; - } - - if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2)) - return NULL; - - for(i = 0; i < vec1->size; i++) { - vec1->vec[i] = vec1->vec[i] - vec2->vec[i]; - } - - BaseMath_WriteCallback(vec1); - Py_INCREF( v1 ); - return v1; -} - -/*------------------------obj * obj------------------------------ - mulplication*/ -static PyObject *Vector_mul(PyObject * v1, PyObject * v2) -{ - VectorObject *vec1 = NULL, *vec2 = NULL; - float scalar; - - if VectorObject_Check(v1) { - vec1= (VectorObject *)v1; - if(!BaseMath_ReadCallback(vec1)) - return NULL; - } - if VectorObject_Check(v2) { - vec2= (VectorObject *)v2; - if(!BaseMath_ReadCallback(vec2)) - return NULL; - } - - - /* make sure v1 is always the vector */ - if (vec1 && vec2 ) { - int i; - double dot = 0.0f; - - if(vec1->size != vec2->size) { - PyErr_SetString(PyExc_AttributeError, "Vector multiplication: vectors must have the same dimensions for this operation\n"); - return NULL; - } - - /*dot product*/ - for(i = 0; i < vec1->size; i++) { - dot += vec1->vec[i] * vec2->vec[i]; - } - return PyFloat_FromDouble(dot); - } - - /*swap so vec1 is always the vector */ - if (vec2) { - vec1= vec2; - v2= v1; - } - - if (MatrixObject_Check(v2)) { - /* VEC * MATRIX */ - return row_vector_multiplication(vec1, (MatrixObject*)v2); - } else if (QuaternionObject_Check(v2)) { - QuaternionObject *quat = (QuaternionObject*)v2; /* quat_rotation validates */ - - if(vec1->size != 3) { - PyErr_SetString(PyExc_TypeError, "Vector multiplication: only 3D vector rotations (with quats) currently supported\n"); - return NULL; - } - return quat_rotation((PyObject*)vec1, (PyObject*)quat); - } - else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*FLOAT */ - int i; - float vec[4]; - - for(i = 0; i < vec1->size; i++) { - vec[i] = vec1->vec[i] * scalar; - } - return newVectorObject(vec, vec1->size, Py_NEW, NULL); - - } - - PyErr_SetString(PyExc_TypeError, "Vector multiplication: arguments not acceptable for this operation\n"); - return NULL; -} - -/*------------------------obj *= obj------------------------------ - in place mulplication */ -static PyObject *Vector_imul(PyObject * v1, PyObject * v2) -{ - VectorObject *vec = (VectorObject *)v1; - int i; - float scalar; - - if(!BaseMath_ReadCallback(vec)) - return NULL; - - /* only support vec*=float and vec*=mat - vec*=vec result is a float so that wont work */ - if (MatrixObject_Check(v2)) { - float vecCopy[4]; - int x,y, size = vec->size; - MatrixObject *mat= (MatrixObject*)v2; - - if(!BaseMath_ReadCallback(mat)) - return NULL; - - if(mat->colSize != size){ - if(mat->rowSize == 4 && vec->size != 3){ - PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same"); - return NULL; - } else { - vecCopy[3] = 1.0f; - } - } - - for(i = 0; i < size; i++){ - vecCopy[i] = vec->vec[i]; - } - - size = MIN2(size, mat->colSize); - - /*muliplication*/ - for(x = 0, i = 0; x < size; x++, i++) { - double dot = 0.0f; - for(y = 0; y < mat->rowSize; y++) { - dot += mat->matrix[y][x] * vecCopy[y]; - } - vec->vec[i] = (float)dot; - } - } - else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*=FLOAT */ - - for(i = 0; i < vec->size; i++) { - vec->vec[i] *= scalar; - } - } - else { - PyErr_SetString(PyExc_TypeError, "Vector multiplication: arguments not acceptable for this operation\n"); - return NULL; - } - - BaseMath_WriteCallback(vec); - Py_INCREF( v1 ); - return v1; -} - -/*------------------------obj / obj------------------------------ - divide*/ -static PyObject *Vector_div(PyObject * v1, PyObject * v2) -{ - int i; - float vec[4], scalar; - VectorObject *vec1 = NULL; - - if(!VectorObject_Check(v1)) { /* not a vector */ - PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n"); - return NULL; - } - vec1 = (VectorObject*)v1; /* vector */ - - if(!BaseMath_ReadCallback(vec1)) - return NULL; - - scalar = (float)PyFloat_AsDouble(v2); - if(scalar== -1.0f && PyErr_Occurred()) { /* parsed item not a number */ - PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n"); - return NULL; - } - - if(scalar==0.0) { /* not a vector */ - PyErr_SetString(PyExc_ZeroDivisionError, "Vector division: divide by zero error.\n"); - return NULL; - } - - for(i = 0; i < vec1->size; i++) { - vec[i] = vec1->vec[i] / scalar; - } - return newVectorObject(vec, vec1->size, Py_NEW, NULL); -} - -/*------------------------obj /= obj------------------------------ - divide*/ -static PyObject *Vector_idiv(PyObject * v1, PyObject * v2) -{ - int i; - float scalar; - VectorObject *vec1 = (VectorObject*)v1; - - if(!BaseMath_ReadCallback(vec1)) - return NULL; - - scalar = (float)PyFloat_AsDouble(v2); - if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ - PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n"); - return NULL; - } - - if(scalar==0.0) { /* not a vector */ - PyErr_SetString(PyExc_ZeroDivisionError, "Vector division: divide by zero error.\n"); - return NULL; - } - for(i = 0; i < vec1->size; i++) { - vec1->vec[i] /= scalar; - } - - BaseMath_WriteCallback(vec1); - - Py_INCREF( v1 ); - return v1; -} - -/*-------------------------- -obj ------------------------------- - returns the negative of this object*/ -static PyObject *Vector_neg(VectorObject *self) -{ - int i; - float vec[4]; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - for(i = 0; i < self->size; i++){ - vec[i] = -self->vec[i]; - } - - return newVectorObject(vec, self->size, Py_NEW, Py_TYPE(self)); -} - -/*------------------------vec_magnitude_nosqrt (internal) - for comparing only */ -static double vec_magnitude_nosqrt(float *data, int size) -{ - double dot = 0.0f; - int i; - - for(i=0; i<size; i++){ - dot += data[i]; - } - /*return (double)sqrt(dot);*/ - /* warning, line above removed because we are not using the length, - rather the comparing the sizes and for this we do not need the sqrt - for the actual length, the dot must be sqrt'd */ - return (double)dot; -} - - -/*------------------------tp_richcmpr - returns -1 execption, 0 false, 1 true */ -static PyObject* Vector_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type) -{ - VectorObject *vecA = NULL, *vecB = NULL; - int result = 0; - float epsilon = .000001f; - double lenA,lenB; - - if (!VectorObject_Check(objectA) || !VectorObject_Check(objectB)){ - if (comparison_type == Py_NE){ - Py_RETURN_TRUE; - }else{ - Py_RETURN_FALSE; - } - } - vecA = (VectorObject*)objectA; - vecB = (VectorObject*)objectB; - - if(!BaseMath_ReadCallback(vecA) || !BaseMath_ReadCallback(vecB)) - return NULL; - - if (vecA->size != vecB->size){ - if (comparison_type == Py_NE){ - Py_RETURN_TRUE; - }else{ - Py_RETURN_FALSE; - } - } - - switch (comparison_type){ - case Py_LT: - lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); - lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); - if( lenA < lenB ){ - result = 1; - } - break; - case Py_LE: - lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); - lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); - if( lenA < lenB ){ - result = 1; - }else{ - result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB)); - } - break; - case Py_EQ: - result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->size, 1); - break; - case Py_NE: - result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->size, 1); - if (result == 0){ - result = 1; - }else{ - result = 0; - } - break; - case Py_GT: - lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); - lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); - if( lenA > lenB ){ - result = 1; - } - break; - case Py_GE: - lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); - lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); - if( lenA > lenB ){ - result = 1; - }else{ - result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB)); - } - break; - default: - printf("The result of the comparison could not be evaluated"); - break; - } - if (result == 1){ - Py_RETURN_TRUE; - }else{ - Py_RETURN_FALSE; - } -} - -/*-----------------PROTCOL DECLARATIONS--------------------------*/ -static PySequenceMethods Vector_SeqMethods = { - (inquiry) Vector_len, /* sq_length */ - (binaryfunc) 0, /* sq_concat */ - (ssizeargfunc) 0, /* sq_repeat */ - (ssizeargfunc) Vector_item, /* sq_item */ -#if (PY_VERSION_HEX < 0x03000000) - (ssizessizeargfunc) Vector_slice, /* sq_slice */ /* PY2 ONLY */ -#else - NULL, -#endif - (ssizeobjargproc) Vector_ass_item, /* sq_ass_item */ -#if (PY_VERSION_HEX < 0x03000000) - (ssizessizeobjargproc) Vector_ass_slice, /* sq_ass_slice */ /* PY2 ONLY */ -#else - NULL, -#endif -}; - - -#if (PY_VERSION_HEX >= 0x03000000) -static PyObject *Vector_subscript(VectorObject* self, PyObject* item) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i; - i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - if (i < 0) - i += self->size; - return Vector_item(self, i); - } else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx((PySliceObject*)item, self->size, &start, &stop, &step, &slicelength) < 0) - return NULL; - - if (slicelength <= 0) { - return PyList_New(0); - } - else if (step == 1) { - return Vector_slice(self, start, stop); - } - else { - PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors"); - return NULL; - } - } - else { - PyErr_Format(PyExc_TypeError, - "vector indices must be integers, not %.200s", - item->ob_type->tp_name); - return NULL; - } -} - -static int Vector_ass_subscript(VectorObject* self, PyObject* item, PyObject* value) -{ - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return -1; - if (i < 0) - i += self->size; - return Vector_ass_item(self, i, value); - } - else if (PySlice_Check(item)) { - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx((PySliceObject*)item, self->size, &start, &stop, &step, &slicelength) < 0) - return -1; - - if (step == 1) - return Vector_ass_slice(self, start, stop, value); - else { - PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors"); - return -1; - } - } - else { - PyErr_Format(PyExc_TypeError, - "vector indices must be integers, not %.200s", - item->ob_type->tp_name); - return -1; - } -} - -static PyMappingMethods Vector_AsMapping = { - (lenfunc)Vector_len, - (binaryfunc)Vector_subscript, - (objobjargproc)Vector_ass_subscript -}; -#endif /* (PY_VERSION_HEX >= 0x03000000) */ - -#if (PY_VERSION_HEX >= 0x03000000) -static PyNumberMethods Vector_NumMethods = { - (binaryfunc) Vector_add, /*nb_add*/ - (binaryfunc) Vector_sub, /*nb_subtract*/ - (binaryfunc) Vector_mul, /*nb_multiply*/ - 0, /*nb_remainder*/ - 0, /*nb_divmod*/ - 0, /*nb_power*/ - (unaryfunc) Vector_neg, /*nb_negative*/ - (unaryfunc) 0, /*tp_positive*/ - (unaryfunc) 0, /*tp_absolute*/ - (inquiry) 0, /*tp_bool*/ - (unaryfunc) 0, /*nb_invert*/ - 0, /*nb_lshift*/ - (binaryfunc)0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - 0, /*nb_int*/ - 0, /*nb_reserved*/ - 0, /*nb_float*/ - Vector_iadd, /* nb_inplace_add */ - Vector_isub, /* nb_inplace_subtract */ - Vector_imul, /* nb_inplace_multiply */ - 0, /* nb_inplace_remainder */ - 0, /* nb_inplace_power */ - 0, /* nb_inplace_lshift */ - 0, /* nb_inplace_rshift */ - 0, /* nb_inplace_and */ - 0, /* nb_inplace_xor */ - 0, /* nb_inplace_or */ - 0, /* nb_floor_divide */ - Vector_div, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - Vector_idiv, /* nb_inplace_true_divide */ - 0, /* nb_index */ -}; -#else -static PyNumberMethods Vector_NumMethods = { - (binaryfunc) Vector_add, /* __add__ */ - (binaryfunc) Vector_sub, /* __sub__ */ - (binaryfunc) Vector_mul, /* __mul__ */ - (binaryfunc) Vector_div, /* __div__ */ - (binaryfunc) NULL, /* __mod__ */ - (binaryfunc) NULL, /* __divmod__ */ - (ternaryfunc) NULL, /* __pow__ */ - (unaryfunc) Vector_neg, /* __neg__ */ - (unaryfunc) NULL, /* __pos__ */ - (unaryfunc) NULL, /* __abs__ */ - (inquiry) NULL, /* __nonzero__ */ - (unaryfunc) NULL, /* __invert__ */ - (binaryfunc) NULL, /* __lshift__ */ - (binaryfunc) NULL, /* __rshift__ */ - (binaryfunc) NULL, /* __and__ */ - (binaryfunc) NULL, /* __xor__ */ - (binaryfunc) NULL, /* __or__ */ - /*(coercion)*/ NULL, /* __coerce__ */ - (unaryfunc) NULL, /* __int__ */ - (unaryfunc) NULL, /* __long__ */ - (unaryfunc) NULL, /* __float__ */ - (unaryfunc) NULL, /* __oct__ */ - (unaryfunc) NULL, /* __hex__ */ - - /* Added in release 2.0 */ - (binaryfunc) Vector_iadd, /*__iadd__*/ - (binaryfunc) Vector_isub, /*__isub__*/ - (binaryfunc) Vector_imul, /*__imul__*/ - (binaryfunc) Vector_idiv, /*__idiv__*/ - (binaryfunc) NULL, /*__imod__*/ - (ternaryfunc) NULL, /*__ipow__*/ - (binaryfunc) NULL, /*__ilshift__*/ - (binaryfunc) NULL, /*__irshift__*/ - (binaryfunc) NULL, /*__iand__*/ - (binaryfunc) NULL, /*__ixor__*/ - (binaryfunc) NULL, /*__ior__*/ - - /* Added in release 2.2 */ - /* The following require the Py_TPFLAGS_HAVE_CLASS flag */ - (binaryfunc) NULL, /*__floordiv__ __rfloordiv__*/ - (binaryfunc) NULL, /*__truediv__ __rfloordiv__*/ - (binaryfunc) NULL, /*__ifloordiv__*/ - (binaryfunc) NULL, /*__itruediv__*/ -}; -#endif - -/*------------------PY_OBECT DEFINITION--------------------------*/ - -/* - * vector axis, vector.x/y/z/w - */ - -static PyObject *Vector_getAxis( VectorObject * self, void *type ) -{ - return Vector_item(self, GET_INT_FROM_POINTER(type)); -} - -static int Vector_setAxis( VectorObject * self, PyObject * value, void * type ) -{ - return Vector_ass_item(self, GET_INT_FROM_POINTER(type), value); -} - -/* vector.length */ -static PyObject *Vector_getLength( VectorObject * self, void *type ) -{ - double dot = 0.0f; - int i; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - for(i = 0; i < self->size; i++){ - dot += (self->vec[i] * self->vec[i]); - } - return PyFloat_FromDouble(sqrt(dot)); -} - -static int Vector_setLength( VectorObject * self, PyObject * value ) -{ - double dot = 0.0f, param; - int i; - - if(!BaseMath_ReadCallback(self)) - return -1; - - param= PyFloat_AsDouble( value ); - if(param==-1.0 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "length must be set to a number"); - return -1; - } - - if (param < 0) { - PyErr_SetString( PyExc_TypeError, "cannot set a vectors length to a negative value" ); - return -1; - } - if (param==0) { - for(i = 0; i < self->size; i++){ - self->vec[i]= 0; - } - return 0; - } - - for(i = 0; i < self->size; i++){ - dot += (self->vec[i] * self->vec[i]); - } - - if (!dot) /* cant sqrt zero */ - return 0; - - dot = sqrt(dot); - - if (dot==param) - return 0; - - dot= dot/param; - - for(i = 0; i < self->size; i++){ - self->vec[i]= self->vec[i] / (float)dot; - } - - BaseMath_WriteCallback(self); /* checked alredy */ - - return 0; -} - -/* Get a new Vector according to the provided swizzle. This function has little - error checking, as we are in control of the inputs: the closure is set by us - in Vector_createSwizzleGetSeter. */ -static PyObject *Vector_getSwizzle(VectorObject * self, void *closure) -{ - size_t axisA; - size_t axisB; - float vec[MAX_DIMENSIONS]; - unsigned int swizzleClosure; - - if(!BaseMath_ReadCallback(self)) - return NULL; - - /* Unpack the axes from the closure into an array. */ - axisA = 0; - swizzleClosure = (unsigned int) closure; - while (swizzleClosure & SWIZZLE_VALID_AXIS) - { - axisB = swizzleClosure & SWIZZLE_AXIS; - vec[axisA] = self->vec[axisB]; - swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; - axisA++; - } - - return newVectorObject(vec, axisA, Py_NEW, Py_TYPE(self)); -} - -/* Set the items of this vector using a swizzle. - - If value is a vector or list this operates like an array copy, except that - the destination is effectively re-ordered as defined by the swizzle. At - most min(len(source), len(dest)) values will be copied. - - If the value is scalar, it is copied to all axes listed in the swizzle. - - If an axis appears more than once in the swizzle, the final occurrance is - the one that determines its value. - - Returns 0 on success and -1 on failure. On failure, the vector will be - unchanged. */ -static int Vector_setSwizzle(VectorObject * self, PyObject * value, void *closure) -{ - VectorObject *vecVal; - PyObject *item; - size_t listLen; - float scalarVal; - - size_t axisB; - size_t axisA; - unsigned int swizzleClosure; - - float vecTemp[MAX_DIMENSIONS]; - - if(!BaseMath_ReadCallback(self)) - return -1; - - /* Check that the closure can be used with this vector: even 2D vectors have - swizzles defined for axes z and w, but they would be invalid. */ - swizzleClosure = (unsigned int) closure; - while (swizzleClosure & SWIZZLE_VALID_AXIS) - { - axisA = swizzleClosure & SWIZZLE_AXIS; - if (axisA >= self->size) - { - PyErr_SetString(PyExc_AttributeError, "Error: vector does not have specified axis.\n"); - return -1; - } - swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; - } - - if (VectorObject_Check(value)) - { - /* Copy vector contents onto swizzled axes. */ - vecVal = (VectorObject*) value; - axisB = 0; - swizzleClosure = (unsigned int) closure; - while (swizzleClosure & SWIZZLE_VALID_AXIS && axisB < vecVal->size) - { - axisA = swizzleClosure & SWIZZLE_AXIS; - vecTemp[axisA] = vecVal->vec[axisB]; - - swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; - axisB++; - } - memcpy(self->vec, vecTemp, axisB * sizeof(float)); - /* continue with BaseMathObject_WriteCallback at the end */ - } - else if (PyList_Check(value)) - { - /* Copy list contents onto swizzled axes. */ - listLen = PyList_Size(value); - swizzleClosure = (unsigned int) closure; - axisB = 0; - while (swizzleClosure & SWIZZLE_VALID_AXIS && axisB < listLen) - { - item = PyList_GetItem(value, axisB); - scalarVal = (float)PyFloat_AsDouble(item); - - if (scalarVal==-1.0 && PyErr_Occurred()) { - PyErr_SetString(PyExc_AttributeError, "Error: vector does not have specified axis.\n"); - return -1; - } - - - axisA = swizzleClosure & SWIZZLE_AXIS; - vecTemp[axisA] = scalarVal; - - swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; - axisB++; - } - memcpy(self->vec, vecTemp, axisB * sizeof(float)); - /* continue with BaseMathObject_WriteCallback at the end */ - } - else if (((scalarVal = (float)PyFloat_AsDouble(value)) == -1.0 && PyErr_Occurred())==0) - { - /* Assign the same value to each axis. */ - swizzleClosure = (unsigned int) closure; - while (swizzleClosure & SWIZZLE_VALID_AXIS) - { - axisA = swizzleClosure & SWIZZLE_AXIS; - self->vec[axisA] = scalarVal; - - swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; - } - /* continue with BaseMathObject_WriteCallback at the end */ - } - else { - PyErr_SetString( PyExc_TypeError, "Expected a Vector, list or scalar value." ); - return -1; - } - - if(!BaseMath_WriteCallback(vecVal)) - return -1; - else - return 0; -} - -/*****************************************************************************/ -/* Python attributes get/set structure: */ -/*****************************************************************************/ -static PyGetSetDef Vector_getseters[] = { - {"x", - (getter)Vector_getAxis, (setter)Vector_setAxis, - "Vector X axis", - (void *)0}, - {"y", - (getter)Vector_getAxis, (setter)Vector_setAxis, - "Vector Y axis", - (void *)1}, - {"z", - (getter)Vector_getAxis, (setter)Vector_setAxis, - "Vector Z axis", - (void *)2}, - {"w", - (getter)Vector_getAxis, (setter)Vector_setAxis, - "Vector Z axis", - (void *)3}, - {"length", - (getter)Vector_getLength, (setter)Vector_setLength, - "Vector Length", - NULL}, - {"magnitude", - (getter)Vector_getLength, (setter)Vector_setLength, - "Vector Length", - NULL}, - {"wrapped", - (getter)BaseMathObject_getWrapped, (setter)NULL, - "True when this wraps blenders internal data", - NULL}, - {"__owner__", - (getter)BaseMathObject_getOwner, (setter)NULL, - "Read only owner for vectors that depend on another object", - NULL}, - - /* autogenerated swizzle attrs, see python script below */ - {"xx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 36 */ - {"xxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 292 */ - {"xxxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2340 */ - {"xxxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2852 */ - {"xxxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3364 */ - {"xxxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3876 */ - {"xxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 356 */ - {"xxyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2404 */ - {"xxyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2916 */ - {"xxyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3428 */ - {"xxyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3940 */ - {"xxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 420 */ - {"xxzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2468 */ - {"xxzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2980 */ - {"xxzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3492 */ - {"xxzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4004 */ - {"xxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 484 */ - {"xxwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2532 */ - {"xxwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3044 */ - {"xxwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3556 */ - {"xxww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4068 */ - {"xy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 44 */ - {"xyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 300 */ - {"xyxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2348 */ - {"xyxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2860 */ - {"xyxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3372 */ - {"xyxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3884 */ - {"xyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 364 */ - {"xyyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2412 */ - {"xyyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2924 */ - {"xyyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3436 */ - {"xyyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3948 */ - {"xyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 428 */ - {"xyzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2476 */ - {"xyzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2988 */ - {"xyzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3500 */ - {"xyzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4012 */ - {"xyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 492 */ - {"xywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2540 */ - {"xywy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3052 */ - {"xywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3564 */ - {"xyww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4076 */ - {"xz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 52 */ - {"xzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 308 */ - {"xzxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2356 */ - {"xzxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2868 */ - {"xzxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3380 */ - {"xzxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3892 */ - {"xzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 372 */ - {"xzyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2420 */ - {"xzyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2932 */ - {"xzyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3444 */ - {"xzyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3956 */ - {"xzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 436 */ - {"xzzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2484 */ - {"xzzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2996 */ - {"xzzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3508 */ - {"xzzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4020 */ - {"xzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 500 */ - {"xzwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2548 */ - {"xzwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3060 */ - {"xzwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3572 */ - {"xzww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4084 */ - {"xw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 60 */ - {"xwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 316 */ - {"xwxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2364 */ - {"xwxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2876 */ - {"xwxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3388 */ - {"xwxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3900 */ - {"xwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 380 */ - {"xwyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2428 */ - {"xwyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2940 */ - {"xwyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3452 */ - {"xwyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3964 */ - {"xwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 444 */ - {"xwzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2492 */ - {"xwzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3004 */ - {"xwzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3516 */ - {"xwzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4028 */ - {"xww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 508 */ - {"xwwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2556 */ - {"xwwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3068 */ - {"xwwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3580 */ - {"xwww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4092 */ - {"yx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 37 */ - {"yxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 293 */ - {"yxxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2341 */ - {"yxxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2853 */ - {"yxxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3365 */ - {"yxxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3877 */ - {"yxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 357 */ - {"yxyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2405 */ - {"yxyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2917 */ - {"yxyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3429 */ - {"yxyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3941 */ - {"yxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 421 */ - {"yxzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2469 */ - {"yxzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2981 */ - {"yxzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3493 */ - {"yxzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4005 */ - {"yxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 485 */ - {"yxwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2533 */ - {"yxwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3045 */ - {"yxwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3557 */ - {"yxww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4069 */ - {"yy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 45 */ - {"yyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 301 */ - {"yyxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2349 */ - {"yyxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2861 */ - {"yyxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3373 */ - {"yyxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3885 */ - {"yyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 365 */ - {"yyyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2413 */ - {"yyyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2925 */ - {"yyyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3437 */ - {"yyyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3949 */ - {"yyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 429 */ - {"yyzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2477 */ - {"yyzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2989 */ - {"yyzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3501 */ - {"yyzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4013 */ - {"yyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 493 */ - {"yywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2541 */ - {"yywy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3053 */ - {"yywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3565 */ - {"yyww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4077 */ - {"yz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 53 */ - {"yzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 309 */ - {"yzxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2357 */ - {"yzxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2869 */ - {"yzxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3381 */ - {"yzxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3893 */ - {"yzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 373 */ - {"yzyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2421 */ - {"yzyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2933 */ - {"yzyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3445 */ - {"yzyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3957 */ - {"yzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 437 */ - {"yzzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2485 */ - {"yzzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2997 */ - {"yzzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3509 */ - {"yzzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4021 */ - {"yzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 501 */ - {"yzwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2549 */ - {"yzwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3061 */ - {"yzwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3573 */ - {"yzww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4085 */ - {"yw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 61 */ - {"ywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 317 */ - {"ywxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2365 */ - {"ywxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2877 */ - {"ywxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3389 */ - {"ywxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3901 */ - {"ywy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 381 */ - {"ywyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2429 */ - {"ywyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2941 */ - {"ywyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3453 */ - {"ywyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3965 */ - {"ywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 445 */ - {"ywzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2493 */ - {"ywzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3005 */ - {"ywzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3517 */ - {"ywzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4029 */ - {"yww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 509 */ - {"ywwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2557 */ - {"ywwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3069 */ - {"ywwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3581 */ - {"ywww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4093 */ - {"zx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 38 */ - {"zxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 294 */ - {"zxxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2342 */ - {"zxxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2854 */ - {"zxxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3366 */ - {"zxxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3878 */ - {"zxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 358 */ - {"zxyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2406 */ - {"zxyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2918 */ - {"zxyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3430 */ - {"zxyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3942 */ - {"zxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 422 */ - {"zxzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2470 */ - {"zxzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2982 */ - {"zxzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3494 */ - {"zxzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4006 */ - {"zxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 486 */ - {"zxwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2534 */ - {"zxwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3046 */ - {"zxwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3558 */ - {"zxww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4070 */ - {"zy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 46 */ - {"zyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 302 */ - {"zyxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2350 */ - {"zyxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2862 */ - {"zyxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3374 */ - {"zyxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3886 */ - {"zyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 366 */ - {"zyyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2414 */ - {"zyyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2926 */ - {"zyyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3438 */ - {"zyyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3950 */ - {"zyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 430 */ - {"zyzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2478 */ - {"zyzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2990 */ - {"zyzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3502 */ - {"zyzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4014 */ - {"zyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 494 */ - {"zywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2542 */ - {"zywy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3054 */ - {"zywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3566 */ - {"zyww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4078 */ - {"zz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 54 */ - {"zzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 310 */ - {"zzxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2358 */ - {"zzxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2870 */ - {"zzxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3382 */ - {"zzxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3894 */ - {"zzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 374 */ - {"zzyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2422 */ - {"zzyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2934 */ - {"zzyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3446 */ - {"zzyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3958 */ - {"zzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 438 */ - {"zzzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2486 */ - {"zzzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2998 */ - {"zzzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3510 */ - {"zzzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4022 */ - {"zzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 502 */ - {"zzwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2550 */ - {"zzwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3062 */ - {"zzwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3574 */ - {"zzww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4086 */ - {"zw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 62 */ - {"zwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 318 */ - {"zwxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2366 */ - {"zwxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2878 */ - {"zwxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3390 */ - {"zwxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3902 */ - {"zwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 382 */ - {"zwyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2430 */ - {"zwyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2942 */ - {"zwyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3454 */ - {"zwyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3966 */ - {"zwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 446 */ - {"zwzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2494 */ - {"zwzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3006 */ - {"zwzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3518 */ - {"zwzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4030 */ - {"zww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 510 */ - {"zwwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2558 */ - {"zwwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3070 */ - {"zwwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3582 */ - {"zwww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4094 */ - {"wx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 39 */ - {"wxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 295 */ - {"wxxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2343 */ - {"wxxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2855 */ - {"wxxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3367 */ - {"wxxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3879 */ - {"wxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 359 */ - {"wxyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2407 */ - {"wxyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2919 */ - {"wxyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3431 */ - {"wxyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3943 */ - {"wxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 423 */ - {"wxzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2471 */ - {"wxzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2983 */ - {"wxzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3495 */ - {"wxzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4007 */ - {"wxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 487 */ - {"wxwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2535 */ - {"wxwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3047 */ - {"wxwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3559 */ - {"wxww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4071 */ - {"wy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 47 */ - {"wyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 303 */ - {"wyxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2351 */ - {"wyxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2863 */ - {"wyxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3375 */ - {"wyxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3887 */ - {"wyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 367 */ - {"wyyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2415 */ - {"wyyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2927 */ - {"wyyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3439 */ - {"wyyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3951 */ - {"wyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 431 */ - {"wyzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2479 */ - {"wyzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2991 */ - {"wyzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3503 */ - {"wyzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4015 */ - {"wyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 495 */ - {"wywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2543 */ - {"wywy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3055 */ - {"wywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3567 */ - {"wyww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4079 */ - {"wz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 55 */ - {"wzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 311 */ - {"wzxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2359 */ - {"wzxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2871 */ - {"wzxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3383 */ - {"wzxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3895 */ - {"wzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 375 */ - {"wzyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2423 */ - {"wzyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2935 */ - {"wzyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3447 */ - {"wzyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3959 */ - {"wzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 439 */ - {"wzzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2487 */ - {"wzzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2999 */ - {"wzzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3511 */ - {"wzzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4023 */ - {"wzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 503 */ - {"wzwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2551 */ - {"wzwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3063 */ - {"wzwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3575 */ - {"wzww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4087 */ - {"ww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 63 */ - {"wwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 319 */ - {"wwxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2367 */ - {"wwxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2879 */ - {"wwxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3391 */ - {"wwxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3903 */ - {"wwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 383 */ - {"wwyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2431 */ - {"wwyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2943 */ - {"wwyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3455 */ - {"wwyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3967 */ - {"wwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 447 */ - {"wwzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2495 */ - {"wwzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3007 */ - {"wwzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3519 */ - {"wwzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4031 */ - {"www", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 511 */ - {"wwwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2559 */ - {"wwwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3071 */ - {"wwwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3583 */ - {"wwww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4095 */ - {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ -}; - -/* Python script used to make swizzle array */ -/* -SWIZZLE_BITS_PER_AXIS = 3 -SWIZZLE_VALID_AXIS = 0x4 - -axis_dict = {} -axis_pos = {'x':0, 'y':1, 'z':2, 'w':3} -axises = 'xyzw' -while len(axises) >= 2: - - for axis_0 in axises: - axis_0_pos = axis_pos[axis_0] - for axis_1 in axises: - axis_1_pos = axis_pos[axis_1] - axis_dict[axis_0+axis_1] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS))' % (axis_0_pos, axis_1_pos) - if len(axises)>2: - for axis_2 in axises: - axis_2_pos = axis_pos[axis_2] - axis_dict[axis_0+axis_1+axis_2] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)))' % (axis_0_pos, axis_1_pos, axis_2_pos) - if len(axises)>3: - for axis_3 in axises: - axis_3_pos = axis_pos[axis_3] - axis_dict[axis_0+axis_1+axis_2+axis_3] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((%s|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) ' % (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos) - - axises = axises[:-1] - - -items = axis_dict.items() -items.sort(key = lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3')) - -unique = set() -for key, val in items: - num = eval(val) - print '\t{"%s", %s(getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)%s)}, // %s' % (key, (' '*(4-len(key))), axis_dict[key], num) - unique.add(num) - -if len(unique) != len(items): - print "ERROR" - -*/ - - - - -/* Note - Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing - but this means for eg that - vec*mat and mat*vec both get sent to Vector_mul and it neesd to sort out the order -*/ - -PyTypeObject vector_Type = { -#if (PY_VERSION_HEX >= 0x02060000) - PyVarObject_HEAD_INIT(NULL, 0) -#else - /* python 2.5 and below */ - PyObject_HEAD_INIT( NULL ) /* required py macro */ - 0, /* ob_size */ -#endif - /* For printing, in format "<module>.<name>" */ - "vector", /* char *tp_name; */ - sizeof( VectorObject ), /* int tp_basicsize; */ - 0, /* tp_itemsize; For allocation */ - - /* Methods to implement standard operations */ - - ( destructor ) BaseMathObject_dealloc,/* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ - NULL, /* cmpfunc tp_compare; */ - ( reprfunc ) Vector_repr, /* reprfunc tp_repr; */ - - /* Method suites for standard classes */ - - &Vector_NumMethods, /* PyNumberMethods *tp_as_number; */ - &Vector_SeqMethods, /* PySequenceMethods *tp_as_sequence; */ -#if (PY_VERSION_HEX >= 0x03000000) - &Vector_AsMapping, /* PyMappingMethods *tp_as_mapping; */ -#else - NULL, -#endif - - /* More standard operations (here for binary compatibility) */ - - NULL, /* hashfunc tp_hash; */ - NULL, /* ternaryfunc tp_call; */ - NULL, /* reprfunc tp_str; */ - NULL, /* getattrofunc tp_getattro; */ - NULL, /* setattrofunc tp_setattro; */ - - /* Functions to access object as input/output buffer */ - NULL, /* PyBufferProcs *tp_as_buffer; */ - - /*** Flags to define presence of optional/expanded features ***/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - NULL, /* char *tp_doc; Documentation string */ - /*** Assigned meaning in release 2.0 ***/ - /* call function for all accessible objects */ - NULL, /* traverseproc tp_traverse; */ - - /* delete references to contained objects */ - NULL, /* inquiry tp_clear; */ - - /*** Assigned meaning in release 2.1 ***/ - /*** rich comparisons ***/ - (richcmpfunc)Vector_richcmpr, /* richcmpfunc tp_richcompare; */ - - /*** weak reference enabler ***/ - 0, /* long tp_weaklistoffset; */ - - /*** Added in release 2.2 ***/ - /* Iterators */ - NULL, /* getiterfunc tp_iter; */ - NULL, /* iternextfunc tp_iternext; */ - - /*** Attribute descriptor and subclassing stuff ***/ - Vector_methods, /* struct PyMethodDef *tp_methods; */ - NULL, /* struct PyMemberDef *tp_members; */ - Vector_getseters, /* struct PyGetSetDef *tp_getset; */ - NULL, /* struct _typeobject *tp_base; */ - NULL, /* PyObject *tp_dict; */ - NULL, /* descrgetfunc tp_descr_get; */ - NULL, /* descrsetfunc tp_descr_set; */ - 0, /* long tp_dictoffset; */ - NULL, /* initproc tp_init; */ - NULL, /* allocfunc tp_alloc; */ - Vector_new, /* newfunc tp_new; */ - /* Low-level free-memory routine */ - NULL, /* freefunc tp_free; */ - /* For PyObject_IS_GC */ - NULL, /* inquiry tp_is_gc; */ - NULL, /* PyObject *tp_bases; */ - /* method resolution order */ - NULL, /* PyObject *tp_mro; */ - NULL, /* PyObject *tp_cache; */ - NULL, /* PyObject *tp_subclasses; */ - NULL, /* PyObject *tp_weaklist; */ - NULL -}; - - -/*------------------------newVectorObject (internal)------------- - creates a new vector object - pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER - (i.e. it was allocated elsewhere by MEM_mallocN()) - pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON - (i.e. it must be created here with PyMEM_malloc())*/ -PyObject *newVectorObject(float *vec, int size, int type, PyTypeObject *base_type) -{ - int i; - VectorObject *self; - - if(base_type) self = (VectorObject *)base_type->tp_alloc(base_type, 0); - else self = PyObject_NEW(VectorObject, &vector_Type); - - if(size > 4 || size < 2) - return NULL; - self->size = size; - - /* init callbacks as NULL */ - self->cb_user= NULL; - self->cb_type= self->cb_subtype= 0; - - if(type == Py_WRAP) { - self->vec = vec; - self->wrapped = Py_WRAP; - } else if (type == Py_NEW) { - self->vec = PyMem_Malloc(size * sizeof(float)); - if(!vec) { /*new empty*/ - for(i = 0; i < size; i++){ - self->vec[i] = 0.0f; - } - if(size == 4) /* do the homogenous thing */ - self->vec[3] = 1.0f; - }else{ - for(i = 0; i < size; i++){ - self->vec[i] = vec[i]; - } - } - self->wrapped = Py_NEW; - }else{ /*bad type*/ - return NULL; - } - return (PyObject *) self; -} - -PyObject *newVectorObject_cb(PyObject *cb_user, int size, int cb_type, int cb_subtype) -{ - float dummy[4] = {0.0, 0.0, 0.0, 0.0}; /* dummy init vector, callbacks will be used on access */ - VectorObject *self= (VectorObject *)newVectorObject(dummy, size, Py_NEW, NULL); - if(self) { - Py_INCREF(cb_user); - self->cb_user= cb_user; - self->cb_type= (unsigned char)cb_type; - self->cb_subtype= (unsigned char)cb_subtype; - } - - return (PyObject *)self; -} - -//-----------------row_vector_multiplication (internal)----------- -//ROW VECTOR Multiplication - Vector X Matrix -//[x][y][z] * [1][2][3] -// [4][5][6] -// [7][8][9] -//vector/matrix multiplication IS NOT COMMUTATIVE!!!! -static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat) -{ - float vecNew[4], vecCopy[4]; - double dot = 0.0f; - int x, y, z = 0, vec_size = vec->size; - - if(mat->colSize != vec_size){ - if(mat->rowSize == 4 && vec_size != 3){ - PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same"); - return NULL; - }else{ - vecCopy[3] = 1.0f; - } - } - - if(!BaseMath_ReadCallback(vec) || !BaseMath_ReadCallback(mat)) - return NULL; - - for(x = 0; x < vec_size; x++){ - vecCopy[x] = vec->vec[x]; - } - - //muliplication - for(x = 0; x < mat->colSize; x++) { - for(y = 0; y < mat->rowSize; y++) { - dot += mat->matrix[y][x] * vecCopy[y]; - } - vecNew[z++] = (float)dot; - dot = 0.0f; - } - return newVectorObject(vecNew, vec_size, Py_NEW, NULL); -} - -/*----------------------------Vector.negate() -------------------- - set the vector to it's negative -x, -y, -z */ -static PyObject *Vector_Negate(VectorObject * self) -{ - int i; - if(!BaseMath_ReadCallback(self)) - return NULL; - - for(i = 0; i < self->size; i++) - self->vec[i] = -(self->vec[i]); - - BaseMath_WriteCallback(self); // alredy checked for error - - Py_INCREF(self); - return (PyObject*)self; -} diff --git a/source/blender/python/generic/vector.h b/source/blender/python/generic/vector.h deleted file mode 100644 index f6babac7ed9..00000000000 --- a/source/blender/python/generic/vector.h +++ /dev/null @@ -1,55 +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): Willian P. Germano & Joseph Gilbert - * - * ***** END GPL LICENSE BLOCK ***** - * - */ - -#ifndef EXPP_vector_h -#define EXPP_vector_h - -#include <Python.h> -#include "../intern/bpy_compat.h" - -extern PyTypeObject vector_Type; -#define VectorObject_Check(_v) PyObject_TypeCheck((_v), &vector_Type) - -typedef struct { /* keep aligned with BaseMathObject in Mathutils.h */ - PyObject_VAR_HEAD - float *vec; /*1D array of data (alias), wrapped status depends on wrapped status */ - PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */ - unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ - unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */ - unsigned char wrapped; /* wrapped data type? */ - /* end BaseMathObject */ - - unsigned char size; /* vec size 2,3 or 4 */ -} VectorObject; - -/*prototypes*/ -PyObject *newVectorObject(float *vec, int size, int type, PyTypeObject *base_type); -PyObject *newVectorObject_cb(PyObject *user, int size, int callback_type, int subtype); - -#endif /* EXPP_vector_h */ diff --git a/source/blender/python/intern/Makefile b/source/blender/python/intern/Makefile index d210cfaf973..3e28f5aac31 100644 --- a/source/blender/python/intern/Makefile +++ b/source/blender/python/intern/Makefile @@ -1,5 +1,5 @@ # -# $Id$ +# $Id: Makefile 11904 2007-08-31 16:16:33Z sirdude $ # # ***** BEGIN GPL LICENSE BLOCK ***** # @@ -37,7 +37,6 @@ CFLAGS += $(LEVEL_1_C_WARNINGS) # OpenGL and Python CPPFLAGS += $(OGL_CPPFLAGS) -CPPFLAGS += -I$(NAN_GLEW)/include CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) # PreProcessor stuff diff --git a/source/blender/python/intern/bpy_compat.h b/source/blender/python/intern/bpy_compat.h index e999f57c733..ad6b7a5e85c 100644 --- a/source/blender/python/intern/bpy_compat.h +++ b/source/blender/python/intern/bpy_compat.h @@ -85,34 +85,8 @@ typedef Py_ssize_t (*lenfunc)(PyObject *); #ifndef Py_RETURN_TRUE #define Py_RETURN_TRUE return PyBool_FromLong(1) #endif - -#define PyInt_FromSsize_t PyInt_FromLong -#define PyNumber_AsSsize_t(ob, exc) PyInt_AsLong(ob) -#define PyIndex_Check(ob) PyInt_Check(ob) - - -#endif - - -#if PY_VERSION_HEX < 0x03000000 -#ifndef ssizeargfunc -#define ssizeargfunc intargfunc #endif -#ifndef ssizessizeargfunc -#define ssizessizeargfunc intintargfunc -#endif - -#ifndef ssizeobjargproc -#define ssizeobjargproc intobjargproc -#endif - -#ifndef ssizessizeobjargproc -#define ssizessizeobjargproc intintobjargproc -#endif -#endif - - /* defined in bpy_util.c */ #if PY_VERSION_HEX < 0x03000000 diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index a07c447c718..7b3a67ebff5 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -36,14 +36,6 @@ #include "BPY_extern.h" -#include "../generic/bpy_internal_import.h" // our own imports -/* external util modules */ - -#include "../generic/Mathutils.h" -#include "../generic/Geometry.h" -#include "../generic/BGL.h" - - void BPY_free_compiled_text( struct Text *text ) { if( text->compiled ) { @@ -64,19 +56,12 @@ static void bpy_init_modules( void ) PyModule_AddObject( mod, "data", BPY_rna_module() ); /* PyModule_AddObject( mod, "doc", BPY_rna_doc() ); */ PyModule_AddObject( mod, "types", BPY_rna_types() ); - PyModule_AddObject( mod, "props", BPY_rna_props() ); PyModule_AddObject( mod, "ops", BPY_operator_module() ); - PyModule_AddObject( mod, "ui", BPY_ui_module() ); // XXX very experimental, consider this a test, especially PyCObject is not meant to be permanent + PyModule_AddObject( mod, "ui", BPY_ui_module() ); // XXX very experemental, consider this a test, especially PyCObject is not meant to be perminant /* add the module so we can import it */ PyDict_SetItemString(PySys_GetObject("modules"), "bpy", mod); Py_DECREF(mod); - - - /* stand alone utility modules not related to blender directly */ - Geometry_Init("Geometry"); - Mathutils_Init("Mathutils"); - BGL_Init("BGL"); } #if (PY_VERSION_HEX < 0x02050000) @@ -115,7 +100,6 @@ static PyObject *CreateGlobalDictionary( bContext *C ) {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""}, {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""}, {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""}, {NULL, NULL, 0, NULL} }; @@ -132,81 +116,13 @@ static PyObject *CreateGlobalDictionary( bContext *C ) return dict; } -/* Use this so we can include our own python bundle */ -#if 0 -wchar_t* Py_GetPath(void) -{ - int i; - static wchar_t py_path[FILE_MAXDIR] = L""; - char *dirname= BLI_gethome_folder("python"); - if(dirname) { - i= mbstowcs(py_path, dirname, FILE_MAXDIR); - printf("py path %s, %d\n", dirname, i); - } - return py_path; -} -#endif - - -/* must be called before Py_Initialize */ -void BPY_start_python_path(void) -{ - char *py_path_bundle= BLI_gethome_folder("python"); - - if(py_path_bundle==NULL) - return; - - /* set the environment path */ - printf("found bundled python: %s\n", py_path_bundle); - -#if (defined(WIN32) || defined(WIN64)) -#if defined(FREE_WINDOWS) - { - char py_path[FILE_MAXDIR + 11] = ""; - sprintf(py_path, "PYTHONPATH=%s", py_path_bundle); - putenv(py_path); - } -#else - _putenv_s("PYTHONPATH", py_path_bundle); -#endif -#else -#ifdef __sgi - { - char py_path[FILE_MAXDIR + 11] = ""; - sprintf(py_path, "PYTHONPATH=%s", py_path_bundle); - putenv(py_path); - } -#else - setenv("PYTHONPATH", py_path_bundle, 1); -#endif -#endif - -} - - void BPY_start_python( int argc, char **argv ) { PyThreadState *py_tstate = NULL; - BPY_start_python_path(); /* allow to use our own included python */ - Py_Initialize( ); -#if (PY_VERSION_HEX < 0x03000000) - PySys_SetArgv( argc, argv); -#else - /* sigh, why do python guys not have a char** version anymore? :( */ - { - int i; - PyObject *py_argv= PyList_New(argc); - - for (i=0; i<argc; i++) - PyList_SET_ITEM(py_argv, i, PyUnicode_FromString(argv[i])); - - PySys_SetObject("argv", py_argv); - Py_DECREF(py_argv); - } -#endif + //PySys_SetArgv( argc_copy, argv_copy ); /* Initialize thread support (also acquires lock) */ PyEval_InitThreads(); @@ -215,17 +131,10 @@ void BPY_start_python( int argc, char **argv ) /* bpy.* and lets us import it */ bpy_init_modules(); - { /* our own import and reload functions */ - PyObject *item; - //PyObject *m = PyImport_AddModule("__builtin__"); - //PyObject *d = PyModule_GetDict(m); - PyObject *d = PyEval_GetBuiltins( ); - PyDict_SetItemString(d, "reload", item=PyCFunction_New(bpy_reload_meth, NULL)); Py_DECREF(item); - PyDict_SetItemString(d, "__import__", item=PyCFunction_New(bpy_import_meth, NULL)); Py_DECREF(item); - } py_tstate = PyGILState_GetThisThreadState(); PyEval_ReleaseThread(py_tstate); + } void BPY_end_python( void ) @@ -241,7 +150,7 @@ void BPY_end_python( void ) } /* Can run a file or text block */ -int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struct ReportList *reports) +int BPY_run_python_script( bContext *C, const char *fn, struct Text *text ) { PyObject *py_dict, *py_result; PyGILState_STATE gilstate; @@ -255,7 +164,6 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc gilstate = PyGILState_Ensure(); BPY_update_modules(); /* can give really bad results if this isnt here */ - bpy_import_main_set(CTX_data_main(C)); py_dict = CreateGlobalDictionary(C); @@ -270,7 +178,7 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc MEM_freeN( buf ); if( PyErr_Occurred( ) ) { - BPy_errors_to_report(reports); + PyErr_Print(); PyErr_Clear(); BPY_free_compiled_text( text ); PyGILState_Release(gilstate); return 0; @@ -286,14 +194,13 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc } if (!py_result) { - BPy_errors_to_report(reports); + PyErr_Print(); PyErr_Clear(); } else { Py_DECREF( py_result ); } Py_DECREF(py_dict); PyGILState_Release(gilstate); - bpy_import_main_set(NULL); //BPY_end_python(); return py_result ? 1:0; @@ -314,7 +221,7 @@ static void exit_pydraw( SpaceScript * sc, short err ) script = sc->script; if( err ) { - BPy_errors_to_report(NULL); // TODO, reports + PyErr_Print(); PyErr_Clear(); script->flags = 0; /* mark script struct for deletion */ SCRIPT_SET_NULL(script); script->scriptname[0] = '\0'; @@ -343,7 +250,7 @@ static int bpy_run_script_init(bContext *C, SpaceScript * sc) return 0; if (sc->script->py_draw==NULL && sc->script->scriptname[0] != '\0') - BPY_run_python_script(C, sc->script->scriptname, NULL, NULL); + BPY_run_python_script(C, sc->script->scriptname, NULL); if (sc->script->py_draw==NULL) return 0; @@ -351,9 +258,9 @@ static int bpy_run_script_init(bContext *C, SpaceScript * sc) return 1; } -int BPY_run_script_space_draw(const struct bContext *C, SpaceScript * sc) +int BPY_run_script_space_draw(struct bContext *C, SpaceScript * sc) { - if (bpy_run_script_init( (bContext *)C, sc)) { + if (bpy_run_script_init(C, sc)) { PyGILState_STATE gilstate = PyGILState_Ensure(); PyObject *result = PyObject_CallObject( sc->script->py_draw, NULL ); @@ -422,7 +329,7 @@ int BPY_run_python_script_space(const char *modulename, const char *func) } if (!py_result) { - BPy_errors_to_report(NULL); // TODO - reports + PyErr_Print(); PyErr_Clear(); } else Py_DECREF( py_result ); @@ -450,72 +357,69 @@ void BPY_run_ui_scripts(bContext *C, int reload) DIR *dir; struct dirent *de; char *file_extension; - char *dirname; char path[FILE_MAX]; - char *dirs[] = {"io", "ui", NULL}; - int a; + char *dirname= BLI_gethome_folder("ui"); + int filelen; /* filename length */ PyGILState_STATE gilstate; PyObject *mod; - PyObject *sys_path; + PyObject *sys_path_orig; + PyObject *sys_path_new; + + if(!dirname) + return; + + dir = opendir(dirname); + if(!dir) + return; + gilstate = PyGILState_Ensure(); + /* backup sys.path */ + sys_path_orig= PySys_GetObject("path"); + Py_INCREF(sys_path_orig); /* dont free it */ + + sys_path_new= PyList_New(1); + PyList_SET_ITEM(sys_path_new, 0, PyUnicode_FromString(dirname)); + PySys_SetObject("path", sys_path_new); + Py_DECREF(sys_path_new); + // XXX - evil, need to access context BPy_SetContext(C); - bpy_import_main_set(CTX_data_main(C)); - - - sys_path= PySys_GetObject("path"); /* borrow */ - PyList_Insert(sys_path, 0, Py_None); /* place holder, resizes the list */ - - for(a=0; dirs[a]; a++) { - dirname= BLI_gethome_folder(dirs[a]); - - if(!dirname) - continue; - - dir = opendir(dirname); - - if(!dir) - continue; + + while((de = readdir(dir)) != NULL) { + /* We could stat the file but easier just to let python + * import it and complain if theres a problem */ - /* set the first dir in the sys.path for fast importing of modules */ - PyList_SetItem(sys_path, 0, PyUnicode_FromString(dirname)); /* steals the ref */ - - while((de = readdir(dir)) != NULL) { - /* We could stat the file but easier just to let python - * import it and complain if theres a problem */ - - file_extension = strstr(de->d_name, ".py"); + file_extension = strstr(de->d_name, ".py"); + + if(file_extension && *(file_extension + 3) == '\0') { + filelen = strlen(de->d_name); + BLI_strncpy(path, de->d_name, filelen-2); /* cut off the .py on copy */ - if(file_extension && file_extension[3] == '\0') { - BLI_strncpy(path, de->d_name, (file_extension - de->d_name) + 1); /* cut off the .py on copy */ - mod= PyImport_ImportModuleLevel(path, NULL, NULL, NULL, 0); - if (mod) { - if (reload) { - PyObject *mod_orig= mod; - mod= PyImport_ReloadModule(mod); - Py_DECREF(mod_orig); - } - } - - if(mod) { - Py_DECREF(mod); /* could be NULL from reloading */ - } else { - BPy_errors_to_report(NULL); - fprintf(stderr, "unable to import \"%s\" %s/%s\n", path, dirname, de->d_name); + mod= PyImport_ImportModuleLevel(path, NULL, NULL, NULL, 0); + if (mod) { + if (reload) { + PyObject *mod_orig= mod; + mod= PyImport_ReloadModule(mod); + Py_DECREF(mod_orig); } - + } + + if(mod) { + Py_DECREF(mod); /* could be NULL from reloading */ + } else { + PyErr_Print(); PyErr_Clear(); + fprintf(stderr, "unable to import \"%s\" %s/%s\n", path, dirname, de->d_name); } } - - closedir(dir); } - - PyList_SetSlice(sys_path, 0, 1, NULL); /* remove the first item */ - bpy_import_main_set(NULL); + closedir(dir); + + PySys_SetObject("path", sys_path_orig); + Py_DECREF(sys_path_orig); PyGILState_Release(gilstate); #ifdef TIME_REGISTRATION @@ -626,7 +530,7 @@ static float pydriver_error(ChannelDriver *driver) driver->flag |= DRIVER_FLAG_INVALID; /* py expression failed */ fprintf(stderr, "\nError in Driver: The following Python expression failed:\n\t'%s'\n\n", driver->expression); - BPy_errors_to_report(NULL); // TODO - reports + PyErr_Print(); PyErr_Clear(); return 0.0f; } @@ -685,7 +589,7 @@ float BPY_pydriver_eval (ChannelDriver *driver) } fprintf(stderr, "\tBPY_pydriver_eval() - couldn't add variable '%s' to namespace \n", dtar->name); - BPy_errors_to_report(NULL); // TODO - reports + PyErr_Print(); PyErr_Clear(); } } diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index b57ef54304b..004cf2fb7c7 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -68,7 +68,7 @@ static PyObject *pyop_base_call( PyObject * self, PyObject * args, PyObject * k return NULL; } - ot= WM_operatortype_find(opname, 1); + ot= WM_operatortype_find(opname); if (ot == NULL) { PyErr_Format( PyExc_SystemError, "Operator \"%s\"could not be found", opname); return NULL; @@ -130,18 +130,11 @@ static PyObject *pyop_base_getattro( BPy_OperatorBase * self, PyObject *pyname ) PyObject *ret; wmOperatorType *ot; - /* First look for the operator, then our own methods if that fails. - * when methods are searched first, PyObject_GenericGetAttr will raise an error - * each time we want to call an operator, we could clear the error but I prefer - * not to since calling operators is a lot more common then adding and removing. - Campbell */ - - if ((ot= WM_operatortype_find(name, 1))) { + if ((ot= WM_operatortype_find(name))) { ret = PyCFunction_New( pyop_base_call_meth, pyname); /* set the name string as self, PyCFunction_New incref's self */ } else if ((ret = PyObject_GenericGetAttr((PyObject *)self, pyname))) { - /* do nothing, this accounts for methoddef's add and remove - * An exception is raised when PyObject_GenericGetAttr fails - * but its ok because its overwritten below */ + /* do nothing, this accounts for methoddef's add and remove */ } else { PyErr_Format( PyExc_AttributeError, "Operator \"%s\" not found", name); @@ -177,7 +170,7 @@ static PyObject *pyop_base_rna(PyObject *self, PyObject *pyname) char *name = _PyUnicode_AsString(pyname); wmOperatorType *ot; - if ((ot= WM_operatortype_find(name, 1))) { + if ((ot= WM_operatortype_find(name))) { BPy_StructRNA *pyrna; PointerRNA ptr; diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index f8567414717..6ab990acdf5 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -40,13 +40,116 @@ #include "bpy_compat.h" #include "bpy_util.h" -#include "../generic/bpy_internal_import.h" // our own imports - #define PYOP_ATTR_PROP "__props__" #define PYOP_ATTR_UINAME "__label__" #define PYOP_ATTR_IDNAME "__name__" /* use pythons class name */ #define PYOP_ATTR_DESCRIPTION "__doc__" /* use pythons docstring */ +static PyObject *pyop_dict_from_event(wmEvent *event) +{ + PyObject *dict= PyDict_New(); + PyObject *item; + char *cstring, ascii[2]; + + /* type */ + item= PyUnicode_FromString(WM_key_event_string(event->type)); + PyDict_SetItemString(dict, "type", item); Py_DECREF(item); + + /* val */ + switch(event->val) { + case KM_ANY: + cstring = "ANY"; + break; + case KM_RELEASE: + cstring = "RELEASE"; + break; + case KM_PRESS: + cstring = "PRESS"; + break; + default: + cstring = "UNKNOWN"; + break; + } + + item= PyUnicode_FromString(cstring); + PyDict_SetItemString(dict, "val", item); Py_DECREF(item); + + /* x, y (mouse) */ + item= PyLong_FromLong(event->x); + PyDict_SetItemString(dict, "x", item); Py_DECREF(item); + + item= PyLong_FromLong(event->y); + PyDict_SetItemString(dict, "y", item); Py_DECREF(item); + + item= PyLong_FromLong(event->prevx); + PyDict_SetItemString(dict, "prevx", item); Py_DECREF(item); + + item= PyLong_FromLong(event->prevy); + PyDict_SetItemString(dict, "prevy", item); Py_DECREF(item); + + /* ascii */ + ascii[0]= event->ascii; + ascii[1]= '\0'; + item= PyUnicode_FromString(ascii); + PyDict_SetItemString(dict, "ascii", item); Py_DECREF(item); + + /* modifier keys */ + item= PyLong_FromLong(event->shift); + PyDict_SetItemString(dict, "shift", item); Py_DECREF(item); + + item= PyLong_FromLong(event->ctrl); + PyDict_SetItemString(dict, "ctrl", item); Py_DECREF(item); + + item= PyLong_FromLong(event->alt); + PyDict_SetItemString(dict, "alt", item); Py_DECREF(item); + + item= PyLong_FromLong(event->oskey); + PyDict_SetItemString(dict, "oskey", item); Py_DECREF(item); + + + + /* modifier */ +#if 0 + item= PyTuple_New(0); + if(event->keymodifier & KM_SHIFT) { + _PyTuple_Resize(&item, size+1); + PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("SHIFT")); + size++; + } + if(event->keymodifier & KM_CTRL) { + _PyTuple_Resize(&item, size+1); + PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("CTRL")); + size++; + } + if(event->keymodifier & KM_ALT) { + _PyTuple_Resize(&item, size+1); + PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("ALT")); + size++; + } + if(event->keymodifier & KM_OSKEY) { + _PyTuple_Resize(&item, size+1); + PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("OSKEY")); + size++; + } + PyDict_SetItemString(dict, "keymodifier", item); Py_DECREF(item); +#endif + + return dict; +} + +/* TODO - a whole traceback would be ideal */ +static void pyop_error_report(ReportList *reports) +{ + PyObject *exception, *v, *tb; + PyErr_Fetch(&exception, &v, &tb); + if (exception == NULL) + return; + /* Now we know v != NULL too */ + BKE_report(reports, RPT_ERROR, _PyUnicode_AsString(v)); + + PyErr_Print(); +} + static struct BPY_flag_def pyop_ret_flags[] = { {"RUNNING_MODAL", OPERATOR_RUNNING_MODAL}, {"CANCELLED", OPERATOR_CANCELLED}, @@ -87,13 +190,9 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PyObject *ret= NULL, *py_class_instance, *item= NULL; int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED); PointerRNA ptr_context; - PointerRNA ptr_operator; - PointerRNA ptr_event; - PyObject *py_operator; + PyObject *py_context; PyGILState_STATE gilstate = PyGILState_Ensure(); - - bpy_import_main_set(CTX_data_main(C)); BPY_update_modules(); // XXX - the RNA pointers can change so update before running, would like a nicer solutuon for this. @@ -107,9 +206,15 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve /* Assign instance attributes from operator properties */ { + PropertyRNA *prop, *iterprop; + CollectionPropertyIterator iter; const char *arg_name; - RNA_STRUCT_BEGIN(op->ptr, prop) { + iterprop= RNA_struct_iterator_property(op->ptr->type); + RNA_property_collection_begin(op->ptr, iterprop, &iter); + + for(; iter.valid; RNA_property_collection_next(&iter)) { + prop= iter.ptr.data; arg_name= RNA_property_identifier(prop); if (strcmp(arg_name, "rna_type")==0) continue; @@ -118,33 +223,23 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PyObject_SetAttrString(py_class_instance, arg_name, item); Py_DECREF(item); } - RNA_STRUCT_END; - } - - /* set operator pointer RNA as instance "__operator__" attribute */ - RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator); - py_operator= pyrna_struct_CreatePyObject(&ptr_operator); - PyObject_SetAttrString(py_class_instance, "__operator__", py_operator); - Py_DECREF(py_operator); - RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context); + RNA_property_collection_end(&iter); + } + if (mode==PYOP_INVOKE) { item= PyObject_GetAttrString(py_class, "invoke"); - args = PyTuple_New(3); - - RNA_pointer_create(NULL, &RNA_Event, event, &ptr_event); - - // PyTuple_SET_ITEM "steals" object reference, it is - // an object passed shouldn't be DECREF'ed - PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context)); - PyTuple_SET_ITEM(args, 2, pyrna_struct_CreatePyObject(&ptr_event)); + args = PyTuple_New(2); + PyTuple_SET_ITEM(args, 1, pyop_dict_from_event(event)); } else if (mode==PYOP_EXEC) { - item= PyObject_GetAttrString(py_class, "execute"); + item= PyObject_GetAttrString(py_class, "exec"); args = PyTuple_New(2); - PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context)); + RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context); + py_context = pyrna_struct_CreatePyObject(&ptr_context); + PyTuple_SET_ITEM(args, 1, py_context); } else if (mode==PYOP_POLL) { item= PyObject_GetAttrString(py_class, "poll"); @@ -161,13 +256,13 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve } if (ret == NULL) { /* covers py_class_instance failing too */ - BPy_errors_to_report(op->reports); + pyop_error_report(op->reports); } else { if (mode==PYOP_POLL) { if (PyBool_Check(ret) == 0) { PyErr_SetString(PyExc_ValueError, "Python poll function return value "); - BPy_errors_to_report(op->reports); + pyop_error_report(op->reports); } else { ret_flag= ret==Py_True ? 1:0; @@ -175,9 +270,8 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve } else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) { /* the returned value could not be converted into a flag */ - BPy_errors_to_report(op->reports); - - ret_flag = OPERATOR_CANCELLED; + pyop_error_report(op->reports); + } /* there is no need to copy the py keyword dict modified by * pyot->py_invoke(), back to the operator props since they are just @@ -190,34 +284,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve Py_DECREF(ret); } - /* print operator return value */ - if (mode != PYOP_POLL) { - char flag_str[100]; - char class_name[100]; - BPY_flag_def *flag_def = pyop_ret_flags; - - strcpy(flag_str, ""); - - while(flag_def->name) { - if (ret_flag & flag_def->flag) { - if(flag_str[1]) - sprintf(flag_str, "%s | %s", flag_str, flag_def->name); - else - strcpy(flag_str, flag_def->name); - } - flag_def++; - } - - /* get class name */ - item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME); - Py_DECREF(item); - strcpy(class_name, _PyUnicode_AsString(item)); - - fprintf(stderr, "%s's %s returned %s\n", class_name, mode == PYOP_EXEC ? "execute" : "invoke", flag_str); - } - PyGILState_Release(gilstate); - bpy_import_main_set(NULL); return ret_flag; } @@ -267,7 +334,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) /* api callbacks, detailed checks dont on adding */ if (PyObject_HasAttrString(py_class, "invoke")) ot->invoke= PYTHON_OT_invoke; - if (PyObject_HasAttrString(py_class, "execute")) + if (PyObject_HasAttrString(py_class, "exec")) ot->exec= PYTHON_OT_exec; if (PyObject_HasAttrString(py_class, "poll")) ot->poll= PYTHON_OT_poll; @@ -320,7 +387,6 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class) { PyObject *base_class, *item; - wmOperatorType *ot; char *idname= NULL; @@ -331,8 +397,8 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class) {PYOP_ATTR_UINAME, 's', 0, BPY_CLASS_ATTR_OPTIONAL}, {PYOP_ATTR_PROP, 'l', 0, BPY_CLASS_ATTR_OPTIONAL}, {PYOP_ATTR_DESCRIPTION, 's', 0, BPY_CLASS_ATTR_NONE_OK}, - {"execute", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, - {"invoke", 'f', 3, BPY_CLASS_ATTR_OPTIONAL}, + {"exec", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, + {"invoke", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {"poll", 'f', 2, BPY_CLASS_ATTR_OPTIONAL}, {NULL, 0, 0, 0} }; @@ -351,12 +417,9 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class) Py_DECREF(item); idname = _PyUnicode_AsString(item); - /* remove if it already exists */ - if ((ot=WM_operatortype_exists(idname))) { - if(ot->pyop_data) { - Py_XDECREF((PyObject*)ot->pyop_data); - } - WM_operatortype_remove(idname); + if (WM_operatortype_find(idname)) { + PyErr_Format( PyExc_AttributeError, "Operator alredy exists with this name \"%s\"", idname); + return NULL; } /* If we have properties set, check its a list of dicts */ @@ -403,7 +466,7 @@ PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value) return NULL; } - if (!(ot= WM_operatortype_exists(idname))) { + if (!(ot= WM_operatortype_find(idname))) { PyErr_Format( PyExc_AttributeError, "Operator \"%s\" does not exists, cant remove", idname); return NULL; } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 9ce9ec8e838..9fa7d1b6693 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -35,102 +35,16 @@ #include "RNA_define.h" /* for defining our own rna */ #include "MEM_guardedalloc.h" -#include "BKE_utildefines.h" #include "BKE_context.h" #include "BKE_global.h" /* evil G.* */ #include "BKE_report.h" -/* only for keyframing */ -#include "DNA_scene_types.h" -#include "ED_keyframing.h" - -#define USE_MATHUTILS - -#ifdef USE_MATHUTILS -#include "../generic/Mathutils.h" /* so we can have mathutils callbacks */ - -/* bpyrna vector/euler/quat callbacks */ -static int mathutils_rna_array_cb_index= -1; /* index for our callbacks */ - -static int mathutils_rna_generic_check(BPy_PropertyRNA *self) -{ - return self->prop?1:0; -} - -static int mathutils_rna_vector_get(BPy_PropertyRNA *self, int subtype, float *vec_from) -{ - if(self->prop==NULL) - return 0; - - RNA_property_float_get_array(&self->ptr, self->prop, vec_from); - return 1; -} - -static int mathutils_rna_vector_set(BPy_PropertyRNA *self, int subtype, float *vec_to) -{ - if(self->prop==NULL) - return 0; - - RNA_property_float_set_array(&self->ptr, self->prop, vec_to); - return 1; -} - -static int mathutils_rna_vector_get_index(BPy_PropertyRNA *self, int subtype, float *vec_from, int index) -{ - if(self->prop==NULL) - return 0; - - vec_from[index]= RNA_property_float_get_index(&self->ptr, self->prop, index); - return 1; -} - -static int mathutils_rna_vector_set_index(BPy_PropertyRNA *self, int subtype, float *vec_to, int index) -{ - if(self->prop==NULL) - return 0; - - RNA_property_float_set_index(&self->ptr, self->prop, index, vec_to[index]); - return 1; -} - -Mathutils_Callback mathutils_rna_array_cb = { - (BaseMathCheckFunc) mathutils_rna_generic_check, - (BaseMathGetFunc) mathutils_rna_vector_get, - (BaseMathSetFunc) mathutils_rna_vector_set, - (BaseMathGetIndexFunc) mathutils_rna_vector_get_index, - (BaseMathSetIndexFunc) mathutils_rna_vector_set_index -}; - - -/* bpyrna matrix callbacks */ -static int mathutils_rna_matrix_cb_index= -1; /* index for our callbacks */ - -static int mathutils_rna_matrix_get(BPy_PropertyRNA *self, int subtype, float *mat_from) -{ - if(self->prop==NULL) - return 0; - - RNA_property_float_get_array(&self->ptr, self->prop, mat_from); - return 1; -} - -static int mathutils_rna_matrix_set(BPy_PropertyRNA *self, int subtype, float *mat_to) -{ - if(self->prop==NULL) - return 0; - - RNA_property_float_set_array(&self->ptr, self->prop, mat_to); - return 1; -} - -Mathutils_Callback mathutils_rna_matrix_cb = { - (BaseMathCheckFunc) mathutils_rna_generic_check, - (BaseMathGetFunc) mathutils_rna_matrix_get, - (BaseMathSetFunc) mathutils_rna_matrix_set, - (BaseMathGetIndexFunc) NULL, - (BaseMathSetIndexFunc) NULL -}; - +#if 0 +#define bpy_PyObject_New(type, typeobj) \ +( (type *) PyObject_Init( \ + (PyObject *) MEM_callocN( _PyObject_SIZE(typeobj), "python memory from bpy_rna.c" ), (typeobj)) ) +#else +#define bpy_PyObject_New(type, typeobj) PyObject_New(type, typeobj) #endif static int pyrna_struct_compare( BPy_StructRNA * a, BPy_StructRNA * b ) @@ -167,39 +81,39 @@ static PyObject *pyrna_prop_richcmp(BPy_PropertyRNA * a, BPy_PropertyRNA * b, in /*----------------------repr--------------------------------------------*/ static PyObject *pyrna_struct_repr( BPy_StructRNA * self ) { - PyObject *pyob; - char *name; + PropertyRNA *prop; + char str[512]; /* print name if available */ - name= RNA_struct_name_get_alloc(&self->ptr, NULL, 0); - if(name) { - pyob= PyUnicode_FromFormat( "[BPy_StructRNA \"%.200s\" -> \"%.200s\"]", RNA_struct_identifier(self->ptr.type), name); - MEM_freeN(name); - return pyob; + prop= RNA_struct_name_property(self->ptr.type); + if(prop) { + RNA_property_string_get(&self->ptr, prop, str); + return PyUnicode_FromFormat( "[BPy_StructRNA \"%s\" -> \"%s\"]", RNA_struct_identifier(self->ptr.type), str); } - return PyUnicode_FromFormat( "[BPy_StructRNA \"%.200s\"]", RNA_struct_identifier(self->ptr.type)); + return PyUnicode_FromFormat( "[BPy_StructRNA \"%s\"]", RNA_struct_identifier(self->ptr.type)); } static PyObject *pyrna_prop_repr( BPy_PropertyRNA * self ) { - PyObject *pyob; + PropertyRNA *prop; PointerRNA ptr; - char *name; + char str[512]; /* if a pointer, try to print name of pointer target too */ if(RNA_property_type(self->prop) == PROP_POINTER) { ptr= RNA_property_pointer_get(&self->ptr, self->prop); - name= RNA_struct_name_get_alloc(&ptr, NULL, 0); - if(name) { - pyob= PyUnicode_FromFormat( "[BPy_PropertyRNA \"%.200s\" -> \"%.200s\" -> \"%.200s\" ]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop), name); - MEM_freeN(name); - return pyob; + if(ptr.data) { + prop= RNA_struct_name_property(ptr.type); + if(prop) { + RNA_property_string_get(&ptr, prop, str); + return PyUnicode_FromFormat( "[BPy_PropertyRNA \"%s\" -> \"%s\" -> \"%s\" ]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop), str); + } } } - return PyUnicode_FromFormat( "[BPy_PropertyRNA \"%.200s\" -> \"%.200s\"]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop)); + return PyUnicode_FromFormat( "[BPy_PropertyRNA \"%s\" -> \"%s\"]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop)); } static long pyrna_struct_hash( BPy_StructRNA * self ) @@ -210,35 +124,24 @@ static long pyrna_struct_hash( BPy_StructRNA * self ) /* use our own dealloc so we can free a property if we use one */ static void pyrna_struct_dealloc( BPy_StructRNA * self ) { + /* Note!! for some weired reason calling PyObject_DEL() directly crashes blender! */ if (self->freeptr && self->ptr.data) { IDP_FreeProperty(self->ptr.data); MEM_freeN(self->ptr.data); self->ptr.data= NULL; } - /* Note, for subclassed PyObjects we cant just call PyObject_DEL() directly or it will crash */ Py_TYPE(self)->tp_free(self); return; } static char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop) { - EnumPropertyItem *item; - char *result; - int free= 0; - - RNA_property_enum_items(BPy_GetContext(), ptr, prop, &item, NULL, &free); - if(item) { - result= (char*)BPy_enum_as_string(item); - } - else { - result= ""; - } - - if(free) - MEM_freeN(item); + const EnumPropertyItem *item; + int totitem; - return result; + RNA_property_enum_items(ptr, prop, &item, &totitem); + return (char*)BPy_enum_as_string((EnumPropertyItem*)item); } PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) @@ -249,52 +152,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) if (len > 0) { /* resolve the array from a new pytype */ - PyObject *ret = pyrna_prop_CreatePyObject(ptr, prop); - -#ifdef USE_MATHUTILS - - /* return a mathutils vector where possible */ - if(RNA_property_type(prop)==PROP_FLOAT) { - switch(RNA_property_subtype(prop)) { - case PROP_VECTOR: - if(len>=2 && len <= 4) { - PyObject *vec_cb= newVectorObject_cb(ret, len, mathutils_rna_array_cb_index, 0); - Py_DECREF(ret); /* the vector owns now */ - ret= vec_cb; /* return the vector instead */ - } - break; - case PROP_MATRIX: - if(len==16) { - PyObject *mat_cb= newMatrixObject_cb(ret, 4,4, mathutils_rna_matrix_cb_index, 0); - Py_DECREF(ret); /* the matrix owns now */ - ret= mat_cb; /* return the matrix instead */ - } - else if (len==9) { - PyObject *mat_cb= newMatrixObject_cb(ret, 3,3, mathutils_rna_matrix_cb_index, 0); - Py_DECREF(ret); /* the matrix owns now */ - ret= mat_cb; /* return the matrix instead */ - } - break; - case PROP_ROTATION: - if(len==3) { /* euler */ - PyObject *eul_cb= newEulerObject_cb(ret, mathutils_rna_array_cb_index, 0); - Py_DECREF(ret); /* the matrix owns now */ - ret= eul_cb; /* return the matrix instead */ - } - else if (len==4) { - PyObject *quat_cb= newQuaternionObject_cb(ret, mathutils_rna_array_cb_index, 0); - Py_DECREF(ret); /* the matrix owns now */ - ret= quat_cb; /* return the matrix instead */ - } - break; - default: - break; - } - } - -#endif - - return ret; + return pyrna_prop_CreatePyObject(ptr, prop); } /* see if we can coorce into a python type - PropertyType */ @@ -321,32 +179,11 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) const char *identifier; int val = RNA_property_enum_get(ptr, prop); - if (RNA_property_enum_identifier(BPy_GetContext(), ptr, prop, val, &identifier)) { + if (RNA_property_enum_identifier(ptr, prop, val, &identifier)) { ret = PyUnicode_FromString( identifier ); } else { - EnumPropertyItem *item; - int free= 0; - - /* don't throw error here, can't trust blender 100% to give the - * right values, python code should not generate error for that */ - RNA_property_enum_items(BPy_GetContext(), ptr, prop, &item, NULL, &free); - if(item && item->identifier) { - ret = PyUnicode_FromString( item->identifier ); - } - else { - /* prefer not fail silently incase of api errors, maybe disable it later */ - char error_str[128]; - sprintf(error_str, "RNA Warning: Current value \"%d\" matches no enum", val); - PyErr_Warn(PyExc_RuntimeWarning, error_str); - - ret = PyUnicode_FromString( "" ); - } - - if(free) - MEM_freeN(item); - - /*PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val); - ret = NULL;*/ + PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val); + ret = NULL; } break; @@ -384,15 +221,23 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi const char *arg_name= NULL; PyObject *item; + PropertyRNA *prop, *iterprop; + CollectionPropertyIterator iter; + + iterprop= RNA_struct_iterator_property(ptr->type); + RNA_property_collection_begin(ptr, iterprop, &iter); + totkw = kw ? PyDict_Size(kw):0; - RNA_STRUCT_BEGIN(ptr, prop) { + for(; iter.valid; RNA_property_collection_next(&iter)) { + prop= iter.ptr.data; + arg_name= RNA_property_identifier(prop); if (strcmp(arg_name, "rna_type")==0) continue; if (kw==NULL) { - PyErr_Format( PyExc_AttributeError, "%.200s: no keywords, expected \"%.200s\"", error_prefix, arg_name ? arg_name : "<UNKNOWN>"); + PyErr_Format( PyExc_AttributeError, "%s: no keywords, expected \"%s\"", error_prefix, arg_name ? arg_name : "<UNKNOWN>"); error_val= -1; break; } @@ -400,7 +245,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi item= PyDict_GetItemString(kw, arg_name); if (item == NULL) { - PyErr_Format( PyExc_AttributeError, "%.200s: keyword \"%.200s\" missing", error_prefix, arg_name ? arg_name : "<UNKNOWN>"); + PyErr_Format( PyExc_AttributeError, "%s: keyword \"%s\" missing", error_prefix, arg_name ? arg_name : "<UNKNOWN>"); error_val = -1; /* pyrna_py_to_prop sets the error */ break; } @@ -412,7 +257,8 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi totkw--; } - RNA_STRUCT_END; + + RNA_property_collection_end(&iter); if (error_val==0 && totkw > 0) { /* some keywords were given that were not used :/ */ PyObject *key, *value; @@ -424,7 +270,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi arg_name= NULL; } - PyErr_Format( PyExc_AttributeError, "%.200s: keyword \"%.200s\" unrecognized", error_prefix, arg_name ? arg_name : "<UNKNOWN>"); + PyErr_Format( PyExc_AttributeError, "%s: keyword \"%s\" unrecognized", error_prefix, arg_name ? arg_name : "<UNKNOWN>"); error_val = -1; } @@ -433,15 +279,12 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw); -PyObject *pyrna_func_to_py(BPy_StructRNA *pyrna, FunctionRNA *func) +PyObject *pyrna_func_to_py(PointerRNA *ptr, FunctionRNA *func) { static PyMethodDef func_meth = {"<generic rna function>", (PyCFunction)pyrna_func_call, METH_VARARGS|METH_KEYWORDS, "python rna function"}; PyObject *self= PyTuple_New(2); PyObject *ret; - - PyTuple_SET_ITEM(self, 0, (PyObject *)pyrna); - Py_INCREF(pyrna); - + PyTuple_SET_ITEM(self, 0, pyrna_struct_CreatePyObject(ptr)); PyTuple_SET_ITEM(self, 1, PyCObject_FromVoidPtr((void *)func, NULL)); ret= PyCFunction_New(&func_meth, self); @@ -459,30 +302,15 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v if (len > 0) { PyObject *item; - int py_len = -1; int i; - -#ifdef USE_MATHUTILS - if(MatrixObject_Check(value)) { - MatrixObject *mat = (MatrixObject*)value; - if(!BaseMath_ReadCallback(mat)) - return -1; - - py_len = mat->rowSize * mat->colSize; - } else /* continue... */ -#endif - if (PySequence_Check(value)) { - py_len= (int)PySequence_Length(value); - } - else { - PyErr_Format(PyExc_TypeError, "RNA array assignment expected a sequence instead of %.200s instance.", Py_TYPE(value)->tp_name); + if (!PySequence_Check(value)) { + PyErr_SetString(PyExc_TypeError, "expected a python sequence type assigned to an RNA array."); return -1; } - /* done getting the length */ - if (py_len != len) { - PyErr_Format(PyExc_AttributeError, "python sequence length %d did not match the RNA array length %d.", py_len, len); + if ((int)PySequence_Length(value) != len) { + PyErr_SetString(PyExc_AttributeError, "python sequence length did not match the RNA array."); return -1; } @@ -548,21 +376,14 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v else param_arr = MEM_mallocN(sizeof(float) * len, "pyrna float array"); -#ifdef USE_MATHUTILS - if(MatrixObject_Check(value) && RNA_property_subtype(prop) == PROP_MATRIX) { - MatrixObject *mat = (MatrixObject*)value; - memcpy(param_arr, mat->contigPtr, sizeof(float) * len); - } else /* continue... */ -#endif - { - /* collect the variables */ - for (i=0; i<len; i++) { - item = PySequence_GetItem(value, i); - param_arr[i] = (float)PyFloat_AsDouble(item); /* deal with any errors later */ - Py_DECREF(item); - } + + /* collect the variables */ + for (i=0; i<len; i++) { + item = PySequence_GetItem(value, i); + param_arr[i] = (float)PyFloat_AsDouble(item); /* deal with any errors later */ + Py_DECREF(item); } - + if (PyErr_Occurred()) { if(data==NULL) MEM_freeN(param_arr); @@ -637,17 +458,17 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v if (param==NULL) { char *enum_str= pyrna_enum_as_string(ptr, prop); - PyErr_Format(PyExc_TypeError, "expected a string enum type in (%.200s)", enum_str); + PyErr_Format(PyExc_TypeError, "expected a string enum type in (%s)", enum_str); MEM_freeN(enum_str); return -1; } else { int val; - if (RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, &val)) { + if (RNA_property_enum_value(ptr, prop, param, &val)) { if(data) *((int*)data)= val; else RNA_property_enum_set(ptr, prop, val); } else { char *enum_str= pyrna_enum_as_string(ptr, prop); - PyErr_Format(PyExc_AttributeError, "enum \"%.200s\" not found in (%.200s)", param, enum_str); + PyErr_Format(PyExc_AttributeError, "enum \"%s\" not found in (%s)", param, enum_str); MEM_freeN(enum_str); return -1; } @@ -662,15 +483,13 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v if(!BPy_StructRNA_Check(value) && value != Py_None) { PointerRNA tmp; RNA_pointer_create(NULL, ptype, NULL, &tmp); - PyErr_Format(PyExc_TypeError, "expected a %.200s type", RNA_struct_identifier(tmp.type)); + PyErr_Format(PyExc_TypeError, "expected a %s type", RNA_struct_identifier(tmp.type)); return -1; } else { BPy_StructRNA *param= (BPy_StructRNA*)value; int raise_error= 0; if(data) { - int flag = RNA_property_flag(prop); - - if(flag & PROP_RNAPTR) { + if(ptype == &RNA_AnyType) { if(value == Py_None) memset(data, 0, sizeof(PointerRNA)); else @@ -699,7 +518,7 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v else { PointerRNA tmp; RNA_pointer_create(NULL, ptype, NULL, &tmp); - PyErr_Format(PyExc_TypeError, "expected a %.200s type", RNA_struct_identifier(tmp.type)); + PyErr_Format(PyExc_TypeError, "expected a %s type", RNA_struct_identifier(tmp.type)); return -1; } } @@ -707,7 +526,7 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v if(raise_error) { PointerRNA tmp; RNA_pointer_create(NULL, ptype, NULL, &tmp); - PyErr_Format(PyExc_TypeError, "expected a %.200s type", RNA_struct_identifier(tmp.type)); + PyErr_Format(PyExc_TypeError, "expected a %s type", RNA_struct_identifier(tmp.type)); return -1; } } @@ -718,10 +537,6 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v int seq_len, i; PyObject *item; PointerRNA itemptr; - ListBase *lb; - CollectionPointerLink *link; - - lb= (data)? (ListBase*)data: NULL; /* convert a sequence of dict's into a collection */ if(!PySequence_Check(value)) { @@ -737,15 +552,8 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v Py_XDECREF(item); return -1; } - - if(lb) { - link= MEM_callocN(sizeof(CollectionPointerLink), "PyCollectionPointerLink"); - link->ptr= itemptr; - BLI_addtail(lb, link); - } - else - RNA_property_collection_add(ptr, prop, &itemptr); - + + RNA_property_collection_add(ptr, prop, &itemptr); if(pyrna_pydict_to_props(&itemptr, item, "Converting a python list to an RNA collection")==-1) { Py_DECREF(item); return -1; @@ -859,317 +667,117 @@ static Py_ssize_t pyrna_prop_len( BPy_PropertyRNA * self ) return len; } -/* internal use only */ -static PyObject *prop_subscript_collection_int(BPy_PropertyRNA * self, int keynum) -{ - PointerRNA newptr; - - if(keynum < 0) keynum += RNA_property_collection_length(&self->ptr, self->prop); - - if(RNA_property_collection_lookup_int(&self->ptr, self->prop, keynum, &newptr)) - return pyrna_struct_CreatePyObject(&newptr); - - PyErr_Format(PyExc_IndexError, "index %d out of range", keynum); - return NULL; -} -static PyObject *prop_subscript_array_int(BPy_PropertyRNA * self, int keynum) -{ - int len= RNA_property_array_length(self->prop); - - if(keynum < 0) keynum += len; - - if(keynum >= 0 && keynum < len) - return pyrna_prop_to_py_index(&self->ptr, self->prop, keynum); - - PyErr_Format(PyExc_IndexError, "index %d out of range", keynum); - return NULL; -} - -static PyObject *prop_subscript_collection_str(BPy_PropertyRNA * self, char *keyname) -{ - PointerRNA newptr; - if(RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr)) - return pyrna_struct_CreatePyObject(&newptr); - - PyErr_Format(PyExc_KeyError, "key \"%.200s\" not found", keyname); - return NULL; -} -/* static PyObject *prop_subscript_array_str(BPy_PropertyRNA * self, char *keyname) */ - - - - -#if PY_VERSION_HEX >= 0x03000000 -static PyObject *prop_subscript_collection_slice(BPy_PropertyRNA * self, int start, int stop) +static PyObject *pyrna_prop_subscript( BPy_PropertyRNA * self, PyObject *key ) { + PyObject *ret; PointerRNA newptr; - PyObject *list = PyList_New(stop - start); - int count; - - start = MIN2(start,stop); /* values are clamped from */ - - for(count = start; count < stop; count++) { - if(RNA_property_collection_lookup_int(&self->ptr, self->prop, count - start, &newptr)) { - PyList_SetItem(list, count - start, pyrna_struct_CreatePyObject(&newptr)); - } - else { - Py_DECREF(list); - - PyErr_SetString(PyExc_RuntimeError, "error getting an rna struct from a collection"); - return NULL; - } - } - - return list; -} -static PyObject *prop_subscript_array_slice(BPy_PropertyRNA * self, int start, int stop) -{ - PyObject *list = PyList_New(stop - start); - int count; - - start = MIN2(start,stop); /* values are clamped from PySlice_GetIndicesEx */ - - for(count = start; count < stop; count++) - PyList_SetItem(list, count - start, pyrna_prop_to_py_index(&self->ptr, self->prop, count)); - - return list; -} -#endif - -static PyObject *prop_subscript_collection(BPy_PropertyRNA * self, PyObject *key) -{ + int keynum = 0; + char *keyname = NULL; + if (PyUnicode_Check(key)) { - return prop_subscript_collection_str(self, _PyUnicode_AsString(key)); - } - else if (PyIndex_Check(key)) { - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - - return prop_subscript_collection_int(self, i); - } -#if PY_VERSION_HEX >= 0x03000000 - else if (PySlice_Check(key)) { - int len= RNA_property_collection_length(&self->ptr, self->prop); - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0) - return NULL; - - if (slicelength <= 0) { - return PyList_New(0); - } - else if (step == 1) { - return prop_subscript_collection_slice(self, start, stop); - } - else { - PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna"); - return NULL; - } - } -#endif - else { - PyErr_Format(PyExc_TypeError, "invalid rna key, key must be a string or an int instead of %.200s instance.", Py_TYPE(key)->tp_name); - return NULL; - } -} - -static PyObject *prop_subscript_array(BPy_PropertyRNA * self, PyObject *key) -{ - /*if (PyUnicode_Check(key)) { - return prop_subscript_array_str(self, _PyUnicode_AsString(key)); - } else*/ - if (PyIndex_Check(key)) { - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return NULL; - return prop_subscript_array_int(self, PyLong_AsSsize_t(key)); - } -#if PY_VERSION_HEX >= 0x03000000 - else if (PySlice_Check(key)) { - int len= RNA_property_array_length(self->prop); - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0) - return NULL; - - if (slicelength <= 0) { - return PyList_New(0); - } - else if (step == 1) { - return prop_subscript_array_slice(self, start, stop); - } - else { - PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna"); - return NULL; - } - } -#endif - else { - PyErr_SetString(PyExc_AttributeError, "invalid key, key must be an int"); + keyname = _PyUnicode_AsString(key); + } else if (PyLong_Check(key)) { + keynum = PyLong_AsSsize_t(key); + } else { + PyErr_SetString(PyExc_AttributeError, "invalid key, key must be a string or an int"); return NULL; } -} - -static PyObject *pyrna_prop_subscript( BPy_PropertyRNA * self, PyObject *key ) -{ + if (RNA_property_type(self->prop) == PROP_COLLECTION) { - return prop_subscript_collection(self, key); - } else if (RNA_property_array_length(self->prop)) { /* arrays are currently fixed length, zero length means its not an array */ - return prop_subscript_array(self, key); + int ok; + if (keyname) ok = RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr); + else ok = RNA_property_collection_lookup_int(&self->ptr, self->prop, keynum, &newptr); + + if (ok) { + ret = pyrna_struct_CreatePyObject(&newptr); + } else { + PyErr_SetString(PyExc_AttributeError, "out of range"); + ret = NULL; + } + + } else if (keyname) { + PyErr_SetString(PyExc_AttributeError, "string keys are only supported for collections"); + ret = NULL; } else { - PyErr_SetString(PyExc_TypeError, "rna type is not an array or a collection"); - return NULL; - } - -} - -#if PY_VERSION_HEX >= 0x03000000 -static int prop_subscript_ass_array_slice(BPy_PropertyRNA * self, int begin, int end, PyObject *value) -{ - int count; - - /* values are clamped from */ - begin = MIN2(begin,end); - - for(count = begin; count < end; count++) { - if(pyrna_py_to_prop_index(&self->ptr, self->prop, count - begin, value) == -1) { - /* TODO - this is wrong since some values have been assigned... will need to fix that */ - return -1; /* pyrna_struct_CreatePyObject should set the error */ + int len = RNA_property_array_length(self->prop); + + if (len==0) { /* not an array*/ + PyErr_Format(PyExc_AttributeError, "not an array or collection %d", keynum); + ret = NULL; + } + + if (keynum >= len){ + PyErr_SetString(PyExc_AttributeError, "index out of range"); + ret = NULL; + } else { /* not an array*/ + ret = pyrna_prop_to_py_index(&self->ptr, self->prop, keynum); } } - - return 0; + + return ret; } -#endif - -static int prop_subscript_ass_array_int(BPy_PropertyRNA * self, int keynum, PyObject *value) -{ - - int len= RNA_property_array_length(self->prop); - - if(keynum < 0) keynum += len; - if(keynum >= 0 && keynum < len) - return pyrna_py_to_prop_index(&self->ptr, self->prop, keynum, value); - PyErr_SetString(PyExc_IndexError, "out of range"); - return -1; -} - -static int pyrna_prop_ass_subscript( BPy_PropertyRNA * self, PyObject *key, PyObject *value ) +static int pyrna_prop_assign_subscript( BPy_PropertyRNA * self, PyObject *key, PyObject *value ) { - /* char *keyname = NULL; */ /* not supported yet */ + int ret = 0; + int keynum = 0; + char *keyname = NULL; if (!RNA_property_editable(&self->ptr, self->prop)) { - PyErr_Format( PyExc_AttributeError, "PropertyRNA - attribute \"%.200s\" from \"%.200s\" is read-only", RNA_property_identifier(self->prop), RNA_struct_identifier(self->ptr.type) ); + PyErr_Format( PyExc_AttributeError, "PropertyRNA - attribute \"%s\" from \"%s\" is read-only", RNA_property_identifier(self->prop), RNA_struct_identifier(self->ptr.type) ); return -1; } - /* maybe one day we can support this... */ - if (RNA_property_type(self->prop) == PROP_COLLECTION) { - PyErr_Format( PyExc_AttributeError, "PropertyRNA - attribute \"%.200s\" from \"%.200s\" is a collection, assignment not supported", RNA_property_identifier(self->prop), RNA_struct_identifier(self->ptr.type) ); + if (PyUnicode_Check(key)) { + keyname = _PyUnicode_AsString(key); + } else if (PyLong_Check(key)) { + keynum = PyLong_AsSsize_t(key); + } else { + PyErr_SetString(PyExc_AttributeError, "PropertyRNA - invalid key, key must be a string or an int"); return -1; } - - if (PyIndex_Check(key)) { - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) - return -1; - - return prop_subscript_ass_array_int(self, i, value); - } -#if PY_VERSION_HEX >= 0x03000000 - else if (PySlice_Check(key)) { - int len= RNA_property_array_length(self->prop); - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0) - return -1; - - if (slicelength <= 0) { - return 0; - } - else if (step == 1) { - return prop_subscript_ass_array_slice(self, start, stop, value); + + if (RNA_property_type(self->prop) == PROP_COLLECTION) { + PyErr_SetString(PyExc_AttributeError, "PropertyRNA - assignment is not supported for collections (yet)"); + ret = -1; + } else if (keyname) { + PyErr_SetString(PyExc_AttributeError, "PropertyRNA - string keys are only supported for collections"); + ret = -1; + } else { + int len = RNA_property_array_length(self->prop); + + if (len==0) { /* not an array*/ + PyErr_Format(PyExc_AttributeError, "PropertyRNA - not an array or collection %d", keynum); + ret = -1; } - else { - PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna"); - return -1; + + if (keynum >= len){ + PyErr_SetString(PyExc_AttributeError, "PropertyRNA - index out of range"); + ret = -1; + } else { + ret = pyrna_py_to_prop_index(&self->ptr, self->prop, keynum, value); } } -#endif - else { - PyErr_SetString(PyExc_AttributeError, "invalid key, key must be an int"); - return -1; - } + + return ret; } + static PyMappingMethods pyrna_prop_as_mapping = { ( lenfunc ) pyrna_prop_len, /* mp_length */ ( binaryfunc ) pyrna_prop_subscript, /* mp_subscript */ - ( objobjargproc ) pyrna_prop_ass_subscript, /* mp_ass_subscript */ + ( objobjargproc ) pyrna_prop_assign_subscript, /* mp_ass_subscript */ }; -static int pyrna_prop_contains(BPy_PropertyRNA * self, PyObject *value) -{ - PointerRNA newptr; /* not used, just so RNA_property_collection_lookup_string runs */ - char *keyname = _PyUnicode_AsString(value); - - if(keyname==NULL) { - PyErr_SetString(PyExc_TypeError, "PropertyRNA - key in prop, key must be a string type"); - return -1; - } - - if (RNA_property_type(self->prop) != PROP_COLLECTION) { - PyErr_SetString(PyExc_TypeError, "PropertyRNA - key in prop, is only valid for collection types"); - return -1; - } - - - if (RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr)) - return 1; - - return 0; -} - -static PySequenceMethods pyrna_prop_as_sequence = { - NULL, /* Cant set the len otherwise it can evaluate as false */ - NULL, /* sq_concat */ - NULL, /* sq_repeat */ - NULL, /* sq_item */ - NULL, /* sq_slice */ - NULL, /* sq_ass_item */ - NULL, /* sq_ass_slice */ - (objobjproc)pyrna_prop_contains, /* sq_contains */ -}; - - -static PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA * self, PyObject *args) -{ - char *path; - int index= 0; - float cfra = CTX_data_scene(BPy_GetContext())->r.cfra; - - if(!RNA_struct_is_ID(self->ptr.type)) { - PyErr_SetString( PyExc_TypeError, "StructRNA - keyframe_insert only for ID type"); - return NULL; - } - - if (!PyArg_ParseTuple(args, "s|if:keyframe_insert", &path, &index, &cfra)) - return NULL; - - return PyBool_FromLong( insert_keyframe((ID *)self->ptr.data, NULL, NULL, path, index, cfra, 0)); -} - - static PyObject *pyrna_struct_dir(BPy_StructRNA * self) { PyObject *ret, *dict; PyObject *pystring; /* for looping over attrs and funcs */ + CollectionPropertyIterator iter; PropertyRNA *iterprop; /* Include this incase this instance is a subtype of a python class @@ -1198,23 +806,26 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA * self) /* * Collect RNA attributes */ + PropertyRNA *nameprop; char name[256], *nameptr; iterprop= RNA_struct_iterator_property(self->ptr.type); + RNA_property_collection_begin(&self->ptr, iterprop, &iter); - RNA_PROP_BEGIN(&self->ptr, itemptr, iterprop) { - nameptr= RNA_struct_name_get_alloc(&itemptr, name, sizeof(name)); - - if(nameptr) { + for(; iter.valid; RNA_property_collection_next(&iter)) { + if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) { + nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name)); + pystring = PyUnicode_FromString(nameptr); PyList_Append(ret, pystring); Py_DECREF(pystring); - if(name != nameptr) + if ((char *)&name != nameptr) MEM_freeN(nameptr); } } - RNA_PROP_END; + RNA_property_collection_end(&iter); + } @@ -1227,25 +838,15 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA * self) RNA_pointer_create(NULL, &RNA_Struct, self->ptr.type, &tptr); iterprop= RNA_struct_find_property(&tptr, "functions"); - RNA_PROP_BEGIN(&tptr, itemptr, iterprop) { - pystring = PyUnicode_FromString(RNA_function_identifier(itemptr.data)); - PyList_Append(ret, pystring); - Py_DECREF(pystring); - } - RNA_PROP_END; - } - - if(self->ptr.type == &RNA_Context) { - ListBase lb = CTX_data_dir_get(self->ptr.data); - LinkData *link; + RNA_property_collection_begin(&tptr, iterprop, &iter); - for(link=lb.first; link; link=link->next) { - pystring = PyUnicode_FromString(link->data); + for(; iter.valid; RNA_property_collection_next(&iter)) { + pystring = PyUnicode_FromString(RNA_function_identifier(iter.ptr.data)); PyList_Append(ret, pystring); Py_DECREF(pystring); } - BLI_freelistN(&lb); + RNA_property_collection_end(&iter); } return ret; @@ -1274,7 +875,7 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname ) ret = pyrna_prop_to_py(&self->ptr, prop); } else if ((func = RNA_struct_find_function(&self->ptr, name))) { - ret = pyrna_func_to_py(self, func); + ret = pyrna_func_to_py(&self->ptr, func); } else if (self->ptr.type == &RNA_Context) { PointerRNA newptr; @@ -1305,7 +906,7 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname ) BLI_freelistN(&newlb); } else { - PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%.200s\" not found", name); + PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%s\" not found", name); ret = NULL; } @@ -1323,13 +924,13 @@ static int pyrna_struct_setattro( BPy_StructRNA * self, PyObject *pyname, PyObje return 0; } else { - PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%.200s\" not found", name); + PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%s\" not found", name); return -1; } } if (!RNA_property_editable(&self->ptr, prop)) { - PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%.200s\" from \"%.200s\" is read-only", RNA_property_identifier(prop), RNA_struct_identifier(self->ptr.type) ); + PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%s\" from \"%s\" is read-only", RNA_property_identifier(prop), RNA_struct_identifier(self->ptr.type) ); return -1; } @@ -1337,7 +938,7 @@ static int pyrna_struct_setattro( BPy_StructRNA * self, PyObject *pyname, PyObje return pyrna_py_to_prop(&self->ptr, prop, NULL, value); } -static PyObject *pyrna_prop_keys(BPy_PropertyRNA *self) +PyObject *pyrna_prop_keys(BPy_PropertyRNA *self) { PyObject *ret; if (RNA_property_type(self->prop) != PROP_COLLECTION) { @@ -1345,31 +946,34 @@ static PyObject *pyrna_prop_keys(BPy_PropertyRNA *self) ret = NULL; } else { PyObject *item; + CollectionPropertyIterator iter; + PropertyRNA *nameprop; char name[256], *nameptr; ret = PyList_New(0); - RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) { - nameptr= RNA_struct_name_get_alloc(&itemptr, name, sizeof(name)); - - if(nameptr) { + RNA_property_collection_begin(&self->ptr, self->prop, &iter); + for(; iter.valid; RNA_property_collection_next(&iter)) { + if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) { + nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name)); + /* add to python list */ item = PyUnicode_FromString( nameptr ); PyList_Append(ret, item); Py_DECREF(item); /* done */ - if(name != nameptr) + if ((char *)&name != nameptr) MEM_freeN(nameptr); } } - RNA_PROP_END; + RNA_property_collection_end(&iter); } return ret; } -static PyObject *pyrna_prop_items(BPy_PropertyRNA *self) +PyObject *pyrna_prop_items(BPy_PropertyRNA *self) { PyObject *ret; if (RNA_property_type(self->prop) != PROP_COLLECTION) { @@ -1377,315 +981,60 @@ static PyObject *pyrna_prop_items(BPy_PropertyRNA *self) ret = NULL; } else { PyObject *item; + CollectionPropertyIterator iter; + PropertyRNA *nameprop; char name[256], *nameptr; - int i= 0; ret = PyList_New(0); - RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) { - if(itemptr.data) { - /* add to python list */ - item= PyTuple_New(2); - nameptr= RNA_struct_name_get_alloc(&itemptr, name, sizeof(name)); - if(nameptr) { - PyTuple_SET_ITEM(item, 0, PyUnicode_FromString( nameptr )); - if(name != nameptr) - MEM_freeN(nameptr); - } - else { - PyTuple_SET_ITEM(item, 0, PyLong_FromSsize_t(i)); /* a bit strange but better then returning an empty list */ - } - PyTuple_SET_ITEM(item, 1, pyrna_struct_CreatePyObject(&itemptr)); + RNA_property_collection_begin(&self->ptr, self->prop, &iter); + for(; iter.valid; RNA_property_collection_next(&iter)) { + if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) { + nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name)); + /* add to python list */ + item = Py_BuildValue("(NN)", PyUnicode_FromString( nameptr ), pyrna_struct_CreatePyObject(&iter.ptr)); PyList_Append(ret, item); Py_DECREF(item); + /* done */ - i++; + if ((char *)&name != nameptr) + MEM_freeN(nameptr); } } - RNA_PROP_END; + RNA_property_collection_end(&iter); } return ret; } -static PyObject *pyrna_prop_values(BPy_PropertyRNA *self) +PyObject *pyrna_prop_values(BPy_PropertyRNA *self) { PyObject *ret; - if (RNA_property_type(self->prop) != PROP_COLLECTION) { PyErr_SetString( PyExc_TypeError, "values() is only valid for collection types" ); ret = NULL; } else { PyObject *item; + CollectionPropertyIterator iter; + PropertyRNA *nameprop; + ret = PyList_New(0); - RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) { - item = pyrna_struct_CreatePyObject(&itemptr); - PyList_Append(ret, item); - Py_DECREF(item); - } - RNA_PROP_END; - } - - return ret; -} - -static PyObject *pyrna_prop_get(BPy_PropertyRNA *self, PyObject *args) -{ - PointerRNA newptr; - - char *key; - PyObject* def = Py_None; - - if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) - return NULL; - - if(RNA_property_collection_lookup_string(&self->ptr, self->prop, key, &newptr)) - return pyrna_struct_CreatePyObject(&newptr); - - Py_INCREF(def); - return def; -} - - -#if (PY_VERSION_HEX >= 0x03000000) /* foreach needs py3 */ -static void foreach_attr_type( BPy_PropertyRNA *self, char *attr, - /* values to assign */ - RawPropertyType *raw_type, int *attr_tot, int *attr_signed ) -{ - PropertyRNA *prop; - *raw_type= -1; - *attr_tot= 0; - *attr_signed= 0; - - RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) { - prop = RNA_struct_find_property(&itemptr, attr); - *raw_type= RNA_property_raw_type(prop); - *attr_tot = RNA_property_array_length(prop); - *attr_signed= (RNA_property_subtype(prop)==PROP_UNSIGNED) ? 0:1; - break; - } - RNA_PROP_END; -} - -/* pyrna_prop_foreach_get/set both use this */ -static int foreach_parse_args( - BPy_PropertyRNA *self, PyObject *args, - - /*values to assign */ - char **attr, PyObject **seq, int *tot, int *size, RawPropertyType *raw_type, int *attr_tot, int *attr_signed) -{ -#if 0 - int array_tot; - int target_tot; -#endif - - *size= *raw_type= *attr_tot= *attr_signed= 0; - - if(!PyArg_ParseTuple(args, "sO", attr, seq) || (!PySequence_Check(*seq) && PyObject_CheckBuffer(*seq))) { - PyErr_SetString( PyExc_TypeError, "foreach_get(attr, sequence) expects a string and a sequence" ); - return -1; - } - - *tot= PySequence_Length(*seq); // TODO - buffer may not be a sequence! array.array() is tho. - - if(*tot>0) { - foreach_attr_type(self, *attr, raw_type, attr_tot, attr_signed); - *size= RNA_raw_type_sizeof(*raw_type); - -#if 0 // works fine but not strictly needed, we could allow RNA_property_collection_raw_* to do the checks - if((*attr_tot) < 1) - *attr_tot= 1; - - if (RNA_property_type(self->prop) == PROP_COLLECTION) - array_tot = RNA_property_collection_length(&self->ptr, self->prop); - else - array_tot = RNA_property_array_length(self->prop); - - - target_tot= array_tot * (*attr_tot); - - /* rna_access.c - rna_raw_access(...) uses this same method */ - if(target_tot != (*tot)) { - PyErr_Format( PyExc_TypeError, "foreach_get(attr, sequence) sequence length mismatch given %d, needed %d", *tot, target_tot); - return -1; - } -#endif - } - - return 0; -} - -static int foreach_compat_buffer(RawPropertyType raw_type, int attr_signed, const char *format) -{ - char f = format ? *format:'B'; /* B is assumed when not set */ - - switch(raw_type) { - case PROP_RAW_CHAR: - if (attr_signed) return (f=='b') ? 1:0; - else return (f=='B') ? 1:0; - case PROP_RAW_SHORT: - if (attr_signed) return (f=='h') ? 1:0; - else return (f=='H') ? 1:0; - case PROP_RAW_INT: - if (attr_signed) return (f=='i') ? 1:0; - else return (f=='I') ? 1:0; - case PROP_RAW_FLOAT: - return (f=='f') ? 1:0; - case PROP_RAW_DOUBLE: - return (f=='d') ? 1:0; - } - - return 0; -} - -static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set) -{ - PyObject *item; - int i=0, ok, buffer_is_compat; - void *array= NULL; - - /* get/set both take the same args currently */ - char *attr; - PyObject *seq; - int tot, size, attr_tot, attr_signed; - RawPropertyType raw_type; - - if(foreach_parse_args(self, args, &attr, &seq, &tot, &size, &raw_type, &attr_tot, &attr_signed) < 0) - return NULL; - - if(tot==0) - Py_RETURN_NONE; - - - - if(set) { /* get the array from python */ - buffer_is_compat = 0; - if(PyObject_CheckBuffer(seq)) { - Py_buffer buf; - PyObject_GetBuffer(seq, &buf, PyBUF_SIMPLE | PyBUF_FORMAT); - - /* check if the buffer matches */ - - buffer_is_compat = foreach_compat_buffer(raw_type, attr_signed, buf.format); - - if(buffer_is_compat) { - ok = RNA_property_collection_raw_set(NULL, &self->ptr, self->prop, attr, buf.buf, raw_type, tot); - } - - PyBuffer_Release(&buf); - } - - /* could not use the buffer, fallback to sequence */ - if(!buffer_is_compat) { - array= PyMem_Malloc(size * tot); - - for( ; i<tot; i++) { - item= PySequence_GetItem(seq, i); - switch(raw_type) { - case PROP_RAW_CHAR: - ((char *)array)[i]= (char)PyLong_AsSsize_t(item); - break; - case PROP_RAW_SHORT: - ((short *)array)[i]= (short)PyLong_AsSsize_t(item); - break; - case PROP_RAW_INT: - ((int *)array)[i]= (int)PyLong_AsSsize_t(item); - break; - case PROP_RAW_FLOAT: - ((float *)array)[i]= (float)PyFloat_AsDouble(item); - break; - case PROP_RAW_DOUBLE: - ((double *)array)[i]= (double)PyFloat_AsDouble(item); - break; - } - - Py_DECREF(item); - } - - ok = RNA_property_collection_raw_set(NULL, &self->ptr, self->prop, attr, array, raw_type, tot); - } - } - else { - buffer_is_compat = 0; - if(PyObject_CheckBuffer(seq)) { - Py_buffer buf; - PyObject_GetBuffer(seq, &buf, PyBUF_SIMPLE | PyBUF_FORMAT); - - /* check if the buffer matches, TODO - signed/unsigned types */ - - buffer_is_compat = foreach_compat_buffer(raw_type, attr_signed, buf.format); - - if(buffer_is_compat) { - ok = RNA_property_collection_raw_get(NULL, &self->ptr, self->prop, attr, buf.buf, raw_type, tot); - } - - PyBuffer_Release(&buf); - } - - /* could not use the buffer, fallback to sequence */ - if(!buffer_is_compat) { - array= PyMem_Malloc(size * tot); - - ok = RNA_property_collection_raw_get(NULL, &self->ptr, self->prop, attr, array, raw_type, tot); - - if(!ok) i= tot; /* skip the loop */ - - for( ; i<tot; i++) { - - switch(raw_type) { - case PROP_RAW_CHAR: - item= PyLong_FromSsize_t( (Py_ssize_t) ((char *)array)[i] ); - break; - case PROP_RAW_SHORT: - item= PyLong_FromSsize_t( (Py_ssize_t) ((short *)array)[i] ); - break; - case PROP_RAW_INT: - item= PyLong_FromSsize_t( (Py_ssize_t) ((int *)array)[i] ); - break; - case PROP_RAW_FLOAT: - item= PyFloat_FromDouble( (double) ((float *)array)[i] ); - break; - case PROP_RAW_DOUBLE: - item= PyFloat_FromDouble( (double) ((double *)array)[i] ); - break; - } - - PySequence_SetItem(seq, i, item); + RNA_property_collection_begin(&self->ptr, self->prop, &iter); + for(; iter.valid; RNA_property_collection_next(&iter)) { + if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) { + item = pyrna_struct_CreatePyObject(&iter.ptr); + PyList_Append(ret, item); Py_DECREF(item); } } + RNA_property_collection_end(&iter); } - - if(PyErr_Occurred()) { - /* Maybe we could make our own error */ - PyErr_Print(); - PyErr_SetString(PyExc_SystemError, "could not access the py sequence"); - return NULL; - } - if (!ok) { - PyErr_SetString(PyExc_SystemError, "internal error setting the array"); - return NULL; - } - - if(array) - PyMem_Free(array); - - Py_RETURN_NONE; -} - -static PyObject *pyrna_prop_foreach_get(BPy_PropertyRNA *self, PyObject *args) -{ - return foreach_getset(self, args, 0); -} - -static PyObject *pyrna_prop_foreach_set(BPy_PropertyRNA *self, PyObject *args) -{ - return foreach_getset(self, args, 1); + + return ret; } -#endif /* #if (PY_VERSION_HEX >= 0x03000000) */ /* A bit of a kludge, make a list out of a collection or array, * then return the lists iter function, not especially fast but convenient for now */ @@ -1721,26 +1070,14 @@ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self) } static struct PyMethodDef pyrna_struct_methods[] = { - - /* maybe this become and ID function */ - {"keyframe_insert", (PyCFunction)pyrna_struct_keyframe_insert, METH_VARARGS, NULL}, - - {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL}, + {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, ""}, {NULL, NULL, 0, NULL} }; static struct PyMethodDef pyrna_prop_methods[] = { - {"keys", (PyCFunction)pyrna_prop_keys, METH_NOARGS, NULL}, - {"items", (PyCFunction)pyrna_prop_items, METH_NOARGS,NULL}, - {"values", (PyCFunction)pyrna_prop_values, METH_NOARGS, NULL}, - - {"get", (PyCFunction)pyrna_prop_get, METH_VARARGS, NULL}, - -#if (PY_VERSION_HEX >= 0x03000000) - /* array accessor function */ - {"foreach_get", (PyCFunction)pyrna_prop_foreach_get, METH_VARARGS, NULL}, - {"foreach_set", (PyCFunction)pyrna_prop_foreach_set, METH_VARARGS, NULL}, -#endif + {"keys", (PyCFunction)pyrna_prop_keys, METH_NOARGS, ""}, + {"items", (PyCFunction)pyrna_prop_items, METH_NOARGS, ""}, + {"values", (PyCFunction)pyrna_prop_values, METH_NOARGS, ""}, {NULL, NULL, 0, NULL} }; @@ -1834,17 +1171,11 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data) const char *identifier; int val = *(int*)data; - if (RNA_property_enum_identifier(BPy_GetContext(), ptr, prop, val, &identifier)) { + if (RNA_property_enum_identifier(ptr, prop, val, &identifier)) { ret = PyUnicode_FromString( identifier ); } else { - /* prefer not fail silently incase of api errors, maybe disable it later */ - char error_str[128]; - sprintf(error_str, "RNA Warning: Current value \"%d\" matches no enum", val); - PyErr_Warn(PyExc_RuntimeWarning, error_str); - - ret = PyUnicode_FromString( "" ); - /*PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val); - ret = NULL;*/ + PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val); + ret = NULL; } break; @@ -1853,9 +1184,8 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data) { PointerRNA newptr; StructRNA *type= RNA_property_pointer_type(ptr, prop); - int flag = RNA_property_flag(prop); - if(flag & PROP_RNAPTR) { + if(type == &RNA_AnyType) { /* in this case we get the full ptr */ newptr= *(PointerRNA*)data; } @@ -1873,21 +1203,10 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data) break; } case PROP_COLLECTION: - { - ListBase *lb= (ListBase*)data; - CollectionPointerLink *link; - PyObject *linkptr; - - ret = PyList_New(0); - - for(link=lb->first; link; link=link->next) { - linkptr= pyrna_struct_CreatePyObject(&link->ptr); - PyList_Append(ret, linkptr); - Py_DECREF(linkptr); - } - + /* XXX not supported yet + * ret = pyrna_prop_CreatePyObject(ptr, prop); */ + ret = NULL; break; - } default: PyErr_Format(PyExc_AttributeError, "RNA Error: unknown type \"%d\" (pyrna_param_to_py)", type); ret = NULL; @@ -1946,7 +1265,7 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw) tid= RNA_struct_identifier(self_ptr->type); fid= RNA_function_identifier(self_func); - PyErr_Format(PyExc_AttributeError, "%.200s.%.200s(): required parameter \"%.200s\" not specified", tid, fid, pid); + PyErr_Format(PyExc_AttributeError, "%s.%s(): required parameter \"%s\" not specified", tid, fid, pid); err= -1; break; } @@ -1963,19 +1282,11 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw) ret= NULL; if (err==0) { /* call function */ - ReportList reports; - bContext *C= BPy_GetContext(); - - BKE_reports_init(&reports, RPT_STORE); - RNA_function_call(C, &reports, self_ptr, self_func, parms); - - err= (BPy_reports_to_error(&reports))? -1: 0; - BKE_reports_clear(&reports); + RNA_function_call(self_ptr, self_func, parms); /* return value */ - if(err==0) - if(pret) - ret= pyrna_param_to_py(&funcptr, pret, retdata); + if(pret) + ret= pyrna_param_to_py(&funcptr, pret, retdata); } /* cleanup */ @@ -2064,7 +1375,7 @@ PyTypeObject pyrna_struct_Type = { NULL, /* allocfunc tp_alloc; */ pyrna_struct_new, /* newfunc tp_new; */ /* Low-level free-memory routine */ - NULL, /* freefunc tp_free; */ + NULL, //MEM_freeN, /* freefunc tp_free; */ /* For PyObject_IS_GC */ NULL, /* inquiry tp_is_gc; */ NULL, /* PyObject *tp_bases; */ @@ -2090,7 +1401,7 @@ PyTypeObject pyrna_prop_Type = { sizeof( BPy_PropertyRNA ), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - NULL, /* tp_dealloc */ + NULL, /* tp_dealloc */ NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ @@ -2100,7 +1411,7 @@ PyTypeObject pyrna_prop_Type = { /* Method suites for standard classes */ NULL, /* PyNumberMethods *tp_as_number; */ - &pyrna_prop_as_sequence, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ &pyrna_prop_as_mapping, /* PyMappingMethods *tp_as_mapping; */ /* More standard operations (here for binary compatibility) */ @@ -2150,7 +1461,7 @@ PyTypeObject pyrna_prop_Type = { NULL, /* allocfunc tp_alloc; */ pyrna_prop_new, /* newfunc tp_new; */ /* Low-level free-memory routine */ - NULL, /* freefunc tp_free; */ + NULL, //MEM_freeN, /* freefunc tp_free; */ /* For PyObject_IS_GC */ NULL, /* inquiry tp_is_gc; */ NULL, /* PyObject *tp_bases; */ @@ -2185,52 +1496,43 @@ static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna) /* done with rna instance */ } -PyObject* pyrna_srna_Subtype(StructRNA *srna) +PyObject* pyrna_struct_Subtype(PointerRNA *ptr) { PyObject *newclass = NULL; + PropertyRNA *nameprop; - if (srna == NULL) { + if (ptr->type==NULL) { newclass= NULL; /* Nothing to do */ - } else if ((newclass= RNA_struct_py_type_get(srna))) { + } else if ((newclass= RNA_struct_py_type_get(ptr->data))) { Py_INCREF(newclass); - } else { - StructRNA *base; - + } else if ((nameprop = RNA_struct_name_property(ptr->type))) { /* for now, return the base RNA type rather then a real module */ - /* Assume RNA_struct_py_type_get(srna) was alredy checked */ + /* Assume RNA_struct_py_type_get(ptr->data) was alredy checked */ /* subclass equivelents - class myClass(myBase): some='value' # or ... - - myClass = type(name='myClass', bases=(myBase,), dict={'__module__':'bpy.types'}) + - myClass = type(name='myClass', bases=(myBase,), dict={'some':'value'}) */ - const char *descr= RNA_struct_ui_description(srna); + char name[256], *nameptr; + const char *descr= RNA_struct_ui_description(ptr->type); PyObject *args = PyTuple_New(3); PyObject *bases = PyTuple_New(1); - PyObject *py_base= NULL; PyObject *dict = PyDict_New(); PyObject *item; - + + + nameptr= RNA_property_string_get_alloc(ptr, nameprop, name, sizeof(name)); // arg 1 //PyTuple_SET_ITEM(args, 0, PyUnicode_FromString(tp_name)); - PyTuple_SET_ITEM(args, 0, PyUnicode_FromString(RNA_struct_identifier(srna))); + PyTuple_SET_ITEM(args, 0, PyUnicode_FromString(nameptr)); // arg 2 - base= RNA_struct_base(srna); - if(base && base != srna) { - /*/printf("debug subtype %s %p\n", RNA_struct_identifier(srna), srna); */ - py_base= pyrna_srna_Subtype(base); - } - - if(py_base==NULL) { - py_base= (PyObject *)&pyrna_struct_Type; - Py_INCREF(py_base); - } - - PyTuple_SET_ITEM(bases, 0, py_base); + PyTuple_SET_ITEM(bases, 0, (PyObject *)&pyrna_struct_Type); + Py_INCREF(&pyrna_struct_Type); PyTuple_SET_ITEM(args, 1, bases); @@ -2241,13 +1543,6 @@ PyObject* pyrna_srna_Subtype(StructRNA *srna) Py_DECREF(item); } - /* this isnt needed however its confusing if we get python script names in blender types, - * because the __module__ is used when printing the class */ - item= PyUnicode_FromString("bpy.types"); /* just to know its an internal type */ - PyDict_SetItemString(dict, "__module__", item); - Py_DECREF(item); - - PyTuple_SET_ITEM(args, 2, dict); // fill with useful subclass things! if (PyErr_Occurred()) { @@ -2258,25 +1553,16 @@ PyObject* pyrna_srna_Subtype(StructRNA *srna) newclass = PyObject_CallObject((PyObject *)&PyType_Type, args); Py_DECREF(args); - if (newclass) { - pyrna_subtype_set_rna(newclass, srna); - // PyObSpit("NewStructRNA Type: ", (PyObject *)newclass); - } - else { - /* this should not happen */ - PyErr_Print(); - PyErr_Clear(); - } + if (newclass) + pyrna_subtype_set_rna(newclass, ptr->data); + + if (name != nameptr) + MEM_freeN(nameptr); } return newclass; } -PyObject* pyrna_struct_Subtype(PointerRNA *ptr) -{ - return pyrna_srna_Subtype((ptr->type == &RNA_Struct) ? ptr->data : ptr->type); -} - /*-----------------------CreatePyObject---------------------------------*/ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) { @@ -2285,7 +1571,8 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) if (ptr->data==NULL && ptr->type==NULL) { /* Operator RNA has NULL data */ Py_RETURN_NONE; } - else { + + if (ptr->type == &RNA_Struct) { /* always return a python subtype from rna struct types */ PyTypeObject *tp = (PyTypeObject *)pyrna_struct_Subtype(ptr); if (tp) { @@ -2293,10 +1580,13 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) } else { fprintf(stderr, "Could not make type\n"); - pyrna = ( BPy_StructRNA * ) PyObject_NEW( BPy_StructRNA, &pyrna_struct_Type ); + pyrna = ( BPy_StructRNA * ) bpy_PyObject_New( BPy_StructRNA, &pyrna_struct_Type ); } } - + else { + pyrna = ( BPy_StructRNA * ) bpy_PyObject_New( BPy_StructRNA, &pyrna_struct_Type ); + } + if( !pyrna ) { PyErr_SetString( PyExc_MemoryError, "couldn't create BPy_StructRNA object" ); return NULL; @@ -2304,9 +1594,6 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) pyrna->ptr= *ptr; pyrna->freeptr= 0; - - // PyObSpit("NewStructRNA: ", (PyObject *)pyrna); - return ( PyObject * ) pyrna; } @@ -2314,7 +1601,7 @@ PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop ) { BPy_PropertyRNA *pyrna; - pyrna = ( BPy_PropertyRNA * ) PyObject_NEW( BPy_PropertyRNA, &pyrna_prop_Type ); + pyrna = ( BPy_PropertyRNA * ) bpy_PyObject_New( BPy_PropertyRNA, &pyrna_prop_Type ); if( !pyrna ) { PyErr_SetString( PyExc_MemoryError, "couldn't create BPy_rna object" ); @@ -2331,11 +1618,6 @@ PyObject *BPY_rna_module( void ) { PointerRNA ptr; -#ifdef USE_MATHUTILS // register mathutils callbacks, ok to run more then once. - mathutils_rna_array_cb_index= Mathutils_RegisterCallback(&mathutils_rna_array_cb); - mathutils_rna_matrix_cb_index= Mathutils_RegisterCallback(&mathutils_rna_matrix_cb); -#endif - /* This can't be set in the pytype struct because some compilers complain */ pyrna_prop_Type.tp_getattro = PyObject_GenericGetAttr; pyrna_prop_Type.tp_setattro = PyObject_GenericSetAttr; @@ -2382,12 +1664,12 @@ static PyObject *pyrna_basetype_getattro( BPy_BaseTypeRNA * self, PyObject *pyna if (RNA_property_collection_lookup_string(&self->ptr, self->prop, _PyUnicode_AsString(pyname), &newptr)) { ret= pyrna_struct_Subtype(&newptr); if (ret==NULL) { - PyErr_Format(PyExc_SystemError, "bpy.types.%.200s subtype could not be generated, this is a bug!", _PyUnicode_AsString(pyname)); + PyErr_Format(PyExc_SystemError, "bpy.types.%s subtype could not be generated, this is a bug!", _PyUnicode_AsString(pyname)); } return ret; } else { /* Override the error */ - PyErr_Format(PyExc_AttributeError, "bpy.types.%.200s not a valid RNA_Struct", _PyUnicode_AsString(pyname)); + PyErr_Format(PyExc_AttributeError, "bpy.types.%s not a valid RNA_Struct", _PyUnicode_AsString(pyname)); return NULL; } } @@ -2428,12 +1710,13 @@ PyObject *BPY_rna_types(void) pyrna_basetype_Type.tp_getattro = ( getattrofunc )pyrna_basetype_getattro; pyrna_basetype_Type.tp_flags = Py_TPFLAGS_DEFAULT; pyrna_basetype_Type.tp_methods = pyrna_basetype_methods; + //pyrna_basetype_Type.tp_free = MEM_freeN; if( PyType_Ready( &pyrna_basetype_Type ) < 0 ) return NULL; } - self= (BPy_BaseTypeRNA *)PyObject_NEW( BPy_BaseTypeRNA, &pyrna_basetype_Type ); + self= (BPy_BaseTypeRNA *)bpy_PyObject_New( BPy_BaseTypeRNA, &pyrna_basetype_Type ); /* avoid doing this lookup for every getattr */ RNA_blender_rna_pointer_create(&self->ptr); @@ -2442,44 +1725,7 @@ PyObject *BPY_rna_types(void) return (PyObject *)self; } -static struct PyMethodDef props_methods[] = { - {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {NULL, NULL, 0, NULL} -}; -#if PY_VERSION_HEX >= 0x03000000 -static struct PyModuleDef props_module = { - PyModuleDef_HEAD_INIT, - "bpyprops", - "", - -1,/* multiple "initialization" just copies the module dict. */ - props_methods, - NULL, NULL, NULL, NULL -}; -#endif - -PyObject *BPY_rna_props( void ) -{ - PyObject *submodule, *mod; -#if PY_VERSION_HEX >= 0x03000000 - submodule= PyModule_Create(&props_module); -#else /* Py2.x */ - submodule= Py_InitModule3( "bpy.props", props_methods, "" ); -#endif - - mod = PyModule_New("props"); - PyModule_AddObject( submodule, "props", mod ); - - /* INCREF since its its assumed that all these functions return the - * module with a new ref like PyDict_New, since they are passed to - * PyModule_AddObject which steals a ref */ - Py_INCREF(submodule); - - return submodule; -} /* Orphan functions, not sure where they should go */ @@ -2499,7 +1745,7 @@ PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; } - if (self && PyCObject_Check(self)) { + if (self) { StructRNA *srna = PyCObject_AsVoidPtr(self); RNA_def_float(srna, id, def, min, max, name, description, soft_min, soft_max); Py_RETURN_NONE; @@ -2526,7 +1772,7 @@ PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; } - if (self && PyCObject_Check(self)) { + if (self) { StructRNA *srna = PyCObject_AsVoidPtr(self); RNA_def_int(srna, id, def, min, max, name, description, soft_min, soft_max); Py_RETURN_NONE; @@ -2545,7 +1791,7 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) char *id, *name="", *description=""; int def=0; - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssi:BoolProperty", kwlist, &id, &name, &description, &def)) + if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssi:IntProperty", kwlist, &id, &name, &description, &def)) return NULL; if (PyTuple_Size(args) > 0) { @@ -2553,40 +1799,13 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; } - if (self && PyCObject_Check(self)) { + if (self) { StructRNA *srna = PyCObject_AsVoidPtr(self); RNA_def_boolean(srna, id, def, name, description); Py_RETURN_NONE; } else { PyObject *ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr((void *)BPy_BoolProperty, NULL)); - PyTuple_SET_ITEM(ret, 1, kw); - Py_INCREF(kw); - return ret; - } -} - -PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw) -{ - static char *kwlist[] = {"attr", "name", "description", "maxlen", "default", NULL}; - char *id, *name="", *description="", *def=""; - int maxlen=0; - - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssis:StringProperty", kwlist, &id, &name, &description, &maxlen, &def)) - return NULL; - - if (PyTuple_Size(args) > 0) { - PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this. - return NULL; - } - - if (self && PyCObject_Check(self)) { - StructRNA *srna = PyCObject_AsVoidPtr(self); - RNA_def_string(srna, id, def, maxlen, name, description); - Py_RETURN_NONE; - } else { - PyObject *ret = PyTuple_New(2); - PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr((void *)BPy_StringProperty, NULL)); + PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr((void *)BPy_IntProperty, NULL)); PyTuple_SET_ITEM(ret, 1, kw); Py_INCREF(kw); return ret; @@ -2629,7 +1848,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun if (base_class) { if (!PyObject_IsSubclass(py_class, base_class)) { PyObject *name= PyObject_GetAttrString(base_class, "__name__"); - PyErr_Format( PyExc_AttributeError, "expected %.200s subclass of class \"%.200s\"", class_type, name ? _PyUnicode_AsString(name):"<UNKNOWN>"); + PyErr_Format( PyExc_AttributeError, "expected %s subclass of class \"%s\"", class_type, name ? _PyUnicode_AsString(name):"<UNKNOWN>"); Py_XDECREF(name); return -1; } @@ -2652,7 +1871,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun if (item==NULL) { if ((flag & FUNC_REGISTER_OPTIONAL)==0) { - PyErr_Format( PyExc_AttributeError, "expected %.200s class to have an \"%.200s\" attribute", class_type, RNA_function_identifier(func)); + PyErr_Format( PyExc_AttributeError, "expected %s class to have an \"%s\" attribute", class_type, RNA_function_identifier(func)); return -1; } @@ -2667,7 +1886,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun fitem= item; /* py 3.x */ if (PyFunction_Check(fitem)==0) { - PyErr_Format( PyExc_AttributeError, "expected %.200s class \"%.200s\" attribute to be a function", class_type, RNA_function_identifier(func)); + PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute to be a function", class_type, RNA_function_identifier(func)); return -1; } @@ -2679,7 +1898,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun Py_DECREF(py_arg_count); if (arg_count != func_arg_count) { - PyErr_Format( PyExc_AttributeError, "expected %.200s class \"%.200s\" function to have %d args", class_type, RNA_function_identifier(func), func_arg_count); + PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" function to have %d args", class_type, RNA_function_identifier(func), func_arg_count); return -1; } } @@ -2711,7 +1930,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun } if (item==NULL && (flag & PROP_REGISTER_OPTIONAL)==0) { - PyErr_Format( PyExc_AttributeError, "expected %.200s class to have an \"%.200s\" attribute", class_type, identifier); + PyErr_Format( PyExc_AttributeError, "expected %s class to have an \"%s\" attribute", class_type, identifier); return -1; } @@ -2795,12 +2014,12 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par } else { Py_DECREF(py_class_instance); - PyErr_Format(PyExc_AttributeError, "could not find function %.200s in %.200s to execute callback.", RNA_function_identifier(func), RNA_struct_identifier(ptr->type)); + PyErr_Format(PyExc_AttributeError, "could not find function %s in %s to execute callback.", RNA_function_identifier(func), RNA_struct_identifier(ptr->type)); err= -1; } } else { - PyErr_Format(PyExc_AttributeError, "could not create instance of %.200s to call callback function %.200s.", RNA_struct_identifier(ptr->type), RNA_function_identifier(func)); + PyErr_Format(PyExc_AttributeError, "could not create instance of %s to call callback function %s.", RNA_struct_identifier(ptr->type), RNA_function_identifier(func)); err= -1; } @@ -2875,7 +2094,7 @@ PyObject *pyrna_basetype_register(PyObject *self, PyObject *args) C= BPy_GetContext(); /* call the register callback */ - BKE_reports_init(&reports, RPT_STORE); + BKE_reports_init(&reports, RPT_PRINT); srna= reg(C, &reports, py_class, bpy_class_validate, bpy_class_call, bpy_class_free); if(!srna) { diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index d2f01b06336..a2a3015912b 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -63,7 +63,6 @@ typedef struct { PyObject *BPY_rna_module( void ); /*PyObject *BPY_rna_doc( void );*/ PyObject *BPY_rna_types( void ); -PyObject *BPY_rna_props( void ); PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ); PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop ); @@ -77,7 +76,6 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop); PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw); PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw); PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw); -PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw); /* function for registering types */ PyObject *pyrna_basetype_register(PyObject *self, PyObject *args); diff --git a/source/blender/python/intern/bpy_ui.c b/source/blender/python/intern/bpy_ui.c index 088fe436c69..c15315ca350 100644 --- a/source/blender/python/intern/bpy_ui.c +++ b/source/blender/python/intern/bpy_ui.c @@ -373,7 +373,7 @@ static struct PyMethodDef ui_methods[] = { #if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef ui_module = { PyModuleDef_HEAD_INIT, - "bpy.ui", + "bpyui", "", -1,/* multiple "initialization" just copies the module dict. */ ui_methods, diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index b451923e780..c447e7de982 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -81,7 +81,6 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag) char *cstring; PyObject *item; BPY_flag_def *fd; - *flag = 0; if (PySequence_Check(seq)) { i= PySequence_Length(seq); @@ -109,9 +108,6 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag) error_val= 1; } - if (*flag == 0) - error_val = 1; - if (error_val) { char *buf = bpy_flag_error_str(flagdef); PyErr_SetString(PyExc_AttributeError, buf); @@ -171,13 +167,7 @@ void PyObSpit(char *name, PyObject *var) { else { PyObject_Print(var, stderr, 0); fprintf(stderr, " ref:%d ", var->ob_refcnt); - fprintf(stderr, " ptr:%p", (void *)var); - - fprintf(stderr, " type:"); - if(Py_TYPE(var)) - fprintf(stderr, "%s", Py_TYPE(var)->tp_name); - else - fprintf(stderr, "<NIL>"); + fprintf(stderr, " ptr:%ld", (long)var); } fprintf(stderr, "\n"); } @@ -339,81 +329,6 @@ int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_c return 0; } - - -/* returns the exception string as a new PyUnicode object, depends on external StringIO module */ -PyObject *BPY_exception_buffer(void) -{ - PyObject *stdout_backup = PySys_GetObject("stdout"); /* borrowed */ - PyObject *stderr_backup = PySys_GetObject("stderr"); /* borrowed */ - PyObject *string_io = NULL; - PyObject *string_io_buf = NULL; - PyObject *string_io_mod= NULL; - PyObject *string_io_getvalue= NULL; - - PyObject *error_type, *error_value, *error_traceback; - - if (!PyErr_Occurred()) - return NULL; - - PyErr_Fetch(&error_type, &error_value, &error_traceback); - - PyErr_Clear(); - - /* import StringIO / io - * string_io = StringIO.StringIO() - */ - -#if PY_VERSION_HEX < 0x03000000 - if(! (string_io_mod= PyImport_ImportModule("StringIO")) ) { -#else - if(! (string_io_mod= PyImport_ImportModule("io")) ) { -#endif - goto error_cleanup; - } else if (! (string_io = PyObject_CallMethod(string_io_mod, "StringIO", NULL))) { - goto error_cleanup; - } else if (! (string_io_getvalue= PyObject_GetAttrString(string_io, "getvalue"))) { - goto error_cleanup; - } - - Py_INCREF(stdout_backup); // since these were borrowed we dont want them freed when replaced. - Py_INCREF(stderr_backup); - - PySys_SetObject("stdout", string_io); // both of these are free'd when restoring - PySys_SetObject("stderr", string_io); - - PyErr_Restore(error_type, error_value, error_traceback); - PyErr_Print(); /* print the error */ - PyErr_Clear(); - - string_io_buf = PyObject_CallObject(string_io_getvalue, NULL); - - PySys_SetObject("stdout", stdout_backup); - PySys_SetObject("stderr", stderr_backup); - - Py_DECREF(stdout_backup); /* now sys owns the ref again */ - Py_DECREF(stderr_backup); - - Py_DECREF(string_io_mod); - Py_DECREF(string_io_getvalue); - Py_DECREF(string_io); /* free the original reference */ - - PyErr_Clear(); - return string_io_buf; - - -error_cleanup: - /* could not import the module so print the error and close */ - Py_XDECREF(string_io_mod); - Py_XDECREF(string_io); - - PyErr_Restore(error_type, error_value, error_traceback); - PyErr_Print(); /* print the error */ - PyErr_Clear(); - - return NULL; -} - char *BPy_enum_as_string(EnumPropertyItem *item) { DynStr *dynstr= BLI_dynstr_new(); @@ -421,8 +336,7 @@ char *BPy_enum_as_string(EnumPropertyItem *item) char *cstring; for (e= item; item->identifier; item++) { - if(item->identifier[0]) - BLI_dynstr_appendf(dynstr, (e==item)?"'%s'":", '%s'", item->identifier); + BLI_dynstr_appendf(dynstr, (e==item)?"'%s'":", '%s'", item->identifier); } cstring = BLI_dynstr_get_cstring(dynstr); @@ -444,33 +358,3 @@ int BPy_reports_to_error(ReportList *reports) return (report_str != NULL); } - -int BPy_errors_to_report(ReportList *reports) -{ - PyObject *pystring; - char *cstring; - - if (!PyErr_Occurred()) - return 1; - - /* less hassle if we allow NULL */ - if(reports==NULL) { - PyErr_Print(); - PyErr_Clear(); - return 1; - } - - pystring= BPY_exception_buffer(); - - if(pystring==NULL) { - BKE_report(reports, RPT_ERROR, "unknown py-exception, could not convert"); - return 0; - } - - cstring= _PyUnicode_AsString(pystring); - - BKE_report(reports, RPT_ERROR, cstring); - fprintf(stderr, "%s\n", cstring); // not exactly needed. just for testing - Py_DECREF(pystring); - return 1; -} diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h index 6429af67eb0..49f48802249 100644 --- a/source/blender/python/intern/bpy_util.h +++ b/source/blender/python/intern/bpy_util.h @@ -47,8 +47,6 @@ void PyObSpit(char *name, PyObject *var); void PyLineSpit(void); void BPY_getFileAndNum(char **filename, int *lineno); -PyObject *BPY_exception_buffer(void); - /* own python like utility function */ PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...); @@ -75,7 +73,6 @@ char *BPy_enum_as_string(struct EnumPropertyItem *item); /* error reporting */ int BPy_reports_to_error(struct ReportList *reports); -int BPy_errors_to_report(struct ReportList *reports); /* TODO - find a better solution! */ struct bContext *BPy_GetContext(void); diff --git a/source/blender/readblenfile/intern/BLO_readblenfile.c b/source/blender/readblenfile/intern/BLO_readblenfile.c index 40a991ad702..496ac529406 100644 --- a/source/blender/readblenfile/intern/BLO_readblenfile.c +++ b/source/blender/readblenfile/intern/BLO_readblenfile.c @@ -170,4 +170,3 @@ cleanup: return bfd; } - diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 65942a14be9..a047dc63829 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1439,7 +1439,7 @@ static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int if(sd->uvco && ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) { for(i=0; i<sd->totuv; i++) { if(num != DMCACHE_NOTFOUND) { - MFace *mface = dm->getFaceData(dm, num, CD_MFACE); + MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE); MTFace *mtface = (MTFace*)CustomData_get_layer_n(&dm->faceData, CD_MTFACE, i); mtface += num; @@ -1456,7 +1456,7 @@ static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int if(sd->mcol && ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) { for(i=0; i<sd->totcol; i++) { if(num != DMCACHE_NOTFOUND) { - MFace *mface = dm->getFaceData(dm, num, CD_MFACE); + MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE); MCol *mc = (MCol*)CustomData_get_layer_n(&dm->faceData, CD_MCOL, i); mc += num * 4; @@ -1671,8 +1671,8 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if(ma->amb != 0.0f) dosurfacecache= 1; - totface= psmd->dm->getNumFaces(psmd->dm); - origindex= psmd->dm->getFaceDataArray(psmd->dm, CD_ORIGINDEX); + totface= psmd->dm->getNumTessFaces(psmd->dm); + origindex= psmd->dm->getTessFaceDataArray(psmd->dm, CD_ORIGINDEX); if(origindex) { for(a=0; a<totface; a++) strandbuf->totbound= MAX2(strandbuf->totbound, origindex[a]); @@ -1732,7 +1732,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem num= pa->num_dmcache; if(num == DMCACHE_NOTFOUND) - if(pa->num < psmd->dm->getNumFaces(psmd->dm)) + if(pa->num < psmd->dm->getNumTessFaces(psmd->dm)) num= pa->num; get_particle_uvco_mcol(part->from, psmd->dm, pa->fuv, num, &sd); @@ -1807,7 +1807,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem num = parent->num_dmcache; if(num == DMCACHE_NOTFOUND) - if(parent->num < psmd->dm->getNumFaces(psmd->dm)) + if(parent->num < psmd->dm->getNumTessFaces(psmd->dm)) num = parent->num; get_particle_uvco_mcol(part->from, psmd->dm, parent->fuv, num, &sd); @@ -2889,10 +2889,10 @@ static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort) unsigned int *mcol=NULL; int a, totedge=0, totface; - mface= dm->getFaceArray(dm); - totface= dm->getNumFaces(dm); - tface= dm->getFaceDataArray(dm, CD_MTFACE); - mcol= dm->getFaceDataArray(dm, CD_MCOL); + mface= dm->getTessFaceArray(dm); + totface= dm->getNumTessFaces(dm); + tface= dm->getTessFaceDataArray(dm, CD_MTFACE); + mcol= dm->getTessFaceDataArray(dm, CD_MCOL); if(mcol==NULL && tface==NULL) return NULL; @@ -3068,7 +3068,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) totvert= dm->getNumVerts(dm); /* attempt to autsmooth on original mesh, only without subsurf */ - if(do_autosmooth && me->totvert==totvert && me->totface==dm->getNumFaces(dm)) + if(do_autosmooth && me->totvert==totvert && me->totface==dm->getNumTessFaces(dm)) use_original_normals= 1; ms = (totvert==me->totvert)?me->msticky:NULL; @@ -3129,8 +3129,8 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) } if(ok) { - end= dm->getNumFaces(dm); - mface= dm->getFaceArray(dm); + end= dm->getNumTessFaces(dm); + mface= dm->getTessFaceArray(dm); for(a=0; a<end; a++, mface++) { int v1, v2, v3, v4, flag; diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index 130cda9f107..f67826a9806 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -377,25 +377,6 @@ void renderspothalo(ShadeInput *shi, float *col, float alpha) /* ---------------- shaders ----------------------- */ -static double Normalize_d(double *n) -{ - double d; - - d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2]; - - if(d>0.00000000000000001) { - d= sqrt(d); - - n[0]/=d; - n[1]/=d; - n[2]/=d; - } else { - n[0]=n[1]=n[2]= 0.0; - d= 0.0; - } - return d; -} - /* mix of 'real' fresnel and allowing control. grad defines blending gradient */ float fresnel_fac(float *view, float *vn, float grad, float fac) { diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c index 3c8c1640b75..fc52f0fc9f4 100644 --- a/source/blender/render/intern/source/strand.c +++ b/source/blender/render/intern/source/strand.c @@ -943,7 +943,7 @@ StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, int a, totvert, totface; totvert= dm->getNumVerts(dm); - totface= dm->getNumFaces(dm); + totface= dm->getNumTessFaces(dm); for(mesh=re->strandsurface.first; mesh; mesh=mesh->next) if(mesh->obr.ob == obr->ob && mesh->obr.par == obr->par @@ -975,7 +975,7 @@ StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, Mat4MulVecfl(mat, co[a]); } - mface= dm->getFaceArray(dm); + mface= dm->getTessFaceArray(dm); for(a=0; a<mesh->totface; a++, mface++) { mesh->face[a][0]= mface->v1; mesh->face[a][1]= mface->v2; |