diff options
30 files changed, 7868 insertions, 1273 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 8b2882ca4e6..fe371c32529 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -45,142 +45,342 @@ * conversion to DLM. */ +#include "BKE_customdata.h" + struct MVert; +struct MEdge; +struct MFace; struct TFace; struct Object; +struct Mesh; struct EditMesh; struct DispListMesh; struct ModifierData; +/* 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 + typedef struct DerivedMesh DerivedMesh; struct DerivedMesh { + /* custom data for verts, edges & faces */ + CustomData vertData, edgeData, faceData; + /* Misc. Queries */ - /* Also called in Editmode */ + /* Also called in Editmode */ int (*getNumVerts)(DerivedMesh *dm); - /* Also called in Editmode */ + /* Also called in Editmode */ int (*getNumFaces)(DerivedMesh *dm); - /* Iterate over each mapped vertex in the derived mesh, calling the - * given function with the original vert and the mapped vert's new - * coordinate and normal. For historical reasons the normal can be - * passed as a float or short array, only one should be non-NULL. - */ - void (*foreachMappedVert)(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData); - - /* Iterate over each mapped vertex in the derived mesh, calling the - * given function with the original vert and the mapped edge's new - * coordinates. - */ - void (*foreachMappedEdge)(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData); - - /* Iterate over each mapped face in the derived mesh, calling the - * given function with the original face and the mapped face's (or - * faces') center and normal. - */ - void (*foreachMappedFaceCenter)(DerivedMesh *dm, void (*func)(void *userData, int index, float *cent, float *no), void *userData); - - /* Convert to new DispListMesh, should be free'd by caller. - * - * If allowShared is true then the caller is committing to not free'ng - * the DerivedMesh before free'ng the DispListMesh, which means that - * certain fields of the returned DispListMesh can safely be share with - * the DerivedMesh's internal data. - */ - struct DispListMesh* (*convertToDispListMesh)(DerivedMesh *dm, int allowShared); - - /* Iterate over all vertex points, calling DO_MINMAX with given args. - * - * Also called in Editmode - */ + int (*getNumEdges)(DerivedMesh *dm); + + /* copy a single vert/edge/face from the derived mesh into + * *{vert/edge/face}_r + */ + 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); + + /* copy all verts/edges/faces from the derived mesh into + * *{vert/edge/face}_r (must point to a buffer large enough) + */ + void (*getVertArray)(DerivedMesh *dm, struct MVert *vert_r); + void (*getEdgeArray)(DerivedMesh *dm, struct MEdge *edge_r); + void (*getFaceArray)(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); + + /* 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 + * a copy) + */ + void *(*getVertData)(DerivedMesh *dm, int index, int type); + void *(*getEdgeData)(DerivedMesh *dm, int index, int type); + void *(*getFaceData)(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 + * a copy) + */ + void *(*getVertDataArray)(DerivedMesh *dm, int type); + void *(*getEdgeDataArray)(DerivedMesh *dm, int type); + void *(*getFaceDataArray)(DerivedMesh *dm, int type); + + /* Iterate over each mapped vertex in the derived mesh, calling the + * given function with the original vert and the mapped vert's new + * coordinate and normal. For historical reasons the normal can be + * passed as a float or short array, only one should be non-NULL. + */ + void (*foreachMappedVert)( + DerivedMesh *dm, + void (*func)(void *userData, int index, float *co, + float *no_f, short *no_s), + void *userData); + + /* Iterate over each mapped edge in the derived mesh, calling the + * given function with the original edge and the mapped edge's new + * coordinates. + */ + void (*foreachMappedEdge)(DerivedMesh *dm, + void (*func)(void *userData, int index, + float *v0co, float *v1co), + void *userData); + + /* Iterate over each mapped face in the derived mesh, calling the + * given function with the original face and the mapped face's (or + * faces') center and normal. + */ + void (*foreachMappedFaceCenter)(DerivedMesh *dm, + void (*func)(void *userData, int index, + float *cent, float *no), + void *userData); + + /* Convert to new DispListMesh, should be free'd by caller. + * + * If allowShared is true then the caller is committing to not free'ng + * the DerivedMesh before free'ng the DispListMesh, which means that + * certain fields of the returned DispListMesh can safely be share with + * the DerivedMesh's internal data. + */ + struct DispListMesh* (*convertToDispListMesh)(DerivedMesh *dm, + int allowShared); + + /* Iterate over all vertex points, calling DO_MINMAX with given args. + * + * Also called in Editmode + */ void (*getMinMax)(DerivedMesh *dm, float min_r[3], float max_r[3]); /* Direct Access Operations */ /* o Can be undefined */ /* o Must be defined for modifiers that only deform however */ - - /* Get vertex location, undefined if index is not valid */ + + /* Get vertex location, undefined if index is not valid */ void (*getVertCo)(DerivedMesh *dm, int index, float co_r[3]); - /* Fill the array (of length .getNumVerts()) with all vertex locations */ + /* Fill the array (of length .getNumVerts()) with all vertex locations */ void (*getVertCos)(DerivedMesh *dm, float (*cos_r)[3]); - /* Get vertex normal, undefined if index is not valid */ + /* Get vertex normal, undefined if index is not valid */ void (*getVertNo)(DerivedMesh *dm, int index, float no_r[3]); /* Drawing Operations */ - /* Draw all vertices as bgl points (no options) */ + /* Draw all vertices as bgl points (no options) */ void (*drawVerts)(DerivedMesh *dm); - /* Draw edges in the UV mesh (if exists) */ + /* Draw edges in the UV mesh (if exists) */ void (*drawUVEdges)(DerivedMesh *dm); - /* Draw all edges as lines (no options) - * - * Also called for *final* editmode DerivedMeshes - */ + /* Draw all edges as lines (no options) + * + * Also called for *final* editmode DerivedMeshes + */ void (*drawEdges)(DerivedMesh *dm, int drawLooseEdges); - /* Draw all loose edges (edges w/ no adjoining faces) */ + /* Draw all loose edges (edges w/ no adjoining faces) */ void (*drawLooseEdges)(DerivedMesh *dm); - /* Draw all faces - * o Set face normal or vertex normal based on inherited face flag - * o Use inherited face material index to call setMaterial - * o Only if setMaterial returns true - * - * Also called for *final* editmode DerivedMeshes - */ + /* Draw all faces + * o Set face normal or vertex normal based on inherited face flag + * o Use inherited face material index to call setMaterial + * o Only if setMaterial returns true + * + * Also called for *final* editmode DerivedMeshes + */ void (*drawFacesSolid)(DerivedMesh *dm, int (*setMaterial)(int)); - /* Draw all faces - * o If useTwoSided, draw front and back using col arrays - * o col1,col2 are arrays of length numFace*4 of 4 component colors - * in ABGR format, and should be passed as per-face vertex color. - */ - void (*drawFacesColored)(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2); - - /* Draw all faces using TFace - * o Drawing options too complicated to enumerate, look at code. - */ - void (*drawFacesTex)(DerivedMesh *dm, int (*setDrawOptions)(struct TFace *tface, int matnr)); - - /* Draw mapped faces (no color, or texture) - * o Only if !setDrawOptions or setDrawOptions(userData, mapped-face-index, drawSmooth_r) returns true - * - * If drawSmooth is set to true then vertex normals should be set and glShadeModel - * called with GL_SMOOTH. Otherwise the face normal should be set and glShadeModel - * called with GL_FLAT. - * - * The setDrawOptions is allowed to not set drawSmooth (for example, when lighting - * is disabled), in which case the implementation should draw as smooth shaded. - */ - void (*drawMappedFaces)(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors); - - /* Draw mapped faces using TFace - * o Drawing options too complicated to enumerate, look at code. - */ - void (*drawMappedFacesTex)(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData); - - /* Draw mapped edges as lines - * o Only if !setDrawOptions or setDrawOptions(userData, mapped-edge) returns true - */ - void (*drawMappedEdges)(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData); - - /* Draw mapped edges as lines with interpolation values - * o Only if !setDrawOptions or setDrawOptions(userData, mapped-edge, mapped-v0, mapped-v1, t) returns true - * - * NOTE: This routine is optional! - */ + /* Draw all faces + * o If useTwoSided, draw front and back using col arrays + * o col1,col2 are arrays of length numFace*4 of 4 component colors + * in ABGR format, and should be passed as per-face vertex color. + */ + void (*drawFacesColored)(DerivedMesh *dm, int useTwoSided, + unsigned char *col1, unsigned char *col2); + + /* Draw all faces using TFace + * o Drawing options too complicated to enumerate, look at code. + */ + void (*drawFacesTex)(DerivedMesh *dm, + int (*setDrawOptions)(struct TFace *tface, int matnr)); + + /* Draw mapped faces (no color, or texture) + * o Only if !setDrawOptions or + * setDrawOptions(userData, mapped-face-index, drawSmooth_r) + * returns true + * + * If drawSmooth is set to true then vertex normals should be set and + * glShadeModel called with GL_SMOOTH. Otherwise the face normal should + * be set and glShadeModel called with GL_FLAT. + * + * The setDrawOptions is allowed to not set drawSmooth (for example, when + * lighting is disabled), in which case the implementation should draw as + * smooth shaded. + */ + void (*drawMappedFaces)(DerivedMesh *dm, + int (*setDrawOptions)(void *userData, int index, + int *drawSmooth_r), + void *userData, int useColors); + + /* Draw mapped faces using TFace + * o Drawing options too complicated to enumerate, look at code. + */ + void (*drawMappedFacesTex)(DerivedMesh *dm, + int (*setDrawOptions)(void *userData, + int index), + void *userData); + + /* Draw mapped edges as lines + * o Only if !setDrawOptions or setDrawOptions(userData, mapped-edge) + * returns true + */ + void (*drawMappedEdges)(DerivedMesh *dm, + int (*setDrawOptions)(void *userData, int index), + void *userData); + + /* Draw mapped edges as lines with interpolation values + * o Only if !setDrawOptions or + * setDrawOptions(userData, mapped-edge, mapped-v0, mapped-v1, t) + * returns true + * + * NOTE: This routine is optional! + */ void (*drawMappedEdgesInterp)(DerivedMesh *dm, - int (*setDrawOptions)(void *userData, int index), - void (*setDrawInterpOptions)(void *userData, int index, float t), - void *userData); + int (*setDrawOptions)(void *userData, + int index), + void (*setDrawInterpOptions)(void *userData, + int index, + float t), + void *userData); void (*release)(DerivedMesh *dm); }; +/* utility function to initialise a DerivedMesh's function pointers to + * the default implementation (for those functions which have a default) + */ +void DM_init_funcs(DerivedMesh *dm); + +/* utility function to initialise a DerivedMesh for the desired number + * 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); + +/* 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); + +/* utility function to release a DerivedMesh's layers + */ +void DM_release(DerivedMesh *dm); + +/* utility function to convert a DerivedMesh to a Mesh + */ +void DM_to_mesh(DerivedMesh *dm, struct Mesh *me); + +/* adds a vertex/edge/face custom data layer to a DerivedMesh, optionally + * backed by an external data array + * if layer != NULL, it is used as the layer data array, otherwise new memory + * is allocated + * the layer data will be freed by dm->release unless + * (flag & LAYERFLAG_NOFREE) is true + */ +void DM_add_vert_layer(struct DerivedMesh *dm, int type, int flag, + void *layer); +void DM_add_edge_layer(struct DerivedMesh *dm, int type, int flag, + void *layer); +void DM_add_face_layer(struct DerivedMesh *dm, int type, int flag, + void *layer); + +/* custom data access functions + * return pointer to data from first layer which matches type + * if they return NULL for valid indices, data doesn't exist + * note these return pointers - any change modifies the internals of the mesh + */ +void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type); +void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type); +void *DM_get_face_data(struct DerivedMesh *dm, int index, int type); + +/* custom data layer access functions + * return pointer to first data layer which matches type (a flat array) + * if they return NULL, data doesn't exist + * note these return pointers - any change modifies the internals of the mesh + */ +void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type); +void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type); +void *DM_get_face_data_layer(struct DerivedMesh *dm, int type); + +/* custom data setting functions + * copy supplied data into first layer of type using layer's copy function + * (deep copy if appropriate) + */ +void DM_set_vert_data(struct DerivedMesh *dm, int index, int type, void *data); +void DM_set_edge_data(struct DerivedMesh *dm, int index, int type, void *data); +void DM_set_face_data(struct DerivedMesh *dm, int index, int type, void *data); + +/* custom data copy functions + * copy count elements from source_index in source to dest_index in dest + * these copy all layers for which the LAYERFLAG_NOCOPY flag is not set + */ +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_face_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int source_index, int dest_index, int count); + +/* custom data free functions + * free count elements, starting at index + * they free all layers for which the LAYERFLAG_NOFREE flag is not set + */ +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_face_data(struct DerivedMesh *dm, int index, int count); + +/* 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 + */ +void DM_interp_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int *src_indices, float *weights, + int count, int dest_index); + +/* interpolates edge data from the edges indexed by src_indices in the + * source mesh using the given weights and stores the result in the edge indexed + * by dest_index in the dest mesh. + * if weights is NULL, all weights default to 1. + * if vert_weights is non-NULL, any per-vertex edge data is interpolated using + * vert_weights[i] multiplied by weights[i]. + */ +typedef float EdgeVertWeight[SUB_ELEMS_EDGE][SUB_ELEMS_EDGE]; +void DM_interp_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest, + int *src_indices, + float *weights, EdgeVertWeight *vert_weights, + int count, int dest_index); + +/* interpolates face data from the faces indexed by src_indices in the + * source mesh using the given weights and stores the result in the face indexed + * by dest_index in the dest mesh. + * if weights is NULL, all weights default to 1. + * if vert_weights is non-NULL, any per-vertex face data is interpolated using + * 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, + int *src_indices, + float *weights, FaceVertWeight *vert_weights, + int count, int dest_index); + /* Simple function to get me->totvert amount of vertices/normals, correctly deformed and subsurfered. Needed especially when vertexgroups are involved. In use now by vertex/weigt paint and particles */ diff --git a/source/blender/blenkernel/BKE_booleanops.h b/source/blender/blenkernel/BKE_booleanops.h index f033dd70003..ddc24457ef4 100644 --- a/source/blender/blenkernel/BKE_booleanops.h +++ b/source/blender/blenkernel/BKE_booleanops.h @@ -57,7 +57,10 @@ NewBooleanMesh( struct DispListMesh *NewBooleanMeshDLM(struct Object *ob, struct Object *ob_select, int int_op_type); - +struct DerivedMesh *NewBooleanDerivedMesh(struct Object *ob, + struct Object *ob_select, + int int_op_type); + /** * Functions exposed for use by BKE_booleanops_mesh */ diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h new file mode 100644 index 00000000000..b8313440551 --- /dev/null +++ b/source/blender/blenkernel/BKE_cdderivedmesh.h @@ -0,0 +1,102 @@ +/* +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* The Original Code is Copyright (C) 2006 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Ben Batt <benbatt@gmail.com> +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +/* CDDerivedMesh interface. + * CDDerivedMesh (CD = Custom Data) is a DerivedMesh backend which stores + * mesh elements (vertices, edges and faces) as layers of custom element data. + */ + +#ifndef BKE_CDDERIVEDMESH_H +#define BKE_CDDERIVEDMESH_H + +#include "BKE_DerivedMesh.h" + +struct DerivedMesh; +struct EditMesh; +struct Mesh; + +/* creates a new CDDerivedMesh */ +struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces); + +/* creates a CDDerivedMesh from the given Mesh */ +struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh); + +/* creates a CDDerivedMesh from the given EditMesh */ +struct DerivedMesh *CDDM_from_editmesh(struct EditMesh *em, struct Mesh *me); + +/* Copies the given DerivedMesh with verts, faces & edges stored as + * custom element data. + */ +struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm); + +/* creates a CDDerivedMesh with the same layer stack configuration as the + * given DerivedMesh and containing the requested numbers of elements. + * elements are initialised to all zeros + */ +struct DerivedMesh *CDDM_from_template(struct DerivedMesh *source, + int numVerts, int numEdges, int numFaces); + +/* applies vertex coordinates to a CDDerivedMesh + */ +void CDDM_apply_vert_coords(struct DerivedMesh *cddm, float (*vertCoords)[3]); + +/* recalculates normals for a CDDerivedMesh + */ +void CDDM_calc_normals(struct DerivedMesh *dm); + +/* calculates edges for a CDDerivedMesh (from face data) + * this completely replaces the current edge data in the DerivedMesh + */ +void CDDM_calc_edges(struct DerivedMesh *dm); + +/* sets the number of vertices/edges/faces in a CDDerivedMesh + * if the value given is more than the maximum, the maximum is used + */ +void CDDM_set_num_verts(struct DerivedMesh *dm, int numVerts); +void CDDM_set_num_edges(struct DerivedMesh *dm, int numEdges); +void CDDM_set_num_faces(struct DerivedMesh *dm, int numFaces); + +/* vertex/edge/face access functions + * should always succeed if index is within bounds + * note these return pointers - any change modifies the internals of the mesh + */ +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); + +/* vertex/edge/face array access functions - return the array holding the + * desired data + * should always succeed + * note these return pointers - any change modifies the internals of the mesh + */ +struct MVert *CDDM_get_verts(struct DerivedMesh *dm); +struct MEdge *CDDM_get_edges(struct DerivedMesh *dm); +struct MFace *CDDM_get_faces(struct DerivedMesh *dm); +#endif + diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h new file mode 100644 index 00000000000..6f8d9911d89 --- /dev/null +++ b/source/blender/blenkernel/BKE_customdata.h @@ -0,0 +1,161 @@ +/* +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* The Original Code is Copyright (C) 2006 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Ben Batt <benbatt@gmail.com> +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +/* CustomData interface. + * CustomData is a structure which stores custom element data associated + * with mesh elements (vertices, edges or faces). The custom data is + * organised into a series of layers, each with a data type (e.g. TFace, + * MDeformVert, etc.). + */ + +#ifndef BKE_CUSTOMDATA_H +#define BKE_CUSTOMDATA_H + +typedef struct CustomData { + struct LayerDesc *layers; /* data layer descriptors, ordered by type */ + int numLayers; /* current number of layers */ + int maxLayers; /* maximum number of layers */ + int numElems; /* current number of elements */ + int maxElems; /* maximum number of elements */ + int subElems; /* number of sub-elements layers can have */ +} CustomData; + +/* custom data types */ +enum { + LAYERTYPE_MVERT = 0, + LAYERTYPE_MSTICKY, + LAYERTYPE_MDEFORMVERT, + LAYERTYPE_MEDGE, + LAYERTYPE_MFACE, + LAYERTYPE_TFACE, + LAYERTYPE_MCOL, + LAYERTYPE_ORIGINDEX, + LAYERTYPE_NORMAL, + LAYERTYPE_FLAGS, + LAYERTYPE_NUMTYPES +}; + +#define ORIGINDEX_NONE -1 /* indicates no original index for this element */ + +/* layer flags - to be used with CustomData_add_layer */ + +/* indicates layer should not be copied by CustomData_from_template or + * CustomData_copy_data (for temporary utility layers) + */ +#define LAYERFLAG_NOCOPY 1<<0 + +/* indicates layer should not be freed (for layers backed by external data) + */ +#define LAYERFLAG_NOFREE 1<<1 + +/* initialises a CustomData object with space for the given number + * of data layers and the given number of elements per layer + */ +void CustomData_init(CustomData *data, + int maxLayers, int maxElems, int subElems); + +/* initialises a CustomData object with the same layer setup as source + * and memory space for maxElems elements + */ +void CustomData_from_template(const CustomData *source, CustomData *dest, + int maxElems); + +/* frees data associated with a CustomData object (doesn't free the object + * itself, though) + */ +void CustomData_free(CustomData *data); + +/* adds a data layer of the given type to the CustomData object, optionally + * backed by an external data array + * if layer != NULL, it is used as the layer data array, otherwise new memory + * is allocated + * the layer data will be freed by CustomData_free unless + * (flag & LAYERFLAG_NOFREE) is true + * grows the number of layers in data if data->maxLayers has been reached + * returns 1 on success, 0 on failure + */ +int CustomData_add_layer(CustomData *data, int type, int flag, void *layer); + +/* returns 1 if the two objects are compatible (same layer types and + * flags in the same order), 0 if not + */ +int CustomData_compat(const CustomData *data1, const CustomData *data2); + +/* copies data from one CustomData object to another + * objects need not be compatible, each source layer is copied to the + * first dest layer of correct type (if there is none, the layer is skipped) + * return 1 on success, 0 on failure + */ +int CustomData_copy_data(const CustomData *source, CustomData *dest, + int source_index, int dest_index, int count); + +/* frees data in a CustomData object + * return 1 on success, 0 on failure + */ +int CustomData_free_elem(CustomData *data, int index, int count); + +/* interpolates data from one CustomData object to another + * objects need not be compatible, each source layer is interpolated to the + * first dest layer of correct type (if there is none, the layer is skipped) + * if weights == NULL or sub_weights == NULL, they default to all 1's + * + * src_indices gives the source elements to interpolate from + * weights gives the weight for each source element + * sub_weights is an array of matrices of weights for sub-elements (matrices + * should be source->subElems * source->subElems in size) + * count gives the number of source elements to interpolate from + * dest_index gives the dest element to write the interpolated value to + * + * returns 1 on success, 0 on failure + */ +int CustomData_interp(const CustomData *source, CustomData *dest, + int *src_indices, float *weights, float *sub_weights, + int count, int dest_index); + +/* gets a pointer to the data element at index from the first layer of type + * returns NULL if there is no layer of type + */ +void *CustomData_get(const CustomData *data, int index, int type); + +/* gets a pointer to the first layer of type + * returns NULL if there is no layer of type + */ +void *CustomData_get_layer(const CustomData *data, int type); + +/* copies the data from source to the data element at index in the first + * layer of type + * no effect if there is no layer of type + */ +void CustomData_set(const CustomData *data, int index, int type, void *source); + +/* sets the number of elements in a CustomData object + * if the value given is more than the maximum, the maximum is used + */ +void CustomData_set_num_elems(CustomData *data, int numElems); +#endif diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 2f7ae6bb329..a7533a614eb 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -36,6 +36,7 @@ struct Lattice; struct Object; +struct DerivedMesh; struct BPoint; extern struct Lattice *editLatt; @@ -52,9 +53,13 @@ void calc_latt_deform(float *co, float weight); void end_latt_deform(void); int object_deform_mball(struct Object *ob); void outside_lattice(struct Lattice *lt); -void curve_deform_verts(struct Object *cuOb, struct Object *target, float (*vertexCos)[3], int numVerts, char *vgroup); -void lattice_deform_verts(struct Object *laOb, struct Object *target, float (*vertexCos)[3], int numVerts, char *vgroup); -void armature_deform_verts(struct Object *armOb, struct Object *target, float (*vertexCos)[3], int numVerts, int deformflag); +void curve_deform_verts(struct Object *cuOb, struct Object *target, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup); +void lattice_deform_verts(struct Object *laOb, struct Object *target, + struct DerivedMesh *dm, float (*vertexCos)[3], + int numVerts, char *vgroup); +void armature_deform_verts(struct Object *armOb, struct Object *target, + struct DerivedMesh *dm, float (*vertexCos)[3], + int numVerts, int deformflag); float (*lattice_getVertexCos(struct Object *ob, int *numVerts_r))[3]; void lattice_applyVertexCos(struct Object *ob, float (*vertexCos)[3]); void lattice_calc_modifiers(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 9afefbfc5a9..a4c050429e5 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -33,6 +33,7 @@ #ifndef BKE_MODIFIER_H #define BKE_MODIFIER_H +struct EditMesh; struct DerivedMesh; struct DagForest; struct DagNode; @@ -41,14 +42,14 @@ struct ListBase; struct bArmature; typedef enum { - /* Should not be used, only for None modifier type */ + /* Should not be used, only for None modifier type */ eModifierTypeType_None, - /* Modifier only does deformation, implies that modifier - * type should have a valid deformVerts function. OnlyDeform - * style modifiers implicitly accept either mesh or CV - * input but should still declare flags appropriately. - */ + /* Modifier only does deformation, implies that modifier + * type should have a valid deformVerts function. OnlyDeform + * style modifiers implicitly accept either mesh or CV + * input but should still declare flags appropriately. + */ eModifierTypeType_OnlyDeform, eModifierTypeType_Constructive, @@ -56,165 +57,203 @@ typedef enum { } ModifierTypeType; typedef enum { - eModifierTypeFlag_AcceptsMesh = (1<<0), - eModifierTypeFlag_AcceptsCVs = (1<<1), - eModifierTypeFlag_SupportsMapping = (1<<2), - eModifierTypeFlag_SupportsEditmode = (1<<3), - - /* For modifiers that support editmode this determines if the - * modifier should be enabled by default in editmode. This should - * only be used by modifiers that are relatively speedy and - * also generally used in editmode, otherwise let the user enable - * it by hand. - */ - eModifierTypeFlag_EnableInEditmode = (1<<4), - - /* For modifiers that require original data and so cannot - * be placed after any non-deformative modifier. - */ + eModifierTypeFlag_AcceptsMesh = (1<<0), + eModifierTypeFlag_AcceptsCVs = (1<<1), + eModifierTypeFlag_SupportsMapping = (1<<2), + eModifierTypeFlag_SupportsEditmode = (1<<3), + + /* For modifiers that support editmode this determines if the + * modifier should be enabled by default in editmode. This should + * only be used by modifiers that are relatively speedy and + * also generally used in editmode, otherwise let the user enable + * it by hand. + */ + eModifierTypeFlag_EnableInEditmode = (1<<4), + + /* For modifiers that require original data and so cannot + * be placed after any non-deformative modifier. + */ eModifierTypeFlag_RequiresOriginalData = (1<<5), } ModifierTypeFlag; +typedef void (*ObjectWalkFunc)(void *userData, Object *ob, Object **obpoin); +typedef void (*IDWalkFunc)(void *userData, Object *ob, ID **idpoin); + typedef struct ModifierTypeInfo { - /* The user visible name for this modifier */ + /* The user visible name for this modifier */ char name[32]; - /* The DNA struct name for the modifier data type, used to - * write the DNA data out. - */ + /* The DNA struct name for the modifier data type, used to + * write the DNA data out. + */ char structName[32]; - /* The size of the modifier data type, used by allocation. */ + /* The size of the modifier data type, used by allocation. */ int structSize; ModifierTypeType type; ModifierTypeFlag flags; - /* Initialize new instance data for this modifier type, this function - * should set modifier variables to their default values. - * - * This function is optional. - */ - void (*initData)(ModifierData *md); - /* Copy instance data for this modifier type. Should copy all user - * level settings to the target modifier. - */ + /********************* Non-optional functions *********************/ + + /* Copy instance data for this modifier type. Should copy all user + * level settings to the target modifier. + */ void (*copyData)(ModifierData *md, ModifierData *target); - /* Free internal modifier data variables, this function should - * not free the _md_ variable itself. - * - * This function is optional. - */ + + /********************* Deform modifier functions *********************/ + + /* Only for deform types, should apply the deformation + * to the given vertex array. If the deformer requires information from + * the object it can obtain it from the derivedData argument if non-NULL, + * and otherwise the ob argument. + */ + void (*deformVerts)(ModifierData *md, struct Object *ob, + struct DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts); + + /* Like deformVerts but called during editmode (for supporting modifiers) + */ + void (*deformVertsEM)( + ModifierData *md, struct Object *ob, + struct EditMesh *editData, struct DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts); + + + /********************* Non-deform modifier functions *********************/ + + /* For non-deform types: apply the modifier and return a derived + * data object (type is dependent on object type). + * + * The derivedData argument should always be non-NULL; the modifier + * should read the object data from the derived object instead of the + * actual object data. + * + * The useRenderParams argument indicates if the modifier is being + * applied in the service of the renderer which may alter quality + * settings. + * + * The isFinalCalc parameter indicates if the modifier is being + * calculated for a final result or for something temporary + * (like orcos). This is a hack at the moment, it is meant so subsurf + * can know if it is safe to reuse its internal cache. + * + * The modifier may reuse the derivedData argument (i.e. return it in + * modified form), but must not release it. + */ + struct DerivedMesh *(*applyModifier)( + ModifierData *md, struct Object *ob, + struct DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc); + + /* Like applyModifier but called during editmode (for supporting + * modifiers). + * + * The derived object that is returned must support the operations that + * are expected from editmode objects. The same qualifications regarding + * derivedData apply as for applyModifier. + */ + struct DerivedMesh *(*applyModifierEM)( + ModifierData *md, struct Object *ob, + struct EditMesh *editData, + struct DerivedMesh *derivedData); + + + /********************* Optional functions *********************/ + + /* Initialize new instance data for this modifier type, this function + * should set modifier variables to their default values. + * + * This function is optional. + */ + void (*initData)(ModifierData *md); + + /* Free internal modifier data variables, this function should + * not free the md variable itself. + * + * This function is optional. + */ void (*freeData)(ModifierData *md); - /* Return a boolean value indicating if this modifier is able to be calculated - * based on the modifier data. This is *not* regarding the md->flag, that is - * tested by the system, this is just if the data validates (for example, a - * lattice will return false if the lattice object is not defined). - * - * This function is optional (assumes never disabled if not present). - */ + /* Return a boolean value indicating if this modifier is able to be + * calculated based on the modifier data. This is *not* regarding the + * md->flag, that is tested by the system, this is just if the data + * validates (for example, a lattice will return false if the lattice + * object is not defined). + * + * This function is optional (assumes never disabled if not present). + */ int (*isDisabled)(ModifierData *md); - /* Add the appropriate relations to the DEP graph depending on the modifier - * data. - * - * This function is optional. - */ - void (*updateDepgraph)(ModifierData *md, struct DagForest *forest, struct Object *ob, struct DagNode *obNode); - - /* Should return true if the modifier needs to be recalculated on time changes. - * - * This function is optional (assumes false if not present). - */ - int (*dependsOnTime)(ModifierData *md); + /* Add the appropriate relations to the DEP graph depending on the + * modifier data. + * + * This function is optional. + */ + void (*updateDepgraph)(ModifierData *md, struct DagForest *forest, + struct Object *ob, struct DagNode *obNode); - /* Should call the given _walk_ function on with a pointer to each Object pointer - * that the modifier data stores. This is used for linking on file load and for - * unlinking objects or forwarding object references. - * - * This function is optional. - */ - void (*foreachObjectLink)(ModifierData *md, struct Object *ob, void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData); - - /* Only for deform types, should apply the deformation - * to the given vertex array. If the deformer requires information from - * the object it can obtain it from the _derivedData_ argument if non-NULL, - * and otherwise the _ob_ argument. - */ - void (*deformVerts)(ModifierData *md, struct Object *ob, void *derivedData, float (*vertexCos)[3], int numVerts); - - /* Like deformVerts but called during editmode (for supporting modifiers) */ - void (*deformVertsEM)(ModifierData *md, struct Object *ob, void *editData, void *derivedData, float (*vertexCos)[3], int numVerts); - - /* For non-deform types: apply the modifier and return a new derived - * data object (type is dependent on object type). If the _derivedData_ - * argument is non-NULL then the modifier should read the object data - * from the derived object instead of the actual object data. - * - * If the _vertexCos_ argument is non-NULL then the modifier should read - * the vertex coordinates from that (even if _derivedData_ is non-NULL). - * The length of the _vertexCos_ array is either the number of verts in - * the derived object (if non-NULL) or otherwise the number of verts in - * the original object. - * - * The _useRenderParams_ indicates if the modifier is being applied in - * the service of the renderer which may alter quality settings. - * - * The _isFinalCalc_ parameter indicates if the modifier is being calculated - * for a final result or for something temporary (like orcos). This is a hack - * at the moment, it is meant so subsurf can know if it is safe to reuse its - * internal cache. - * - * The modifier *MAY NOT* reuse or release the _derivedData_ argument - * if non-NULL. The modifier *MAY NOT* share the _vertexCos_ argument. - */ - void *(*applyModifier)(ModifierData *md, struct Object *ob, void *derivedData, float (*vertexCos)[3], int useRenderParams, int isFinalCalc); - - /* Like applyModifier but called during editmode (for supporting modifiers). - * - * The derived object that is returned must support the operations that are expected - * from editmode objects. The same qualifications regarding _derivedData_ and _vertexCos_ - * apply as for applyModifier. - */ - void *(*applyModifierEM)(ModifierData *md, struct Object *ob, void *editData, void *derivedData, float (*vertexCos)[3]); -} ModifierTypeInfo; + /* Should return true if the modifier needs to be recalculated on time + * changes. + * + * This function is optional (assumes false if not present). + */ + int (*dependsOnTime)(ModifierData *md); -ModifierTypeInfo* modifierType_getInfo (ModifierType type); + /* Should call the given walk function on with a pointer to each Object + * pointer that the modifier data stores. This is used for linking on file + * load and for unlinking objects or forwarding object references. + * + * This function is optional. + */ + void (*foreachObjectLink)(ModifierData *md, struct Object *ob, + ObjectWalkFunc walk, void *userData); - /* Modifier utility calls, do call through type pointer and return - * default values if pointer is optional. + /* Should call the given walk function with a pointer to each ID + * pointer (i.e. each datablock pointer) that the modifier data + * stores. This is used for linking on file load and for + * unlinking datablocks or forwarding datablock references. + * + * This function is optional. If it is not present, foreachObjectLink + * will be used. */ -ModifierData* modifier_new (int type); -void modifier_free (ModifierData *md); + void (*foreachIDLink)(ModifierData *md, struct Object *ob, + IDWalkFunc walk, void *userData); +} ModifierTypeInfo; -void modifier_copyData (ModifierData *md, ModifierData *target); -int modifier_dependsOnTime (ModifierData *md); -int modifier_supportsMapping (ModifierData *md); -int modifier_couldBeCage (ModifierData *md); -void modifier_setError (ModifierData *md, char *format, ...); +ModifierTypeInfo *modifierType_getInfo (ModifierType type); -void modifiers_foreachObjectLink (struct Object *ob, void (*walk)(void *userData, struct Object *ob, struct Object **obpoin), void *userData); -ModifierData* modifiers_findByType (struct Object *ob, ModifierType type); -void modifiers_clearErrors (struct Object *ob); -int modifiers_getCageIndex (struct Object *ob, int *lastPossibleCageIndex_r); +/* Modifier utility calls, do call through type pointer and return + * default values if pointer is optional. + */ +ModifierData *modifier_new(int type); +void modifier_free(ModifierData *md); -int modifiers_isSoftbodyEnabled (struct Object *ob); -struct Object* modifiers_isDeformedByArmature(struct Object *ob); -int modifiers_usesArmature(struct Object *ob, struct bArmature *arm); -int modifiers_isDeformed (struct Object *ob); +void modifier_copyData(ModifierData *md, ModifierData *target); +int modifier_dependsOnTime(ModifierData *md); +int modifier_supportsMapping(ModifierData *md); +int modifier_couldBeCage(ModifierData *md); +void modifier_setError(ModifierData *md, char *format, ...); -ModifierData* modifiers_getVirtualModifierList (struct Object *ob); +void modifiers_foreachObjectLink(struct Object *ob, + ObjectWalkFunc walk, + void *userData); +void modifiers_foreachIDLink(struct Object *ob, + IDWalkFunc walk, + void *userData); +ModifierData *modifiers_findByType(struct Object *ob, ModifierType type); +void modifiers_clearErrors(struct Object *ob); +int modifiers_getCageIndex(struct Object *ob, + int *lastPossibleCageIndex_r); - /* Modifier utility calls, do call through type pointer and return - * default values if pointer is optional. - */ -struct ModifierData* modifier_new (int type); -void modifier_free (struct ModifierData *md); +int modifiers_isSoftbodyEnabled(struct Object *ob); +struct Object *modifiers_isDeformedByArmature(struct Object *ob); +int modifiers_usesArmature(struct Object *ob, struct bArmature *arm); +int modifiers_isDeformed(struct Object *ob); -int modifier_dependsOnTime (struct ModifierData *md); +ModifierData *modifiers_getVirtualModifierList(struct Object *ob); #endif diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h index 2289fb027eb..3d1ffd3e52f 100644 --- a/source/blender/blenkernel/BKE_subsurf.h +++ b/source/blender/blenkernel/BKE_subsurf.h @@ -40,6 +40,11 @@ struct SubsurfModifierData; struct DerivedMesh *subsurf_make_derived_from_editmesh(struct EditMesh *em, struct SubsurfModifierData *smd, float (*vertexCos)[3]); struct DerivedMesh *subsurf_make_derived_from_dlm_em(struct DispListMesh *dlm, struct SubsurfModifierData *smd, float (*vertCos)[3]); struct DerivedMesh *subsurf_make_derived_from_mesh(struct Mesh *me, struct DispListMesh *dlm, struct SubsurfModifierData *smd, int useRenderParams, float (*vertCos)[3], int isFinalCalc); +struct DerivedMesh *subsurf_make_derived_from_derived( + struct DerivedMesh *dm, + struct SubsurfModifierData *smd, + int useRenderParams, float (*vertCos)[3], + int isFinalCalc, int editMode); void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 4187e5c0320..016d5c298c3 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -44,6 +44,7 @@ #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" @@ -56,6 +57,7 @@ #include "BLI_editVert.h" #include "BKE_utildefines.h" +#include "BKE_cdderivedmesh.h" #include "BKE_DerivedMesh.h" #include "BKE_displist.h" #include "BKE_effect.h" @@ -82,6 +84,269 @@ /////////////////////////////////// /////////////////////////////////// +#define DERIVEDMESH_INITIAL_LAYERS 5 + +MVert *dm_dupVertArray(DerivedMesh *dm) +{ + MVert *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumVerts(dm), + "dm_dupVertArray tmp"); + + if(tmp) dm->getVertArray(dm, tmp); + + return tmp; +} + +MEdge *dm_dupEdgeArray(DerivedMesh *dm) +{ + MEdge *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumEdges(dm), + "dm_dupEdgeArray tmp"); + + if(tmp) dm->getEdgeArray(dm, tmp); + + return tmp; +} + +MFace *dm_dupFaceArray(DerivedMesh *dm) +{ + MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumFaces(dm), + "dm_dupFaceArray tmp"); + + if(tmp) dm->getFaceArray(dm, tmp); + + return tmp; +} + +void DM_init_funcs(DerivedMesh *dm) +{ + /* default function implementations */ + dm->dupVertArray = dm_dupVertArray; + dm->dupEdgeArray = dm_dupEdgeArray; + dm->dupFaceArray = dm_dupFaceArray; + + dm->getVertData = DM_get_vert_data; + dm->getEdgeData = DM_get_edge_data; + dm->getFaceData = 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; +} + +void DM_init(DerivedMesh *dm, + int numVerts, int numEdges, int numFaces) +{ + if(numVerts > 0) { + CustomData_init(&dm->vertData, DERIVEDMESH_INITIAL_LAYERS, numVerts, + SUB_ELEMS_VERT); + CustomData_init(&dm->edgeData, DERIVEDMESH_INITIAL_LAYERS, numEdges, + SUB_ELEMS_EDGE); + CustomData_init(&dm->faceData, DERIVEDMESH_INITIAL_LAYERS, numFaces, + SUB_ELEMS_FACE); + + CustomData_add_layer(&dm->vertData, LAYERTYPE_ORIGINDEX, 0, NULL); + CustomData_add_layer(&dm->edgeData, LAYERTYPE_ORIGINDEX, 0, NULL); + CustomData_add_layer(&dm->faceData, LAYERTYPE_ORIGINDEX, 0, NULL); + } + + DM_init_funcs(dm); +} + +void DM_from_template(DerivedMesh *dm, DerivedMesh *source, + int numVerts, int numEdges, int numFaces) +{ + if(numVerts > 0) { + CustomData_from_template(&source->vertData, &dm->vertData, numVerts); + CustomData_from_template(&source->edgeData, &dm->edgeData, numEdges); + CustomData_from_template(&source->faceData, &dm->faceData, numFaces); + } + + DM_init_funcs(dm); +} + +void DM_release(DerivedMesh *dm) +{ + CustomData_free(&dm->vertData); + CustomData_free(&dm->edgeData); + CustomData_free(&dm->faceData); +} + +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 = *me; + int numVerts = dm->getNumVerts(dm); + + tmp_me.dvert = NULL; + tmp_me.tface = NULL; + tmp_me.mcol = NULL; + + tmp_me.totvert = numVerts; + tmp_me.totedge = dm->getNumEdges(dm); + tmp_me.totface = dm->getNumFaces(dm); + + tmp_me.mvert = dm->dupVertArray(dm); + tmp_me.medge = dm->dupEdgeArray(dm); + tmp_me.mface = dm->dupFaceArray(dm); + + if(dm->getFaceDataArray(dm, LAYERTYPE_TFACE)) + tmp_me.tface = MEM_dupallocN(dm->getFaceDataArray(dm, + LAYERTYPE_TFACE)); + if(dm->getFaceDataArray(dm, LAYERTYPE_MCOL)) + tmp_me.mcol = MEM_dupallocN(dm->getFaceDataArray(dm, + LAYERTYPE_MCOL)); + if(dm->getVertDataArray(dm, LAYERTYPE_MDEFORMVERT)) { + int i; + MDeformVert *dv; + + tmp_me.dvert = MEM_dupallocN( + dm->getVertDataArray(dm, LAYERTYPE_MDEFORMVERT)); + + for(i = 0, dv = tmp_me.dvert; i < numVerts; ++i, ++dv) + dv->dw = MEM_dupallocN(dv->dw); + } + + if(me->mvert) MEM_freeN(me->mvert); + if(me->dvert) free_dverts(me->dvert, me->totvert); + if(me->mface) MEM_freeN(me->mface); + if(me->tface) MEM_freeN(me->tface); + if(me->mcol) MEM_freeN(me->mcol); + if(me->medge) MEM_freeN(me->medge); + + /* if the number of verts has changed, remove invalid data */ + if(numVerts != me->totvert) { + if(me->msticky) MEM_freeN(me->msticky); + me->msticky = NULL; + + if(me->key) me->key->id.us--; + me->key = NULL; + } + + *me = tmp_me; +} + +void DM_add_vert_layer(DerivedMesh *dm, int type, int flag, void *layer) +{ + CustomData_add_layer(&dm->vertData, type, flag, layer); +} + +void DM_add_edge_layer(DerivedMesh *dm, int type, int flag, void *layer) +{ + CustomData_add_layer(&dm->edgeData, type, flag, layer); +} + +void DM_add_face_layer(DerivedMesh *dm, int type, int flag, void *layer) +{ + CustomData_add_layer(&dm->faceData, type, flag, layer); +} + +void *DM_get_vert_data(DerivedMesh *dm, int index, int type) +{ + return CustomData_get(&dm->vertData, index, type); +} + +void *DM_get_edge_data(DerivedMesh *dm, int index, int type) +{ + return CustomData_get(&dm->edgeData, index, type); +} + +void *DM_get_face_data(DerivedMesh *dm, int index, int type) +{ + return CustomData_get(&dm->faceData, index, type); +} + +void *DM_get_vert_data_layer(DerivedMesh *dm, int type) +{ + return CustomData_get_layer(&dm->vertData, type); +} + +void *DM_get_edge_data_layer(DerivedMesh *dm, int type) +{ + return CustomData_get_layer(&dm->edgeData, type); +} + +void *DM_get_face_data_layer(DerivedMesh *dm, int type) +{ + return CustomData_get_layer(&dm->faceData, type); +} + +void DM_set_vert_data(DerivedMesh *dm, int index, int type, void *data) +{ + CustomData_set(&dm->vertData, index, type, data); +} + +void DM_set_edge_data(DerivedMesh *dm, int index, int type, void *data) +{ + CustomData_set(&dm->edgeData, index, type, data); +} + +void DM_set_face_data(DerivedMesh *dm, int index, int type, void *data) +{ + CustomData_set(&dm->faceData, index, type, data); +} + +void DM_copy_vert_data(DerivedMesh *source, DerivedMesh *dest, + int source_index, int dest_index, int count) +{ + CustomData_copy_data(&source->vertData, &dest->vertData, + source_index, dest_index, + count); +} + +void DM_copy_edge_data(DerivedMesh *source, DerivedMesh *dest, + int source_index, int dest_index, int count) +{ + CustomData_copy_data(&source->edgeData, &dest->edgeData, + 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->faceData, &dest->faceData, + source_index, dest_index, + count); +} + +void DM_free_vert_data(struct DerivedMesh *dm, int index, int count) +{ + CustomData_free_elem(&dm->vertData, index, count); +} + +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) +{ + CustomData_free_elem(&dm->faceData, index, count); +} + +void DM_interp_vert_data(DerivedMesh *source, DerivedMesh *dest, + int *src_indices, float *weights, + int count, int dest_index) +{ + CustomData_interp(&source->vertData, &dest->vertData, src_indices, + weights, NULL, count, dest_index); +} + +void DM_interp_edge_data(DerivedMesh *source, DerivedMesh *dest, + int *src_indices, + float *weights, EdgeVertWeight *vert_weights, + int count, int dest_index) +{ + CustomData_interp(&source->edgeData, &dest->edgeData, src_indices, + weights, (float *)vert_weights, count, dest_index); +} + +void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest, + int *src_indices, + float *weights, FaceVertWeight *vert_weights, + int count, int dest_index) +{ + CustomData_interp(&source->faceData, &dest->faceData, src_indices, + weights, (float *)vert_weights, count, dest_index); +} typedef struct { DerivedMesh dm; @@ -457,7 +722,7 @@ static void meshDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void * for (i=0; i<me->totface; i++) { MFace *mf= &mface[i]; - int drawSmooth = 1; + int drawSmooth = (mf->flag & ME_SMOOTH); if (!setDrawOptions || setDrawOptions(userData, i, &drawSmooth)) { unsigned char *cp = NULL; @@ -516,6 +781,15 @@ static int meshDM_getNumVerts(DerivedMesh *dm) return me->totvert; } + +static int meshDM_getNumEdges(DerivedMesh *dm) +{ + MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm; + Mesh *me = mdm->me; + + return me->totedge; +} + static int meshDM_getNumFaces(DerivedMesh *dm) { MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm; @@ -524,10 +798,51 @@ static int meshDM_getNumFaces(DerivedMesh *dm) return me->totface; } +void meshDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) +{ + MVert *verts = ((MeshDerivedMesh *)dm)->verts; + + *vert_r = verts[index]; +} + +void meshDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) +{ + Mesh *me = ((MeshDerivedMesh *)dm)->me; + + *edge_r = me->medge[index]; +} + +void meshDM_getFace(DerivedMesh *dm, int index, MFace *face_r) +{ + Mesh *me = ((MeshDerivedMesh *)dm)->me; + + *face_r = me->mface[index]; +} + +void meshDM_getVertArray(DerivedMesh *dm, MVert *vert_r) +{ + MeshDerivedMesh *mdm = (MeshDerivedMesh *)dm; + memcpy(vert_r, mdm->verts, sizeof(*vert_r) * mdm->me->totvert); +} + +void meshDM_getEdgeArray(DerivedMesh *dm, MEdge *edge_r) +{ + MeshDerivedMesh *mdm = (MeshDerivedMesh *)dm; + memcpy(edge_r, mdm->me->medge, sizeof(*edge_r) * mdm->me->totedge); +} + +void meshDM_getFaceArray(DerivedMesh *dm, MFace *face_r) +{ + MeshDerivedMesh *mdm = (MeshDerivedMesh *)dm; + memcpy(face_r, mdm->me->mface, sizeof(*face_r) * mdm->me->totface); +} + static void meshDM_release(DerivedMesh *dm) { MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm; + DM_release(dm); + if (mdm->wpaintMCol) MEM_freeN(mdm->wpaintMCol); if (mdm->freeNors) MEM_freeN(mdm->nors); if (mdm->freeVerts) MEM_freeN(mdm->verts); @@ -538,12 +853,22 @@ static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3] { MeshDerivedMesh *mdm = MEM_callocN(sizeof(*mdm), "mdm"); + DM_init(&mdm->dm, me->totvert, me->totedge, me->totface); + mdm->dm.getMinMax = meshDM_getMinMax; mdm->dm.convertToDispListMesh = meshDM_convertToDispListMesh; mdm->dm.getNumVerts = meshDM_getNumVerts; + mdm->dm.getNumEdges = meshDM_getNumEdges; mdm->dm.getNumFaces = meshDM_getNumFaces; + mdm->dm.getVert = meshDM_getVert; + mdm->dm.getEdge = meshDM_getEdge; + mdm->dm.getFace = meshDM_getFace; + mdm->dm.getVertArray = meshDM_getVertArray; + mdm->dm.getEdgeArray = meshDM_getEdgeArray; + mdm->dm.getFaceArray = meshDM_getFaceArray; + mdm->dm.getVertCos = meshDM_getVertCos; mdm->dm.getVertCo = meshDM_getVertCo; mdm->dm.getVertNo = meshDM_getVertNo; @@ -565,6 +890,21 @@ static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3] mdm->dm.release = meshDM_release; + /* add appropriate data layers (don't copy, just reference) */ + if(me->msticky) + DM_add_vert_layer(&mdm->dm, LAYERTYPE_MSTICKY, + LAYERFLAG_NOFREE, me->msticky); + if(me->dvert) + DM_add_vert_layer(&mdm->dm, LAYERTYPE_MDEFORMVERT, + LAYERFLAG_NOFREE, me->dvert); + + if(me->tface) + DM_add_face_layer(&mdm->dm, LAYERTYPE_TFACE, + LAYERFLAG_NOFREE, me->tface); + if(me->mcol) + DM_add_face_layer(&mdm->dm, LAYERTYPE_MCOL, + LAYERFLAG_NOFREE, me->mcol); + /* Works in conjunction with hack during modifier calc */ if ((G.f & G_WEIGHTPAINT) && ob==(G.scene->basact?G.scene->basact->object:NULL)) { mdm->wpaintMCol = MEM_dupallocN(me->mcol); @@ -793,12 +1133,12 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us if (emdm->vertexCos) { EditVert *eve, *preveve; - int drawSmooth = 1; for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next) eve->prev = (EditVert*) i++; for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) { + int drawSmooth = (efa->flag & ME_SMOOTH); if(!setDrawOptions || setDrawOptions(userData, i, &drawSmooth)) { glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); @@ -828,9 +1168,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us for (preveve=NULL, eve=emdm->em->verts.first; eve; preveve=eve, eve= eve->next) eve->prev = preveve; } else { - int drawSmooth = 1; - for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) { + int drawSmooth = (efa->flag & ME_SMOOTH); if(!setDrawOptions || setDrawOptions(userData, i, &drawSmooth)) { glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); @@ -883,6 +1222,14 @@ static int emDM_getNumVerts(DerivedMesh *dm) return BLI_countlist(&emdm->em->verts); } + +static int emDM_getNumEdges(DerivedMesh *dm) +{ + EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + + return BLI_countlist(&emdm->em->edges); +} + static int emDM_getNumFaces(DerivedMesh *dm) { EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; @@ -890,10 +1237,182 @@ static int emDM_getNumFaces(DerivedMesh *dm) return BLI_countlist(&emdm->em->faces); } +void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) +{ + EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first; + int i; + + for(i = 0; i < index; ++i) ev = ev->next; + + VECCOPY(vert_r->co, ev->co); + + vert_r->no[0] = ev->no[0] * 32767.0; + vert_r->no[1] = ev->no[1] * 32767.0; + vert_r->no[2] = ev->no[2] * 32767.0; + + /* TODO what to do with vert_r->flag and vert_r->mat_nr? */ + vert_r->mat_nr = 0; +} + +void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) +{ + EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; + EditEdge *ee = em->edges.first; + EditVert *ev, *v1, *v2; + int i; + + for(i = 0; i < index; ++i) ee = ee->next; + + edge_r->crease = (unsigned char) (ee->crease*255.0f); + /* TODO what to do with edge_r->flag? */ + edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER; + if (ee->seam) edge_r->flag |= ME_SEAM; + if (ee->sharp) edge_r->flag |= ME_SHARP; +#if 0 + /* this needs setup of f2 field */ + if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE; +#endif + + /* goddamn, we have to search all verts to find indices */ + v1 = ee->v1; + v2 = ee->v2; + for(i = 0, ev = em->verts.first; v1 || v2; i++, ev = ev->next) { + if(ev == v1) { + edge_r->v1 = i; + v1 = NULL; + } + if(ev == v2) { + edge_r->v2 = i; + v2 = NULL; + } + } +} + +void emDM_getFace(DerivedMesh *dm, int index, MFace *face_r) +{ + EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; + EditFace *ef = em->faces.first; + EditVert *ev, *v1, *v2, *v3, *v4; + int i; + + for(i = 0; i < index; ++i) ef = ef->next; + + face_r->mat_nr = ef->mat_nr; + face_r->flag = ef->flag; + + /* goddamn, we have to search all verts to find indices */ + v1 = ef->v1; + v2 = ef->v2; + v3 = ef->v3; + v4 = ef->v4; + if(!v4) face_r->v4 = 0; + + for(i = 0, ev = em->verts.first; v1 || v2 || v3 || v4; + i++, ev = ev->next) { + if(ev == v1) { + face_r->v1 = i; + v1 = NULL; + } + if(ev == v2) { + face_r->v2 = i; + v2 = NULL; + } + if(ev == v3) { + face_r->v3 = i; + v3 = NULL; + } + if(ev == v4) { + face_r->v4 = i; + v4 = NULL; + } + } + + test_index_face(face_r, NULL, NULL, ef->v4?4:3); +} + +void emDM_getVertArray(DerivedMesh *dm, MVert *vert_r) +{ + EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first; + + for( ; ev; ev = ev->next, ++vert_r) { + VECCOPY(vert_r->co, ev->co); + + vert_r->no[0] = ev->no[0] * 32767.0; + vert_r->no[1] = ev->no[1] * 32767.0; + vert_r->no[2] = 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 = 0; + } +} + +void emDM_getEdgeArray(DerivedMesh *dm, MEdge *edge_r) +{ + EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; + EditEdge *ee = em->edges.first; + EditVert *ev, *prevev; + int i; + + /* store vert indices in the prev pointer (kind of hacky) */ + for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i) + ev->prev = (EditVert*) i++; + + for( ; ee; ee = ee->next, ++edge_r) { + edge_r->crease = (unsigned char) (ee->crease*255.0f); + /* TODO what to do with edge_r->flag? */ + edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER; + if (ee->seam) edge_r->flag |= ME_SEAM; + if (ee->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)ee->v1->prev; + edge_r->v2 = (int)ee->v2->prev; + } + + /* restore prev pointers */ + for(prevev = NULL, ev = em->verts.first; ev; prevev = ev, ev = ev->next) + ev->prev = prevev; +} + +void emDM_getFaceArray(DerivedMesh *dm, MFace *face_r) +{ + EditMesh *em = ((EditMeshDerivedMesh *)dm)->em; + EditFace *ef = em->faces.first; + EditVert *ev, *prevev; + int i; + + /* store vert indices in the prev pointer (kind of hacky) */ + for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i) + ev->prev = (EditVert*) i++; + + for( ; ef; ef = ef->next, ++face_r) { + face_r->mat_nr = ef->mat_nr; + face_r->flag = ef->flag; + + face_r->v1 = (int)ef->v1->prev; + face_r->v2 = (int)ef->v2->prev; + face_r->v3 = (int)ef->v3->prev; + if(ef->v4) face_r->v4 = (int)ef->v4->prev; + else face_r->v4 = 0; + + test_index_face(face_r, NULL, NULL, ef->v4?4:3); + } + + /* restore prev pointers */ + for(prevev = NULL, ev = em->verts.first; ev; prevev = ev, ev = ev->next) + ev->prev = prevev; +} + static void emDM_release(DerivedMesh *dm) { EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm; + DM_release(dm); + if (emdm->vertexCos) { MEM_freeN(emdm->vertexCos); MEM_freeN(emdm->vertexNos); @@ -903,14 +1422,28 @@ static void emDM_release(DerivedMesh *dm) MEM_freeN(emdm); } -static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, float (*vertexCos)[3]) +static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, Object *ob, + float (*vertexCos)[3]) { EditMeshDerivedMesh *emdm = MEM_callocN(sizeof(*emdm), "emdm"); + Mesh *me = ob->data; + + DM_init(&emdm->dm, BLI_countlist(&em->verts), + BLI_countlist(&em->edges), BLI_countlist(&em->faces)); emdm->dm.getMinMax = emDM_getMinMax; emdm->dm.getNumVerts = emDM_getNumVerts; + emdm->dm.getNumEdges = emDM_getNumEdges; emdm->dm.getNumFaces = emDM_getNumFaces; + + emdm->dm.getVert = emDM_getVert; + emdm->dm.getEdge = emDM_getEdge; + emdm->dm.getFace = emDM_getFace; + emdm->dm.getVertArray = emDM_getVertArray; + emdm->dm.getEdgeArray = emDM_getEdgeArray; + emdm->dm.getFaceArray = emDM_getFaceArray; + emdm->dm.foreachMappedVert = emDM_foreachMappedVert; emdm->dm.foreachMappedEdge = emDM_foreachMappedEdge; emdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter; @@ -925,7 +1458,19 @@ static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, float (*vertexCos)[3]) emdm->em = em; emdm->vertexCos = vertexCos; - if (vertexCos) { + if(me->dvert) { + EditVert *eve; + int i; + DM_add_vert_layer(&emdm->dm, LAYERTYPE_MDEFORMVERT, 0, NULL); + + for(eve = em->verts.first, i = 0; eve; eve = eve->next, ++i) { + if(eve->keyindex != -1) + DM_set_vert_data(&emdm->dm, i, LAYERTYPE_MDEFORMVERT, + &me->dvert[eve->keyindex]); + } + } + + if(vertexCos) { EditVert *eve, *preveve; EditFace *efa; int totface = BLI_countlist(&em->faces); @@ -960,7 +1505,8 @@ static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, float (*vertexCos)[3]) for(i=0, eve= em->verts.first; eve; i++, eve=eve->next) { float *no = emdm->vertexNos[i]; - /* following Mesh convention; we use vertex coordinate itself for normal in this case */ + /* following Mesh convention; we use vertex coordinate itself + * for normal in this case */ if (Normalise(no)==0.0) { VECCOPY(no, vertexCos[i]); Normalise(no); @@ -986,47 +1532,44 @@ static void ssDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, { SSDerivedMesh *ssdm = (SSDerivedMesh*) dm; DispListMesh *dlm = ssdm->dlm; - int i, index=-1; + int i; + int *index = dm->getVertDataArray(dm, LAYERTYPE_ORIGINDEX); - for (i=0; i<dlm->totvert; i++) { + for (i=0; i<dlm->totvert; i++, index++) { MVert *mv = &dlm->mvert[i]; - if (mv->flag&ME_VERT_STEPINDEX) { - index++; - - func(userData, index, mv->co, NULL, mv->no); - } + if(*index != ORIGINDEX_NONE) + func(userData, *index, mv->co, NULL, mv->no); } } static void ssDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) { SSDerivedMesh *ssdm = (SSDerivedMesh*) dm; DispListMesh *dlm = ssdm->dlm; - int i, index=-1; + int i; + int *index = dm->getEdgeDataArray(dm, LAYERTYPE_ORIGINDEX); - for (i=0; i<dlm->totedge; i++) { + for (i=0; i<dlm->totedge; i++, index++) { MEdge *med = &dlm->medge[i]; - if (med->flag&ME_EDGE_STEPINDEX) index++; - - if (index!=-1) { - func(userData, index, dlm->mvert[med->v1].co, dlm->mvert[med->v2].co); - } + if(*index != ORIGINDEX_NONE) + func(userData, *index, dlm->mvert[med->v1].co, + dlm->mvert[med->v2].co); } } static void ssDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) { SSDerivedMesh *ssdm = (SSDerivedMesh*) dm; DispListMesh *dlm = ssdm->dlm; - int i, index=-1; + int i; + int *index = dm->getEdgeDataArray(dm, LAYERTYPE_ORIGINDEX); glBegin(GL_LINES); - for(i=0; i<dlm->totedge; i++) { + for(i=0; i<dlm->totedge; i++, index++) { MEdge *med = &dlm->medge[i]; - if (med->flag&ME_EDGE_STEPINDEX) index++; - - if (index!=-1 && (!setDrawOptions || setDrawOptions(userData, index))) { + if(*index != ORIGINDEX_NONE + && (!setDrawOptions || setDrawOptions(userData, *index))) { glVertex3fv(dlm->mvert[med->v1].co); glVertex3fv(dlm->mvert[med->v2].co); } @@ -1038,14 +1581,13 @@ static void ssDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use { SSDerivedMesh *ssdm = (SSDerivedMesh*) dm; DispListMesh *dlm = ssdm->dlm; - int i, index=-1; + int i; + int *index = dm->getFaceDataArray(dm, LAYERTYPE_ORIGINDEX); - for (i=0; i<dlm->totface; i++) { + for (i=0; i<dlm->totface; i++, index++) { MFace *mf = &dlm->mface[i]; - if (mf->flag&ME_FACE_STEPINDEX) index++; - - if(index!=-1) { + if(*index != ORIGINDEX_NONE) { float cent[3]; float no[3]; @@ -1062,7 +1604,7 @@ static void ssDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use VecMulf(cent, 0.33333333333f); } - func(userData, index, cent, no); + func(userData, *index, cent, no); } } } @@ -1253,9 +1795,10 @@ static void ssDM_drawFacesTex_common(DerivedMesh *dm, int (*drawParams)(TFace *t MFace *mface= dlm->mface; TFace *tface = dlm->tface; float *nors = dlm->nors; - int a, index=-1; + int a; + int *index = dm->getFaceDataArray(dm, LAYERTYPE_ORIGINDEX); - for (a=0; a<dlm->totface; a++) { + for (a=0; a<dlm->totface; a++, index++) { MFace *mf= &mface[a]; TFace *tf = tface?&tface[a]:NULL; int flag; @@ -1265,8 +1808,8 @@ static void ssDM_drawFacesTex_common(DerivedMesh *dm, int (*drawParams)(TFace *t flag = drawParams(tf, mf->mat_nr); } else { - if (mf->flag&ME_FACE_STEPINDEX) index++; - flag = drawParamsMapped(userData, index); + if(*index != ORIGINDEX_NONE) + flag = drawParamsMapped(userData, *index); } if (flag==0) { @@ -1324,15 +1867,16 @@ static void ssDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us MVert *mvert= dlm->mvert; MFace *mface= dlm->mface; float *nors = dlm->nors; - int i, index=-1; + int i; + int *index = dm->getFaceDataArray(dm, LAYERTYPE_ORIGINDEX); - for (i=0; i<dlm->totface; i++) { + for (i=0; i<dlm->totface; i++, index++) { MFace *mf = &mface[i]; - int drawSmooth = 1; - - if (mf->flag&ME_FACE_STEPINDEX) index++; + int drawSmooth = (mf->flag & ME_SMOOTH); - if (index!=-1 && (!setDrawOptions || setDrawOptions(userData, index, &drawSmooth))) { + if(*index != ORIGINDEX_NONE + && (!setDrawOptions + || setDrawOptions(userData, *index, &drawSmooth))) { unsigned char *cp = NULL; if (useColors) { @@ -1412,6 +1956,14 @@ static int ssDM_getNumVerts(DerivedMesh *dm) return ssdm->dlm->totvert; } + +static int ssDM_getNumEdges(DerivedMesh *dm) +{ + SSDerivedMesh *ssdm = (SSDerivedMesh*) dm; + + return ssdm->dlm->totedge; +} + static int ssDM_getNumFaces(DerivedMesh *dm) { SSDerivedMesh *ssdm = (SSDerivedMesh*) dm; @@ -1419,6 +1971,39 @@ static int ssDM_getNumFaces(DerivedMesh *dm) return ssdm->dlm->totface; } +void ssDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) +{ + *vert_r = ((SSDerivedMesh *)dm)->dlm->mvert[index]; +} + +void ssDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) +{ + *edge_r = ((SSDerivedMesh *)dm)->dlm->medge[index]; +} + +void ssDM_getFace(DerivedMesh *dm, int index, MFace *face_r) +{ + *face_r = ((SSDerivedMesh *)dm)->dlm->mface[index]; +} + +void ssDM_getVertArray(DerivedMesh *dm, MVert *vert_r) +{ + SSDerivedMesh *ssdm = (SSDerivedMesh *)dm; + memcpy(vert_r, ssdm->dlm->mvert, sizeof(*vert_r) * ssdm->dlm->totvert); +} + +void ssDM_getEdgeArray(DerivedMesh *dm, MEdge *edge_r) +{ + SSDerivedMesh *ssdm = (SSDerivedMesh *)dm; + memcpy(edge_r, ssdm->dlm->medge, sizeof(*edge_r) * ssdm->dlm->totedge); +} + +void ssDM_getFaceArray(DerivedMesh *dm, MFace *face_r) +{ + SSDerivedMesh *ssdm = (SSDerivedMesh *)dm; + memcpy(face_r, ssdm->dlm->mface, sizeof(*face_r) * ssdm->dlm->totface); +} + static DispListMesh *ssDM_convertToDispListMesh(DerivedMesh *dm, int allowShared) { SSDerivedMesh *ssdm = (SSDerivedMesh*) dm; @@ -1434,6 +2019,8 @@ static void ssDM_release(DerivedMesh *dm) { SSDerivedMesh *ssdm = (SSDerivedMesh*) dm; + DM_release(dm); + displistmesh_free(ssdm->dlm); MEM_freeN(dm); @@ -1443,10 +2030,21 @@ DerivedMesh *derivedmesh_from_displistmesh(DispListMesh *dlm, float (*vertexCos) { SSDerivedMesh *ssdm = MEM_callocN(sizeof(*ssdm), "ssdm"); + DM_init(&ssdm->dm, dlm->totvert, dlm->totedge, dlm->totface); + ssdm->dm.getMinMax = ssDM_getMinMax; ssdm->dm.getNumVerts = ssDM_getNumVerts; + ssdm->dm.getNumEdges = ssDM_getNumEdges; ssdm->dm.getNumFaces = ssDM_getNumFaces; + + ssdm->dm.getVert = ssDM_getVert; + ssdm->dm.getEdge = ssDM_getEdge; + ssdm->dm.getFace = ssDM_getFace; + ssdm->dm.getVertArray = ssDM_getVertArray; + ssdm->dm.getEdgeArray = ssDM_getEdgeArray; + ssdm->dm.getFaceArray = ssDM_getFaceArray; + ssdm->dm.convertToDispListMesh = ssDM_convertToDispListMesh; ssdm->dm.getVertCos = ssDM_getVertCos; @@ -1991,27 +2589,36 @@ DerivedMesh *mesh_create_derived_for_modifier(Object *ob, ModifierData *md) MEM_freeN(deformedVerts); } else { - dm = mti->applyModifier(md, ob, NULL, NULL, 0, 0); + DerivedMesh *tdm = getMeshDerivedMesh(me, ob, NULL); + dm = mti->applyModifier(md, ob, tdm, 0, 0); + + if(tdm != dm) tdm->release(tdm); } return dm; } -static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedMesh **deform_r, DerivedMesh **final_r, int useRenderParams, int useDeform, int needMapping) +static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], + DerivedMesh **deform_r, DerivedMesh **final_r, + int useRenderParams, int useDeform, + int needMapping) { Mesh *me = ob->data; - ModifierData *md= modifiers_getVirtualModifierList(ob); + ModifierData *md = modifiers_getVirtualModifierList(ob); float (*deformedVerts)[3] = NULL; DerivedMesh *dm; int numVerts = me->totvert; int fluidsimMeshUsed = 0; + int required_mode; modifiers_clearErrors(ob); - if (deform_r) *deform_r = NULL; + if(deform_r) *deform_r = NULL; *final_r = NULL; - /* replace original mesh by fluidsim surface mesh for fluidsim domain objects */ + /* replace original mesh by fluidsim surface mesh for fluidsim + * domain objects + */ if((G.obedit!=ob) && !needMapping) { if (ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) { if(ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN) { @@ -2023,30 +2630,35 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedM } } } - - if (useDeform) { - if(do_ob_key(ob)) /* shape key makes deform verts */ + + if(useRenderParams) required_mode = eModifierMode_Render; + else required_mode = eModifierMode_Realtime; + + if(useDeform) { + if(do_ob_key(ob)) /* shape key makes deform verts */ deformedVerts = mesh_getVertexCos(me, &numVerts); - /* Apply all leading deforming modifiers */ - for (; md; md=md->next) { + /* Apply all leading deforming modifiers */ + for(; md; md = md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!(md->mode&(1<<useRenderParams))) continue; - if (mti->isDisabled && mti->isDisabled(md)) continue; + if((md->mode & required_mode) != required_mode) continue; + if(mti->isDisabled && mti->isDisabled(md)) continue; + + if(mti->type == eModifierTypeType_OnlyDeform) { + if(!deformedVerts) + deformedVerts = mesh_getVertexCos(me, &numVerts); - if (mti->type==eModifierTypeType_OnlyDeform) { - if (!deformedVerts) deformedVerts = mesh_getVertexCos(me, &numVerts); mti->deformVerts(md, ob, NULL, deformedVerts, numVerts); } else { break; } } - /* Result of all leading deforming modifiers is cached for - * places that wish to use the original mesh but with deformed - * coordinates (vpaint, etc.) - */ + /* Result of all leading deforming modifiers is cached for + * places that wish to use the original mesh but with deformed + * coordinates (vpaint, etc.) + */ if (deform_r) #ifdef WITH_VERSE if(me->vnode) *deform_r = derivedmesh_from_versemesh(me->vnode, deformedVerts); @@ -2056,46 +2668,50 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedM #endif } else { if(!fluidsimMeshUsed) { - // default behaviour for meshes + /* default behaviour for meshes */ deformedVerts = inputVertexCos; } else { - // the fluid sim mesh might have more vertices than the original - // one, so inputVertexCos shouldnt be used + /* the fluid sim mesh might have more vertices than the original + * one, so inputVertexCos shouldnt be used + */ deformedVerts = mesh_getVertexCos(me, &numVerts); } } - /* Now apply all remaining modifiers. If useDeform is off then skip - * OnlyDeform ones. - */ + /* Now apply all remaining modifiers. If useDeform is off then skip + * OnlyDeform ones. + */ dm = NULL; - for (; md; md=md->next) { + for(; md; md = md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!(md->mode&(1<<useRenderParams))) continue; - if (mti->type==eModifierTypeType_OnlyDeform && !useDeform) continue; - if ((mti->flags&eModifierTypeFlag_RequiresOriginalData) && dm) { - modifier_setError(md, "Internal error, modifier requires original data (bad stack position)."); + if((md->mode & required_mode) != required_mode) continue; + if(mti->type == eModifierTypeType_OnlyDeform && !useDeform) continue; + if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { + modifier_setError(md, "Internal error, modifier requires " + "original data (bad stack position)."); continue; } - if (mti->isDisabled && mti->isDisabled(md)) continue; - if (needMapping && !modifier_supportsMapping(md)) continue; + if(mti->isDisabled && mti->isDisabled(md)) continue; + if(needMapping && !modifier_supportsMapping(md)) continue; - /* How to apply modifier depends on (a) what we already have as - * a result of previous modifiers (could be a DerivedMesh or just - * deformed vertices) and (b) what type the modifier is. - */ + /* How to apply modifier depends on (a) what we already have as + * a result of previous modifiers (could be a DerivedMesh or just + * deformed vertices) and (b) what type the modifier is. + */ - if (mti->type==eModifierTypeType_OnlyDeform) { - /* No existing verts to deform, need to build them. */ - if (!deformedVerts) { - if (dm) { - /* Deforming a derived mesh, read the vertex locations out of the mesh and - * deform them. Once done with this run of deformers verts will be written back. - */ + if(mti->type == eModifierTypeType_OnlyDeform) { + /* No existing verts to deform, need to build them. */ + if(!deformedVerts) { + if(dm) { + /* Deforming a derived mesh, read the vertex locations + * out of the mesh and deform them. Once done with this + * run of deformers verts will be written back. + */ numVerts = dm->getNumVerts(dm); - deformedVerts = MEM_mallocN(sizeof(*deformedVerts)*numVerts, "dfmv"); + deformedVerts = + MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv"); dm->getVertCos(dm, deformedVerts); } else { deformedVerts = mesh_getVertexCos(me, &numVerts); @@ -2104,38 +2720,58 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedM mti->deformVerts(md, ob, dm, deformedVerts, numVerts); } else { - /* There are 4 cases here (have deform? have dm?) but they all are handled - * by the modifier apply function, which will also free the DerivedMesh if - * it exists. - */ - DerivedMesh *ndm = mti->applyModifier(md, ob, dm, deformedVerts, useRenderParams, !inputVertexCos); + DerivedMesh *ndm; - if (ndm) { - if (dm) dm->release(dm); + /* apply vertex coordinates or build a DerivedMesh as necessary */ + if(dm) { + if(deformedVerts) { + DerivedMesh *tdm = CDDM_copy(dm); + dm->release(dm); + dm = tdm; + + CDDM_apply_vert_coords(dm, deformedVerts); + CDDM_calc_normals(dm); + } + } else { + dm = CDDM_from_mesh(me); + + if(deformedVerts) { + CDDM_apply_vert_coords(dm, deformedVerts); + CDDM_calc_normals(dm); + } + } + + ndm = mti->applyModifier(md, ob, dm, useRenderParams, + !inputVertexCos); + + if(ndm) { + /* if the modifier returned a new dm, release the old one */ + if(dm && dm != ndm) dm->release(dm); dm = ndm; - if (deformedVerts) { - if (deformedVerts!=inputVertexCos) { + if(deformedVerts) { + if(deformedVerts != inputVertexCos) MEM_freeN(deformedVerts); - } + deformedVerts = NULL; } } } } - /* Yay, we are done. If we have a DerivedMesh and deformed vertices need to apply - * these back onto the DerivedMesh. If we have no DerivedMesh then we need to build - * one. - */ - if (dm && deformedVerts) { - DispListMesh *dlm = dm->convertToDispListMesh(dm, 0); + /* Yay, we are done. If we have a DerivedMesh and deformed vertices + * need to apply these back onto the DerivedMesh. If we have no + * DerivedMesh then we need to build one. + */ + if(dm && deformedVerts) { + *final_r = CDDM_copy(dm); dm->release(dm); - *final_r = derivedmesh_from_displistmesh(dlm, deformedVerts); - } else if (dm) { + CDDM_apply_vert_coords(*final_r, deformedVerts); + CDDM_calc_normals(*final_r); + } else if(dm) { *final_r = dm; } else { #ifdef WITH_VERSE @@ -2146,10 +2782,10 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedM #endif } - if (deformedVerts && deformedVerts!=inputVertexCos) { + if(deformedVerts && deformedVerts != inputVertexCos) MEM_freeN(deformedVerts); - } - // restore mesh in any case + + /* restore mesh in any case */ if(fluidsimMeshUsed) ob->data = ob->fluidsimSettings->orgMesh; } @@ -2175,40 +2811,43 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, DerivedMesh **final_r) float (*deformedVerts)[3] = NULL; DerivedMesh *dm; int i, numVerts = 0, cageIndex = modifiers_getCageIndex(ob, NULL); + int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; modifiers_clearErrors(ob); - if (cage_r && cageIndex==-1) { - *cage_r = getEditMeshDerivedMesh(em, NULL); + if(cage_r && cageIndex == -1) { + *cage_r = getEditMeshDerivedMesh(em, ob, NULL); } dm = NULL; - for (i=0,md= ob->modifiers.first; md; i++,md=md->next) { + for(i = 0, md = ob->modifiers.first; md; i++, md = md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!(md->mode&eModifierMode_Realtime)) continue; - if (!(md->mode&eModifierMode_Editmode)) continue; - if ((mti->flags&eModifierTypeFlag_RequiresOriginalData) && dm) { - modifier_setError(md, "Internal error, modifier requires original data (bad stack position)."); + if((md->mode & required_mode) != required_mode) continue; + if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) { + modifier_setError(md, "Internal error, modifier requires" + "original data (bad stack position)."); continue; } - if (mti->isDisabled && mti->isDisabled(md)) continue; - if (!(mti->flags&eModifierTypeFlag_SupportsEditmode)) continue; + if(mti->isDisabled && mti->isDisabled(md)) continue; + if(!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue; - /* How to apply modifier depends on (a) what we already have as - * a result of previous modifiers (could be a DerivedMesh or just - * deformed vertices) and (b) what type the modifier is. - */ + /* How to apply modifier depends on (a) what we already have as + * a result of previous modifiers (could be a DerivedMesh or just + * deformed vertices) and (b) what type the modifier is. + */ - if (mti->type==eModifierTypeType_OnlyDeform) { - /* No existing verts to deform, need to build them. */ - if (!deformedVerts) { - if (dm) { - /* Deforming a derived mesh, read the vertex locations out of the mesh and - * deform them. Once done with this run of deformers verts will be written back. - */ + if(mti->type == eModifierTypeType_OnlyDeform) { + /* No existing verts to deform, need to build them. */ + if(!deformedVerts) { + if(dm) { + /* Deforming a derived mesh, read the vertex locations + * out of the mesh and deform them. Once done with this + * run of deformers verts will be written back. + */ numVerts = dm->getNumVerts(dm); - deformedVerts = MEM_mallocN(sizeof(*deformedVerts)*numVerts, "dfmv"); + deformedVerts = + MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv"); dm->getVertCos(dm, deformedVerts); } else { deformedVerts = editmesh_getVertexCos(em, &numVerts); @@ -2217,14 +2856,37 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, DerivedMesh **final_r) mti->deformVertsEM(md, ob, em, dm, deformedVerts, numVerts); } else { - /* There are 4 cases here (have deform? have dm?) but they all are handled - * by the modifier apply function, which will also free the DerivedMesh if - * it exists. - */ - DerivedMesh *ndm = mti->applyModifierEM(md, ob, em, dm, deformedVerts); + DerivedMesh *ndm; + + /* apply vertex coordinates or build a DerivedMesh as necessary */ + if(dm) { + if(deformedVerts) { + DerivedMesh *tdm = CDDM_copy(dm); + if(!(cage_r && dm == *cage_r)) dm->release(dm); + dm = tdm; + + CDDM_apply_vert_coords(dm, deformedVerts); + CDDM_calc_normals(dm); + } else if(cage_r && dm == *cage_r) { + /* dm may be changed by this modifier, so we need to copy it + */ + dm = CDDM_copy(dm); + } + + } else { + dm = CDDM_from_editmesh(em, ob->data); + + if(deformedVerts) { + CDDM_apply_vert_coords(dm, deformedVerts); + CDDM_calc_normals(dm); + } + } + + ndm = mti->applyModifierEM(md, ob, em, dm); if (ndm) { - if (dm && (!cage_r || dm!=*cage_r)) dm->release(dm); + if(dm && dm != ndm) + dm->release(dm); dm = ndm; @@ -2235,36 +2897,37 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, DerivedMesh **final_r) } } - if (cage_r && i==cageIndex) { - if (dm && deformedVerts) { - DispListMesh *dlm; - - dlm = dm->convertToDispListMesh(dm, 0); - - *cage_r = derivedmesh_from_displistmesh(dlm, deformedVerts); - } else if (dm) { + if(cage_r && i == cageIndex) { + if(dm && deformedVerts) { + *cage_r = CDDM_copy(dm); + CDDM_apply_vert_coords(*cage_r, deformedVerts); + } else if(dm) { *cage_r = dm; } else { - *cage_r = getEditMeshDerivedMesh(em, deformedVerts?MEM_dupallocN(deformedVerts):NULL); + *cage_r = + getEditMeshDerivedMesh(em, ob, + deformedVerts ? MEM_dupallocN(deformedVerts) : NULL); } } } - /* Yay, we are done. If we have a DerivedMesh and deformed vertices need to apply - * these back onto the DerivedMesh. If we have no DerivedMesh then we need to build - * one. - */ - if (dm && deformedVerts) { - DispListMesh *dlm = dm->convertToDispListMesh(dm, 0); + /* Yay, we are done. If we have a DerivedMesh and deformed vertices need + * to apply these back onto the DerivedMesh. If we have no DerivedMesh + * then we need to build one. + */ + if(dm && deformedVerts) { + *final_r = CDDM_copy(dm); - if (!cage_r || dm!=*cage_r) dm->release(dm); + if(!(cage_r && dm == *cage_r)) dm->release(dm); + + CDDM_apply_vert_coords(*final_r, deformedVerts); + CDDM_calc_normals(*final_r); - *final_r = derivedmesh_from_displistmesh(dlm, deformedVerts); MEM_freeN(deformedVerts); } else if (dm) { *final_r = dm; } else { - *final_r = getEditMeshDerivedMesh(em, deformedVerts); + *final_r = getEditMeshDerivedMesh(em, ob, deformedVerts); } } @@ -2384,18 +3047,22 @@ static void mesh_build_data(Object *ob) MCol *mcol = me->mcol; TFace *tface = me->tface; - me->tface = NULL; me->mcol = (MCol*) calc_weightpaint_colors(ob); + if(me->tface) { + me->tface = MEM_dupallocN(me->tface); + mcol_to_tface(me, 1); + } mesh_calc_modifiers(ob, NULL, &ob->derivedDeform, &ob->derivedFinal, 0, 1, needMapping); - MEM_freeN(me->mcol); + if(me->mcol) MEM_freeN(me->mcol); + if(me->tface) MEM_freeN(me->tface); me->mcol = mcol; me->tface = tface; } else { - mesh_calc_modifiers(ob, NULL, &ob->derivedDeform, &ob->derivedFinal, 0, 1, - needMapping); + mesh_calc_modifiers(ob, NULL, &ob->derivedDeform, + &ob->derivedFinal, 0, 1, needMapping); } INIT_MINMAX(min, max); @@ -2525,7 +3192,7 @@ DerivedMesh *editmesh_get_derived_cage(int *needsFree_r) DerivedMesh *editmesh_get_derived_base(void) { - return getEditMeshDerivedMesh(G.editMesh, NULL); + return getEditMeshDerivedMesh(G.editMesh, G.obedit, NULL); } @@ -2536,6 +3203,10 @@ static void make_vertexcosnos__mapFunc(void *userData, int index, float *co, flo float *vec = userData; vec+= 6*index; + + /* check if we've been here before (normal should not be 0) */ + if(vec[3] || vec[4] || vec[5]) return; + VECCOPY(vec, co); vec+= 3; if(no_f) { @@ -2563,7 +3234,7 @@ float *mesh_get_mapped_verts_nors(Object *ob) return NULL; dm= mesh_get_derived_final(ob, &needsFree); - vertexcosnos= MEM_mallocN(6*sizeof(float)*me->totvert, "vertexcosnos map"); + vertexcosnos= MEM_callocN(6*sizeof(float)*me->totvert, "vertexcosnos map"); if(dm->foreachMappedVert) { dm->foreachMappedVert(dm, make_vertexcosnos__mapFunc, vertexcosnos); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index b0341e6ddcc..545efdf10e6 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -48,6 +48,7 @@ #include "BKE_curve.h" #include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" #include "BKE_displist.h" #include "BKE_global.h" #include "BKE_main.h" @@ -661,16 +662,18 @@ static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, flo (*contrib)+=weight; } -void armature_deform_verts(Object *armOb, Object *target, float (*vertexCos)[3], int numVerts, int deformflag) +void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts, int deformflag) { bPoseChannel *pchan, **defnrToPC = NULL; - MDeformVert *dverts= NULL; + MDeformVert *dverts = NULL; float obinv[4][4], premat[4][4], postmat[4][4]; - int use_envelope= deformflag & ARM_DEF_ENVELOPE; - int numGroups= 0; /* safety for vertexgroup index overflow too */ + int use_envelope = deformflag & ARM_DEF_ENVELOPE; + int numGroups = 0; /* safety for vertexgroup index overflow too */ int i; + int use_dverts = 0; - if(armOb==G.obedit) return; + if(armOb == G.obedit) return; Mat4Invert(obinv, target->obmat); Mat4CpyMat4(premat, target->obmat); @@ -681,23 +684,32 @@ void armature_deform_verts(Object *armOb, Object *target, float (*vertexCos)[3], /* bone defmats are already in the channels, chan_mat */ /* initialize B_bone matrices */ - for(pchan= armOb->pose->chanbase.first; pchan; pchan= pchan->next) { + for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) { if(!(pchan->bone->flag & BONE_NO_DEFORM)) - if(pchan->bone->segments>1) + if(pchan->bone->segments > 1) pchan_b_bone_defmats(pchan); } /* get a vertex-deform-index to posechannel array */ if(deformflag & ARM_DEF_VGROUP) { - if (target->type==OB_MESH){ + if(target->type == OB_MESH){ bDeformGroup *dg; numGroups = BLI_countlist(&target->defbase); - dverts = ((Mesh*)target->data)->dvert; - if(dverts) { - defnrToPC = MEM_callocN(sizeof(*defnrToPC)*numGroups, "defnrToBone"); - for (i=0,dg=target->defbase.first; dg; i++,dg=dg->next) { + + /* if we have a DerivedMesh, only use dverts if it has them */ + if(dm) + if(dm->getVertData(dm, 0, LAYERTYPE_MDEFORMVERT)) + use_dverts = 1; + else use_dverts = 0; + else if(dverts) use_dverts = 1; + + if(use_dverts) { + defnrToPC = MEM_callocN(sizeof(*defnrToPC) * numGroups, + "defnrToBone"); + for(i = 0, dg = target->defbase.first; dg; + i++, dg = dg->next) { defnrToPC[i] = get_pose_channel(armOb->pose, dg->name); /* exclude non-deforming bones */ if(defnrToPC[i]) { @@ -709,77 +721,84 @@ void armature_deform_verts(Object *armOb, Object *target, float (*vertexCos)[3], } } - for(i=0; i<numVerts; i++) { + for(i = 0; i < numVerts; i++) { MDeformVert *dvert; float *co = vertexCos[i]; float vec[3]; - float contrib=0.0; + float contrib = 0.0; int j; - vec[0]=vec[1]=vec[2]=0; + vec[0] = vec[1] = vec[2] = 0; /* Apply the object's matrix */ Mat4MulVecfl(premat, co); - if(dverts && i<((Mesh*)target->data)->totvert) - dvert= dverts+i; - else - dvert= NULL; + if(use_dverts) { + if(dm) dvert = dm->getVertData(dm, i, LAYERTYPE_MDEFORMVERT); + else if(i < ((Mesh*)target->data)->totvert) dvert = dverts + i; + } else + dvert = NULL; if(dvert && dvert->totweight) { // use weight groups ? - int deformed= 0; + int deformed = 0; - for (j=0; j<dvert->totweight; j++){ - int index= dvert->dw[j].def_nr; - pchan = index<numGroups?defnrToPC[index]:NULL; - if (pchan) { - float weight= dvert->dw[j].weight; - Bone *bone= pchan->bone; + for(j = 0; j < dvert->totweight; j++){ + int index = dvert->dw[j].def_nr; + pchan = index < numGroups?defnrToPC[index]:NULL; + if(pchan) { + float weight = dvert->dw[j].weight; + Bone *bone = pchan->bone; - deformed= 1; + deformed = 1; if(bone && bone->flag & BONE_MULT_VG_ENV) { - - weight*= distfactor_to_bone(co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist); + weight *= distfactor_to_bone(co, bone->arm_head, + bone->arm_tail, + bone->rad_head, + bone->rad_tail, + bone->dist); } pchan_bone_deform(pchan, weight, vec, co, &contrib); } } - /* if there are vertexgroups but not groups with bones (like for softbody groups) */ - if(deformed==0 && use_envelope) { - for(pchan= armOb->pose->chanbase.first; pchan; pchan= pchan->next) { + /* if there are vertexgroups but not groups with bones + * (like for softbody groups) + */ + if(deformed == 0 && use_envelope) { + for(pchan = armOb->pose->chanbase.first; pchan; + pchan = pchan->next) { if(!(pchan->bone->flag & BONE_NO_DEFORM)) - contrib+= dist_bone_deform(pchan, vec, co); + contrib += dist_bone_deform(pchan, vec, co); } } } else if(use_envelope) { - for(pchan= armOb->pose->chanbase.first; pchan; pchan= pchan->next) { + for(pchan = armOb->pose->chanbase.first; pchan; + pchan = pchan->next) { if(!(pchan->bone->flag & BONE_NO_DEFORM)) - contrib+= dist_bone_deform(pchan, vec, co); + contrib += dist_bone_deform(pchan, vec, co); } } - if (contrib>0.0){ - vec[0]/=contrib; - vec[1]/=contrib; - vec[2]/=contrib; + if(contrib > 0.0){ + vec[0] /= contrib; + vec[1] /= contrib; + vec[2] /= contrib; } VecAddf(co, vec, co); Mat4MulVecfl(postmat, co); } - if (defnrToPC) MEM_freeN(defnrToPC); + if(defnrToPC) MEM_freeN(defnrToPC); /* free B_bone matrices */ - for(pchan= armOb->pose->chanbase.first; pchan; pchan= pchan->next) { + for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) { if(pchan->b_bone_mats) { MEM_freeN(pchan->b_bone_mats); - pchan->b_bone_mats= NULL; + pchan->b_bone_mats = NULL; } } - } /* ************ END Armature Deform ******************* */ diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c new file mode 100644 index 00000000000..2429da66c15 --- /dev/null +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -0,0 +1,1045 @@ +/* +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* The Original Code is Copyright (C) 2006 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Ben Batt <benbatt@gmail.com> +* +* ***** END GPL LICENSE BLOCK ***** +* +* Implementation of CDDerivedMesh. +* +* BKE_cdderivedmesh.h contains the function prototypes for this file. +* +*/ + +/* TODO maybe BIF_gl.h should include string.h? */ +#include <string.h> +#include "BIF_gl.h" + +#include "BKE_cdderivedmesh.h" +#include "BKE_DerivedMesh.h" +#include "BKE_displist.h" +#include "BKE_mesh.h" +#include "BKE_utildefines.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_edgehash.h" +#include "BLI_editVert.h" +#include "BLI_ghash.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "MEM_guardedalloc.h" + +#include <string.h> +#include <limits.h> + + +/**************** DerivedMesh interface functions ****************/ +static int cdDM_getNumVerts(DerivedMesh *dm) +{ + return dm->vertData.numElems; +} + +static int cdDM_getNumFaces(DerivedMesh *dm) +{ + return dm->faceData.numElems; +} + +static int cdDM_getNumEdges(DerivedMesh *dm) +{ + return dm->edgeData.numElems; +} + +static void cdDM_getVert(DerivedMesh *dm, int index, MVert *vert_r) +{ + *vert_r = *CDDM_get_vert(dm, index); +} + +static void cdDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r) +{ + *edge_r = *CDDM_get_edge(dm, index); +} + +static void cdDM_getFace(DerivedMesh *dm, int index, MFace *face_r) +{ + *face_r = *CDDM_get_face(dm, index); +} + +static void cdDM_getVertArray(DerivedMesh *dm, MVert *vert_r) +{ + memcpy(vert_r, CDDM_get_verts(dm), sizeof(*vert_r) * dm->getNumVerts(dm)); +} + +static void cdDM_getEdgeArray(DerivedMesh *dm, MEdge *edge_r) +{ + memcpy(edge_r, CDDM_get_edges(dm), sizeof(*edge_r) * dm->getNumEdges(dm)); +} + +static void cdDM_getFaceArray(DerivedMesh *dm, MFace *face_r) +{ + memcpy(face_r, CDDM_get_faces(dm), sizeof(*face_r) * dm->getNumFaces(dm)); +} + +static void cdDM_foreachMappedVert( + DerivedMesh *dm, + void (*func)(void *userData, int index, float *co, + float *no_f, short *no_s), + void *userData) +{ + int i; + int maxVerts = dm->getNumVerts(dm); + MVert *mv = CDDM_get_verts(dm); + int *index = DM_get_vert_data_layer(dm, LAYERTYPE_ORIGINDEX); + + for(i = 0; i < maxVerts; i++, mv++, index++) { + if(*index == ORIGINDEX_NONE) continue; + + func(userData, *index, mv->co, NULL, mv->no); + } +} + +static void cdDM_foreachMappedEdge( + DerivedMesh *dm, + void (*func)(void *userData, int index, + float *v0co, float *v1co), + void *userData) +{ + int i; + int maxEdges = dm->getNumEdges(dm); + MEdge *med = CDDM_get_edges(dm); + MVert *mv = CDDM_get_verts(dm); + int *index = DM_get_edge_data_layer(dm, LAYERTYPE_ORIGINDEX); + + for(i = 0; i < maxEdges; i++, med++, index++) { + if(*index == ORIGINDEX_NONE) continue; + + func(userData, *index, mv[med->v1].co, mv[med->v2].co); + } +} + +static void cdDM_foreachMappedFaceCenter( + DerivedMesh *dm, + void (*func)(void *userData, int index, + float *cent, float *no), + void *userData) +{ + int i; + int maxFaces = dm->getNumFaces(dm); + MFace *mf = CDDM_get_faces(dm); + MVert *mv = CDDM_get_verts(dm); + int *index = DM_get_face_data_layer(dm, LAYERTYPE_ORIGINDEX); + + for(i = 0; i < maxFaces; i++, mf++, index++) { + float cent[3]; + float no[3]; + + if(*index == ORIGINDEX_NONE) continue; + + 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); + } else { + CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, no); + VecMulf(cent, 0.33333333333f); + } + + func(userData, *index, cent, no); + } +} + +static DispListMesh *cdDM_convertToDispListMesh(DerivedMesh *dm, + int allowShared) +{ + DispListMesh *dlm = MEM_callocN(sizeof(*dlm), + "cdDM_convertToDispListMesh dlm"); + + dlm->totvert = dm->vertData.numElems; + dlm->totedge = dm->edgeData.numElems; + dlm->totface = dm->faceData.numElems; + dlm->mvert = dm->dupVertArray(dm); + dlm->medge = dm->dupEdgeArray(dm); + dlm->mface = dm->dupFaceArray(dm); + + dlm->tface = dm->getFaceDataArray(dm, LAYERTYPE_TFACE); + if(dlm->tface) + dlm->tface = MEM_dupallocN(dlm->tface); + + dlm->mcol = dm->getFaceDataArray(dm, LAYERTYPE_MCOL); + if(dlm->mcol) + dlm->mcol = MEM_dupallocN(dlm->mcol); + + dlm->nors = NULL; + dlm->dontFreeVerts = dlm->dontFreeOther = dlm->dontFreeNors = 0; + + return dlm; +} + +static void cdDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) +{ + int i; + + for(i = 0; i < dm->vertData.numElems; i++) { + DO_MINMAX(CDDM_get_vert(dm, i)->co, min_r, max_r); + } +} + +static void cdDM_getVertCo(DerivedMesh *dm, int index, float co_r[3]) +{ + VECCOPY(co_r, CDDM_get_vert(dm, index)->co); +} + +static void cdDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3]) +{ + int i; + MVert *mv = CDDM_get_verts(dm); + + for(i = 0; i < dm->vertData.numElems; i++, mv++) + VECCOPY(cos_r[i], mv->co); +} + +static void cdDM_getVertNo(DerivedMesh *dm, int index, float no_r[3]) +{ + short *no = CDDM_get_vert(dm, index)->no; + + no_r[0] = no[0] / 32767.f; + no_r[1] = no[1] / 32767.f; + no_r[2] = no[2] / 32767.f; +} + +static void cdDM_drawVerts(DerivedMesh *dm) +{ + int i; + MVert *mv = CDDM_get_verts(dm); + + glBegin(GL_POINTS); + for(i = 0; i < dm->vertData.numElems; i++, mv++) + glVertex3fv(mv->co); + glEnd(); +} + +static void cdDM_drawUVEdges(DerivedMesh *dm) +{ + int i; + TFace *tf = DM_get_face_data_layer(dm, LAYERTYPE_TFACE); + MFace *mf = CDDM_get_faces(dm); + + if(tf) { + glBegin(GL_LINES); + for(i = 0; i < dm->faceData.numElems; i++, tf++, mf++) { + if(!(tf->flag&TF_HIDE)) { + glVertex2fv(tf->uv[0]); + glVertex2fv(tf->uv[1]); + + glVertex2fv(tf->uv[1]); + glVertex2fv(tf->uv[2]); + + if(!mf->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(); + } +} + +static void cdDM_drawEdges(DerivedMesh *dm, int drawLooseEdges) +{ + int i; + MEdge *medge = CDDM_get_edges(dm); + MVert *mvert = CDDM_get_verts(dm); + + glBegin(GL_LINES); + for(i = 0; i < dm->edgeData.numElems; i++, medge++) { + if((medge->flag&ME_EDGEDRAW) + && (drawLooseEdges || !(medge->flag&ME_LOOSEEDGE))) { + glVertex3fv(mvert[medge->v1].co); + glVertex3fv(mvert[medge->v2].co); + } + } + glEnd(); +} + +static void cdDM_drawLooseEdges(DerivedMesh *dm) +{ + MEdge *medge = CDDM_get_edges(dm); + MVert *mvert = CDDM_get_verts(dm); + int i; + + glBegin(GL_LINES); + for(i = 0; i < dm->edgeData.numElems; i++, medge++) { + if(medge->flag&ME_LOOSEEDGE) { + glVertex3fv(mvert[medge->v1].co); + glVertex3fv(mvert[medge->v2].co); + } + } + glEnd(); +} + +static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int)) +{ + int a; + int glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1; + MFace *mface = CDDM_get_faces(dm); + MVert *mvert = CDDM_get_verts(dm); + +#define PASSVERT(index) { \ + if(shademodel == GL_SMOOTH) { \ + short *no = mvert[index].no; \ + glNormal3sv(no); \ + } \ + glVertex3fv(mvert[index].co); \ +} + + glBegin(glmode = GL_QUADS); + for(a = 0; a < dm->faceData.numElems; a++, mface++) { + int new_glmode, new_matnr, new_shademodel; + + new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES; + new_matnr = mface->mat_nr + 1; + new_shademodel = (mface->flag & ME_SMOOTH)?GL_SMOOTH:GL_FLAT; + + if(new_glmode != glmode || new_matnr != matnr + || new_shademodel != shademodel) { + glEnd(); + + drawCurrentMat = setMaterial(matnr = new_matnr); + + glShadeModel(shademodel = new_shademodel); + glBegin(glmode = new_glmode); + } + + if(drawCurrentMat) { + /* TODO make this better (cache facenormals as layer?) */ + if(shademodel == GL_FLAT) { + float nor[3]; + if(mface->v4) { + CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co, + mvert[mface->v3].co, mvert[mface->v4].co, + nor); + } else { + CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co, + mvert[mface->v3].co, nor); + } + glNormal3fv(nor); + } + + PASSVERT(mface->v1); + PASSVERT(mface->v2); + PASSVERT(mface->v3); + if(mface->v4) { + PASSVERT(mface->v4); + } + } + } + glEnd(); + + glShadeModel(GL_FLAT); +#undef PASSVERT +} + +static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2) +{ + int a, glmode; + unsigned char *cp1, *cp2; + MFace *mface = CDDM_get_faces(dm); + MVert *mvert = CDDM_get_verts(dm); + + cp1 = col1; + if(col2) { + cp2 = col2; + } else { + cp2 = NULL; + useTwoSided = 0; + } + + /* there's a conflict here... twosided colors versus culling...? */ + /* defined by history, only texture faces have culling option */ + /* we need that as mesh option builtin, next to double sided lighting */ + if(col1 && col2) + glEnable(GL_CULL_FACE); + + glShadeModel(GL_SMOOTH); + glBegin(glmode = GL_QUADS); + for(a = 0; a < dm->faceData.numElems; a++, mface++, cp1 += 16) { + int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES; + + if(new_glmode != glmode) { + glEnd(); + glBegin(glmode = new_glmode); + } + + glColor3ub(cp1[3], cp1[2], cp1[1]); + glVertex3fv(mvert[mface->v1].co); + glColor3ub(cp1[7], cp1[6], cp1[5]); + glVertex3fv(mvert[mface->v2].co); + glColor3ub(cp1[11], cp1[10], cp1[9]); + glVertex3fv(mvert[mface->v3].co); + if(mface->v4) { + glColor3ub(cp1[15], cp1[14], cp1[13]); + glVertex3fv(mvert[mface->v4].co); + } + + if(useTwoSided) { + glColor3ub(cp2[11], cp2[10], cp2[9]); + glVertex3fv(mvert[mface->v3].co ); + glColor3ub(cp2[7], cp2[6], cp2[5]); + glVertex3fv(mvert[mface->v2].co ); + glColor3ub(cp2[3], cp2[2], cp2[1]); + glVertex3fv(mvert[mface->v1].co ); + if(mface->v4) { + glColor3ub(cp2[15], cp2[14], cp2[13]); + glVertex3fv(mvert[mface->v4].co ); + } + } + if(col2) cp2 += 16; + } + glEnd(); + + glShadeModel(GL_FLAT); + glDisable(GL_CULL_FACE); +} + +static void cdDM_drawFacesTex_common(DerivedMesh *dm, + int (*drawParams)(TFace *tface, int matnr), + int (*drawParamsMapped)(void *userData, int index), + void *userData) +{ + int i; + MFace *mf = CDDM_get_faces(dm); + TFace *tf = DM_get_face_data_layer(dm, LAYERTYPE_TFACE); + MVert *mv = CDDM_get_verts(dm); + int *index = DM_get_face_data_layer(dm, LAYERTYPE_ORIGINDEX); + + for(i = 0; i < dm->faceData.numElems; i++, mf++, index++) { + MVert *mvert; + int flag; + unsigned char *cp = NULL; + + if(drawParams) + if(tf) flag = drawParams(&tf[i], mf->mat_nr); + else flag = drawParams(NULL, mf->mat_nr); + else if(*index != ORIGINDEX_NONE) + flag = drawParamsMapped(userData, *index); + else + flag = 0; + + if(flag == 0) { + continue; + } else if(flag == 1) { + if(tf) { + cp = (unsigned char *)tf[i].col; + } else { + cp = DM_get_face_data(dm, i, LAYERTYPE_MCOL); + } + } + + /* TODO make this better (cache facenormals as layer?) */ + if(!(mf->flag&ME_SMOOTH)) { + float nor[3]; + if(mf->v4) { + CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, mv[mf->v4].co, nor); + } else { + CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, nor); + } + glNormal3fv(nor); + } + + glBegin(mf->v4?GL_QUADS:GL_TRIANGLES); + if(tf) glTexCoord2fv(tf[i].uv[0]); + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + mvert = &mv[mf->v1]; + if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no); + glVertex3fv(mvert->co); + + if(tf) glTexCoord2fv(tf[i].uv[1]); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + mvert = &mv[mf->v2]; + if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no); + glVertex3fv(mvert->co); + + if(tf) glTexCoord2fv(tf[i].uv[2]); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + mvert = &mv[mf->v3]; + if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no); + glVertex3fv(mvert->co); + + if(mf->v4) { + if(tf) glTexCoord2fv(tf[i].uv[3]); + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + mvert = &mv[mf->v4]; + if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no); + glVertex3fv(mvert->co); + } + glEnd(); + } +} + +static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(TFace *tface, int matnr)) +{ + cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL); +} + +static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) +{ + int i; + MFace *mf = CDDM_get_faces(dm); + MVert *mv = CDDM_get_verts(dm); + int *index = DM_get_face_data_layer(dm, LAYERTYPE_ORIGINDEX); + TFace *tf = DM_get_face_data_layer(dm, LAYERTYPE_TFACE); + MCol *mc = DM_get_face_data_layer(dm, LAYERTYPE_MCOL); + + for(i = 0; i < dm->faceData.numElems; i++, mf++, index++) { + int drawSmooth = (mf->flag & ME_SMOOTH); + + if(setDrawOptions && *index == ORIGINDEX_NONE) continue; + + if(!setDrawOptions || setDrawOptions(userData, *index, &drawSmooth)) { + unsigned char *cp = NULL; + + if(useColors) { + if(tf) { + cp = (unsigned char *)tf[i].col; + } else if(mc) { + cp = (unsigned char *)&mc[i * 4]; + } + } + + glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT); + glBegin(mf->v4?GL_QUADS:GL_TRIANGLES); + + if(!drawSmooth) { + /* TODO make this better (cache facenormals as layer?) */ + float nor[3]; + if(mf->v4) { + CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, mv[mf->v4].co, nor); + } else { + CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, nor); + } + glNormal3fv(nor); + + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glVertex3fv(mv[mf->v1].co); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glVertex3fv(mv[mf->v2].co); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glVertex3fv(mv[mf->v3].co); + if(mf->v4) { + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glVertex3fv(mv[mf->v4].co); + } + } else { + if(cp) glColor3ub(cp[3], cp[2], cp[1]); + glNormal3sv(mv[mf->v1].no); + glVertex3fv(mv[mf->v1].co); + if(cp) glColor3ub(cp[7], cp[6], cp[5]); + glNormal3sv(mv[mf->v2].no); + glVertex3fv(mv[mf->v2].co); + if(cp) glColor3ub(cp[11], cp[10], cp[9]); + glNormal3sv(mv[mf->v3].no); + glVertex3fv(mv[mf->v3].co); + if(mf->v4) { + if(cp) glColor3ub(cp[15], cp[14], cp[13]); + glNormal3sv(mv[mf->v4].no); + glVertex3fv(mv[mf->v4].co); + } + } + + glEnd(); + } + } +} + +static void cdDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) +{ + cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData); +} + +static void cdDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) +{ + int i; + int *index = DM_get_edge_data_layer(dm, LAYERTYPE_ORIGINDEX); + MEdge *edge = CDDM_get_edges(dm); + MVert *vert = CDDM_get_verts(dm); + + glBegin(GL_LINES); + for(i = 0; i < dm->edgeData.numElems; i++, edge++, index++) { + + if(setDrawOptions && *index == ORIGINDEX_NONE) continue; + + if(!setDrawOptions || setDrawOptions(userData, *index)) { + glVertex3fv(vert[edge->v1].co); + glVertex3fv(vert[edge->v2].co); + } + } + glEnd(); +} + +static void cdDM_release(DerivedMesh *dm) +{ + CustomData_free(&dm->vertData); + CustomData_free(&dm->edgeData); + CustomData_free(&dm->faceData); + + MEM_freeN(dm); +} + + +/**************** CDDM interface functions ****************/ +static DerivedMesh *cdDM_create(const char *desc) +{ + DerivedMesh *dm; + + dm = MEM_callocN(sizeof(*dm), desc); + + dm->getMinMax = cdDM_getMinMax; + + dm->convertToDispListMesh = cdDM_convertToDispListMesh; + + dm->getNumVerts = cdDM_getNumVerts; + dm->getNumFaces = cdDM_getNumFaces; + dm->getNumEdges = cdDM_getNumEdges; + + dm->getVert = cdDM_getVert; + dm->getEdge = cdDM_getEdge; + dm->getFace = cdDM_getFace; + dm->getVertArray = cdDM_getVertArray; + dm->getEdgeArray = cdDM_getEdgeArray; + dm->getFaceArray = cdDM_getFaceArray; + dm->getVertData = DM_get_vert_data; + dm->getEdgeData = DM_get_edge_data; + dm->getFaceData = 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->getVertCos = cdDM_getVertCos; + dm->getVertCo = cdDM_getVertCo; + dm->getVertNo = cdDM_getVertNo; + + dm->drawVerts = cdDM_drawVerts; + + dm->drawUVEdges = cdDM_drawUVEdges; + dm->drawEdges = cdDM_drawEdges; + dm->drawLooseEdges = cdDM_drawLooseEdges; + dm->drawMappedEdges = cdDM_drawMappedEdges; + + dm->drawFacesSolid = cdDM_drawFacesSolid; + dm->drawFacesColored = cdDM_drawFacesColored; + dm->drawFacesTex = cdDM_drawFacesTex; + dm->drawMappedFaces = cdDM_drawMappedFaces; + dm->drawMappedFacesTex = cdDM_drawMappedFacesTex; + + dm->foreachMappedVert = cdDM_foreachMappedVert; + dm->foreachMappedEdge = cdDM_foreachMappedEdge; + dm->foreachMappedFaceCenter = cdDM_foreachMappedFaceCenter; + + dm->release = cdDM_release; + + return dm; +} + +DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces) +{ + DerivedMesh *dm = cdDM_create("CDDM_new dm"); + DM_init(dm, numVerts, numEdges, numFaces); + + CustomData_add_layer(&dm->vertData, LAYERTYPE_MVERT, LAYERFLAG_NOCOPY, + NULL); + CustomData_add_layer(&dm->edgeData, LAYERTYPE_MEDGE, LAYERFLAG_NOCOPY, + NULL); + CustomData_add_layer(&dm->faceData, LAYERTYPE_MFACE, LAYERFLAG_NOCOPY, + NULL); + + return dm; +} + +DerivedMesh *CDDM_from_mesh(Mesh *mesh) +{ + DerivedMesh *dm = CDDM_new(mesh->totvert, mesh->totedge, mesh->totface); + int i; + + if(mesh->msticky) + CustomData_add_layer(&dm->vertData, LAYERTYPE_MSTICKY, 0, NULL); + if(mesh->dvert) + CustomData_add_layer(&dm->vertData, LAYERTYPE_MDEFORMVERT, 0, NULL); + + if(mesh->tface) + CustomData_add_layer(&dm->faceData, LAYERTYPE_TFACE, 0, NULL); + if(mesh->mcol) + CustomData_add_layer(&dm->faceData, LAYERTYPE_MCOL, 0, NULL); + + for(i = 0; i < mesh->totvert; ++i) { + DM_set_vert_data(dm, i, LAYERTYPE_MVERT, &mesh->mvert[i]); + if(mesh->msticky) + DM_set_vert_data(dm, i, LAYERTYPE_MSTICKY, &mesh->msticky[i]); + if(mesh->dvert) + DM_set_vert_data(dm, i, LAYERTYPE_MDEFORMVERT, &mesh->dvert[i]); + + DM_set_vert_data(dm, i, LAYERTYPE_ORIGINDEX, &i); + } + + for(i = 0; i < mesh->totedge; ++i) { + DM_set_edge_data(dm, i, LAYERTYPE_MEDGE, &mesh->medge[i]); + + DM_set_edge_data(dm, i, LAYERTYPE_ORIGINDEX, &i); + } + + for(i = 0; i < mesh->totface; ++i) { + DM_set_face_data(dm, i, LAYERTYPE_MFACE, &mesh->mface[i]); + if(mesh->tface) + DM_set_face_data(dm, i, LAYERTYPE_TFACE, &mesh->tface[i]); + if(mesh->mcol) + DM_set_face_data(dm, i, LAYERTYPE_MCOL, &mesh->mcol[i * 4]); + + DM_set_face_data(dm, i, LAYERTYPE_ORIGINDEX, &i); + } + + return dm; +} + +DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me) +{ + DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts), + BLI_countlist(&em->edges), + BLI_countlist(&em->faces)); + EditVert *eve; + EditEdge *eed; + EditFace *efa; + int i; + MVert *mvert = CDDM_get_verts(dm); + MEdge *medge = CDDM_get_edges(dm); + MFace *mface = CDDM_get_faces(dm); + int *index; + + /* this maps from vert pointer to vert index */ + GHash *vertHash = BLI_ghash_new(BLI_ghashutil_ptrhash, + BLI_ghashutil_ptrcmp); + + for(i = 0, eve = em->verts.first; eve; eve = eve->next, ++i) + BLI_ghash_insert(vertHash, eve, (void *)i); + + if(me->msticky) + CustomData_add_layer(&dm->vertData, LAYERTYPE_MDEFORMVERT, 0, NULL); + if(me->dvert) + CustomData_add_layer(&dm->vertData, LAYERTYPE_MDEFORMVERT, 0, NULL); + + if(me->tface) + CustomData_add_layer(&dm->faceData, LAYERTYPE_TFACE, 0, NULL); + + /* Need to be able to mark loose edges */ + for(eed = em->edges.first; eed; eed = eed->next) { + eed->f2 = 0; + } + for(efa = em->faces.first; efa; efa = efa->next) { + efa->e1->f2 = 1; + efa->e2->f2 = 1; + efa->e3->f2 = 1; + if(efa->e4) efa->e4->f2 = 1; + } + + index = dm->getVertDataArray(dm, LAYERTYPE_ORIGINDEX); + for(i = 0, eve = em->verts.first; i < dm->vertData.numElems; + i++, eve = eve->next, index++) { + MVert *mv = &mvert[i]; + + VECCOPY(mv->co, eve->co); + + 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->mat_nr = 0; + mv->flag = 0; + + *index = i; + + if(me->msticky && eve->keyindex != -1) + DM_set_vert_data(dm, i, LAYERTYPE_MSTICKY, + &me->msticky[eve->keyindex]); + if(me->dvert && eve->keyindex != -1) + DM_set_vert_data(dm, i, LAYERTYPE_MDEFORMVERT, + &me->dvert[eve->keyindex]); + } + + index = dm->getEdgeDataArray(dm, LAYERTYPE_ORIGINDEX); + for(i = 0, eed = em->edges.first; i < dm->edgeData.numElems; + i++, eed = eed->next, index++) { + MEdge *med = &medge[i]; + + med->v1 = (int) BLI_ghash_lookup(vertHash, eed->v1); + med->v2 = (int) BLI_ghash_lookup(vertHash, eed->v2); + med->crease = (unsigned char) (eed->crease * 255.0f); + med->flag = ME_EDGEDRAW|ME_EDGERENDER; + + if(eed->seam) med->flag |= ME_SEAM; + if(eed->sharp) med->flag |= ME_SHARP; + if(!eed->f2) med->flag |= ME_LOOSEEDGE; + + *index = i; + } + + index = dm->getFaceDataArray(dm, LAYERTYPE_ORIGINDEX); + for(i = 0, efa = em->faces.first; i < dm->faceData.numElems; + i++, efa = efa->next, index++) { + MFace *mf = &mface[i]; + + mf->v1 = (int) BLI_ghash_lookup(vertHash, efa->v1); + mf->v2 = (int) BLI_ghash_lookup(vertHash, efa->v2); + mf->v3 = (int) BLI_ghash_lookup(vertHash, efa->v3); + mf->v4 = efa->v4 ? (int)BLI_ghash_lookup(vertHash, efa->v4) : 0; + mf->mat_nr = efa->mat_nr; + mf->flag = efa->flag; + test_index_face(mf, NULL, NULL, efa->v4?4:3); + + *index = i; + + if(me->tface) + DM_set_face_data(dm, i, LAYERTYPE_TFACE, &efa->tf); + } + + BLI_ghash_free(vertHash, NULL, NULL); + + return dm; +} + +DerivedMesh *CDDM_copy(DerivedMesh *source) +{ + DerivedMesh *dest = CDDM_from_template(source, + source->vertData.numElems, + source->edgeData.numElems, + source->faceData.numElems); + + CustomData_copy_data(&source->vertData, &dest->vertData, 0, 0, + source->vertData.numElems); + CustomData_copy_data(&source->edgeData, &dest->edgeData, 0, 0, + source->edgeData.numElems); + CustomData_copy_data(&source->faceData, &dest->faceData, 0, 0, + source->faceData.numElems); + + /* copy vert/face/edge data from source */ + source->getVertArray(source, CDDM_get_verts(dest)); + source->getEdgeArray(source, CDDM_get_edges(dest)); + source->getFaceArray(source, CDDM_get_faces(dest)); + + return dest; +} + +DerivedMesh *CDDM_from_template(DerivedMesh *source, + int numVerts, int numEdges, int numFaces) +{ + DerivedMesh *dest = cdDM_create("CDDM_from_template dest"); + DM_from_template(dest, source, numVerts, numEdges, numFaces); + + /* if no vert/face/edge layers in custom data, add them */ + if(!CDDM_get_verts(dest)) + CustomData_add_layer(&dest->vertData, LAYERTYPE_MVERT, + LAYERFLAG_NOCOPY, NULL); + if(!CDDM_get_edges(dest)) + CustomData_add_layer(&dest->edgeData, LAYERTYPE_MEDGE, + LAYERFLAG_NOCOPY, NULL); + if(!CDDM_get_faces(dest)) + CustomData_add_layer(&dest->faceData, LAYERTYPE_MFACE, + LAYERFLAG_NOCOPY, NULL); + + return dest; +} + +void CDDM_apply_vert_coords(DerivedMesh *dm, float (*vertCoords)[3]) +{ + int i; + MVert *vert = CDDM_get_verts(dm); + + for(i = 0; i < dm->vertData.numElems; ++i, ++vert) + VECCOPY(vert->co, vertCoords[i]); +} + +/* adapted from mesh_calc_normals */ +void CDDM_calc_normals(DerivedMesh *dm) +{ + float (*temp_nors)[3]; + float (*face_nors)[3]; + int i; + int numVerts = dm->getNumVerts(dm); + int numFaces = dm->getNumFaces(dm); + MFace *mf; + MVert *mv = CDDM_get_verts(dm); + + if(!mv) return; + + temp_nors = MEM_callocN(numVerts * sizeof(*temp_nors), + "CDDM_calc_normals temp_nors"); + face_nors = MEM_mallocN(numFaces * sizeof(*face_nors), + "CDDM_calc_normals face_nors"); + + mf = CDDM_get_faces(dm); + for(i = 0; i < numFaces; i++, mf++) { + float *f_no = face_nors[i]; + + if(mf->v4) + CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, mv[mf->v4].co, f_no); + else + CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co, + mv[mf->v3].co, f_no); + + VecAddf(temp_nors[mf->v1], temp_nors[mf->v1], f_no); + VecAddf(temp_nors[mf->v2], temp_nors[mf->v2], f_no); + VecAddf(temp_nors[mf->v3], temp_nors[mf->v3], f_no); + if(mf->v4) + VecAddf(temp_nors[mf->v4], temp_nors[mf->v4], f_no); + } + + for(i = 0; i < numVerts; i++, mv++) { + float *no = temp_nors[i]; + + if (Normalise(no) == 0.0) { + VECCOPY(no, mv->co); + Normalise(no); + } + + mv->no[0] = (short)(no[0] * 32767.0); + mv->no[1] = (short)(no[1] * 32767.0); + mv->no[2] = (short)(no[2] * 32767.0); + } + + MEM_freeN(temp_nors); + + /* TODO maybe cache face normals here? */ + MEM_freeN(face_nors); +} + +void CDDM_calc_edges(DerivedMesh *dm) +{ + CustomData edgeData; + EdgeHash *eh = BLI_edgehash_new(); + EdgeHashIterator *ehi; + int i; + int maxFaces = dm->getNumFaces(dm); + MFace *mf = CDDM_get_faces(dm); + MEdge *med; + + for (i = 0; i < maxFaces; 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); + } + } + + CustomData_from_template(&dm->edgeData, &edgeData, BLI_edgehash_size(eh)); + + if(!CustomData_get_layer(&edgeData, LAYERTYPE_MEDGE)) + CustomData_add_layer(&edgeData, LAYERTYPE_MEDGE, + LAYERFLAG_NOCOPY, NULL); + + ehi = BLI_edgehashIterator_new(eh); + med = CustomData_get_layer(&edgeData, LAYERTYPE_MEDGE); + for(i = 0; !BLI_edgehashIterator_isDone(ehi); + BLI_edgehashIterator_step(ehi), ++i, ++med) { + BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2); + + med->flag = ME_EDGEDRAW|ME_EDGERENDER; + } + BLI_edgehashIterator_free(ehi); + + CustomData_free(&dm->edgeData); + dm->edgeData = edgeData; + + BLI_edgehash_free(eh, NULL); +} + +void CDDM_set_num_verts(DerivedMesh *dm, int numVerts) +{ + CustomData_set_num_elems(&dm->vertData, numVerts); +} + +void CDDM_set_num_edges(DerivedMesh *dm, int numEdges) +{ + CustomData_set_num_elems(&dm->edgeData, numEdges); +} + +void CDDM_set_num_faces(DerivedMesh *dm, int numFaces) +{ + CustomData_set_num_elems(&dm->faceData, numFaces); +} + +MVert *CDDM_get_vert(DerivedMesh *dm, int index) +{ + return CustomData_get(&dm->vertData, index, LAYERTYPE_MVERT); +} + +MEdge *CDDM_get_edge(DerivedMesh *dm, int index) +{ + return CustomData_get(&dm->edgeData, index, LAYERTYPE_MEDGE); +} + +MFace *CDDM_get_face(DerivedMesh *dm, int index) +{ + return CustomData_get(&dm->faceData, index, LAYERTYPE_MFACE); +} + +MVert *CDDM_get_verts(DerivedMesh *dm) +{ + return CustomData_get_layer(&dm->vertData, LAYERTYPE_MVERT); +} + +MEdge *CDDM_get_edges(DerivedMesh *dm) +{ + return CustomData_get_layer(&dm->edgeData, LAYERTYPE_MEDGE); +} + +MFace *CDDM_get_faces(DerivedMesh *dm) +{ + return CustomData_get_layer(&dm->faceData, LAYERTYPE_MFACE); +} + diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c new file mode 100644 index 00000000000..d774324f1c1 --- /dev/null +++ b/source/blender/blenkernel/intern/customdata.c @@ -0,0 +1,630 @@ +/* +* $Id$ +* +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +* The Original Code is Copyright (C) 2006 Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Ben Batt <benbatt@gmail.com> +* +* ***** END GPL LICENSE BLOCK ***** +* +* Implementation of CustomData. +* +* BKE_customdata.h contains the function prototypes for this file. +* +*/ + +#include "BKE_customdata.h" + +#include "BLI_linklist.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "MEM_guardedalloc.h" + +#include <string.h> + +/* number of layers to add when growing a CustomData object */ +#define CUSTOMDATA_GROW 5 + +/* descriptor and storage for a custom data layer */ +typedef struct LayerDesc { + int type; /* type of data in layer */ + int flag; /* general purpose flag */ + void *data; /* layer data */ +} LayerDesc; + +/********************* Layer type information **********************/ +typedef struct LayerTypeInfo { + int size; /* the memory size of one element of this layer's data */ + + /* a function to copy count elements of this layer's data + * (deep copy if appropriate) + * size should be the size of one element of this layer's data (e.g. + * LayerTypeInfo.size) + * if NULL, memcpy is used + */ + void (*copy)(const void *source, void *dest, int count, int size); + + /* a function to free any dynamically allocated components of this + * layer's data (note the data pointer itself should not be freed) + * size should be the size of one element of this layer's data (e.g. + * LayerTypeInfo.size) + */ + void (*free)(void *data, int count, int size); + + /* a function to interpolate between count source elements of this + * layer's data and store the result in dest + * if weights == NULL or sub_weights == NULL, they should default to 1 + * + * weights gives the weight for each element in sources + * sub_weights gives the sub-element weights for each element in sources + * (there should be (sub element count)^2 weights per element) + * count gives the number of elements in sources + */ + void (*interp)(void **sources, float *weights, float *sub_weights, + int count, void *dest); +} LayerTypeInfo; + +static void layerCopy_mdeformvert(const void *source, void *dest, + int count, int size); + +static void layerFree_mdeformvert(void *data, int count, int size); + +static void layerInterp_mdeformvert(void **sources, float *weights, + float *sub_weights, int count, void *dest); + +static void layerInterp_tface(void **sources, float *weights, + float *sub_weights, int count, void *dest); + +static void layerInterp_mcol(void **sources, float *weights, + float *sub_weights, int count, void *dest); + +const LayerTypeInfo LAYERTYPEINFO[LAYERTYPE_NUMTYPES] = { + {sizeof(MVert), NULL, NULL, NULL}, + {sizeof(MSticky), NULL, NULL, NULL}, + {sizeof(MDeformVert), + layerCopy_mdeformvert, layerFree_mdeformvert, layerInterp_mdeformvert}, + {sizeof(MEdge), NULL, NULL, NULL}, + {sizeof(MFace), NULL, NULL, NULL}, + {sizeof(TFace), NULL, NULL, layerInterp_tface}, + /* 4 MCol structs per face */ + {sizeof(MCol) * 4, NULL, NULL, layerInterp_mcol}, + {sizeof(int), NULL, NULL, NULL}, + /* 3 floats per normal vector */ + {sizeof(float) * 3, NULL, NULL, NULL}, + {sizeof(int), NULL, NULL, NULL}, +}; + +const LayerTypeInfo *layerType_getInfo(int type) +{ + if(type < 0 || type >= LAYERTYPE_NUMTYPES) return NULL; + + return &LAYERTYPEINFO[type]; +} + +static void layerCopy_mdeformvert(const void *source, void *dest, + int count, int size) +{ + int i; + + memcpy(dest, source, count * size); + + for(i = 0; i < count; ++i) { + MDeformVert *dvert = (MDeformVert *)((char *)dest + i * size); + MDeformWeight *dw = MEM_callocN(dvert->totweight * sizeof(*dw), + "layerCopy_mdeformvert dw"); + + memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw)); + dvert->dw = dw; + } +} + +static void layerFree_mdeformvert(void *data, int count, int size) +{ + int i; + + for(i = 0; i < count; ++i) { + MDeformVert *dvert = (MDeformVert *)((char *)data + i * size); + + if(dvert->dw) { + MEM_freeN(dvert->dw); + dvert->dw = NULL; + } + } +} + +static void linklist_free_simple(void *link) +{ + MEM_freeN(link); +} + +static void layerInterp_mdeformvert(void **sources, float *weights, + float *sub_weights, int count, void *dest) +{ + MDeformVert *dvert = dest; + LinkNode *dest_dw = NULL; /* a list of lists of MDeformWeight pointers */ + LinkNode *node; + int i, j, totweight; + + if(count <= 0) return; + + /* build a list of unique def_nrs for dest */ + totweight = 0; + for(i = 0; i < count; ++i) { + MDeformVert *source = sources[i]; + float interp_weight = weights ? weights[i] : 1.0f; + + for(j = 0; j < source->totweight; ++j) { + MDeformWeight *dw = &source->dw[j]; + + for(node = dest_dw; node; node = node->next) { + MDeformWeight *tmp_dw = (MDeformWeight *)node->link; + + if(tmp_dw->def_nr == dw->def_nr) { + tmp_dw->weight += dw->weight * interp_weight; + break; + } + } + + /* if this def_nr is not in the list, add it */ + if(!node) { + MDeformWeight *tmp_dw = MEM_callocN(sizeof(*tmp_dw), + "layerInterp_mdeformvert tmp_dw"); + tmp_dw->def_nr = dw->def_nr; + tmp_dw->weight = dw->weight * interp_weight; + BLI_linklist_prepend(&dest_dw, tmp_dw); + totweight++; + } + } + } + + /* now we know how many unique deform weights there are, so realloc */ + if(dvert->dw) MEM_freeN(dvert->dw); + dvert->dw = MEM_callocN(sizeof(*dvert->dw) * totweight, + "layerInterp_mdeformvert dvert->dw"); + dvert->totweight = totweight; + + for(i = 0, node = dest_dw; node; node = node->next, ++i) + dvert->dw[i] = *((MDeformWeight *)node->link); + + BLI_linklist_free(dest_dw, linklist_free_simple); +} + +static void layerInterp_tface(void **sources, float *weights, + float *sub_weights, int count, void *dest) +{ + TFace *tf = dest; + int i, j, k; + float uv[4][2]; + float col[4][4]; + + if(count <= 0) return; + + memset(uv, 0, sizeof(uv)); + memset(col, 0, sizeof(col)); + + for(i = 0; i < count; ++i) { + float weight = weights ? weights[i] : 1; + TFace *src = sources[i]; + + for(j = 0; j < 4; ++j) { + if(sub_weights) { + for(k = 0; k < 4; ++k) { + float sub_weight = sub_weights[j * 4 + k]; + char *tmp_col = (char *)&src->col[k]; + float *tmp_uv = src->uv[k]; + + uv[j][0] += tmp_uv[0] * sub_weight * weight; + uv[j][1] += tmp_uv[1] * sub_weight * weight; + + col[j][0] += tmp_col[0] * sub_weight * weight; + col[j][1] += tmp_col[1] * sub_weight * weight; + col[j][2] += tmp_col[2] * sub_weight * weight; + col[j][3] += tmp_col[3] * sub_weight * weight; + } + } else { + char *tmp_col = (char *)&src->col[j]; + uv[j][0] += src->uv[j][0] * weight; + uv[j][1] += src->uv[j][1] * weight; + + col[j][0] += tmp_col[0] * weight; + col[j][1] += tmp_col[1] * weight; + col[j][2] += tmp_col[2] * weight; + col[j][3] += tmp_col[3] * weight; + } + } + } + + *tf = *(TFace *)sources[0]; + for(j = 0; j < 4; ++j) { + char *tmp_col = (char *)&tf->col[j]; + + tf->uv[j][0] = uv[j][0]; + tf->uv[j][1] = uv[j][1]; + + tmp_col[0] = (int)col[j][0]; + tmp_col[1] = (int)col[j][1]; + tmp_col[2] = (int)col[j][2]; + tmp_col[3] = (int)col[j][3]; + } +} + +static void layerInterp_mcol(void **sources, float *weights, + float *sub_weights, int count, void *dest) +{ + MCol *mc = dest; + int i, j, k; + struct { + float a; + float r; + float g; + float b; + } col[4]; + + if(count <= 0) return; + + memset(col, 0, sizeof(col)); + + for(i = 0; i < count; ++i) { + float weight = weights ? weights[i] : 1; + float *sub_weight = sub_weights; + + for(j = 0; j < 4; ++j) { + if(sub_weights) { + MCol *src = sources[i]; + for(k = 0; k < 4; ++k, ++sub_weight, ++src) { + col[j].a += src->a * (*sub_weight) * weight; + col[j].r += src->r * (*sub_weight) * weight; + col[j].g += src->g * (*sub_weight) * weight; + col[j].b += src->b * (*sub_weight) * weight; + } + } else { + MCol *src = sources[i]; + col[j].a += src[j].a * weight; + col[j].r += src[j].r * weight; + col[j].g += src[j].g * weight; + col[j].b += src[j].b * weight; + } + } + } + + for(j = 0; j < 4; ++j) { + mc[j].a = (int)col[j].a; + mc[j].r = (int)col[j].r; + mc[j].g = (int)col[j].g; + mc[j].b = (int)col[j].b; + } +} + +/********************* CustomData functions *********************/ +void CustomData_init(CustomData *data, + int maxLayers, int maxElems, int subElems) +{ + data->layers = MEM_callocN(maxLayers * sizeof(*data->layers), + "CustomData->layers"); + data->numLayers = 0; + data->maxLayers = maxLayers; + data->numElems = maxElems; + data->maxElems = maxElems; + data->subElems = subElems; +} + +void CustomData_from_template(const CustomData *source, CustomData *dest, + int maxElems) +{ + int i; + + CustomData_init(dest, source->maxLayers, maxElems, source->subElems); + + for(i = 0; i < source->numLayers; ++i) { + if(source->layers[i].flag & LAYERFLAG_NOCOPY) continue; + + CustomData_add_layer(dest, source->layers[i].type, + source->layers[i].flag & ~LAYERFLAG_NOFREE, NULL); + } +} + +void CustomData_free(CustomData *data) +{ + int i; + const LayerTypeInfo *typeInfo; + + for(i = 0; i < data->numLayers; ++i) { + if(!(data->layers[i].flag & LAYERFLAG_NOFREE)) { + typeInfo = layerType_getInfo(data->layers[i].type); + if(typeInfo->free) + typeInfo->free(data->layers[i].data, data->numElems, + typeInfo->size); + + MEM_freeN(data->layers[i].data); + } + } + + data->numLayers = 0; + + if(data->layers) { + MEM_freeN(data->layers); + data->layers = NULL; + } +} + +static int customData_grow(CustomData *data, int amount) +{ + LayerDesc *tmp = MEM_callocN(sizeof(*tmp) * (data->maxLayers + amount), + "CustomData->layers"); + if(!tmp) return 0; + + data->maxLayers += amount; + memcpy(tmp, data->layers, sizeof(*tmp) * data->numLayers); + + MEM_freeN(data->layers); + data->layers = tmp; + + return 1; +} + +static int customData_add_layer__internal(CustomData *data, int type, + int flag, void *layer) +{ + int index = data->numLayers; + + if(index >= data->maxLayers) + if(!customData_grow(data, CUSTOMDATA_GROW)) return 0; + + /* keep layers ordered by type */ + for( ; index > 0 && data->layers[index - 1].type > type; --index) + data->layers[index] = data->layers[index - 1]; + + data->layers[index].type = type; + data->layers[index].flag = flag; + data->layers[index].data = layer; + + data->numLayers++; + + return 1; +} + +int CustomData_add_layer(CustomData *data, int type, int flag, void *layer) +{ + int size = layerType_getInfo(type)->size * data->numElems; + void *tmp_layer = layer; + + if(!layer) tmp_layer = MEM_callocN(size, "LayerDesc.data"); + + if(!tmp_layer) return 0; + + if(customData_add_layer__internal(data, type, flag, tmp_layer)) + return 1; + else { + MEM_freeN(tmp_layer); + return 0; + } +} + +int CustomData_compat(const CustomData *data1, const CustomData *data2) +{ + int i; + + if(data1->numLayers != data2->numLayers) return 0; + + for(i = 0; i < data1->numLayers; ++i) { + if(data1->layers[i].type != data2->layers[i].type) return 0; + if(data1->layers[i].flag != data2->layers[i].flag) return 0; + } + + return 1; +} + +/* gets index of first layer matching type after start_index + * if start_index < 0, starts searching at 0 + * returns -1 if there is no layer of type + */ +static int CustomData_find_next(const CustomData *data, int type, + int start_index) +{ + int i = start_index + 1; + + if(i < 0) i = 0; + + for(; i < data->numLayers; ++i) + if(data->layers[i].type == type) return i; + + return -1; +} + +int CustomData_copy_data(const CustomData *source, CustomData *dest, + int source_index, int dest_index, int count) +{ + const LayerTypeInfo *type_info; + int src_i, dest_i; + int src_offset; + int dest_offset; + + if(count < 0) return 0; + if(source_index < 0 || (source_index + count) > source->numElems) + return 0; + if(dest_index < 0 || (dest_index + count) > dest->numElems) + return 0; + + /* copies a layer at a time */ + dest_i = 0; + for(src_i = 0; src_i < source->numLayers; ++src_i) { + if(source->layers[src_i].flag & LAYERFLAG_NOCOPY) continue; + + /* find the first dest layer with type >= the source type + * (this should work because layers are ordered by type) + */ + while(dest_i < dest->numLayers + && dest->layers[dest_i].type < source->layers[src_i].type) + ++dest_i; + + /* if there are no more dest layers, we're done */ + if(dest_i >= dest->numLayers) return 1; + + /* if we found a matching layer, copy the data */ + if(dest->layers[dest_i].type == source->layers[src_i].type) { + char *src_data = source->layers[src_i].data; + char *dest_data = dest->layers[dest_i].data; + + type_info = layerType_getInfo(source->layers[src_i].type); + + src_offset = source_index * type_info->size; + dest_offset = dest_index * type_info->size; + + if(type_info->copy) + type_info->copy(src_data + src_offset, + dest_data + dest_offset, + count, type_info->size); + else + memcpy(dest_data + dest_offset, + src_data + src_offset, + count * type_info->size); + + /* if there are multiple source & dest layers of the same type, + * we don't want to copy all source layers to the same dest, so + * increment dest_i + */ + ++dest_i; + } + } + + return 1; +} + +int CustomData_free_elem(CustomData *data, int index, int count) +{ + int i; + const LayerTypeInfo *typeInfo; + + if(index < 0 || count <= 0 || index + count > data->numElems) return 0; + + for(i = 0; i < data->numLayers; ++i) { + if(!(data->layers[i].flag & LAYERFLAG_NOFREE)) { + typeInfo = layerType_getInfo(data->layers[i].type); + + if(typeInfo->free) { + int offset = typeInfo->size * index; + + typeInfo->free((char *)data->layers[i].data + offset, + count, typeInfo->size); + } + } + } + + return 1; +} + +#define SOURCE_BUF_SIZE 100 + +int CustomData_interp(const CustomData *source, CustomData *dest, + int *src_indices, float *weights, float *sub_weights, + int count, int dest_index) +{ + int src_i, dest_i; + int dest_offset; + int j; + void *source_buf[SOURCE_BUF_SIZE]; + void **sources = source_buf; + + if(count <= 0) return 0; + if(dest_index < 0 || dest_index >= dest->numElems) return 0; + + /* slow fallback in case we're interpolating a ridiculous number of + * elements + */ + if(count > SOURCE_BUF_SIZE) + sources = MEM_callocN(sizeof(*sources) * count, + "CustomData_interp sources"); + + /* interpolates a layer at a time */ + for(src_i = 0; src_i < source->numLayers; ++src_i) { + LayerDesc *source_layer = &source->layers[src_i]; + const LayerTypeInfo *type_info = + layerType_getInfo(source_layer->type); + + dest_i = CustomData_find_next(dest, source_layer->type, -1); + + if(dest_i >= 0 && type_info->interp) { + void *src_data = source_layer->data; + + for(j = 0; j < count; ++j) + sources[j] = (char *)src_data + + type_info->size * src_indices[j]; + + dest_offset = dest_index * type_info->size; + + type_info->interp(sources, weights, sub_weights, count, + (char *)dest->layers[dest_i].data + dest_offset); + } + } + + if(count > SOURCE_BUF_SIZE) MEM_freeN(sources); + return 1; +} + +void *CustomData_get(const CustomData *data, int index, int type) +{ + int offset; + int layer_index; + + if(index < 0 || index > data->numElems) return NULL; + + /* get the layer index of the first layer of type */ + layer_index = CustomData_find_next(data, type, -1); + if(layer_index < 0) return NULL; + + /* get the offset of the desired element */ + 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 first layer of type */ + int layer_index = CustomData_find_next(data, type, -1); + + if(layer_index < 0) return NULL; + + return data->layers[layer_index].data; +} + +void CustomData_set(const CustomData *data, int index, int type, void *source) +{ + void *dest = CustomData_get(data, index, type); + const LayerTypeInfo *type_info = layerType_getInfo(type); + + if(!dest) return; + + if(type_info->copy) + type_info->copy(source, dest, 1, type_info->size); + else + memcpy(dest, source, type_info->size); +} + +void CustomData_set_num_elems(CustomData *data, int numElems) +{ + if(numElems < 0) return; + if(numElems < data->maxElems) data->numElems = numElems; + else data->numElems = data->maxElems; +} diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 8f92a0a0d68..b262dac695a 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -1189,13 +1189,18 @@ static ModifierData *curve_get_tesselate_point(Object *ob, int forRender, int ed { ModifierData *md = modifiers_getVirtualModifierList(ob); ModifierData *preTesselatePoint; + int required_mode; + + if(forRender) required_mode = eModifierMode_Render; + else required_mode = eModifierMode_Realtime; + + if(editmode) required_mode |= eModifierMode_Editmode; preTesselatePoint = NULL; for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!(md->mode&(1<<forRender))) continue; - if (editmode && !(md->mode&eModifierMode_Editmode)) continue; + if ((md->mode & required_mode) != required_mode) continue; if (mti->isDisabled && mti->isDisabled(md)) continue; if (md->type==eModifierType_Hook || md->type==eModifierType_Softbody) { @@ -1214,6 +1219,12 @@ void curve_calc_modifiers_pre(Object *ob, ListBase *nurb, int forRender, float ( int numVerts = 0; float (*originalVerts)[3] = NULL; float (*deformedVerts)[3] = NULL; + int required_mode; + + if(forRender) required_mode = eModifierMode_Render; + else required_mode = eModifierMode_Realtime; + + if(editmode) required_mode |= eModifierMode_Editmode; if(ob!=G.obedit && do_ob_key(ob)) { deformedVerts = curve_getVertexCos(ob->data, nurb, &numVerts); @@ -1224,8 +1235,7 @@ void curve_calc_modifiers_pre(Object *ob, ListBase *nurb, int forRender, float ( for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!(md->mode&(1<<forRender))) continue; - if (editmode && !(md->mode&eModifierMode_Editmode)) continue; + if ((md->mode & required_mode) != required_mode) continue; if (mti->isDisabled && mti->isDisabled(md)) continue; if (mti->type!=eModifierTypeType_OnlyDeform) continue; @@ -1256,6 +1266,12 @@ void curve_calc_modifiers_post(Object *ob, ListBase *nurb, ListBase *dispbase, i ModifierData *md = modifiers_getVirtualModifierList(ob); ModifierData *preTesselatePoint = curve_get_tesselate_point(ob, forRender, editmode); DispList *dl; + int required_mode; + + if(forRender) required_mode = eModifierMode_Render; + else required_mode = eModifierMode_Realtime; + + if(editmode) required_mode |= eModifierMode_Editmode; if (preTesselatePoint) { md = preTesselatePoint->next; @@ -1264,8 +1280,7 @@ void curve_calc_modifiers_post(Object *ob, ListBase *nurb, ListBase *dispbase, i for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!(md->mode&(1<<forRender))) continue; - if (editmode && !(md->mode&eModifierMode_Editmode)) continue; + if ((md->mode & required_mode) != required_mode) continue; if (mti->isDisabled && mti->isDisabled(md)) continue; if (mti->type!=eModifierTypeType_OnlyDeform) continue; diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 81f7eb7a0eb..768fedd86ea 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -56,6 +56,8 @@ #include "BKE_anim.h" #include "BKE_armature.h" #include "BKE_curve.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_DerivedMesh.h" #include "BKE_deform.h" #include "BKE_displist.h" #include "BKE_global.h" @@ -161,7 +163,7 @@ void resizelattice(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) Mat4CpyMat4(mat, ltOb->obmat); Mat4One(ltOb->obmat); - lattice_deform_verts(ltOb, NULL, vertexCos, uNew*vNew*wNew, NULL); + lattice_deform_verts(ltOb, NULL, NULL, vertexCos, uNew*vNew*wNew, NULL); Mat4CpyMat4(ltOb->obmat, mat); lt->typeu = typeu; @@ -556,52 +558,85 @@ static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *c } -void curve_deform_verts(Object *cuOb, Object *target, float (*vertexCos)[3], int numVerts, char *vgroup) +void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup) { Curve *cu = cuOb->data; int a, flag = cu->flag; CurveDeform cd; + int use_vgroups; cu->flag |= (CU_PATH|CU_FOLLOW); // needed for path & bevlist init_curve_deform(cuOb, target, &cd); - INIT_MINMAX(cd.dmin, cd.dmax); - - for(a=0; a<numVerts; a++) { - Mat4MulVecfl(cd.curvespace, vertexCos[a]); - DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax); - } - - if(vgroup && vgroup[0] && target->type==OB_MESH) { + /* check whether to use vertex groups (only possible if target is a Mesh) + * we want either a Mesh with no derived data, or derived data with + * deformverts + */ + if(target && target->type==OB_MESH) { + /* if there's derived data without deformverts, don't use vgroups */ + if(dm && !dm->getVertData(dm, 0, LAYERTYPE_MDEFORMVERT)) + use_vgroups = 0; + else + use_vgroups = 1; + } else + use_vgroups = 0; + + if(vgroup && vgroup[0] && use_vgroups) { bDeformGroup *curdef; Mesh *me= target->data; - int index= 0; + int index; /* find the group (weak loop-in-loop) */ - for (curdef = target->defbase.first; curdef; curdef=curdef->next, index++) + for(index = 0, curdef = target->defbase.first; curdef; + curdef = curdef->next, index++) if (!strcmp(curdef->name, vgroup)) break; - /* check for numVerts because old files can have modifier over subsurf still */ - if(curdef && me->dvert && numVerts==me->totvert) { - MDeformVert *dvert= me->dvert; + + if(curdef && (me->dvert || dm)) { + MDeformVert *dvert = me->dvert; float vec[3]; int j; - - for(a=0; a<numVerts; a++, dvert++) { - for(j=0; j<dvert->totweight; j++) { - if (dvert->dw[j].def_nr == index) { + + INIT_MINMAX(cd.dmin, cd.dmax); + + for(a = 0; a < numVerts; a++, dvert++) { + if(dm) dvert = dm->getVertData(dm, a, LAYERTYPE_MDEFORMVERT); + + for(j = 0; j < dvert->totweight; j++) { + if(dvert->dw[j].def_nr == index) { + Mat4MulVecfl(cd.curvespace, vertexCos[a]); + DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax); + break; + } + } + } + + dvert = me->dvert; + for(a = 0; a < numVerts; a++, dvert++) { + if(dm) dvert = dm->getVertData(dm, a, LAYERTYPE_MDEFORMVERT); + + for(j = 0; j < dvert->totweight; j++) { + if(dvert->dw[j].def_nr == index) { VECCOPY(vec, vertexCos[a]); calc_curve_deform(cuOb, vec, target->trackflag, &cd); - VecLerpf(vertexCos[a], vertexCos[a], vec, dvert->dw[j].weight); + VecLerpf(vertexCos[a], vertexCos[a], vec, + dvert->dw[j].weight); Mat4MulVecfl(cd.objectspace, vertexCos[a]); + break; } } } } - } - else { - for(a=0; a<numVerts; a++) { + } else { + INIT_MINMAX(cd.dmin, cd.dmax); + + for(a = 0; a < numVerts; a++) { + Mat4MulVecfl(cd.curvespace, vertexCos[a]); + DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax); + } + + for(a = 0; a < numVerts; a++) { calc_curve_deform(cuOb, vertexCos[a], target->trackflag, &cd); Mat4MulVecfl(cd.objectspace, vertexCos[a]); } @@ -609,37 +644,52 @@ void curve_deform_verts(Object *cuOb, Object *target, float (*vertexCos)[3], int cu->flag = flag; } -void lattice_deform_verts(Object *laOb, Object *target, float (*vertexCos)[3], int numVerts, char *vgroup) +void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm, + float (*vertexCos)[3], int numVerts, char *vgroup) { int a; + int use_vgroups; init_latt_deform(laOb, target); - - if(vgroup && vgroup[0] && target->type==OB_MESH) { + + /* check whether to use vertex groups (only possible if target is a Mesh) + * we want either a Mesh with no derived data, or derived data with + * deformverts + */ + if(target && target->type==OB_MESH) { + /* if there's derived data without deformverts, don't use vgroups */ + if(dm && !dm->getVertData(dm, 0, LAYERTYPE_MDEFORMVERT)) + use_vgroups = 0; + else + use_vgroups = 1; + } else + use_vgroups = 0; + + if(vgroup && vgroup[0] && use_vgroups) { bDeformGroup *curdef; - Mesh *me= target->data; - int index= 0; + Mesh *me = target->data; + int index = 0; /* find the group (weak loop-in-loop) */ - for (curdef = target->defbase.first; curdef; curdef=curdef->next, index++) - if (!strcmp(curdef->name, vgroup)) - break; - /* check for numVerts because old files can have modifier over subsurf still */ - if(curdef && me->dvert && numVerts==me->totvert) { - MDeformVert *dvert= me->dvert; + for(curdef = target->defbase.first; curdef; + curdef = curdef->next, index++) + if(!strcmp(curdef->name, vgroup)) break; + + if(curdef && (me->dvert || dm)) { + MDeformVert *dvert = me->dvert; int j; - for(a=0; a<numVerts; a++, dvert++) { - for(j=0; j<dvert->totweight; j++) { + for(a = 0; a < numVerts; a++, dvert++) { + if(dm) dvert = dm->getVertData(dm, a, LAYERTYPE_MDEFORMVERT); + for(j = 0; j < dvert->totweight; j++) { if (dvert->dw[j].def_nr == index) { calc_latt_deform(vertexCos[a], dvert->dw[j].weight); } } } } - } - else { - for(a=0; a<numVerts; a++) { + } else { + for(a = 0; a < numVerts; a++) { calc_latt_deform(vertexCos[a], 1.0f); } } @@ -652,7 +702,8 @@ int object_deform_mball(Object *ob) DispList *dl; for (dl=ob->disp.first; dl; dl=dl->next) { - lattice_deform_verts(ob->parent, ob, (float(*)[3]) dl->verts, dl->nr, NULL); + lattice_deform_verts(ob->parent, ob, NULL, + (float(*)[3]) dl->verts, dl->nr, NULL); } return 1; @@ -765,7 +816,7 @@ void lattice_calc_modifiers(Object *ob) for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!(md->mode&(1<<0))) continue; + if (!(md->mode&eModifierMode_Realtime)) continue; if (editmode && !(md->mode&eModifierMode_Editmode)) continue; if (mti->isDisabled && mti->isDisabled(md)) continue; if (mti->type!=eModifierTypeType_OnlyDeform) continue; diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index c565cfa5979..9e43e30fa7c 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -1,3 +1,41 @@ +/* +* $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) 2005 by the Blender Foundation. +* All rights reserved. +* +* The Original Code is: all of this file. +* +* Contributor(s): Daniel Dunbar +* Ton Roosendaal, +* Ben Batt, +* Brecht Van Lommel, +* Campbell Barton +* +* ***** 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" @@ -5,29 +43,36 @@ #include "BLI_blenlib.h" #include "BLI_rand.h" #include "BLI_arithb.h" +#include "BLI_linklist.h" #include "BLI_edgehash.h" +#include "BLI_ghash.h" #include "MEM_guardedalloc.h" #include "DNA_armature_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_scene_types.h" +#include "DNA_texture_types.h" #include "DNA_curve_types.h" +#include "DNA_camera_types.h" #include "BLI_editVert.h" #include "MTC_matrixops.h" #include "MTC_vectorops.h" +#include "BKE_main.h" #include "BKE_anim.h" #include "BKE_bad_level_calls.h" #include "BKE_global.h" #include "BKE_utildefines.h" +#include "BKE_cdderivedmesh.h" #include "BKE_DerivedMesh.h" #include "BKE_booleanops.h" #include "BKE_displist.h" @@ -37,6 +82,7 @@ #include "BKE_object.h" #include "BKE_mesh.h" #include "BKE_softbody.h" +#include "BKE_material.h" #include "depsgraph_private.h" #include "LOD_DependKludge.h" @@ -44,6 +90,8 @@ #include "CCGSubSurf.h" +#include "RE_shader_ext.h" + /* helper function for modifiers - usage is of this is discouraged, but avoids duplicate modifier code for DispListMesh and EditMesh */ @@ -85,7 +133,7 @@ DispListMesh *displistmesh_from_editmesh(EditMesh *em) VECCOPY(mv->co, eve->co); mv->mat_nr = 0; - mv->flag = ME_VERT_STEPINDEX; + mv->flag = 0; } for (i=0,eed=em->edges.first; i<outDLM->totedge; i++,eed=eed->next) { MEdge *med = &outDLM->medge[i]; @@ -93,7 +141,7 @@ DispListMesh *displistmesh_from_editmesh(EditMesh *em) med->v1 = (int) eed->v1->prev; med->v2 = (int) eed->v2->prev; med->crease = (unsigned char) (eed->crease*255.0f); - med->flag = ME_EDGEDRAW|ME_EDGERENDER|ME_EDGE_STEPINDEX; + med->flag = ME_EDGEDRAW | ME_EDGERENDER; if (eed->seam) med->flag |= ME_SEAM; if (!eed->f2) med->flag |= ME_LOOSEEDGE; @@ -105,7 +153,7 @@ DispListMesh *displistmesh_from_editmesh(EditMesh *em) mf->v3 = (int) efa->v3->prev; mf->v4 = efa->v4?(int) efa->v4->prev:0; mf->mat_nr = efa->mat_nr; - mf->flag = efa->flag|ME_FACE_STEPINDEX; + mf->flag = efa->flag; test_index_face(mf, NULL, NULL, efa->v4?4:3); } @@ -139,34 +187,51 @@ static int curveModifier_isDisabled(ModifierData *md) return !cmd->object; } -static void curveModifier_foreachObjectLink(ModifierData *md, Object *ob, void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData) +static void curveModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { CurveModifierData *cmd = (CurveModifierData*) md; walk(userData, ob, &cmd->object); } -static void curveModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode) +static void curveModifier_updateDepgraph( + ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) { CurveModifierData *cmd = (CurveModifierData*) md; if (cmd->object) { DagNode *curNode = dag_get_node(forest, cmd->object); - dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); } } -static void curveModifier_deformVerts(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int numVerts) +static void curveModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { CurveModifierData *cmd = (CurveModifierData*) md; - curve_deform_verts(cmd->object, ob, vertexCos, numVerts, cmd->name); + curve_deform_verts(cmd->object, ob, derivedData, vertexCos, numVerts, + cmd->name); } -static void curveModifier_deformVertsEM(ModifierData *md, Object *ob, void *editData, void *derivedData, float (*vertexCos)[3], int numVerts) +static void curveModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { - curveModifier_deformVerts(md, ob, NULL, vertexCos, numVerts); + DerivedMesh *dm = derivedData; + + if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + + curveModifier_deformVerts(md, ob, dm, vertexCos, numVerts); + + if(!derivedData) dm->release(dm); } /* Lattice */ @@ -186,34 +251,50 @@ static int latticeModifier_isDisabled(ModifierData *md) return !lmd->object; } -static void latticeModifier_foreachObjectLink(ModifierData *md, Object *ob, void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData) +static void latticeModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { LatticeModifierData *lmd = (LatticeModifierData*) md; walk(userData, ob, &lmd->object); } -static void latticeModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode) +static void latticeModifier_updateDepgraph(ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) { LatticeModifierData *lmd = (LatticeModifierData*) md; - if (lmd->object) { + if(lmd->object) { DagNode *latNode = dag_get_node(forest, lmd->object); - dag_add_relation(forest, latNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(forest, latNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); } } -static void latticeModifier_deformVerts(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int numVerts) +static void latticeModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { LatticeModifierData *lmd = (LatticeModifierData*) md; - lattice_deform_verts(lmd->object, ob, vertexCos, numVerts, lmd->name); + lattice_deform_verts(lmd->object, ob, derivedData, + vertexCos, numVerts, lmd->name); } -static void latticeModifier_deformVertsEM(ModifierData *md, Object *ob, void *editData, void *derivedData, float (*vertexCos)[3], int numVerts) +static void latticeModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { - latticeModifier_deformVerts(md, ob, NULL, vertexCos, numVerts); + DerivedMesh *dm = derivedData; + + if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + + latticeModifier_deformVerts(md, ob, dm, vertexCos, numVerts); + + if(!derivedData) dm->release(dm); } /* Subsurf */ @@ -221,7 +302,7 @@ static void latticeModifier_deformVertsEM(ModifierData *md, Object *ob, void *ed static void subsurfModifier_initData(ModifierData *md) { SubsurfModifierData *smd = (SubsurfModifierData*) md; - + smd->levels = 1; smd->renderLevels = 2; smd->flags |= eSubsurfModifierFlag_SubsurfUv; @@ -242,55 +323,39 @@ static void subsurfModifier_freeData(ModifierData *md) { SubsurfModifierData *smd = (SubsurfModifierData*) md; - if (smd->mCache) { + if(smd->mCache) { ccgSubSurf_free(smd->mCache); } - if (smd->emCache) { + if(smd->emCache) { ccgSubSurf_free(smd->emCache); } -} +} -static void *subsurfModifier_applyModifier(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int useRenderParams, int isFinalCalc) +static DerivedMesh *subsurfModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { - DerivedMesh *dm = derivedData; SubsurfModifierData *smd = (SubsurfModifierData*) md; - Mesh *me = ob->data; - - if (dm) { - DispListMesh *dlm = dm->convertToDispListMesh(dm, 0); - int i; - - if (vertexCos) { - int numVerts = dm->getNumVerts(dm); - - for (i=0; i<numVerts; i++) { - VECCOPY(dlm->mvert[i].co, vertexCos[i]); - } - } + DerivedMesh *result; - dm = subsurf_make_derived_from_mesh(me, dlm, smd, useRenderParams, NULL, isFinalCalc); + result = subsurf_make_derived_from_derived(derivedData, smd, + useRenderParams, NULL, + isFinalCalc, 0); - return dm; - } else { - return subsurf_make_derived_from_mesh(me, NULL, smd, useRenderParams, vertexCos, isFinalCalc); - } + return result; } -static void *subsurfModifier_applyModifierEM(ModifierData *md, Object *ob, void *editData, void *derivedData, float (*vertexCos)[3]) +static DerivedMesh *subsurfModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) { - EditMesh *em = editData; - DerivedMesh *dm = derivedData; SubsurfModifierData *smd = (SubsurfModifierData*) md; + DerivedMesh *result; - if (dm) { - DispListMesh *dlm = dm->convertToDispListMesh(dm, 0); - - dm = subsurf_make_derived_from_dlm_em(dlm, smd, vertexCos); + result = subsurf_make_derived_from_derived(derivedData, smd, 0, + NULL, 0, 1); - return dm; - } else { - return subsurf_make_derived_from_editmesh(em, smd, vertexCos); - } + return result; } /* Build */ @@ -319,214 +384,213 @@ static int buildModifier_dependsOnTime(ModifierData *md) return 1; } -static void *buildModifier_applyModifier(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int useRenderParams, int isFinalCalc) +static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob, + DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { DerivedMesh *dm = derivedData; + DerivedMesh *result; BuildModifierData *bmd = (BuildModifierData*) md; - DispListMesh *dlm=NULL, *ndlm = MEM_callocN(sizeof(*ndlm), "build_dlm"); - MVert *mvert; - MEdge *medge; - MFace *mface; - MCol *mcol; - TFace *tface; - int totvert, totedge, totface; - int i,j; + int i; + int numFaces, numEdges; + int maxVerts, maxEdges, maxFaces; + int *vertMap, *edgeMap, *faceMap; float frac; - - if (dm) { - dlm = dm->convertToDispListMesh(dm, 1); - mvert = dlm->mvert; - medge = dlm->medge; - mface = dlm->mface; - mcol = dlm->mcol; - tface = dlm->tface; - totvert = dlm->totvert; - totedge = dlm->totedge; - totface = dlm->totface; - } else { - Mesh *me = ob->data; - mvert = me->mvert; - medge = me->medge; - mface = me->mface; - mcol = me->mcol; - tface = me->tface; - totvert = me->totvert; - totedge = me->totedge; - totface = me->totface; - } + GHashIterator *hashIter; + /* maps vert indices in old mesh to indices in new mesh */ + GHash *vertHash = BLI_ghash_new(BLI_ghashutil_inthash, + BLI_ghashutil_intcmp); + /* maps edge indices in new mesh to indices in old mesh */ + GHash *edgeHash = BLI_ghash_new(BLI_ghashutil_inthash, + BLI_ghashutil_intcmp); + + maxVerts = dm->getNumVerts(dm); + vertMap = MEM_callocN(sizeof(*vertMap) * maxVerts, + "build modifier vertMap"); + for(i = 0; i < maxVerts; ++i) vertMap[i] = i; + + maxEdges = dm->getNumEdges(dm); + edgeMap = MEM_callocN(sizeof(*edgeMap) * maxEdges, + "build modifier edgeMap"); + for(i = 0; i < maxEdges; ++i) edgeMap[i] = i; + + maxFaces = dm->getNumFaces(dm); + faceMap = MEM_callocN(sizeof(*faceMap) * maxFaces, + "build modifier faceMap"); + for(i = 0; i < maxFaces; ++i) faceMap[i] = i; if (ob) { - frac = bsystem_time(ob, 0, (float)G.scene->r.cfra, bmd->start-1.0f)/bmd->length; + frac = bsystem_time(ob, 0, (float)G.scene->r.cfra, + bmd->start - 1.0f) / bmd->length; } else { - frac = G.scene->r.cfra - bmd->start/bmd->length; + frac = G.scene->r.cfra - bmd->start / bmd->length; } CLAMP(frac, 0.0, 1.0); - ndlm->totface = totface*frac; - ndlm->totedge = totedge*frac; - if (ndlm->totface) { - ndlm->mvert = MEM_mallocN(sizeof(*ndlm->mvert)*totvert, "build_mvert"); - memcpy(ndlm->mvert, mvert, sizeof(*mvert)*totvert); - for (i=0; i<totvert; i++) { - if (vertexCos) - VECCOPY(ndlm->mvert[i].co, vertexCos[i]); - ndlm->mvert[i].flag = 0; - } + numFaces = dm->getNumFaces(dm) * frac; + numEdges = dm->getNumEdges(dm) * frac; - if (bmd->randomize) { - ndlm->mface = MEM_dupallocN(mface); - BLI_array_randomize(ndlm->mface, sizeof(*mface), totface, bmd->seed); - - if (tface) { - ndlm->tface = MEM_dupallocN(tface); - BLI_array_randomize(ndlm->tface, sizeof(*tface), totface, bmd->seed); - } else if (mcol) { - ndlm->mcol = MEM_dupallocN(mcol); - BLI_array_randomize(ndlm->mcol, sizeof(*mcol)*4, totface, bmd->seed); - } - } else { - ndlm->mface = MEM_mallocN(sizeof(*ndlm->mface)*ndlm->totface, "build_mf"); - memcpy(ndlm->mface, mface, sizeof(*mface)*ndlm->totface); - - if (tface) { - ndlm->tface = MEM_mallocN(sizeof(*ndlm->tface)*ndlm->totface, "build_tf"); - memcpy(ndlm->tface, tface, sizeof(*tface)*ndlm->totface); - } else if (mcol) { - ndlm->mcol = MEM_mallocN(sizeof(*ndlm->mcol)*4*ndlm->totface, "build_mcol"); - memcpy(ndlm->mcol, mcol, sizeof(*mcol)*4*ndlm->totface); - } - } + /* if there's at least one face, build based on faces */ + if(numFaces) { + int maxEdges; - for (i=0; i<ndlm->totface; i++) { - MFace *mf = &ndlm->mface[i]; + if(bmd->randomize) + BLI_array_randomize(faceMap, sizeof(*faceMap), + maxFaces, bmd->seed); - ndlm->mvert[mf->v1].flag = 1; - ndlm->mvert[mf->v2].flag = 1; - ndlm->mvert[mf->v3].flag = 1; - if (mf->v4) ndlm->mvert[mf->v4].flag = 1; + /* get the set of all vert indices that will be in the final mesh, + * mapped to the new indices + */ + for(i = 0; i < numFaces; ++i) { + MFace mf; + dm->getFace(dm, faceMap[i], &mf); + + if(!BLI_ghash_haskey(vertHash, (void *)mf.v1)) + BLI_ghash_insert(vertHash, (void *)mf.v1, + (void *)BLI_ghash_size(vertHash)); + if(!BLI_ghash_haskey(vertHash, (void *)mf.v2)) + BLI_ghash_insert(vertHash, (void *)mf.v2, + (void *)BLI_ghash_size(vertHash)); + if(!BLI_ghash_haskey(vertHash, (void *)mf.v3)) + BLI_ghash_insert(vertHash, (void *)mf.v3, + (void *)BLI_ghash_size(vertHash)); + if(mf.v4 && !BLI_ghash_haskey(vertHash, (void *)mf.v4)) + BLI_ghash_insert(vertHash, (void *)mf.v4, + (void *)BLI_ghash_size(vertHash)); } - /* Store remapped indices in *((int*) mv->no) */ - ndlm->totvert = 0; - for (i=0; i<totvert; i++) { - MVert *mv = &ndlm->mvert[i]; - - if (mv->flag) - *((int*) mv->no) = ndlm->totvert++; + /* get the set of edges that will be in the new mesh (i.e. all edges + * that have both verts in the new mesh) + */ + maxEdges = dm->getNumEdges(dm); + for(i = 0; i < maxEdges; ++i) { + MEdge me; + dm->getEdge(dm, i, &me); + + if(BLI_ghash_haskey(vertHash, (void *)me.v1) + && BLI_ghash_haskey(vertHash, (void *)me.v2)) + BLI_ghash_insert(edgeHash, + (void *)BLI_ghash_size(edgeHash), (void *)i); } + } else if(numEdges) { + if(bmd->randomize) + BLI_array_randomize(edgeMap, sizeof(*edgeMap), + maxEdges, bmd->seed); - /* Remap face vertex indices */ - for (i=0; i<ndlm->totface; i++) { - MFace *mf = &ndlm->mface[i]; - - mf->v1 = *((int*) ndlm->mvert[mf->v1].no); - mf->v2 = *((int*) ndlm->mvert[mf->v2].no); - mf->v3 = *((int*) ndlm->mvert[mf->v3].no); - if (mf->v4) mf->v4 = *((int*) ndlm->mvert[mf->v4].no); + /* get the set of all vert indices that will be in the final mesh, + * mapped to the new indices + */ + for(i = 0; i < numEdges; ++i) { + MEdge me; + dm->getEdge(dm, edgeMap[i], &me); + + if(!BLI_ghash_haskey(vertHash, (void *)me.v1)) + BLI_ghash_insert(vertHash, (void *)me.v1, + (void *)BLI_ghash_size(vertHash)); + if(!BLI_ghash_haskey(vertHash, (void *)me.v2)) + BLI_ghash_insert(vertHash, (void *)me.v2, + (void *)BLI_ghash_size(vertHash)); } - /* Copy in all edges that have both vertices (remap in process) */ - if (totedge) { - ndlm->totedge = 0; - ndlm->medge = MEM_mallocN(sizeof(*ndlm->medge)*totedge, "build_med"); - - for (i=0; i<totedge; i++) { - MEdge *med = &medge[i]; - if (ndlm->mvert[med->v1].flag && ndlm->mvert[med->v2].flag) { - MEdge *nmed = &ndlm->medge[ndlm->totedge++]; - - memcpy(nmed, med, sizeof(*med)); + /* get the set of edges that will be in the new mesh + */ + for(i = 0; i < numEdges; ++i) { + MEdge me; + dm->getEdge(dm, edgeMap[i], &me); - nmed->v1 = *((int*) ndlm->mvert[nmed->v1].no); - nmed->v2 = *((int*) ndlm->mvert[nmed->v2].no); - } - } + BLI_ghash_insert(edgeHash, (void *)BLI_ghash_size(edgeHash), + (void *)edgeMap[i]); } + } else { + int numVerts = dm->getNumVerts(dm) * frac; - /* Collapse vertex array to remove unused verts */ - for(i=j=0; i<totvert; i++) { - MVert *mv = &ndlm->mvert[i]; + if(bmd->randomize) + BLI_array_randomize(vertMap, sizeof(*vertMap), + maxVerts, bmd->seed); - if (mv->flag) { - if (j!=i) - memcpy(&ndlm->mvert[j], mv, sizeof(*mv)); - j++; - } - } - } else if (ndlm->totedge) { - ndlm->mvert = MEM_mallocN(sizeof(*ndlm->mvert)*totvert, "build_mvert"); - memcpy(ndlm->mvert, mvert, sizeof(*mvert)*totvert); - for (i=0; i<totvert; i++) { - if (vertexCos) - VECCOPY(ndlm->mvert[i].co, vertexCos[i]); - ndlm->mvert[i].flag = 0; - } + /* get the set of all vert indices that will be in the final mesh, + * mapped to the new indices + */ + for(i = 0; i < numVerts; ++i) + BLI_ghash_insert(vertHash, (void *)vertMap[i], (void *)i); + } - if (bmd->randomize) { - ndlm->medge = MEM_dupallocN(medge); - BLI_array_randomize(ndlm->medge, sizeof(*medge), totedge, bmd->seed); - } else { - ndlm->medge = MEM_mallocN(sizeof(*ndlm->medge)*ndlm->totedge, "build_mf"); - memcpy(ndlm->medge, medge, sizeof(*medge)*ndlm->totedge); - } + /* now we know the number of verts, edges and faces, we can create + * the mesh + */ + result = CDDM_from_template(dm, BLI_ghash_size(vertHash), + BLI_ghash_size(edgeHash), numFaces); + + /* copy the vertices across */ + for(hashIter = BLI_ghashIterator_new(vertHash); + !BLI_ghashIterator_isDone(hashIter); + BLI_ghashIterator_step(hashIter)) { + MVert source; + MVert *dest; + int oldIndex = (int)BLI_ghashIterator_getKey(hashIter); + int newIndex = (int)BLI_ghashIterator_getValue(hashIter); + + dm->getVert(dm, oldIndex, &source); + dest = CDDM_get_vert(result, newIndex); + + DM_copy_vert_data(dm, result, oldIndex, newIndex, 1); + *dest = source; + } + BLI_ghashIterator_free(hashIter); - for (i=0; i<ndlm->totedge; i++) { - MEdge *med = &ndlm->medge[i]; + /* copy the edges across, remapping indices */ + for(i = 0; i < BLI_ghash_size(edgeHash); ++i) { + MEdge source; + MEdge *dest; + int oldIndex = (int)BLI_ghash_lookup(edgeHash, (void *)i); - ndlm->mvert[med->v1].flag = 1; - ndlm->mvert[med->v2].flag = 1; - } + dm->getEdge(dm, oldIndex, &source); + dest = CDDM_get_edge(result, i); - /* Store remapped indices in *((int*) mv->no) */ - ndlm->totvert = 0; - for (i=0; i<totvert; i++) { - MVert *mv = &ndlm->mvert[i]; + source.v1 = (int)BLI_ghash_lookup(vertHash, (void *)source.v1); + source.v2 = (int)BLI_ghash_lookup(vertHash, (void *)source.v2); - if (mv->flag) - *((int*) mv->no) = ndlm->totvert++; - } + DM_copy_edge_data(dm, result, oldIndex, i, 1); + *dest = source; + } - /* Remap edge vertex indices */ - for (i=0; i<ndlm->totedge; i++) { - MEdge *med = &ndlm->medge[i]; + /* copy the faces across, remapping indices */ + for(i = 0; i < numFaces; ++i) { + MFace source; + MFace *dest; + TFace *tf; + MCol *mc; + int orig_v4; - med->v1 = *((int*) ndlm->mvert[med->v1].no); - med->v2 = *((int*) ndlm->mvert[med->v2].no); - } + dm->getFace(dm, faceMap[i], &source); + dest = CDDM_get_face(result, i); - /* Collapse vertex array to remove unused verts */ - for(i=j=0; i<totvert; i++) { - MVert *mv = &ndlm->mvert[i]; + orig_v4 = source.v4; - if (mv->flag) { - if (j!=i) - memcpy(&ndlm->mvert[j], mv, sizeof(*mv)); - j++; - } - } - } else { - ndlm->totvert = totvert*frac; + source.v1 = (int)BLI_ghash_lookup(vertHash, (void *)source.v1); + source.v2 = (int)BLI_ghash_lookup(vertHash, (void *)source.v2); + source.v3 = (int)BLI_ghash_lookup(vertHash, (void *)source.v3); + if(source.v4) + source.v4 = (int)BLI_ghash_lookup(vertHash, (void *)source.v4); - if (bmd->randomize) { - ndlm->mvert = MEM_dupallocN(mvert); - BLI_array_randomize(ndlm->mvert, sizeof(*mvert), totvert, bmd->seed); - } else { - ndlm->mvert = MEM_mallocN(sizeof(*ndlm->mvert)*ndlm->totvert, "build_mvert"); - memcpy(ndlm->mvert, mvert, sizeof(*mvert)*ndlm->totvert); - } + DM_copy_face_data(dm, result, faceMap[i], i, 1); + *dest = source; - if (vertexCos) { - for (i=0; i<ndlm->totvert; i++) { - VECCOPY(ndlm->mvert[i].co, vertexCos[i]); - } - } + tf = DM_get_face_data(result, i, LAYERTYPE_TFACE); + mc = DM_get_face_data(result, i, LAYERTYPE_MCOL); + test_index_face(dest, mc, tf, (orig_v4 ? 4 : 3)); } - if (dlm) displistmesh_free(dlm); + CDDM_calc_normals(result); - mesh_calc_normals(ndlm->mvert, ndlm->totvert, ndlm->mface, ndlm->totface, &ndlm->nors); - - return derivedmesh_from_displistmesh(ndlm, NULL); + BLI_ghash_free(vertHash, NULL, NULL); + BLI_ghash_free(edgeHash, NULL, NULL); + + MEM_freeN(vertMap); + MEM_freeN(edgeMap); + MEM_freeN(faceMap); + + return result; } /* Array */ @@ -569,10 +633,10 @@ static void arrayModifier_copyData(ModifierData *md, ModifierData *target) tamd->flags = amd->flags; } -static void arrayModifier_foreachObjectLink(ModifierData *md, - Object *ob, - void (*walk)(void *userData, Object *ob, Object **obpoin), - void *userData) +static void arrayModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { ArrayModifierData *amd = (ArrayModifierData*) md; @@ -580,10 +644,8 @@ static void arrayModifier_foreachObjectLink(ModifierData *md, walk(userData, ob, &amd->offset_ob); } -static void arrayModifier_updateDepgraph(ModifierData *md, - DagForest *forest, - Object *ob, - DagNode *obNode) +static void arrayModifier_updateDepgraph(ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) { ArrayModifierData *amd = (ArrayModifierData*) md; @@ -591,32 +653,30 @@ static void arrayModifier_updateDepgraph(ModifierData *md, DagNode *curNode = dag_get_node(forest, amd->curve_ob); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); } if (amd->offset_ob) { DagNode *curNode = dag_get_node(forest, amd->offset_ob); dag_add_relation(forest, curNode, obNode, - DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); } } -float displistmesh_width(DispListMesh *dlm, int axis) +float vertarray_size(MVert *mvert, int numVerts, int axis) { int i; float min_co, max_co; - MVert *mv; /* if there are no vertices, width is 0 */ - if(dlm->totvert == 0) return 0; + if(numVerts == 0) return 0; /* find the minimum and maximum coordinates on the desired axis */ - min_co = max_co = dlm->mvert[0].co[axis]; - for (i=1; i < dlm->totvert; i++) { - mv = &dlm->mvert[i]; - - if(mv->co[axis] < min_co) min_co = mv->co[axis]; - if(mv->co[axis] > max_co) max_co = mv->co[axis]; + min_co = max_co = mvert->co[axis]; + ++mvert; + for(i = 1; i < numVerts; ++i, ++mvert) { + if(mvert->co[axis] < min_co) min_co = mvert->co[axis]; + if(mvert->co[axis] > max_co) max_co = mvert->co[axis]; } return max_co - min_co; @@ -650,6 +710,7 @@ static int calc_mapping(IndexMapEntry *indexMap, int oldVert, int copy) int mergeVert = indexMap[oldVert].merge; /* follow the chain of merges to the end */ + /* TODO should this only go as far as the number of copies allows? */ while(indexMap[mergeVert].merge >= 0 && indexMap[mergeVert].merge != mergeVert) mergeVert = indexMap[mergeVert].merge; @@ -665,10 +726,9 @@ static int calc_mapping(IndexMapEntry *indexMap, int oldVert, int copy) return newVert; } -static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd, - Object *ob, DispListMesh *inDLM, - float (*vertexCos)[3], - int initFlags) +static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, + Object *ob, DerivedMesh *dm, + int initFlags) { int i, j; /* offset matrix */ @@ -677,7 +737,12 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd, float tmp_mat[4][4]; float length = amd->length; int count = amd->count; - DispListMesh *dlm = MEM_callocN(sizeof(*dlm), "array_dlm"); + int numVerts, numEdges, numFaces; + int maxVerts, maxEdges, maxFaces; + DerivedMesh *result; + MVert *mvert, *src_mvert; + MEdge *medge; + MFace *mface; IndexMapEntry *indexMap; @@ -685,11 +750,19 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd, MTC_Mat4One(offset); + indexMap = MEM_callocN(sizeof(*indexMap) * dm->getNumVerts(dm), + "indexmap"); + + src_mvert = dm->dupVertArray(dm); + + maxVerts = dm->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] * displistmesh_width(inDLM, j); + offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, + maxVerts, j); } if((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) { @@ -736,24 +809,10 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd, if(count < 1) count = 1; - dlm->totvert = dlm->totedge = dlm->totface = 0; - indexMap = MEM_callocN(sizeof(*indexMap)*inDLM->totvert, "indexmap"); - /* allocate memory for count duplicates (including original) */ - dlm->mvert = MEM_callocN(sizeof(*dlm->mvert)*inDLM->totvert*count, - "dlm_mvert"); - dlm->mface = MEM_callocN(sizeof(*dlm->mface)*inDLM->totface*count, - "dlm_mface"); - - if (inDLM->medge) - dlm->medge = MEM_callocN(sizeof(*dlm->medge)*inDLM->totedge*count, - "dlm_medge"); - if (inDLM->tface) - dlm->tface = MEM_callocN(sizeof(*dlm->tface)*inDLM->totface*count, - "dlm_tface"); - if (inDLM->mcol) - dlm->mcol = MEM_callocN(sizeof(*dlm->mcol)*inDLM->totface*4*count, - "dlm_mcol"); + result = CDDM_from_template(dm, dm->getNumVerts(dm) * count, + dm->getNumEdges(dm) * count, + dm->getNumFaces(dm) * count); /* calculate the offset matrix of the final copy (for merging) */ MTC_Mat4One(final_offset); @@ -763,20 +822,22 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd, MTC_Mat4CpyMat4(final_offset, tmp_mat); } - for (i=0; i<inDLM->totvert; i++) { - MVert *inMV = &inDLM->mvert[i]; - MVert *mv = &dlm->mvert[dlm->totvert++]; + numVerts = numEdges = numFaces = 0; + mvert = CDDM_get_verts(result); + + for (i = 0; i < maxVerts; i++) { + MVert *inMV; + MVert *mv = &mvert[numVerts]; MVert *mv2; float co[3]; - *mv = *inMV; + inMV = &src_mvert[i]; - if (vertexCos) { - VECCOPY(mv->co, vertexCos[i]); - } - if (initFlags) mv->flag |= ME_VERT_STEPINDEX; + DM_copy_vert_data(dm, result, i, numVerts, 1); + *mv = *inMV; + numVerts++; - indexMap[i].new = dlm->totvert-1; + indexMap[i].new = numVerts - 1; indexMap[i].merge = -1; /* default to no merge */ indexMap[i].merge_final = 0; /* default to no merge */ @@ -793,16 +854,16 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd, VECCOPY(tmp_co, mv->co); MTC_Mat4MulVecfl(offset, tmp_co); - for(j = 0; j < inDLM->totvert; j++) { - inMV = &inDLM->mvert[j]; + for(j = 0; j < maxVerts; j++) { + inMV = &src_mvert[j]; /* if this vert is within merge limit, merge */ if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist)) { indexMap[i].merge = j; /* test for merging with final copy of merge target */ if(amd->flags & MOD_ARR_MERGEFINAL) { - inMV = &inDLM->mvert[i]; - VECCOPY(tmp_co, inDLM->mvert[j].co); + VECCOPY(tmp_co, inMV->co); + inMV = &src_mvert[i]; MTC_Mat4MulVecfl(final_offset, tmp_co); if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist)) indexMap[i].merge_final = 1; @@ -815,67 +876,79 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd, /* if no merging, generate copies of this vert */ if(indexMap[i].merge < 0) { for(j=0; j < count - 1; j++) { - mv2 = &dlm->mvert[dlm->totvert++]; + mv2 = &mvert[numVerts]; + DM_copy_vert_data(result, result, numVerts - 1, numVerts, 1); *mv2 = *mv; + numVerts++; + MTC_Mat4MulVecfl(offset, co); VECCOPY(mv2->co, co); - mv2->flag &= ~ME_VERT_STEPINDEX; } } else if(indexMap[i].merge != i && indexMap[i].merge_final) { /* if this vert is not merging with itself, and it is merging * with the final copy of its merge target, remove the first copy */ - dlm->totvert--; + numVerts--; + DM_free_vert_data(result, numVerts, 1); } } /* make a hashtable so we can avoid duplicate edges from merging */ edges = BLI_edgehash_new(); - for (i=0; i<inDLM->totedge; i++) { - MEdge *inMED = &inDLM->medge[i]; + maxEdges = dm->getNumEdges(dm); + medge = CDDM_get_edges(result); + for(i = 0; i < maxEdges; i++) { + MEdge inMED; MEdge med; MEdge *med2; int vert1, vert2; - med = *inMED; - med.v1 = indexMap[inMED->v1].new; - med.v2 = indexMap[inMED->v2].new; + dm->getEdge(dm, i, &inMED); + + med = inMED; + med.v1 = indexMap[inMED.v1].new; + med.v2 = indexMap[inMED.v2].new; /* if vertices are to be merged with the final copies of their * merge targets, calculate that final copy */ - if(indexMap[inMED->v1].merge_final) { - med.v1 = calc_mapping(indexMap, indexMap[inMED->v1].merge, + if(indexMap[inMED.v1].merge_final) { + med.v1 = calc_mapping(indexMap, indexMap[inMED.v1].merge, count - 2); } - if(indexMap[inMED->v2].merge_final) { - med.v2 = calc_mapping(indexMap, indexMap[inMED->v2].merge, + if(indexMap[inMED.v2].merge_final) { + med.v2 = calc_mapping(indexMap, indexMap[inMED.v2].merge, count - 2); } if (initFlags) { - med.flag |= ME_EDGEDRAW|ME_EDGERENDER|ME_EDGE_STEPINDEX; + med.flag |= ME_EDGEDRAW | ME_EDGERENDER; } if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) { - dlm->medge[dlm->totedge++] = med; + DM_copy_edge_data(dm, result, i, numEdges, 1); + medge[numEdges] = med; + numEdges++; + BLI_edgehash_insert(edges, med.v1, med.v2, NULL); } for(j=0; j < count - 1; j++) { - vert1 = calc_mapping(indexMap, inMED->v1, j); - vert2 = calc_mapping(indexMap, inMED->v2, j); + vert1 = calc_mapping(indexMap, inMED.v1, j); + vert2 = calc_mapping(indexMap, inMED.v2, j); /* avoid duplicate edges */ if(!BLI_edgehash_haskey(edges, vert1, vert2)) { - med2 = &dlm->medge[dlm->totedge++]; + med2 = &medge[numEdges]; + DM_copy_edge_data(dm, result, i, numEdges, 1); *med2 = med; + numEdges++; + med2->v1 = vert1; med2->v2 = vert2; - med2->flag &= ~ME_EDGE_STEPINDEX; BLI_edgehash_insert(edges, med2->v1, med2->v2, NULL); } @@ -885,168 +958,103 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd, /* don't need the hashtable any more */ BLI_edgehash_free(edges, NULL); - for (i=0; i<inDLM->totface; i++) { - MFace *inMF = &inDLM->mface[i]; - MFace *mf = &dlm->mface[dlm->totface++]; - MFace *mf2; - TFace *tf = NULL; - MCol *mc = NULL; + maxFaces = dm->getNumFaces(dm); + mface = CDDM_get_faces(result); + for (i=0; i < maxFaces; i++) { + MFace inMF; + TFace *tf; + MCol *mc; + MFace *mf = &mface[numFaces]; - *mf = *inMF; - mf->v1 = indexMap[inMF->v1].new; - mf->v2 = indexMap[inMF->v2].new; - mf->v3 = indexMap[inMF->v3].new; - if(inMF->v4) - mf->v4 = indexMap[inMF->v4].new; + dm->getFace(dm, i, &inMF); + + DM_copy_face_data(dm, result, i, numFaces, 1); + tf = DM_get_face_data(result, numFaces, LAYERTYPE_TFACE); + mc = DM_get_face_data(result, numFaces, LAYERTYPE_MCOL); + *mf = inMF; + numFaces++; + + mf->v1 = indexMap[inMF.v1].new; + mf->v2 = indexMap[inMF.v2].new; + mf->v3 = indexMap[inMF.v3].new; + if(inMF.v4) + mf->v4 = indexMap[inMF.v4].new; /* if vertices are to be merged with the final copies of their * merge targets, calculate that final copy */ - if(indexMap[inMF->v1].merge_final) - mf->v1 = calc_mapping(indexMap, indexMap[inMF->v1].merge, count-2); - if(indexMap[inMF->v2].merge_final) - mf->v2 = calc_mapping(indexMap, indexMap[inMF->v2].merge, count-2); - if(indexMap[inMF->v3].merge_final) - mf->v3 = calc_mapping(indexMap, indexMap[inMF->v3].merge, count-2); - if(inMF->v4 && indexMap[inMF->v4].merge_final) - mf->v4 = calc_mapping(indexMap, indexMap[inMF->v4].merge, count-2); - - if (initFlags) mf->flag |= ME_FACE_STEPINDEX; - - if (inDLM->tface) { - TFace *inTF = &inDLM->tface[i]; - tf = &dlm->tface[dlm->totface-1]; - - *tf = *inTF; - } else if (inDLM->mcol) { - MCol *inMC = &inDLM->mcol[i*4]; - mc = &dlm->mcol[(dlm->totface-1)*4]; - - mc[0] = inMC[0]; - mc[1] = inMC[1]; - mc[2] = inMC[2]; - mc[3] = inMC[3]; - } - - test_index_face(mf, mc, tf, inMF->v4?4:3); + if(indexMap[inMF.v1].merge_final) + mf->v1 = calc_mapping(indexMap, indexMap[inMF.v1].merge, count-2); + if(indexMap[inMF.v2].merge_final) + mf->v2 = calc_mapping(indexMap, indexMap[inMF.v2].merge, count-2); + if(indexMap[inMF.v3].merge_final) + mf->v3 = calc_mapping(indexMap, indexMap[inMF.v3].merge, count-2); + if(inMF.v4 && indexMap[inMF.v4].merge_final) + mf->v4 = calc_mapping(indexMap, indexMap[inMF.v4].merge, count-2); + + test_index_face(mf, mc, tf, inMF.v4?4:3); /* if the face has fewer than 3 vertices, don't create it */ - if(mf->v3 == 0) - dlm->totface--; + if(mf->v3 == 0) { + numFaces--; + DM_free_face_data(result, numFaces, 1); + } for(j=0; j < count - 1; j++) { - mf2 = &dlm->mface[dlm->totface++]; + MFace *mf2 = &mface[numFaces]; + DM_copy_face_data(dm, result, i, numFaces, 1); + tf = DM_get_face_data(result, numFaces, LAYERTYPE_TFACE); + mc = DM_get_face_data(result, numFaces, LAYERTYPE_MCOL); *mf2 = *mf; + numFaces++; - mf2->v1 = calc_mapping(indexMap, inMF->v1, j); - mf2->v2 = calc_mapping(indexMap, inMF->v2, j); - mf2->v3 = calc_mapping(indexMap, inMF->v3, j); - if (inMF->v4) - mf2->v4 = calc_mapping(indexMap, inMF->v4, j); - - mf2->flag &= ~ME_FACE_STEPINDEX; - - if (inDLM->tface) { - TFace *inTF = &inDLM->tface[i]; - tf = &dlm->tface[dlm->totface-1]; - - *tf = *inTF; - } else if (inDLM->mcol) { - MCol *inMC = &inDLM->mcol[i*4]; - mc = &dlm->mcol[(dlm->totface-1)*4]; - - mc[0] = inMC[0]; - mc[1] = inMC[1]; - mc[2] = inMC[2]; - mc[3] = inMC[3]; - } + mf2->v1 = calc_mapping(indexMap, inMF.v1, j); + mf2->v2 = calc_mapping(indexMap, inMF.v2, j); + mf2->v3 = calc_mapping(indexMap, inMF.v3, j); + if (inMF.v4) + mf2->v4 = calc_mapping(indexMap, inMF.v4, j); - test_index_face(mf2, mc, tf, inMF->v4?4:3); + test_index_face(mf2, mc, tf, inMF.v4?4:3); /* if the face has fewer than 3 vertices, don't create it */ - if(mf2->v3 == 0) - dlm->totface--; + if(mf2->v3 == 0) { + numFaces--; + DM_free_face_data(result, numFaces, 1); + } } } + MEM_freeN(src_mvert); MEM_freeN(indexMap); - return dlm; + CDDM_set_num_verts(result, numVerts); + CDDM_set_num_edges(result, numEdges); + CDDM_set_num_faces(result, numFaces); + + return result; } -static void *arrayModifier_applyModifier_internal(ModifierData *md, - Object *ob, - void *derivedData, - float (*vertexCos)[3], - int useRenderParams, - int isFinalCalc) +static DerivedMesh *arrayModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { - DerivedMesh *dm = derivedData; + DerivedMesh *result; ArrayModifierData *amd = (ArrayModifierData*) md; - DispListMesh *outDLM, *inDLM; - if (dm) { - inDLM = dm->convertToDispListMesh(dm, 1); - } else { - Mesh *me = ob->data; + result = arrayModifier_doArray(amd, ob, derivedData, 0); - inDLM = MEM_callocN(sizeof(*inDLM), "inDLM"); - inDLM->dontFreeVerts = inDLM->dontFreeOther = 1; - inDLM->mvert = me->mvert; - inDLM->medge = me->medge; - inDLM->mface = me->mface; - inDLM->tface = me->tface; - inDLM->mcol = me->mcol; - inDLM->totvert = me->totvert; - inDLM->totedge = me->totedge; - inDLM->totface = me->totface; - } - - outDLM = arrayModifier_doArray(amd, ob, inDLM, vertexCos, dm?0:1); + CDDM_calc_normals(result); - displistmesh_free(inDLM); - - mesh_calc_normals(outDLM->mvert, outDLM->totvert, outDLM->mface, - outDLM->totface, &outDLM->nors); - - return derivedmesh_from_displistmesh(outDLM, NULL); + return result; } -static void *arrayModifier_applyModifier(ModifierData *md, - Object *ob, - void *derivedData, - float (*vertexCos)[3], - int useRenderParams, - int isFinalCalc) +static DerivedMesh *arrayModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) { - return arrayModifier_applyModifier_internal(md, ob, derivedData, - vertexCos, 0, 1); -} - -static void *arrayModifier_applyModifierEM(ModifierData *md, - Object *ob, - void *editData, - void *derivedData, - float (*vertexCos)[3]) -{ - if (derivedData) { - return arrayModifier_applyModifier_internal(md, ob, derivedData, - vertexCos, 0, 1); - } else { - ArrayModifierData *amd = (ArrayModifierData*) md; - DispListMesh *outDLM, *inDLM = displistmesh_from_editmesh(editData); - - outDLM = arrayModifier_doArray(amd, ob, inDLM, vertexCos, 0); - - displistmesh_free(inDLM); - - mesh_calc_normals(outDLM->mvert, outDLM->totvert, - outDLM->mface, outDLM->totface, &outDLM->nors); - - return derivedmesh_from_displistmesh(outDLM, NULL); - } + return arrayModifier_applyModifier(md, ob, derivedData, 0, 1); } /* Mirror */ @@ -1067,127 +1075,120 @@ static void mirrorModifier_copyData(ModifierData *md, ModifierData *target) tmmd->tolerance = mmd->tolerance; } -static DispListMesh *mirrorModifier__doMirror(MirrorModifierData *mmd, DispListMesh *inDLM, float (*vertexCos)[3], int initFlags) +static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd, + DerivedMesh *dm, + int initFlags) { int i, axis = mmd->axis; float tolerance = mmd->tolerance; - DispListMesh *dlm = MEM_callocN(sizeof(*dlm), "mirror_dlm"); + DerivedMesh *result; + int numVerts, numEdges, numFaces; + int maxVerts = dm->getNumVerts(dm); + int maxEdges = dm->getNumEdges(dm); + int maxFaces = dm->getNumFaces(dm); int (*indexMap)[2]; - dlm->totvert = dlm->totedge = dlm->totface = 0; - indexMap = MEM_mallocN(sizeof(*indexMap)*inDLM->totvert, "indexmap"); - dlm->mvert = MEM_callocN(sizeof(*dlm->mvert)*inDLM->totvert*2, "dlm_mvert"); - dlm->mface = MEM_callocN(sizeof(*dlm->mface)*inDLM->totface*2, "dlm_mface"); + numVerts = numEdges = numFaces = 0; - if (inDLM->medge) dlm->medge = MEM_callocN(sizeof(*dlm->medge)*inDLM->totedge*2, "dlm_medge"); - if (inDLM->tface) dlm->tface = MEM_callocN(sizeof(*dlm->tface)*inDLM->totface*2, "dlm_tface"); - if (inDLM->mcol) dlm->mcol = MEM_callocN(sizeof(*dlm->mcol)*inDLM->totface*4*2, "dlm_mcol"); + indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap"); - for (i=0; i<inDLM->totvert; i++) { - MVert *inMV = &inDLM->mvert[i]; - MVert *mv = &dlm->mvert[dlm->totvert++]; - int isShared = ABS(inMV->co[axis])<=tolerance; + result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2); - /* Because the topology result (# of vertices) must be the same - * if the mesh data is overridden by vertex cos, have to calc sharedness - * based on original coordinates. This is why we test before copy. - */ - *mv = *inMV; - if (vertexCos) { - VECCOPY(mv->co, vertexCos[i]); - } - if (initFlags) mv->flag |= ME_VERT_STEPINDEX; + for(i = 0; i < maxVerts; i++) { + MVert inMV; + MVert *mv = CDDM_get_vert(result, numVerts); + int isShared; + + dm->getVert(dm, i, &inMV); + isShared = ABS(inMV.co[axis])<=tolerance; + + /* Because the topology result (# of vertices) must be the same if + * the mesh data is overridden by vertex cos, have to calc sharedness + * based on original coordinates. This is why we test before copy. + */ + DM_copy_vert_data(dm, result, i, numVerts, 1); + *mv = inMV; + numVerts++; - indexMap[i][0] = dlm->totvert-1; + indexMap[i][0] = numVerts - 1; indexMap[i][1] = !isShared; - if (isShared) { + if(isShared) { mv->co[axis] = 0; mv->flag |= ME_VERT_MERGED; } else { - MVert *mv2 = &dlm->mvert[dlm->totvert++]; + MVert *mv2 = CDDM_get_vert(result, numVerts); + DM_copy_vert_data(dm, result, i, numVerts, 1); *mv2 = *mv; + numVerts++; + mv2->co[axis] = -mv2->co[axis]; - mv2->flag &= ~ME_VERT_STEPINDEX; } } - for (i=0; i<inDLM->totedge; i++) { - MEdge *inMED = &inDLM->medge[i]; - MEdge *med = &dlm->medge[dlm->totedge++]; + for(i = 0; i < maxEdges; i++) { + MEdge inMED; + MEdge *med = CDDM_get_edge(result, numEdges); + + dm->getEdge(dm, i, &inMED); - *med = *inMED; - med->v1 = indexMap[inMED->v1][0]; - med->v2 = indexMap[inMED->v2][0]; - if (initFlags) med->flag |= ME_EDGEDRAW|ME_EDGERENDER|ME_EDGE_STEPINDEX; + DM_copy_edge_data(dm, result, i, numEdges, 1); + *med = inMED; + numEdges++; - if (indexMap[inMED->v1][1] || indexMap[inMED->v2][1]) { - MEdge *med2 = &dlm->medge[dlm->totedge++]; + med->v1 = indexMap[inMED.v1][0]; + med->v2 = indexMap[inMED.v2][0]; + if(initFlags) + med->flag |= ME_EDGEDRAW | ME_EDGERENDER; + if(indexMap[inMED.v1][1] || indexMap[inMED.v2][1]) { + MEdge *med2 = CDDM_get_edge(result, numEdges); + + DM_copy_edge_data(dm, result, i, numEdges, 1); *med2 = *med; - med2->v1 += indexMap[inMED->v1][1]; - med2->v2 += indexMap[inMED->v2][1]; - med2->flag &= ~ME_EDGE_STEPINDEX; + numEdges++; + + med2->v1 += indexMap[inMED.v1][1]; + med2->v2 += indexMap[inMED.v2][1]; } } - for (i=0; i<inDLM->totface; i++) { - MFace *inMF = &inDLM->mface[i]; - MFace *mf = &dlm->mface[dlm->totface++]; - - *mf = *inMF; - mf->v1 = indexMap[inMF->v1][0]; - mf->v2 = indexMap[inMF->v2][0]; - mf->v3 = indexMap[inMF->v3][0]; - mf->v4 = indexMap[inMF->v4][0]; - if (initFlags) mf->flag |= ME_FACE_STEPINDEX; + for(i = 0; i < maxFaces; i++) { + MFace inMF; + MFace *mf = CDDM_get_face(result, numFaces); - if (inDLM->tface) { - TFace *inTF = &inDLM->tface[i]; - TFace *tf = &dlm->tface[dlm->totface-1]; + dm->getFace(dm, i, &inMF); - *tf = *inTF; - } else if (inDLM->mcol) { - MCol *inMC = &inDLM->mcol[i*4]; - MCol *mc = &dlm->mcol[(dlm->totface-1)*4]; + DM_copy_face_data(dm, result, i, numFaces, 1); + *mf = inMF; + numFaces++; - mc[0] = inMC[0]; - mc[1] = inMC[1]; - mc[2] = inMC[2]; - mc[3] = inMC[3]; - } + mf->v1 = indexMap[inMF.v1][0]; + mf->v2 = indexMap[inMF.v2][0]; + mf->v3 = indexMap[inMF.v3][0]; + mf->v4 = indexMap[inMF.v4][0]; - if (indexMap[inMF->v1][1] || indexMap[inMF->v2][1] || indexMap[inMF->v3][1] || (mf->v4 && indexMap[inMF->v4][1])) { - MFace *mf2 = &dlm->mface[dlm->totface++]; - TFace *tf = NULL; - MCol *mc = NULL; - + if(indexMap[inMF.v1][1] + || indexMap[inMF.v2][1] + || indexMap[inMF.v3][1] + || (mf->v4 && indexMap[inMF.v4][1])) { + MFace *mf2 = CDDM_get_face(result, numFaces); + TFace *tf = DM_get_face_data(result, numFaces, LAYERTYPE_TFACE); + MCol *mc = DM_get_face_data(result, numFaces, LAYERTYPE_MCOL); + + DM_copy_face_data(dm, result, i, numFaces, 1); *mf2 = *mf; - mf2->v1 += indexMap[inMF->v1][1]; - mf2->v2 += indexMap[inMF->v2][1]; - mf2->v3 += indexMap[inMF->v3][1]; - if (inMF->v4) mf2->v4 += indexMap[inMF->v4][1]; - mf2->flag &= ~ME_FACE_STEPINDEX; - - if (inDLM->tface) { - TFace *inTF = &inDLM->tface[i]; - tf = &dlm->tface[dlm->totface-1]; - - *tf = *inTF; - } else if (inDLM->mcol) { - MCol *inMC = &inDLM->mcol[i*4]; - mc = &dlm->mcol[(dlm->totface-1)*4]; - - mc[0] = inMC[0]; - mc[1] = inMC[1]; - mc[2] = inMC[2]; - mc[3] = inMC[3]; - } + numFaces++; + + mf2->v1 += indexMap[inMF.v1][1]; + mf2->v2 += indexMap[inMF.v2][1]; + mf2->v3 += indexMap[inMF.v3][1]; + if(inMF.v4) mf2->v4 += indexMap[inMF.v4][1]; - /* Flip face normal */ + /* Flip face normal */ SWAP(int, mf2->v1, mf2->v3); - if (tf) { + if(tf) { SWAP(unsigned int, tf->col[0], tf->col[2]); SWAP(float, tf->uv[0][0], tf->uv[2][0]); SWAP(float, tf->uv[0][1], tf->uv[2][1]); @@ -1195,68 +1196,1479 @@ static DispListMesh *mirrorModifier__doMirror(MirrorModifierData *mmd, DispListM SWAP(MCol, mc[0], mc[2]); } - test_index_face(mf2, mc, tf, inMF->v4?4:3); + test_index_face(mf2, mc, tf, inMF.v4?4:3); } } MEM_freeN(indexMap); - return dlm; + CDDM_set_num_verts(result, numVerts); + CDDM_set_num_edges(result, numEdges); + CDDM_set_num_faces(result, numFaces); + + return result; } -static void *mirrorModifier_applyModifier__internal(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int useRenderParams, int isFinalCalc) +static DerivedMesh *mirrorModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { - DerivedMesh *dm = derivedData; + DerivedMesh *result; MirrorModifierData *mmd = (MirrorModifierData*) md; - DispListMesh *outDLM, *inDLM; - if (dm) { - inDLM = dm->convertToDispListMesh(dm, 1); - } else { - Mesh *me = ob->data; + result = mirrorModifier__doMirror(mmd, derivedData, 0); + + CDDM_calc_normals(result); + + return result; +} + +static DerivedMesh *mirrorModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) +{ + return mirrorModifier_applyModifier(md, ob, derivedData, 0, 1); +} + +/* EdgeSplit */ +/* EdgeSplit modifier: Splits edges in the mesh according to sharpness flag + * or edge angle (can be used to achieve autosmoothing) +*/ +#if 0 +#define EDGESPLIT_DEBUG_1 +#define EDGESPLIT_DEBUG_2 +#define EDGESPLIT_DEBUG_0 +#endif + +static void edgesplitModifier_initData(ModifierData *md) +{ + EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md; + + /* default to 30-degree split angle, sharpness from both angle & flag + */ + emd->split_angle = 30; + emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG; +} + +static void edgesplitModifier_copyData(ModifierData *md, ModifierData *target) +{ + EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md; + EdgeSplitModifierData *tamd = (EdgeSplitModifierData*) target; - inDLM = MEM_callocN(sizeof(*inDLM), "inDLM"); - inDLM->dontFreeVerts = inDLM->dontFreeOther = 1; - inDLM->mvert = me->mvert; - inDLM->medge = me->medge; - inDLM->mface = me->mface; - inDLM->tface = me->tface; - inDLM->mcol = me->mcol; - inDLM->totvert = me->totvert; - inDLM->totedge = me->totedge; - inDLM->totface = me->totface; + tamd->split_angle = emd->split_angle; + tamd->flags = emd->flags; +} + +static void linklist_copy(LinkNode **target, LinkNode *source); + +/* Mesh data for edgesplit operation */ +typedef struct SmoothVert { + LinkNode *faces; /* all faces which use this vert */ + int oldIndex; /* the index of the original DispListMesh vert */ + int newIndex; /* the index of the new DispListMesh vert */ +} SmoothVert; + +static SmoothVert *smoothvert_copy(SmoothVert *vert) +{ + SmoothVert *copy = MEM_callocN(sizeof(*copy), "copy_smoothvert"); + + *copy = *vert; + linklist_copy(©->faces, vert->faces); + + return copy; +} + +static void smoothvert_free(void *vert) +{ + BLI_linklist_free(((SmoothVert *)vert)->faces, NULL); + MEM_freeN(vert); +} + +#define SMOOTHEDGE_NUM_VERTS 2 + +typedef struct SmoothEdge { + SmoothVert *verts[SMOOTHEDGE_NUM_VERTS]; /* the verts used by this edge */ + LinkNode *faces; /* all faces which use this edge */ + int oldIndex; /* the index of the original DispListMesh edge */ + int newIndex; /* the index of the new DispListMesh edge */ + short flag; /* the flags from the original DispListMesh edge */ +} SmoothEdge; + +static void smoothedge_free(void *edge) +{ + BLI_linklist_free(((SmoothEdge *)edge)->faces, NULL); + MEM_freeN(edge); +} + +static SmoothEdge *smoothedge_copy(SmoothEdge *edge) +{ + SmoothEdge *copy = MEM_callocN(sizeof(*copy), "copy_smoothedge"); + + *copy = *edge; + linklist_copy(©->faces, edge->faces); + + return copy; +} + +static int smoothedge_has_vert(SmoothEdge *edge, SmoothVert *vert) +{ + int i; + for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++) + if(edge->verts[i] == vert) return 1; + + return 0; +} + +#define SMOOTHFACE_MAX_EDGES 4 + +typedef struct SmoothFace { + SmoothEdge *edges[SMOOTHFACE_MAX_EDGES]; /* nonexistent edges == NULL */ + int flip[SMOOTHFACE_MAX_EDGES]; /* 1 = flip edge dir, 0 = don't flip */ + float normal[3]; /* the normal of this face */ + int oldIndex; /* the index of the original DispListMesh face */ + int newIndex; /* the index of the new DispListMesh face */ +} SmoothFace; + +static void smoothface_free(void *face) +{ + MEM_freeN(face); +} + +static int smoothface_has_edge(SmoothFace *face, SmoothEdge *edge) +{ + int i; + for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) + if(face->edges[i] == edge) return 1; + + return 0; +} + + +typedef struct SmoothMesh { + GHash *verts; + GHash *edges; + GHash *faces; + DerivedMesh *dm; +} SmoothMesh; + +static SmoothMesh *smoothmesh_new() +{ + SmoothMesh *mesh = MEM_callocN(sizeof(*mesh), "smoothmesh"); + mesh->verts = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); + mesh->edges = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); + mesh->faces = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); + + return mesh; +} + +static void smoothmesh_free(SmoothMesh *mesh) +{ + BLI_ghash_free(mesh->verts, NULL, smoothvert_free); + BLI_ghash_free(mesh->edges, NULL, smoothedge_free); + BLI_ghash_free(mesh->faces, NULL, smoothface_free); + MEM_freeN(mesh); +} + +static void smoothmesh_print(SmoothMesh *mesh) +{ + int i, j; + DerivedMesh *dm = mesh->dm; + + printf("--- SmoothMesh ---\n"); + printf("--- Vertices ---\n"); + for(i = 0; i < BLI_ghash_size(mesh->verts); i++) { + SmoothVert *vert = BLI_ghash_lookup(mesh->verts, (void *)i); + LinkNode *node; + MVert mv; + + dm->getVert(dm, vert->oldIndex, &mv); + + printf("%3d: ind={%3d, %3d}, pos={% 5.1f, % 5.1f, % 5.1f}", + i, vert->oldIndex, vert->newIndex, + mv.co[0], mv.co[1], mv.co[2]); + printf(", faces={"); + for(node = vert->faces; node != NULL; node = node->next) { + printf(" %d", ((SmoothFace *)node->link)->newIndex); + } + printf("}\n"); + } + + printf("\n--- Edges ---\n"); + for(i = 0; i < BLI_ghash_size(mesh->edges); i++) { + SmoothEdge *edge = BLI_ghash_lookup(mesh->edges, (void *)i); + LinkNode *node; + + printf("%4d: indices={%4d, %4d}, verts={%4d, %4d}", + i, + edge->oldIndex, edge->newIndex, + edge->verts[0]->newIndex, edge->verts[1]->newIndex); + if(edge->verts[0] == edge->verts[1]) printf(" <- DUPLICATE VERTEX"); + printf(", faces={"); + for(node = edge->faces; node != NULL; node = node->next) { + printf(" %d", ((SmoothFace *)node->link)->newIndex); + } + printf("}\n"); } - outDLM = mirrorModifier__doMirror(mmd, inDLM, vertexCos, dm?0:1); + printf("\n--- Faces ---\n"); + for(i = 0; i < BLI_ghash_size(mesh->faces); i++) { + SmoothFace *face = BLI_ghash_lookup(mesh->faces, (void *)i); + + printf("%4d: indices={%4d, %4d}, edges={", i, + face->oldIndex, face->newIndex); + for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) { + if(face->flip[j]) + printf(" -%-2d", face->edges[j]->newIndex); + else + printf(" %-2d", face->edges[j]->newIndex); + } + printf("}, verts={"); + for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) { + printf(" %d", face->edges[j]->verts[face->flip[j]]->newIndex); + } + printf("}\n"); + } +} - displistmesh_free(inDLM); - - mesh_calc_normals(outDLM->mvert, outDLM->totvert, outDLM->mface, outDLM->totface, &outDLM->nors); - - return derivedmesh_from_displistmesh(outDLM, NULL); +static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm) +{ + SmoothMesh *mesh = smoothmesh_new(); + EdgeHash *edges = BLI_edgehash_new(); + int i; + int totvert, totedge, totface; + + mesh->dm = dm; + + totvert = dm->getNumVerts(dm); + for(i = 0; i < totvert; i++) { + SmoothVert *vert = MEM_callocN(sizeof(*vert), "smoothvert"); + + vert->oldIndex = vert->newIndex = i; + BLI_ghash_insert(mesh->verts, (void *)i, vert); + } + + totedge = dm->getNumEdges(dm); + for(i = 0; i < totedge; i++) { + SmoothEdge *edge = MEM_callocN(sizeof(*edge), "smoothedge"); + MEdge med; + + dm->getEdge(dm, i, &med); + edge->verts[0] = BLI_ghash_lookup(mesh->verts, (void *)med.v1); + edge->verts[1] = BLI_ghash_lookup(mesh->verts, (void *)med.v2); + edge->oldIndex = edge->newIndex = i; + edge->flag = med.flag; + BLI_ghash_insert(mesh->edges, (void *)i, edge); + BLI_edgehash_insert(edges, med.v1, med.v2, edge); + } + + totface = dm->getNumFaces(dm); + for(i = 0; i < totface; i++) { + SmoothFace *face = MEM_callocN(sizeof(*face), "smoothface"); + MFace mf; + MVert v1, v2, v3; + int j; + + dm->getFace(dm, i, &mf); + + dm->getVert(dm, mf.v1, &v1); + dm->getVert(dm, mf.v2, &v2); + dm->getVert(dm, mf.v3, &v3); + face->edges[0] = BLI_edgehash_lookup(edges, mf.v1, mf.v2); + if(face->edges[0]->verts[1]->oldIndex == mf.v1) face->flip[0] = 1; + face->edges[1] = BLI_edgehash_lookup(edges, mf.v2, mf.v3); + if(face->edges[1]->verts[1]->oldIndex == mf.v2) face->flip[1] = 1; + if(mf.v4) { + MVert v4; + dm->getVert(dm, mf.v4, &v4); + face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v4); + if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1; + face->edges[3] = BLI_edgehash_lookup(edges, mf.v4, mf.v1); + if(face->edges[3]->verts[1]->oldIndex == mf.v4) face->flip[3] = 1; + CalcNormFloat4(v1.co, v2.co, v3.co, v4.co, face->normal); + } else { + face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v1); + if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1; + face->edges[3] = NULL; + CalcNormFloat(v1.co, v2.co, v3.co, face->normal); + } + + for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) { + SmoothEdge *edge = face->edges[j]; + BLI_linklist_prepend(&edge->faces, face); + BLI_linklist_prepend(&edge->verts[face->flip[j]]->faces, face); + } + + face->oldIndex = face->newIndex = i; + BLI_ghash_insert(mesh->faces, (void *)i, face); + } + + BLI_edgehash_free(edges, NULL); + + return mesh; +} + +static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh) +{ + DerivedMesh *result = CDDM_from_template(mesh->dm, + BLI_ghash_size(mesh->verts), + BLI_ghash_size(mesh->edges), + BLI_ghash_size(mesh->faces)); + GHashIterator *i; + MVert *new_verts = CDDM_get_verts(result); + MEdge *new_edges = CDDM_get_edges(result); + MFace *new_faces = CDDM_get_faces(result); + + for(i = BLI_ghashIterator_new(mesh->verts); !BLI_ghashIterator_isDone(i); + BLI_ghashIterator_step(i)) { + SmoothVert *vert = BLI_ghashIterator_getValue(i); + MVert *newMV = &new_verts[vert->newIndex]; + + DM_copy_vert_data(mesh->dm, result, + vert->oldIndex, vert->newIndex, 1); + mesh->dm->getVert(mesh->dm, vert->oldIndex, newMV); + } + BLI_ghashIterator_free(i); + + for(i = BLI_ghashIterator_new(mesh->edges); !BLI_ghashIterator_isDone(i); + BLI_ghashIterator_step(i)) { + SmoothEdge *edge = BLI_ghashIterator_getValue(i); + MEdge *newME = &new_edges[edge->newIndex]; + + DM_copy_edge_data(mesh->dm, result, + edge->oldIndex, edge->newIndex, 1); + mesh->dm->getEdge(mesh->dm, edge->oldIndex, newME); + newME->v1 = edge->verts[0]->newIndex; + newME->v2 = edge->verts[1]->newIndex; + } + BLI_ghashIterator_free(i); + + for(i = BLI_ghashIterator_new(mesh->faces); !BLI_ghashIterator_isDone(i); + BLI_ghashIterator_step(i)) { + SmoothFace *face = BLI_ghashIterator_getValue(i); + MFace *newMF = &new_faces[face->newIndex]; + + DM_copy_face_data(mesh->dm, result, + face->oldIndex, face->newIndex, 1); + mesh->dm->getFace(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; + newMF->v3 = face->edges[2]->verts[face->flip[2]]->newIndex; + + if(face->edges[3]) { + newMF->v4 = face->edges[3]->verts[face->flip[3]]->newIndex; + } else { + newMF->v4 = 0; + } + } + BLI_ghashIterator_free(i); + + return result; +} + +/* returns the other edge in the given face that uses the given vert + * returns NULL if no other edge in the given face uses the given vert + * (this should never happen) + */ +static SmoothEdge *other_edge(SmoothFace *face, SmoothVert *vert, + SmoothEdge *edge) +{ + int i,j; + for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) { + SmoothEdge *tmp_edge = face->edges[i]; + if(tmp_edge == edge) continue; + + for(j = 0; j < SMOOTHEDGE_NUM_VERTS; j++) + if(tmp_edge->verts[j] == vert) return tmp_edge; + } + + /* if we get to here, something's wrong (there should always be 2 edges + * which use the same vert in a face) + */ + return NULL; +} + +/* returns the face attached to the given edge which is smoothest with the + * given face. Returns NULL if no other faces use this edge. + */ +static SmoothFace *smoothest_face(SmoothEdge *edge, SmoothFace *face) +{ + /* face with maximum dot product to this face's normal is smoothest */ + float max_dot = -2; + SmoothFace *best_face = NULL; + LinkNode *node; + + for(node = edge->faces; node != NULL; node = node->next) { + SmoothFace *tmp_face = node->link; + float dot; + if(tmp_face == face) continue; + + dot = MTC_dot3Float(tmp_face->normal, face->normal); + + if(dot > max_dot) { + max_dot = dot; + best_face = tmp_face; + } + } + + return best_face; +} + +/* copies source list to target, overwriting target (target is not freed) + * nodes in the copy will be in the same order as in source + */ +static void linklist_copy(LinkNode **target, LinkNode *source) +{ + LinkNode *node = NULL; + *target = NULL; + + for(; source; source = source->next) { + if(node) { + node->next = MEM_mallocN(sizeof(*node->next), "nlink_copy"); + node = node->next; + } else { + node = *target = MEM_mallocN(sizeof(**target), "nlink_copy"); + } + node->link = source->link; + node->next = NULL; + } +} + +/* appends source to target if it's not already in target */ +static void linklist_append_unique(LinkNode **target, void *source) +{ + LinkNode *node; + LinkNode *prev = NULL; + + /* check if source value is already in the list */ + for(node = *target; node; prev = node, node = node->next) + if(node->link == source) return; + + node = MEM_mallocN(sizeof(*node), "nlink"); + node->next = NULL; + node->link = source; + + if(prev) prev->next = node; + else *target = node; +} + +/* appends elements of source which aren't already in target to target */ +static void linklist_append_list_unique(LinkNode **target, LinkNode *source) +{ + for(; source; source = source->next) + linklist_append_unique(target, source->link); +} + +/* prepends prepend to list - doesn't copy nodes, just joins the lists */ +static void linklist_prepend_linklist(LinkNode **list, LinkNode *prepend) +{ + if(prepend) { + LinkNode *node = prepend; + while(node->next) node = node->next; + + node->next = *list; + *list = prepend; + } +} + +/* empties the linked list + * frees pointers with freefunc if freefunc is not NULL + */ +static void linklist_empty(LinkNode **list, LinkNodeFreeFP freefunc) +{ + BLI_linklist_free(*list, freefunc); + *list = NULL; +} + +/* removes the first instance of value from the linked list + * frees the pointer with freefunc if freefunc is not NULL + */ +static void linklist_remove_first(LinkNode **list, void *value, + LinkNodeFreeFP freefunc) +{ + LinkNode *node = *list; + LinkNode *prev = NULL; + + while(node && node->link != value) { + prev = node; + node = node->next; + } + + if(node) { + if(prev) + prev->next = node->next; + else + *list = node->next; + + if(freefunc) + freefunc(node->link); + + MEM_freeN(node); + } +} + +/* removes all elements in source from target */ +static void linklist_remove_list(LinkNode **target, LinkNode *source, + LinkNodeFreeFP freefunc) +{ + for(; source; source = source->next) + linklist_remove_first(target, source->link, freefunc); +} + +static void print_ptr(void *ptr) +{ + printf("%p\n", ptr); +} + +static void print_edge(void *ptr) +{ + SmoothEdge *edge = ptr; + printf(" %4d", edge->newIndex); +} + +static void print_face(void *ptr) +{ + SmoothFace *face = ptr; + printf(" %4d", face->newIndex); +} + +typedef struct ReplaceData { + void *find; + void *replace; +} ReplaceData; + +static void edge_replace_vert(void *ptr, void *userdata) +{ + SmoothEdge *edge = ptr; + SmoothVert *find = ((ReplaceData *)userdata)->find; + SmoothVert *replace = ((ReplaceData *)userdata)->replace; + int i; + +#ifdef EDGESPLIT_DEBUG_2 + printf("replacing vert %4d with %4d in edge %4d", + find->newIndex, replace->newIndex, edge->newIndex); + printf(": {%4d, %4d}", edge->verts[0]->newIndex, edge->verts[1]->newIndex); +#endif + + for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++) { + if(edge->verts[i] == find) { + linklist_append_list_unique(&replace->faces, edge->faces); + linklist_remove_list(&find->faces, edge->faces, NULL); + + edge->verts[i] = replace; + } + } + +#ifdef EDGESPLIT_DEBUG_2 + printf(" -> {%4d, %4d}\n", edge->verts[0]->newIndex, edge->verts[1]->newIndex); +#endif +} + +static void face_replace_vert(void *ptr, void *userdata) +{ + SmoothFace *face = ptr; + int i; + + for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) + edge_replace_vert(face->edges[i], userdata); +} + +static void face_replace_edge(void *ptr, void *userdata) +{ + SmoothFace *face = ptr; + SmoothEdge *find = ((ReplaceData *)userdata)->find; + SmoothEdge *replace = ((ReplaceData *)userdata)->replace; + int i; + +#ifdef EDGESPLIT_DEBUG_2 + printf("replacing edge %4d with %4d in face %4d", + find->newIndex, replace->newIndex, face->newIndex); + if(face->edges[3]) + printf(": {%2d %2d %2d %2d}", + face->edges[0]->newIndex, face->edges[1]->newIndex, + face->edges[2]->newIndex, face->edges[3]->newIndex); + else + printf(": {%2d %2d %2d}", + face->edges[0]->newIndex, face->edges[1]->newIndex, + face->edges[2]->newIndex); +#endif + + for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) { + if(face->edges[i] == find) { + linklist_remove_first(&face->edges[i]->faces, face, NULL); + BLI_linklist_prepend(&replace->faces, face); + face->edges[i] = replace; + } + } + +#ifdef EDGESPLIT_DEBUG_2 + if(face->edges[3]) + printf(" -> {%2d %2d %2d %2d}\n", + face->edges[0]->newIndex, face->edges[1]->newIndex, + face->edges[2]->newIndex, face->edges[3]->newIndex); + else + printf(" -> {%2d %2d %2d}\n", + face->edges[0]->newIndex, face->edges[1]->newIndex, + face->edges[2]->newIndex); +#endif +} + +static int edge_is_sharp(SmoothEdge *edge, int flags, + float threshold) +{ + /* if all flags are disabled, edge cannot be sharp */ + if(!(flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG))) + return 0; + + /* edge can only be sharp if it has at least 2 faces */ + if(edge->faces && edge->faces->next) { + LinkNode *node1; + LinkNode *node2; + + if((flags & MOD_EDGESPLIT_FROMFLAG) && (edge->flag & ME_SHARP)) + return 1; + + if(flags & MOD_EDGESPLIT_FROMANGLE) { + /* check angles between all faces */ + for(node1 = edge->faces; node1; node1 = node1->next) { + SmoothFace *face1 = node1->link; + for(node2 = node1->next; node2; node2 = node2->next) { + SmoothFace *face2 = node2->link; + float edge_angle_cos = MTC_dot3Float(face1->normal, + face2->normal); + if(edge_angle_cos < threshold) return 1; + } + } + } + } + + return 0; +} + +/* returns 1 if vert was split, 0 if not */ +static int split_vert(SmoothVert *vert, + SmoothEdge *start_edge, SmoothEdge *copy_edge, + SmoothFace *start_face, SmoothMesh *mesh, + float threshold, int flags) +{ + ReplaceData repdata; + SmoothVert *copy_vert; + LinkNode *split_edges = NULL; /* edges to use the copy vert */ + + SmoothFace *current_face = start_face; + SmoothEdge *current_edge; + SmoothEdge *sharp_edge = NULL; + SmoothFace *end_face = NULL; + GHash *visited_edges; + +#ifdef EDGESPLIT_DEBUG_2 + printf(">>>>>>>>>>>>>>>>>>>>> split_vert start >>>>>>>>>>>>>>>>>>>>>\n"); + printf("vert = %4d, start_edge =%4d, copy_edge = %4d, start_face = %4d\n", + vert->newIndex, start_edge->newIndex, copy_edge->newIndex, + start_face->newIndex); + printf("*** Beginning face traversal ***\n"); +#endif + + /* sanity check */ + if(!smoothface_has_edge(current_face, copy_edge)) return 0; + if(!smoothedge_has_vert(copy_edge, vert)) return 0; + + visited_edges = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + /* make sure we don't include start_edge in the split edge list */ + BLI_ghash_insert(visited_edges, start_edge, NULL); + + end_face = current_face; + current_edge = other_edge(current_face, vert, copy_edge); + current_face = smoothest_face(current_edge, current_face); + + /* find another sharp edge attached to the current vert */ + while(current_face && !BLI_ghash_haskey(visited_edges, current_edge)) { + BLI_ghash_insert(visited_edges, current_edge, NULL); + + /* if this edge is sharp, use it */ + if(edge_is_sharp(current_edge, flags, threshold)) { + sharp_edge = current_edge; + break; + } + + /* save end face for edge replacement later */ + end_face = current_face; + + /* this edge should use the copy vert */ + BLI_linklist_prepend(&split_edges, current_edge); + + /* get the next edge around the vert */ + current_edge = other_edge(current_face, vert, current_edge); + /* get the smoothest next face */ + current_face = smoothest_face(current_edge, current_face); + } +#ifdef EDGESPLIT_DEBUG_2 + printf("*** Ending face traversal ***\n"); +#endif + BLI_ghash_free(visited_edges, NULL, NULL); + + /* if we've returned to the starting point without finding a sharp edge, + * don't split the vert + */ + if(current_edge == start_edge || (current_face && !sharp_edge)) { + BLI_linklist_free(split_edges, NULL); + return 0; + } + + /* if current_face == NULL, we've hit a loose edge + * before finding a sharp edge + */ + if(!current_face) BLI_linklist_prepend(&split_edges, current_edge); + + /* copy the vertex */ + copy_vert = smoothvert_copy(vert); + copy_vert->newIndex = BLI_ghash_size(mesh->verts); + linklist_empty(©_vert->faces, NULL); + BLI_ghash_insert(mesh->verts, (void *)copy_vert->newIndex, copy_vert); + + /* add copy_edge to split_edges so it will undergo vertex replacement */ + BLI_linklist_prepend(&split_edges, copy_edge); + + /* replace the vertex with the copy in edges being split off */ + repdata.find = vert; + repdata.replace = copy_vert; + BLI_linklist_apply(split_edges, edge_replace_vert, &repdata); + + /* if sharp_edge == NULL, we didn't find a sharp edge, so don't split + * any more edges + */ + if(sharp_edge) { + /* copy the sharpest edge */ + SmoothEdge *copy_sharp = smoothedge_copy(sharp_edge); + copy_sharp->newIndex = BLI_ghash_size(mesh->edges); + linklist_empty(©_sharp->faces, NULL); + BLI_ghash_insert(mesh->edges, (void *)copy_sharp->newIndex, copy_sharp); + +#ifdef EDGESPLIT_DEBUG_2 + printf("sharpest edge is %4d\n", + sharp_edge->newIndex); +#endif + /* replace the sharpest edge with the copy in end_face + */ + repdata.find = sharp_edge; + repdata.replace = copy_sharp; + face_replace_edge(end_face, &repdata); + + /* replace the vertex with its copy in copy_sharp */ + repdata.find = vert; + repdata.replace = copy_vert; + edge_replace_vert(copy_sharp, &repdata); + + /* split the other vertex (don't need to check return value as it + * doesn't matter if the split succeeds - the edge will be split + * regardless + */ + if(copy_sharp->verts[0] == copy_vert) + split_vert(copy_sharp->verts[1], sharp_edge, copy_sharp, + end_face, mesh, threshold, flags); + else + split_vert(copy_sharp->verts[0], sharp_edge, copy_sharp, + end_face, mesh, threshold, flags); + } + + BLI_linklist_free(split_edges, NULL); +#ifdef EDGESPLIT_DEBUG_2 + printf("<<<<<<<<<<<<<<<<<<<<< split_vert end <<<<<<<<<<<<<<<<<<<<<\n"); +#endif + + return 1; +} + +static void split_edge(SmoothEdge *edge, SmoothMesh *mesh, float threshold, + int flags) +{ + LinkNode *split_node; + + /* split all the faces off but the first */ + for(split_node = edge->faces->next; split_node; ) { + ReplaceData repdata; + int success[2]; + SmoothFace *split_face = split_node->link; + + /* copy the start edge */ + SmoothEdge *copy_edge = smoothedge_copy(edge); + copy_edge->newIndex = BLI_ghash_size(mesh->edges); + linklist_empty(©_edge->faces, NULL); + BLI_ghash_insert(mesh->edges, (void *)copy_edge->newIndex, copy_edge); + +#ifdef EDGESPLIT_DEBUG_2 + printf(">>>>>>>>>>>>>>>>>>>> split_edge start >>>>>>>>>>>>>>>>>>>>\n"); +#endif + /* we need to go to the next node before we replace the edge, + * otherwise the current node will have been removed from the list + */ + split_node = split_node->next; + + /* replace the start edge with the copy in the face being split off */ + repdata.find = edge; + repdata.replace = copy_edge; + face_replace_edge(split_face, &repdata); + +#ifdef EDGESPLIT_DEBUG_2 + printf("******************* splitting verts[0] *******************\n"); +#endif + success[0] = split_vert(edge->verts[0], edge, copy_edge, + split_face, mesh, threshold, flags); +#ifdef EDGESPLIT_DEBUG_2 + printf("******************* splitting verts[1] *******************\n"); +#endif + success[1] = split_vert(edge->verts[1], edge, copy_edge, + split_face, mesh, threshold, flags); +#ifdef EDGESPLIT_DEBUG_2 + printf("<<<<<<<<<<<<<<<<<<<<< split_edge end <<<<<<<<<<<<<<<<<<<<<\n"); +#endif + /* if neither split operation succeeded, remove the edge */ + if(!success[0] && !success[1]) { + repdata.find = copy_edge; + repdata.replace = edge; + face_replace_edge(split_face, &repdata); + + BLI_ghash_remove(mesh->edges, (void *)copy_edge->newIndex, + NULL, smoothedge_free); + } + } +} + +static void split_sharp_edges(SmoothMesh *mesh, float split_angle, int flags) +{ + int i; + int num_edges = BLI_ghash_size(mesh->edges); + /* if normal1 dot normal2 < threshold, angle is greater, so split */ + /* FIXME not sure if this always works */ + /* 0.00001 added for floating-point rounding */ + float threshold = cos((split_angle + 0.00001) * M_PI / 180.0); + + /* loop through edges, splitting sharp ones */ + /* can't use an iterator here, because we'll be adding edges */ + for(i = 0; i < num_edges; i++) { + SmoothEdge *edge = BLI_ghash_lookup(mesh->edges, (void *)i); + + if(edge_is_sharp(edge, flags, threshold)) + split_edge(edge, mesh, threshold, flags); + } + +} + +static void split_single_vert(SmoothVert *vert, SmoothFace *face, + SmoothMesh *mesh) +{ + SmoothVert *copy_vert; + ReplaceData repdata; + + copy_vert = smoothvert_copy(vert); + copy_vert->newIndex = BLI_ghash_size(mesh->verts); + linklist_empty(©_vert->faces, NULL); + BLI_ghash_insert(mesh->verts, (void *)copy_vert->newIndex, copy_vert); + + repdata.find = vert; + repdata.replace = copy_vert; + face_replace_vert(face, &repdata); +} + +static void split_single_verts(SmoothMesh *mesh) +{ + int num_faces = BLI_ghash_size(mesh->faces); + int i,j; + + for(i = 0; i < num_faces; i++) { + SmoothFace *face = BLI_ghash_lookup(mesh->faces, (void *)i); + + for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) { + SmoothEdge *edge = face->edges[j]; + SmoothEdge *next_edge; + SmoothVert *vert = edge->verts[1 - face->flip[j]]; + int next = (j + 1) % SMOOTHFACE_MAX_EDGES; + + /* wrap next around if at last edge */ + if(!face->edges[next]) next = 0; + + next_edge = face->edges[next]; + + /* if there are other faces sharing this vertex but not + * these edges, split the vertex + */ + /* vert has to have at least one face (this one), so faces != 0 */ + if(!edge->faces->next && !next_edge->faces->next + && vert->faces->next) + /* FIXME this needs to find all faces that share edges with + * this one and split off together + */ + split_single_vert(vert, face, mesh); + } + } +} + +static DerivedMesh *edgesplitModifier_do(EdgeSplitModifierData *emd, + Object *ob, DerivedMesh *dm) +{ + SmoothMesh *mesh; + DerivedMesh *result; + + mesh = smoothmesh_from_derivedmesh(dm); + +#ifdef EDGESPLIT_DEBUG_1 + printf("********** Pre-split **********\n"); + smoothmesh_print(mesh); +#endif + + split_sharp_edges(mesh, emd->split_angle, emd->flags); +#ifdef EDGESPLIT_DEBUG_1 + printf("********** Post-edge-split **********\n"); + smoothmesh_print(mesh); +#endif + split_single_verts(mesh); + +#ifdef EDGESPLIT_DEBUG_1 + printf("********** Post-vert-split **********\n"); + smoothmesh_print(mesh); +#endif + + result = CDDM_from_smoothmesh(mesh); + smoothmesh_free(mesh); + + return result; +} + +static DerivedMesh *edgesplitModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + DerivedMesh *result; + EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md; + + result = edgesplitModifier_do(emd, ob, derivedData); + + CDDM_calc_normals(result); + + return result; +} + +static DerivedMesh *edgesplitModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) +{ + return edgesplitModifier_applyModifier(md, ob, derivedData, 0, 1); +} + +/* Displace */ + +static void displaceModifier_initData(ModifierData *md) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + + dmd->texture = NULL; + dmd->strength = 1; + dmd->direction = MOD_DISP_DIR_NOR; + dmd->midlevel = 0.5; +} + +static void displaceModifier_copyData(ModifierData *md, ModifierData *target) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + DisplaceModifierData *tdmd = (DisplaceModifierData*) target; + + *tdmd = *dmd; +} + +static void displaceModifier_foreachObjectLink(ModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + + walk(userData, ob, &dmd->map_object); +} + +static void displaceModifier_foreachIDLink(ModifierData *md, Object *ob, + IDWalkFunc walk, void *userData) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + + walk(userData, ob, (ID **)&dmd->texture); + + displaceModifier_foreachObjectLink(md, ob, (ObjectWalkFunc) walk, userData); +} + +static int displaceModifier_isDisabled(ModifierData *md) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + + return !dmd->texture; +} + +static void displaceModifier_updateDepgraph( + ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) +{ + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + + if(dmd->map_object) { + DagNode *curNode = dag_get_node(forest, dmd->map_object); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } } -static void *mirrorModifier_applyModifier(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int useRenderParams, int isFinalCalc) +static void get_texture_coords(DisplaceModifierData *dmd, Object *ob, + DerivedMesh *dm, + float (*co)[3], float (*texco)[3], + int numVerts) { - return mirrorModifier_applyModifier__internal(md, ob, derivedData, vertexCos, 0, 1); + int i; + int texmapping = dmd->texmapping; + + if(texmapping == MOD_DISP_MAP_OBJECT) { + if(dmd->map_object) + Mat4Invert(dmd->map_object->imat, dmd->map_object->obmat); + else /* if there is no map object, default to local */ + texmapping = MOD_DISP_MAP_LOCAL; + } + + /* UVs need special handling, since they come from faces */ + if(texmapping == MOD_DISP_MAP_UV) { + if(dm->getFaceDataArray(dm, LAYERTYPE_TFACE)) { + MFace *mface = dm->dupFaceArray(dm); + MFace *mf; + char *done = MEM_callocN(sizeof(*done) * numVerts, + "get_texture_coords done"); + TFace *tf = dm->getFaceDataArray(dm, LAYERTYPE_TFACE); + int numFaces = dm->getNumFaces(dm); + + /* verts are given the UV from the first face that uses them */ + for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) { + if(!done[mf->v1]) { + texco[mf->v1][0] = tf->uv[0][0]; + texco[mf->v1][1] = tf->uv[0][1]; + texco[mf->v1][2] = 0; + done[mf->v1] = 1; + } + if(!done[mf->v2]) { + texco[mf->v2][0] = tf->uv[1][0]; + texco[mf->v2][1] = tf->uv[1][1]; + texco[mf->v2][2] = 0; + done[mf->v2] = 1; + } + if(!done[mf->v3]) { + texco[mf->v3][0] = tf->uv[2][0]; + texco[mf->v3][1] = tf->uv[2][1]; + texco[mf->v3][2] = 0; + done[mf->v3] = 1; + } + if(!done[mf->v4]) { + texco[mf->v4][0] = tf->uv[3][0]; + texco[mf->v4][1] = tf->uv[3][1]; + texco[mf->v4][2] = 0; + done[mf->v4] = 1; + } + } + + /* remap UVs from [0, 1] to [-1, 1] */ + for(i = 0; i < numVerts; ++i) { + texco[i][0] = texco[i][0] * 2 - 1; + texco[i][1] = texco[i][1] * 2 - 1; + } + + MEM_freeN(done); + MEM_freeN(mface); + return; + } else /* if there are no UVs, default to local */ + texmapping = MOD_DISP_MAP_LOCAL; + } + + for(i = 0; i < numVerts; ++i, ++co, ++texco) { + switch(texmapping) { + case MOD_DISP_MAP_LOCAL: + VECCOPY(*texco, *co); + break; + case MOD_DISP_MAP_GLOBAL: + VECCOPY(*texco, *co); + Mat4MulVecfl(ob->obmat, *texco); + break; + case MOD_DISP_MAP_OBJECT: + VECCOPY(*texco, *co); + Mat4MulVecfl(ob->obmat, *texco); + Mat4MulVecfl(dmd->map_object->imat, *texco); + break; + } + } } -static void *mirrorModifier_applyModifierEM(ModifierData *md, Object *ob, void *editData, void *derivedData, float (*vertexCos)[3]) +/* dm must be a CDDerivedMesh */ +static void displaceModifier_do( + DisplaceModifierData *dmd, Object *ob, + DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { - if (derivedData) { - return mirrorModifier_applyModifier__internal(md, ob, derivedData, vertexCos, 0, 1); + int i; + MVert *mvert; + MDeformVert *dvert = NULL; + int defgrp_index; + float (*tex_co)[3]; + + if(!dmd->texture) return; + + defgrp_index = -1; + + if(dmd->defgrp_name[0]) { + bDeformGroup *def; + for(i = 0, def = ob->defbase.first; def; def = def->next, i++) { + if(!strcmp(def->name, dmd->defgrp_name)) { + defgrp_index = i; + break; + } + } + } + + mvert = CDDM_get_verts(dm); + if(defgrp_index >= 0) + dvert = dm->getVertDataArray(dm, LAYERTYPE_MDEFORMVERT); + + tex_co = MEM_callocN(sizeof(*tex_co) * numVerts, + "displaceModifier_do tex_co"); + get_texture_coords(dmd, ob, dm, vertexCos, tex_co, numVerts); + + for(i = 0; i < numVerts; ++i) { + TexResult texres; + float delta = 0; + MDeformWeight *def_weight = NULL; + + if(dvert) { + int j; + for(j = 0; j < dvert[i].totweight; ++j) { + if(dvert[i].dw[j].def_nr == defgrp_index) { + def_weight = &dvert[i].dw[j]; + break; + } + } + if(!def_weight) continue; + } + + texres.nor = NULL; + multitex_ext(dmd->texture, tex_co[i], NULL, NULL, 1, &texres); + + delta = texres.tin - dmd->midlevel; + + if(def_weight) delta *= def_weight->weight; + + switch(dmd->direction) { + case MOD_DISP_DIR_X: + vertexCos[i][0] += delta * dmd->strength; + break; + case MOD_DISP_DIR_Y: + vertexCos[i][1] += delta * dmd->strength; + break; + case MOD_DISP_DIR_Z: + vertexCos[i][2] += delta * dmd->strength; + break; + case MOD_DISP_DIR_NOR: + delta *= dmd->strength; + vertexCos[i][0] += delta * mvert[i].no[0] / 32767.0f; + vertexCos[i][1] += delta * mvert[i].no[1] / 32767.0f; + vertexCos[i][2] += delta * mvert[i].no[2] / 32767.0f; + break; + } + } + + MEM_freeN(tex_co); +} + +static void displaceModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + + if(derivedData) dm = CDDM_copy(derivedData); + else dm = CDDM_from_mesh(ob->data); + + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + + displaceModifier_do((DisplaceModifierData *)md, ob, dm, + vertexCos, numVerts); + + dm->release(dm); +} + +static void displaceModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + + if(derivedData) dm = CDDM_copy(derivedData); + else dm = CDDM_from_editmesh(editData, ob->data); + + CDDM_apply_vert_coords(dm, vertexCos); + CDDM_calc_normals(dm); + + displaceModifier_do((DisplaceModifierData *)md, ob, dm, + vertexCos, numVerts); + + dm->release(dm); +} + +/* UVProject */ +/* UV Project modifier: Generates UVs projected from an object +*/ + +static void uvprojectModifier_initData(ModifierData *md) +{ + UVProjectModifierData *umd = (UVProjectModifierData*) md; + int i; + + for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) + umd->projectors[i] = NULL; + umd->image = NULL; + umd->flags = MOD_UVPROJECT_ADDUVS; + umd->num_projectors = 1; +} + +static void uvprojectModifier_copyData(ModifierData *md, ModifierData *target) +{ + UVProjectModifierData *umd = (UVProjectModifierData*) md; + UVProjectModifierData *tumd = (UVProjectModifierData*) target; + int i; + + for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) + tumd->projectors[i] = umd->projectors[i]; + tumd->image = umd->image; + tumd->flags = umd->flags; + tumd->num_projectors = umd->num_projectors; +} + +static void uvprojectModifier_foreachObjectLink(ModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) +{ + UVProjectModifierData *umd = (UVProjectModifierData*) md; + int i; + + for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i) + walk(userData, ob, &umd->projectors[i]); +} + +static void uvprojectModifier_foreachIDLink(ModifierData *md, Object *ob, + IDWalkFunc walk, void *userData) +{ + UVProjectModifierData *umd = (UVProjectModifierData*) md; + + walk(userData, ob, (ID **)&umd->image); + + uvprojectModifier_foreachObjectLink(md, ob, (ObjectWalkFunc)walk, + userData); +} + +static void uvprojectModifier_updateDepgraph(ModifierData *md, + DagForest *forest, Object *ob, DagNode *obNode) +{ + UVProjectModifierData *umd = (UVProjectModifierData*) md; + int i; + + for(i = 0; i < umd->num_projectors; ++i) { + if(umd->projectors[i]) { + DagNode *curNode = dag_get_node(forest, umd->projectors[i]); + + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); + } + } +} + +typedef struct Projector { + Object *ob; /* object this projector is derived from */ + float imat[4][4]; /* world space -> projector space matrix */ + float normal[3]; /* projector normal in world space */ +} Projector; + +static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd, + Object *ob, DerivedMesh *dm) +{ + float (*coords)[3], (*co)[3]; + TFace *tface; + MCol *mcol = NULL; + int i, numVerts, numFaces; + Image *image = umd->image; + MFace *mface, *mf; + int new_tfaces = 0; + Projector projectors[MOD_UVPROJECT_MAXPROJECTORS]; + int num_projectors = 0; + + for(i = 0; i < umd->num_projectors; ++i) + if(umd->projectors[i]) + projectors[num_projectors++].ob = umd->projectors[i]; + + tface = dm->getFaceDataArray(dm, LAYERTYPE_TFACE); + + if(num_projectors == 0) return dm; + + if(!tface) { + if(!(umd->flags & MOD_UVPROJECT_ADDUVS)) return dm; + + DM_add_face_layer(dm, LAYERTYPE_TFACE, 0, NULL); + tface = dm->getFaceDataArray(dm, LAYERTYPE_TFACE); + mcol = dm->getFaceDataArray(dm, LAYERTYPE_MCOL); + new_tfaces = 1; + } + + numVerts = dm->getNumVerts(dm); + + coords = MEM_callocN(sizeof(*coords) * numVerts, + "uvprojectModifier_do coords"); + dm->getVertCos(dm, coords); + + /* convert coords to world space */ + for(i = 0, co = coords; i < numVerts; ++i, ++co) + Mat4MulVecfl(ob->obmat, *co); + + if(num_projectors == 1) { + float imat[4][4]; + + /* get projector space matrix */ + Mat4Invert(imat, projectors[0].ob->obmat); + if(projectors[0].ob->type == OB_CAMERA) { + Camera *cam = (Camera *)projectors[0].ob->data; + if(cam->type == CAM_ORTHO) + Mat4MulFloat3(imat[0], 1 / cam->ortho_scale); + } + + /* convert coords to projector space */ + for(i = 0, co = coords; i < numVerts; ++i, ++co) + Mat4MulVecfl(imat, *co); } else { - DispListMesh *inDLM, *outDLM; - MirrorModifierData *mmd = (MirrorModifierData*) md; - - inDLM = displistmesh_from_editmesh((EditMesh*)editData); - outDLM = mirrorModifier__doMirror(mmd, inDLM, vertexCos, 0); - displistmesh_free(inDLM); + /* calculate a world space -> projector space matrix and normal + * for each projector + */ + for(i = 0; i < num_projectors; ++i) { + Mat4Invert(projectors[i].imat, projectors[i].ob->obmat); + if(projectors[i].ob->type == OB_CAMERA) { + Camera *cam = (Camera *)projectors[i].ob->data; + if(cam->type == CAM_ORTHO) + Mat4MulFloat3(*projectors[i].imat, 1 / cam->ortho_scale); + } + projectors[i].normal[0] = 0; + projectors[i].normal[1] = 0; + projectors[i].normal[2] = 1; + Mat4Mul3Vecfl(projectors[i].ob->obmat, projectors[i].normal); + } + } - mesh_calc_normals(outDLM->mvert, outDLM->totvert, outDLM->mface, outDLM->totface, &outDLM->nors); + mface = dm->dupFaceArray(dm); + numFaces = dm->getNumFaces(dm); + + /* apply coords as UVs, and apply image if tfaces are new */ + for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) { + if(new_tfaces || !image || tface->tpage == image) { + if(num_projectors == 1) { + /* apply transformed coords as UVs */ + tface->uv[0][0] = coords[mf->v1][0]; + tface->uv[0][1] = coords[mf->v1][1]; + tface->uv[1][0] = coords[mf->v2][0]; + tface->uv[1][1] = coords[mf->v2][1]; + tface->uv[2][0] = coords[mf->v3][0]; + tface->uv[2][1] = coords[mf->v3][1]; + if(mf->v4) { + tface->uv[3][0] = coords[mf->v4][0]; + tface->uv[3][1] = coords[mf->v4][1]; + } + } else { + /* multiple projectors, select the closest to face normal + * direction + */ + float co1[3], co2[3], co3[3], co4[3]; + float face_no[3]; + int j; + Projector *best_projector; + float best_dot; + + VECCOPY(co1, coords[mf->v1]); + VECCOPY(co2, coords[mf->v2]); + VECCOPY(co3, coords[mf->v3]); + + /* get the untransformed face normal */ + if(mf->v4) { + VECCOPY(co4, coords[mf->v4]); + CalcNormFloat4(co1, co2, co3, co4, face_no); + } else { + CalcNormFloat(co1, co2, co3, face_no); + } + + /* find the projector which the face points at most directly + * (projector normal with largest dot product is best) + */ + best_dot = MTC_dot3Float(projectors[0].normal, face_no); + best_projector = &projectors[0]; + + for(j = 1; j < num_projectors; ++j) { + float tmp_dot = MTC_dot3Float(projectors[j].normal, + face_no); + if(tmp_dot > best_dot) { + best_dot = tmp_dot; + best_projector = &projectors[j]; + } + } - return derivedmesh_from_displistmesh(outDLM, NULL); + Mat4MulVecfl(best_projector->imat, co1); + Mat4MulVecfl(best_projector->imat, co2); + Mat4MulVecfl(best_projector->imat, co3); + if(mf->v4) + Mat4MulVecfl(best_projector->imat, co4); + + /* apply transformed coords as UVs */ + tface->uv[0][0] = co1[0]; + tface->uv[0][1] = co1[1]; + tface->uv[1][0] = co2[0]; + tface->uv[1][1] = co2[1]; + tface->uv[2][0] = co3[0]; + tface->uv[2][1] = co3[1]; + if(mf->v4) { + tface->uv[3][0] = co4[0]; + tface->uv[3][1] = co4[1]; + } + } + } + + if(new_tfaces) { + /* make sure we don't overwrite vert colours */ + if(mcol) { + memcpy(tface->col, mcol, 16); /* based on mcol_to_tface() */ + mcol += 4; + } else + memset(tface->col, 0xFF, 16); + + tface->mode = TF_TEX; + if(image) + tface->tpage = image; + } } + + MEM_freeN(mface); + MEM_freeN(coords); + + return dm; +} + +static DerivedMesh *uvprojectModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + DerivedMesh *result; + UVProjectModifierData *umd = (UVProjectModifierData*) md; + + result = uvprojectModifier_do(umd, ob, derivedData); + + return result; +} + +static DerivedMesh *uvprojectModifier_applyModifierEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData) +{ + return uvprojectModifier_applyModifier(md, ob, derivedData, 0, 1); } /* Decimate */ @@ -1276,11 +2688,12 @@ static void decimateModifier_copyData(ModifierData *md, ModifierData *target) tdmd->percent = dmd->percent; } -static void *decimateModifier_applyModifier(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int useRenderParams, int isFinalCalc) +static DerivedMesh *decimateModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) { DecimateModifierData *dmd = (DecimateModifierData*) md; DerivedMesh *dm = derivedData; - Mesh *me = ob->data; MVert *mvert; MFace *mface; DispListMesh *ndlm=NULL, *dlm=NULL; @@ -1288,18 +2701,11 @@ static void *decimateModifier_applyModifier(ModifierData *md, Object *ob, void * int totvert, totface; int a, numTris; - if (dm) { - dlm = dm->convertToDispListMesh(dm, 1); - mvert = dlm->mvert; - mface = dlm->mface; - totvert = dlm->totvert; - totface = dlm->totface; - } else { - mvert = me->mvert; - mface = me->mface; - totvert = me->totvert; - totface = me->totface; - } + dlm = dm->convertToDispListMesh(dm, 1); + mvert = dlm->mvert; + mface = dlm->mface; + totvert = dlm->totvert; + totface = dlm->totface; numTris = 0; for (a=0; a<totface; a++) { @@ -1309,7 +2715,8 @@ static void *decimateModifier_applyModifier(ModifierData *md, Object *ob, void * } if(numTris<3) { - modifier_setError(md, "There must be more than 3 input faces (triangles)."); + modifier_setError(md, + "There must be more than 3 input faces (triangles)."); goto exit; } @@ -1324,11 +2731,7 @@ static void *decimateModifier_applyModifier(ModifierData *md, Object *ob, void * float *vbCo = &lod.vertex_buffer[a*3]; float *vbNo = &lod.vertex_normal_buffer[a*3]; - if (vertexCos) { - VECCOPY(vbCo, vertexCos[a]); - } else { - VECCOPY(vbCo, mv->co); - } + VECCOPY(vbCo, mv->co); vbNo[0] = mv->no[0]/32767.0f; vbNo[1] = mv->no[1]/32767.0f; @@ -1404,7 +2807,8 @@ exit: if (dlm) displistmesh_free(dlm); if (ndlm) { - mesh_calc_normals(ndlm->mvert, ndlm->totvert, ndlm->mface, ndlm->totface, &ndlm->nors); + mesh_calc_normals(ndlm->mvert, ndlm->totvert, ndlm->mface, + ndlm->totface, &ndlm->nors); return derivedmesh_from_displistmesh(ndlm, NULL); } else { @@ -1450,61 +2854,68 @@ static int waveModifier_dependsOnTime(ModifierData *md) return 1; } -static void waveModifier_deformVerts(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int numVerts) +static void waveModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { WaveModifierData *wmd = (WaveModifierData*) md; float ctime = bsystem_time(ob, 0, (float)G.scene->r.cfra, 0.0); - float minfac = (float)(1.0/exp(wmd->width*wmd->narrow*wmd->width*wmd->narrow)); + float minfac = + (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow)); float lifefac = wmd->height; - if(wmd->damp==0) wmd->damp= 10.0f; + if(wmd->damp == 0) wmd->damp = 10.0f; - if(wmd->lifetime!=0.0) { - float x= ctime - wmd->timeoffs; + if(wmd->lifetime != 0.0) { + float x = ctime - wmd->timeoffs; - if(x>wmd->lifetime) { - lifefac= x-wmd->lifetime; + if(x > wmd->lifetime) { + lifefac = x - wmd->lifetime; - if(lifefac > wmd->damp) lifefac= 0.0; - else lifefac= (float)(wmd->height*(1.0 - sqrt(lifefac/wmd->damp))); + if(lifefac > wmd->damp) lifefac = 0.0; + else lifefac = + (float)(wmd->height * (1.0 - sqrt(lifefac / wmd->damp))); } } - if(lifefac!=0.0) { + if(lifefac != 0.0) { int i; - for (i=0; i<numVerts; i++) { + for(i = 0; i < numVerts; i++) { float *co = vertexCos[i]; - float x= co[0]-wmd->startx; - float y= co[1]-wmd->starty; + float x = co[0] - wmd->startx; + float y = co[1] - wmd->starty; float amplit= 0.0f; if(wmd->flag & WAV_X) { - if(wmd->flag & WAV_Y) amplit= (float)sqrt( (x*x + y*y)); - else amplit= x; + if(wmd->flag & WAV_Y) amplit = (float)sqrt(x*x + y*y); + else amplit = x; } else if(wmd->flag & WAV_Y) amplit= y; /* this way it makes nice circles */ - amplit-= (ctime-wmd->timeoffs)*wmd->speed; + amplit -= (ctime - wmd->timeoffs) * wmd->speed; if(wmd->flag & WAV_CYCL) { - amplit = (float)fmod(amplit-wmd->width, 2.0*wmd->width) + wmd->width; + amplit = (float)fmod(amplit - wmd->width, 2.0 * wmd->width) + + wmd->width; } - /* GAUSSIAN */ - if(amplit> -wmd->width && amplit<wmd->width) { - amplit = amplit*wmd->narrow; - amplit= (float)(1.0/exp(amplit*amplit) - minfac); + /* GAUSSIAN */ + if(amplit > -wmd->width && amplit < wmd->width) { + amplit = amplit * wmd->narrow; + amplit = (float)(1.0 / exp(amplit * amplit) - minfac); - co[2]+= lifefac*amplit; + co[2] += lifefac * amplit; } } } } -static void waveModifier_deformVertsEM(ModifierData *md, Object *ob, void *editData, void *derivedData, float (*vertexCos)[3], int numVerts) +static void waveModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { waveModifier_deformVerts(md, ob, NULL, vertexCos, numVerts); } @@ -1515,7 +2926,7 @@ static void armatureModifier_initData(ModifierData *md) { ArmatureModifierData *amd = (ArmatureModifierData*) md; - amd->deformflag = ARM_DEF_ENVELOPE|ARM_DEF_VGROUP; + amd->deformflag = ARM_DEF_ENVELOPE | ARM_DEF_VGROUP; } static void armatureModifier_copyData(ModifierData *md, ModifierData *target) @@ -1534,36 +2945,53 @@ static int armatureModifier_isDisabled(ModifierData *md) return !amd->object; } -static void armatureModifier_foreachObjectLink(ModifierData *md, Object *ob, void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData) +static void armatureModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { ArmatureModifierData *amd = (ArmatureModifierData*) md; walk(userData, ob, &amd->object); } -static void armatureModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode) +static void armatureModifier_updateDepgraph( + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) { ArmatureModifierData *amd = (ArmatureModifierData*) md; if (amd->object) { DagNode *curNode = dag_get_node(forest, amd->object); - dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); } } -static void armatureModifier_deformVerts(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int numVerts) +static void armatureModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { ArmatureModifierData *amd = (ArmatureModifierData*) md; - armature_deform_verts(amd->object, ob, vertexCos, numVerts, amd->deformflag); + armature_deform_verts(amd->object, ob, derivedData, vertexCos, numVerts, + amd->deformflag); } -static void armatureModifier_deformVertsEM(ModifierData *md, Object *ob, void *editData, void *derivedData, float (*vertexCos)[3], int numVerts) +static void armatureModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { ArmatureModifierData *amd = (ArmatureModifierData*) md; + DerivedMesh *dm = derivedData; + + if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); - armature_deform_verts(amd->object, ob, vertexCos, numVerts, amd->deformflag); + armature_deform_verts(amd->object, ob, dm, vertexCos, numVerts, + amd->deformflag); + + if(!derivedData) dm->release(dm); } /* Hook */ @@ -1603,14 +3031,18 @@ static int hookModifier_isDisabled(ModifierData *md) return !hmd->object; } -static void hookModifier_foreachObjectLink(ModifierData *md, Object *ob, void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData) +static void hookModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { HookModifierData *hmd = (HookModifierData*) md; walk(userData, ob, &hmd->object); } -static void hookModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode) +static void hookModifier_updateDepgraph(ModifierData *md, DagForest *forest, + Object *ob, DagNode *obNode) { HookModifierData *hmd = (HookModifierData*) md; @@ -1621,87 +3053,139 @@ static void hookModifier_updateDepgraph(ModifierData *md, DagForest *forest, Obj } } -static void hookModifier_deformVerts(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int numVerts) +static void hookModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { HookModifierData *hmd = (HookModifierData*) md; float vec[3], mat[4][4]; int i; + DerivedMesh *dm = derivedData; Mat4Invert(ob->imat, ob->obmat); - Mat4MulSerie(mat, ob->imat, hmd->object->obmat, hmd->parentinv, NULL, NULL, NULL, NULL, NULL); + Mat4MulSerie(mat, ob->imat, hmd->object->obmat, hmd->parentinv, + NULL, NULL, NULL, NULL, NULL); /* vertex indices? */ if(hmd->indexar) { - for (i=0; i<hmd->totindex; i++) { + for(i = 0; i < hmd->totindex; i++) { int index = hmd->indexar[i]; - /* This should always be true and I don't generally like - * "paranoid" style code like this, but old files can have - * indices that are out of range because old blender did - * not correct them on exit editmode. - zr - */ - if (index<numVerts) { + /* This should always be true and I don't generally like + * "paranoid" style code like this, but old files can have + * indices that are out of range because old blender did + * not correct them on exit editmode. - zr + */ + if(index < numVerts) { float *co = vertexCos[index]; float fac = hmd->force; - if(hmd->falloff!=0.0) { - float len= VecLenf(co, hmd->cent); - if(len > hmd->falloff) fac = 0.0; - else if(len>0.0) fac *= sqrt(1.0 - len/hmd->falloff); - } + /* if DerivedMesh is present and has original index data, + * use it + */ + if(dm && dm->getVertData(dm, 0, LAYERTYPE_ORIGINDEX)) { + int j; + int orig_index; + for(j = 0; j < numVerts; ++j) { + fac = hmd->force; + orig_index = *(int *)dm->getVertData(dm, j, + LAYERTYPE_ORIGINDEX); + if(orig_index == index) { + co = vertexCos[j]; + if(hmd->falloff != 0.0) { + float len = VecLenf(co, hmd->cent); + if(len > hmd->falloff) fac = 0.0; + else if(len > 0.0) + fac *= sqrt(1.0 - len / hmd->falloff); + } + + if(fac != 0.0) { + VecMat4MulVecfl(vec, mat, co); + VecLerpf(co, co, vec, fac); + } + } + } + } else { + if(hmd->falloff != 0.0) { + float len = VecLenf(co, hmd->cent); + if(len > hmd->falloff) fac = 0.0; + else if(len > 0.0) + fac *= sqrt(1.0 - len / hmd->falloff); + } - if(fac!=0.0) { - VecMat4MulVecfl(vec, mat, co); - VecLerpf(co, co, vec, fac); + if(fac != 0.0) { + VecMat4MulVecfl(vec, mat, co); + VecLerpf(co, co, vec, fac); + } } } } - } - else { /* vertex group hook */ + } else { /* vertex group hook */ bDeformGroup *curdef; - Mesh *me= ob->data; - int index=0; + Mesh *me = ob->data; + int index = 0; + int use_dverts; + int maxVerts; /* find the group (weak loop-in-loop) */ - for (curdef = ob->defbase.first; curdef; curdef=curdef->next, index++) - if (!strcmp(curdef->name, hmd->name)) - break; + for(curdef = ob->defbase.first; curdef; curdef = curdef->next, index++) + if(!strcmp(curdef->name, hmd->name)) break; + + if(dm) + if(dm->getVertData(dm, 0, LAYERTYPE_MDEFORMVERT)) { + use_dverts = 1; + maxVerts = dm->getNumVerts(dm); + } else use_dverts = 0; + else if(me->dvert) { + use_dverts = 1; + maxVerts = me->totvert; + } else use_dverts = 0; - if(curdef && me->dvert) { - MDeformVert *dvert= me->dvert; + if(curdef && use_dverts) { + MDeformVert *dvert = me->dvert; int i, j; - for (i=0; i < me->totvert; i++, dvert++) { - for(j=0; j<dvert->totweight; j++) { - if (dvert->dw[j].def_nr == index) { + for(i = 0; i < maxVerts; i++, dvert++) { + if(dm) dvert = dm->getVertData(dm, i, LAYERTYPE_MDEFORMVERT); + for(j = 0; j < dvert->totweight; j++) { + if(dvert->dw[j].def_nr == index) { float fac = hmd->force*dvert->dw[j].weight; float *co = vertexCos[i]; - if(hmd->falloff!=0.0) { - float len= VecLenf(co, hmd->cent); + if(hmd->falloff != 0.0) { + float len = VecLenf(co, hmd->cent); if(len > hmd->falloff) fac = 0.0; - else if(len>0.0) fac *= sqrt(1.0 - len/hmd->falloff); + else if(len > 0.0) + fac *= sqrt(1.0 - len / hmd->falloff); } VecMat4MulVecfl(vec, mat, co); VecLerpf(co, co, vec, fac); - } } } } - } } -static void hookModifier_deformVertsEM(ModifierData *md, Object *ob, void *editData, void *derivedData, float (*vertexCos)[3], int numVerts) +static void hookModifier_deformVertsEM( + ModifierData *md, Object *ob, EditMesh *editData, + DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) { + DerivedMesh *dm = derivedData; + + if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data); + hookModifier_deformVerts(md, ob, derivedData, vertexCos, numVerts); + + if(!derivedData) dm->release(dm); } /* Softbody */ -static void softbodyModifier_deformVerts(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int numVerts) +static void softbodyModifier_deformVerts( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + float (*vertexCos)[3], int numVerts) { sbObjectStep(ob, (float)G.scene->r.cfra, vertexCos, numVerts); } @@ -1724,41 +3208,51 @@ static int booleanModifier_isDisabled(ModifierData *md) return !bmd->object; } -static void booleanModifier_foreachObjectLink(ModifierData *md, Object *ob, void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData) +static void booleanModifier_foreachObjectLink( + ModifierData *md, Object *ob, + void (*walk)(void *userData, Object *ob, Object **obpoin), + void *userData) { BooleanModifierData *bmd = (BooleanModifierData*) md; walk(userData, ob, &bmd->object); } -static void booleanModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode) +static void booleanModifier_updateDepgraph( + ModifierData *md, DagForest *forest, Object *ob, + DagNode *obNode) { BooleanModifierData *bmd = (BooleanModifierData*) md; - if (bmd->object) { + if(bmd->object) { DagNode *curNode = dag_get_node(forest, bmd->object); - dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA); + dag_add_relation(forest, curNode, obNode, + DAG_RL_DATA_DATA | DAG_RL_OB_DATA); } } -static void *booleanModifier_applyModifier(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int useRenderParams, int isFinalCalc) -{ - // XXX doesn't handle derived data +static DerivedMesh *booleanModifier_applyModifier( + ModifierData *md, Object *ob, DerivedMesh *derivedData, + int useRenderParams, int isFinalCalc) +{ + // XXX doesn't handle derived data BooleanModifierData *bmd = (BooleanModifierData*) md; - + /* we do a quick sanity check */ - if( ((Mesh *)ob->data)->totface>3 && bmd->object && ((Mesh *)bmd->object->data)->totface>3) { - DispListMesh *dlm= NewBooleanMeshDLM(bmd->object, ob, 1+bmd->operation); - - /* if new mesh returned, get derived mesh; otherwise there was - * an error, so delete the modifier object */ + if(((Mesh *)ob->data)->totface > 3 + && bmd->object && ((Mesh *)bmd->object->data)->totface > 3) { + DerivedMesh *result = NewBooleanDerivedMesh(bmd->object, ob, + 1 + bmd->operation); - if( dlm ) - return derivedmesh_from_displistmesh(dlm, NULL); + /* if new mesh returned, return it; otherwise there was + * an error, so delete the modifier object */ + if(result) + return result; else bmd->object = NULL; } + return derivedData; } @@ -1780,9 +3274,11 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) * structName == typeName + 'ModifierData' */ #define INIT_TYPE(typeName) \ - ( strcpy(typeArr[eModifierType_##typeName].name, #typeName), \ - strcpy(typeArr[eModifierType_##typeName].structName, #typeName "ModifierData"), \ - typeArr[eModifierType_##typeName].structSize = sizeof(typeName##ModifierData), \ + (strcpy(typeArr[eModifierType_##typeName].name, #typeName), \ + strcpy(typeArr[eModifierType_##typeName].structName, \ + #typeName "ModifierData"), \ + typeArr[eModifierType_##typeName].structSize = \ + sizeof(typeName##ModifierData), \ &typeArr[eModifierType_##typeName]) mti = &typeArr[eModifierType_None]; @@ -1790,12 +3286,14 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) strcpy(mti->structName, "ModifierData"); mti->structSize = sizeof(ModifierData); mti->type = eModifierType_None; - mti->flags = eModifierTypeFlag_AcceptsMesh|eModifierTypeFlag_AcceptsCVs; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_AcceptsCVs; mti->isDisabled = noneModifier_isDisabled; mti = INIT_TYPE(Curve); mti->type = eModifierTypeType_OnlyDeform; - mti->flags = eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_RequiresOriginalData; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; mti->copyData = curveModifier_copyData; mti->isDisabled = curveModifier_isDisabled; mti->foreachObjectLink = curveModifier_foreachObjectLink; @@ -1805,7 +3303,8 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Lattice); mti->type = eModifierTypeType_OnlyDeform; - mti->flags = eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_RequiresOriginalData; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; mti->copyData = latticeModifier_copyData; mti->isDisabled = latticeModifier_isDisabled; mti->foreachObjectLink = latticeModifier_foreachObjectLink; @@ -1815,7 +3314,10 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Subsurf); mti->type = eModifierTypeType_Constructive; - mti->flags = eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; mti->initData = subsurfModifier_initData; mti->copyData = subsurfModifier_copyData; mti->freeData = subsurfModifier_freeData; @@ -1845,12 +3347,53 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Mirror); mti->type = eModifierTypeType_Constructive; - mti->flags = eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; mti->initData = mirrorModifier_initData; mti->copyData = mirrorModifier_copyData; mti->applyModifier = mirrorModifier_applyModifier; mti->applyModifierEM = mirrorModifier_applyModifierEM; + mti = INIT_TYPE(EdgeSplit); + mti->type = eModifierTypeType_Constructive; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; + mti->initData = edgesplitModifier_initData; + mti->copyData = edgesplitModifier_copyData; + mti->applyModifier = edgesplitModifier_applyModifier; + mti->applyModifierEM = edgesplitModifier_applyModifierEM; + + mti = INIT_TYPE(Displace); + mti->type = eModifierTypeType_OnlyDeform; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; + mti->initData = displaceModifier_initData; + mti->copyData = displaceModifier_copyData; + mti->foreachObjectLink = displaceModifier_foreachObjectLink; + mti->foreachIDLink = displaceModifier_foreachIDLink; + mti->updateDepgraph = displaceModifier_updateDepgraph; + mti->isDisabled = displaceModifier_isDisabled; + mti->deformVerts = displaceModifier_deformVerts; + mti->deformVertsEM = displaceModifier_deformVertsEM; + + mti = INIT_TYPE(UVProject); + mti->type = eModifierTypeType_Nonconstructive; + mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_SupportsMapping + | eModifierTypeFlag_SupportsEditmode + | eModifierTypeFlag_EnableInEditmode; + mti->initData = uvprojectModifier_initData; + mti->copyData = uvprojectModifier_copyData; + mti->foreachObjectLink = uvprojectModifier_foreachObjectLink; + mti->foreachIDLink = uvprojectModifier_foreachIDLink; + mti->updateDepgraph = uvprojectModifier_updateDepgraph; + mti->applyModifier = uvprojectModifier_applyModifier; + mti->applyModifierEM = uvprojectModifier_applyModifierEM; + mti = INIT_TYPE(Decimate); mti->type = eModifierTypeType_Nonconstructive; mti->flags = eModifierTypeFlag_AcceptsMesh; @@ -1860,7 +3403,8 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Wave); mti->type = eModifierTypeType_OnlyDeform; - mti->flags = eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_SupportsEditmode; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; mti->initData = waveModifier_initData; mti->copyData = waveModifier_copyData; mti->dependsOnTime = waveModifier_dependsOnTime; @@ -1869,7 +3413,8 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Armature); mti->type = eModifierTypeType_OnlyDeform; - mti->flags = eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_RequiresOriginalData; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; mti->initData = armatureModifier_initData; mti->copyData = armatureModifier_copyData; mti->isDisabled = armatureModifier_isDisabled; @@ -1880,7 +3425,8 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Hook); mti->type = eModifierTypeType_OnlyDeform; - mti->flags = eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_RequiresOriginalData; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_SupportsEditmode; mti->initData = hookModifier_initData; mti->copyData = hookModifier_copyData; mti->freeData = hookModifier_freeData; @@ -1892,7 +3438,8 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti = INIT_TYPE(Softbody); mti->type = eModifierTypeType_OnlyDeform; - mti->flags = eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_RequiresOriginalData; + mti->flags = eModifierTypeFlag_AcceptsCVs + | eModifierTypeFlag_RequiresOriginalData; mti->deformVerts = softbodyModifier_deformVerts; mti = INIT_TYPE(Boolean); @@ -1925,9 +3472,10 @@ ModifierData *modifier_new(int type) strcpy(md->name, mti->name); md->type = type; - md->mode = eModifierMode_Realtime|eModifierMode_Render|eModifierMode_Expanded; + md->mode = eModifierMode_Realtime + | eModifierMode_Render | eModifierMode_Expanded; - if (mti->flags&eModifierTypeFlag_EnableInEditmode) + if (mti->flags & eModifierTypeFlag_EnableInEditmode) md->mode |= eModifierMode_Editmode; if (mti->initData) mti->initData(md); @@ -1956,9 +3504,9 @@ int modifier_supportsMapping(ModifierData *md) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - return ( (mti->flags&eModifierTypeFlag_SupportsEditmode) && + return ( (mti->flags & eModifierTypeFlag_SupportsEditmode) && ( (mti->type==eModifierTypeType_OnlyDeform || - (mti->flags&eModifierTypeFlag_SupportsMapping))) ); + (mti->flags & eModifierTypeFlag_SupportsMapping))) ); } ModifierData *modifiers_findByType(Object *ob, ModifierType type) @@ -1989,14 +3537,32 @@ void modifiers_clearErrors(Object *ob) if (qRedraw) allqueue(REDRAWBUTSEDIT, 0); } -void modifiers_foreachObjectLink(Object *ob, void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData) +void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, + void *userData) +{ + ModifierData *md = ob->modifiers.first; + + for (; md; md=md->next) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (mti->foreachObjectLink) + mti->foreachObjectLink(md, ob, walk, userData); + } +} + +void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData) { ModifierData *md = ob->modifiers.first; for (; md; md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (mti->foreachObjectLink) mti->foreachObjectLink(md, ob, walk, userData); + if(mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData); + else if(mti->foreachObjectLink) { + /* each Object can masquerade as an ID, so this should be OK */ + ObjectWalkFunc fp = (ObjectWalkFunc)walk; + mti->foreachObjectLink(md, ob, fp, userData); + } } } @@ -2014,8 +3580,8 @@ int modifier_couldBeCage(ModifierData *md) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - return ( (md->mode&eModifierMode_Realtime) && - (md->mode&eModifierMode_Editmode) && + return ( (md->mode & eModifierMode_Realtime) && + (md->mode & eModifierMode_Editmode) && (!mti->isDisabled || !mti->isDisabled(md)) && modifier_supportsMapping(md)); } @@ -2037,8 +3603,12 @@ void modifier_setError(ModifierData *md, char *format, ...) allqueue(REDRAWBUTSEDIT, 0); } -/* used for buttons, to find out if the 'draw deformed in editmode' option is there */ -/* also used in transform_conversion.c, to detect CrazySpace [tm] (2nd arg then is NULL) */ +/* used for buttons, to find out if the 'draw deformed in editmode' option is + * there + * + * also used in transform_conversion.c, to detect CrazySpace [tm] (2nd arg + * then is NULL) + */ int modifiers_getCageIndex(Object *ob, int *lastPossibleCageIndex_r) { ModifierData *md = ob->modifiers.first; @@ -2048,16 +3618,16 @@ int modifiers_getCageIndex(Object *ob, int *lastPossibleCageIndex_r) for (i=0; md; i++,md=md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!(md->mode&eModifierMode_Realtime)) continue; - if (!(md->mode&eModifierMode_Editmode)) continue; + if (!(md->mode & eModifierMode_Realtime)) continue; + if (!(md->mode & eModifierMode_Editmode)) continue; if (mti->isDisabled && mti->isDisabled(md)) continue; - if (!(mti->flags&eModifierTypeFlag_SupportsEditmode)) continue; + if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue; if (!modifier_supportsMapping(md)) break; if (lastPossibleCageIndex_r) *lastPossibleCageIndex_r = i; - if (md->mode&eModifierMode_OnCage) + if (md->mode & eModifierMode_OnCage) cageIndex = i; } @@ -2069,15 +3639,7 @@ int modifiers_isSoftbodyEnabled(Object *ob) { ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody); - /* Softbody not allowed in this situation, enforce! */ - /* if (md && ob->pd && ob->pd->deflect) { */ - /* no reason for that any more BM */ - if (0) { - md->mode &= ~(eModifierMode_Realtime|eModifierMode_Render|eModifierMode_Editmode); - md = NULL; - } - - return (md && md->mode&(eModifierMode_Realtime|eModifierMode_Render)); + return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)); } ModifierData *modifiers_getVirtualModifierList(Object *ob) @@ -2131,14 +3693,17 @@ ModifierData *modifiers_getVirtualModifierList(Object *ob) return ob->modifiers.first; } -/* Takes an object and returns its first selected armature, else just its armature - This should work for multiple armatures per object */ +/* Takes an object and returns its first selected armature, else just its + * armature + * This should work for multiple armatures per object + */ Object *modifiers_isDeformedByArmature(Object *ob) { ModifierData *md = modifiers_getVirtualModifierList(ob); ArmatureModifierData *amd= NULL; - /* return the first selected armaturem, this lets us use multiple armatures */ + /* return the first selected armature, this lets us use multiple armatures + */ for (; md; md=md->next) { if (md->type==eModifierType_Armature) { amd = (ArmatureModifierData*) md; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 44feaf46233..f8798de2650 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -44,6 +44,7 @@ #include "DNA_object_types.h" #include "BKE_bad_level_calls.h" +#include "BKE_cdderivedmesh.h" #include "BKE_utildefines.h" #include "BKE_global.h" #include "BKE_mesh.h" @@ -75,6 +76,11 @@ struct CCGDerivedMesh { Mesh *me; DispListMesh *dlm; + + struct {int startVert; CCGVert *vert;} *vertMap; + struct {int startVert; int startEdge; CCGEdge *edge;} *edgeMap; + struct {int startVert; int startEdge; + int startFace; CCGFace *face;} *faceMap; }; typedef struct CCGDerivedMesh CCGDerivedMesh; @@ -392,7 +398,7 @@ static DispListMesh *ss_to_displistmesh(CCGSubSurf *ss, CCGDerivedMesh *ccgdm, i int edgeSize = ccgSubSurf_getEdgeSize(ss); int gridSize = ccgSubSurf_getGridSize(ss); int edgeBase, faceBase; - int i, j, k, S, x, y, index, lastIndex; + int i, j, k, S, x, y, index; int vertBase = 0; TFace *tface = NULL; MEdge *medge = NULL; @@ -503,6 +509,9 @@ static DispListMesh *ss_to_displistmesh(CCGSubSurf *ss, CCGDerivedMesh *ccgdm, i * note that the vertex with index 0 is always a face * center vert, this is relied upon to ensure we don't * need to do silly test_index_face calls. + * + * NOTE (artificer): The STEPINDEX flag has been removed, so this + * funny order is no longer strictly necessary, but it works. */ faceBase = i = 0; @@ -544,15 +553,10 @@ static DispListMesh *ss_to_displistmesh(CCGSubSurf *ss, CCGDerivedMesh *ccgdm, i } vertBase = i; - lastIndex = -1; for (index=0; index<totvert; index++) { CCGVert *v = vertMap2[index]; - int mapIndex = ccgDM_getVertMapIndex(ccgdm, ss, v); VecCopyf(dlm->mvert[i].co, ccgSubSurf_getVertData(ss, v)); - if (mapIndex!=lastIndex) - dlm->mvert[i].flag = ME_VERT_STEPINDEX; *((int*) ccgSubSurf_getVertUserData(ss, v)) = i++; - lastIndex = mapIndex; } // load edges @@ -591,11 +595,8 @@ static DispListMesh *ss_to_displistmesh(CCGSubSurf *ss, CCGDerivedMesh *ccgdm, i } } - lastIndex = -1; for (index=0; index<totedge; index++) { CCGEdge *e= edgeMap2[index]; - int mapIndex = ccgDM_getEdgeMapIndex(ccgdm, ss, e); - int edgeStart = i; unsigned int flags = 0; if (!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE; @@ -607,18 +608,20 @@ static DispListMesh *ss_to_displistmesh(CCGSubSurf *ss, CCGDerivedMesh *ccgdm, i if (eed->seam) { flags |= ME_SEAM; } - } else { + } else if(medge){ int edgeIdx = (int) ccgSubSurf_getEdgeEdgeHandle(ss, e); if (edgeIdx!=-1) { MEdge *origMed = &medge[edgeIdx]; if (inDLM) { - flags |= origMed->flag&~ME_EDGE_STEPINDEX; + flags |= origMed->flag; } else { flags |= (origMed->flag&ME_SEAM)|ME_EDGEDRAW|ME_EDGERENDER; } } + } else { + flags |= ME_EDGEDRAW | ME_EDGERENDER; } for (x=0; x<edgeSize-1; x++) { @@ -628,16 +631,11 @@ static DispListMesh *ss_to_displistmesh(CCGSubSurf *ss, CCGDerivedMesh *ccgdm, i med->flag = flags; i++; } - - if (mapIndex!=lastIndex) - dlm->medge[edgeStart].flag |= ME_EDGE_STEPINDEX; - lastIndex = mapIndex; } // load faces i=0; - lastIndex = -1; for (index=0; index<totface; index++) { CCGFace *f = faceMap2[index]; CCGFace *uvf = faceMap2Uv? faceMap2Uv[index]: NULL; @@ -649,9 +647,8 @@ static DispListMesh *ss_to_displistmesh(CCGSubSurf *ss, CCGDerivedMesh *ccgdm, i TFace *origTFace = NULL; int mat_nr; int flag; - int mapIndex = ccgDM_getFaceMapIndex(ccgdm, ss, f); - if (!ssFromEditmesh) { + if (!ssFromEditmesh && mface) { int origIdx = (int) ccgSubSurf_getFaceFaceHandle(ss, f); MFace *origMFace = &mface[origIdx]; @@ -695,10 +692,13 @@ static DispListMesh *ss_to_displistmesh(CCGSubSurf *ss, CCGDerivedMesh *ccgdm, i mat_nr = origMFace->mat_nr; flag = origMFace->flag; - } else { + } else if(ssFromEditmesh) { EditFace *ef = ccgSubSurf_getFaceFaceHandle(ss, f); mat_nr = ef->mat_nr; flag = ef->flag; + } else { + mat_nr = 0; + flag = 0; } for (S=0; S<numVerts; S++) { @@ -714,7 +714,7 @@ static DispListMesh *ss_to_displistmesh(CCGSubSurf *ss, CCGDerivedMesh *ccgdm, i mf->v3 = getFaceIndex(ss, f, S, x+1, y+1, edgeSize, gridSize); mf->v4 = getFaceIndex(ss, f, S, x+1, y+0, edgeSize, gridSize); mf->mat_nr = mat_nr; - mf->flag = flag&~ME_FACE_STEPINDEX; + mf->flag = flag; if(uvf) { VECCOPY(smoothuv[0], getFaceUV(uvss, uvf, S, x+0, y+0, edgeSize, gridSize)); @@ -723,12 +723,6 @@ static DispListMesh *ss_to_displistmesh(CCGSubSurf *ss, CCGDerivedMesh *ccgdm, i VECCOPY(smoothuv[3], getFaceUV(uvss, uvf, S, x+1, y+0, edgeSize, gridSize)); } - if (S==0 && x==0 && y==0) { - if (mapIndex!=lastIndex) - mf->flag |= ME_FACE_STEPINDEX; - lastIndex = mapIndex; - } - for (j=0; j<4; j++) { int fx = x + (j==2||j==3); int fy = y + (j==1||j==2); @@ -795,6 +789,478 @@ static DispListMesh *ss_to_displistmesh(CCGSubSurf *ss, CCGDerivedMesh *ccgdm, i return dlm; } +/* face weighting - taken from Brecht's element data patch */ +static void calc_ss_weights(int gridFaces, + FaceVertWeight **qweight, FaceVertWeight **tweight) +{ + FaceVertWeight *qw, *tw; + int x, y, j; + int numWeights = gridFaces * gridFaces; + + *tweight = MEM_mallocN(sizeof(**tweight) * numWeights, "ssTriWeight"); + *qweight = MEM_mallocN(sizeof(**qweight) * numWeights, "ssQuadWeight"); + + qw = *qweight; + tw = *tweight; + + for (y = 0; y < gridFaces; y++) { + for (x = 0; x < gridFaces; x++) { + for (j = 0; j < 4; j++) { + int fx = x + (j == 2 || j == 3); + int fy = y + (j == 1 || j == 2); + float x_v = (float) fx / gridFaces; + float y_v = (float) fy / gridFaces; + float tx_v = (1.0f - x_v), ty_v = (1.0f - y_v); + float center = (1.0f / 3.0f) * tx_v * ty_v; + + (*tw)[j][0] = center + 0.5f * tx_v * y_v; + (*tw)[j][2] = center + 0.5f * x_v * ty_v; + (*tw)[j][1] = 1.0f - (*tw)[j][0] - (*tw)[j][2]; + (*tw)[j][3] = 0.0f; + + tx_v *= 0.5f; + ty_v *= 0.5f; + + (*qw)[j][3] = tx_v * ty_v; + (*qw)[j][0] = (*qw)[j][3] + tx_v * y_v; + (*qw)[j][2] = (*qw)[j][3] + x_v * ty_v; + (*qw)[j][1] = 1.0f - (*qw)[j][0] - (*qw)[j][2] - (*qw)[j][3]; + + } + tw++; + qw++; + } + } +} + +DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh, + int drawInteriorEdges, int useSubsurfUv, + DerivedMesh *dm) +{ + DerivedMesh *result; + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int gridSize = ccgSubSurf_getGridSize(ss); + int gridFaces = gridSize - 1; + int edgeBase, faceBase; + int i, j, k, S, x, y, index; + int vertBase = 0; + CCGVertIterator *vi; + CCGEdgeIterator *ei; + CCGFaceIterator *fi; + CCGFace **faceMap2, **faceMap2Uv = NULL; + CCGEdge **edgeMap2; + CCGVert **vertMap2; + int totvert, totedge, totface; + MVert *mvert; + MEdge *med; + MFace *mf; + TFace *tface; + CCGSubSurf *uvss = NULL; + int *origIndex; + FaceVertWeight *qweight, *tweight; + + calc_ss_weights(gridFaces, &qweight, &tweight); + + /* vert map */ + totvert = ccgSubSurf_getNumVerts(ss); + vertMap2 = MEM_mallocN(totvert*sizeof(*vertMap2), "vertmap"); + vi = ccgSubSurf_getVertIterator(ss); + for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { + CCGVert *v = ccgVertIterator_getCurrent(vi); + + if(ssFromEditmesh) { + vertMap2[ccgDM_getVertMapIndex(NULL, ss, v)] = v; + } else { + vertMap2[(int) ccgSubSurf_getVertVertHandle(ss, v)] = v; + } + } + ccgVertIterator_free(vi); + + totedge = ccgSubSurf_getNumEdges(ss); + edgeMap2 = MEM_mallocN(totedge*sizeof(*edgeMap2), "edgemap"); + ei = ccgSubSurf_getEdgeIterator(ss); + for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + + if(ssFromEditmesh) { + edgeMap2[ccgDM_getEdgeMapIndex(NULL, ss, e)] = e; + } else { + edgeMap2[(int) ccgSubSurf_getEdgeEdgeHandle(ss, e)] = e; + } + } + + totface = ccgSubSurf_getNumFaces(ss); + faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap"); + fi = ccgSubSurf_getFaceIterator(ss); + for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + + if(ssFromEditmesh) { + faceMap2[ccgDM_getFaceMapIndex(NULL, ss, f)] = f; + } else { + faceMap2[(int) ccgSubSurf_getFaceFaceHandle(ss, f)] = f; + } + } + ccgFaceIterator_free(fi); + + if(dm) { + result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + ccgSubSurf_getNumFinalFaces(ss)); + tface = dm->getFaceDataArray(dm, LAYERTYPE_TFACE); + } else { + result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + ccgSubSurf_getNumFinalFaces(ss)); + tface = NULL; + } + + if(useSubsurfUv && tface) { + /* slightly dodgy hack to use current ss_sync_from_uv function */ + DispListMesh dlm; + + dlm.mface = dm->dupFaceArray(dm); + dlm.tface = tface; + dlm.mvert = dm->dupVertArray(dm); + dlm.totvert = dm->getNumVerts(dm); + dlm.totface = dm->getNumFaces(dm); + + /* not for editmesh currently */ + uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), + 0, 1, 0); + + if(ss_sync_from_uv(uvss, ss, NULL, &dlm)) { + faceMap2Uv = MEM_mallocN(totface * sizeof(*faceMap2Uv), + "facemapuv"); + + fi = ccgSubSurf_getFaceIterator(uvss); + for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + faceMap2Uv[(int) ccgSubSurf_getFaceFaceHandle(uvss, f)] = f; + } + ccgFaceIterator_free(fi); + } + + MEM_freeN(dlm.mface); + MEM_freeN(dlm.mvert); + } + + // load verts + faceBase = i = 0; + mvert = CDDM_get_verts(result); + origIndex = result->getVertData(result, 0, LAYERTYPE_ORIGINDEX); + + for(index = 0; index < totface; index++) { + CCGFace *f = faceMap2[index]; + int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight; + int vertIdx[4]; + + for(S = 0; S < numVerts; S++) { + CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S); + + if(ssFromEditmesh) + vertIdx[S] = ccgDM_getVertMapIndex(NULL, ss, v); + else + vertIdx[S] = (int)ccgSubSurf_getVertVertHandle(ss, v); + } + + DM_interp_vert_data(dm, result, vertIdx, weight[0][0], numVerts, i); + VecCopyf(mvert->co, ccgSubSurf_getFaceCenterData(ss, f)); + *origIndex = ORIGINDEX_NONE; + ++mvert; + ++origIndex; + i++; + + for(S = 0; S < numVerts; S++) { + int prevS = (S - 1 + numVerts) % numVerts; + int nextS = (S + 1) % numVerts; + int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3; + for(x = 1; x < gridFaces; x++) { + float w[4]; + w[prevS] = weight[x][0][0]; + 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)); + *origIndex = ORIGINDEX_NONE; + ++mvert; + ++origIndex; + i++; + } + } + + for(S = 0; S < numVerts; S++) { + int prevS = (S - 1 + numVerts) % numVerts; + int nextS = (S + 1) % numVerts; + int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3; + for(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; + ++mvert; + ++origIndex; + i++; + } + } + } + + *((int*)ccgSubSurf_getFaceUserData(ss, f)) = faceBase; + faceBase += 1 + numVerts * ((gridSize-2) + (gridSize-2) * (gridSize-2)); + } + + edgeBase = i; + for(index = 0; index < totedge; index++) { + CCGEdge *e = edgeMap2[index]; + int x; + int vertIdx[2]; + + if(ssFromEditmesh) { + CCGVert *v; + v = ccgSubSurf_getEdgeVert0(ss, e); + vertIdx[0] = ccgDM_getVertMapIndex(NULL, ss, v); + v = ccgSubSurf_getEdgeVert1(ss, e); + vertIdx[1] = ccgDM_getVertMapIndex(NULL, ss, v); + } else { + CCGVert *v; + v = ccgSubSurf_getEdgeVert0(ss, e); + vertIdx[0] = (int)ccgSubSurf_getVertVertHandle(ss, v); + v = ccgSubSurf_getEdgeVert1(ss, e); + vertIdx[1] = (int)ccgSubSurf_getVertVertHandle(ss, 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); + VecCopyf(mvert->co, ccgSubSurf_getEdgeData(ss, e, x)); + *origIndex = ORIGINDEX_NONE; + ++mvert; + ++origIndex; + i++; + } + + *((int*)ccgSubSurf_getEdgeUserData(ss, e)) = edgeBase; + edgeBase += edgeSize-2; + } + + vertBase = i; + for(index = 0; index < totvert; index++) { + CCGVert *v = vertMap2[index]; + int vertIdx; + + if(ssFromEditmesh) + vertIdx = ccgDM_getVertMapIndex(NULL, ss, v); + else + vertIdx = (int)ccgSubSurf_getVertVertHandle(ss, v); + + DM_copy_vert_data(dm, result, vertIdx, i, 1); + VecCopyf(mvert->co, ccgSubSurf_getVertData(ss, v)); + + *((int*)ccgSubSurf_getVertUserData(ss, v)) = i; + *origIndex = ccgDM_getVertMapIndex(NULL, ss, v); + ++mvert; + ++origIndex; + i++; + } + + // load edges + i = 0; + med = CDDM_get_edges(result); + origIndex = result->getEdgeData(result, 0, LAYERTYPE_ORIGINDEX); + + for(index = 0; index < totface; index++) { + CCGFace *f = faceMap2[index]; + int numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + for(k = 0; k < numVerts; k++) { + for(x = 0; x < gridFaces; x++) { + if(drawInteriorEdges) med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, k, x, 0, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, k, x+1, 0, edgeSize, gridSize); + *origIndex = ORIGINDEX_NONE; + ++med; + ++origIndex; + i++; + } + + for(x = 1; x < gridFaces; x++) { + for(y = 0; y < gridFaces; y++) { + if(drawInteriorEdges) + med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, k, x, y, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, k, x, y + 1, + edgeSize, gridSize); + *origIndex = ORIGINDEX_NONE; + ++med; + ++origIndex; + i++; + + if(drawInteriorEdges) + med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, k, y, x, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, k, y + 1, x, + edgeSize, gridSize); + *origIndex = ORIGINDEX_NONE; + ++med; + ++origIndex; + i++; + } + } + } + } + + for(index = 0; index < totedge; index++) { + CCGEdge *e = edgeMap2[index]; + unsigned int flags = 0; + + if(!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE; + + if(ssFromEditmesh) { + EditEdge *eed = ccgSubSurf_getEdgeEdgeHandle(ss, e); + + flags |= ME_EDGEDRAW | ME_EDGERENDER; + if(eed->seam) { + flags |= ME_SEAM; + } + if(eed->sharp) flags |= ME_SHARP; + } else { + int edgeIdx = (int)ccgSubSurf_getEdgeEdgeHandle(ss, e); + + if(edgeIdx != -1 && dm) { + MEdge origMed; + dm->getEdge(dm, edgeIdx, &origMed); + + flags |= origMed.flag; + } + } + + for(x = 0; x < edgeSize - 1; x++) { + med->v1 = getEdgeIndex(ss, e, x, edgeSize); + med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize); + med->flag = flags; + *origIndex = ccgDM_getEdgeMapIndex(NULL, ss, e); + ++med; + ++origIndex; + i++; + } + } + + // load faces + i = 0; + mf = CDDM_get_faces(result); + origIndex = result->getFaceData(result, 0, LAYERTYPE_ORIGINDEX); + + for(index = 0; index < totface; index++) { + CCGFace *f = faceMap2[index]; + CCGFace *uvf = faceMap2Uv ? faceMap2Uv[index] : NULL; + int numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + int mat_nr; + int flag; + int mapIndex = ccgDM_getFaceMapIndex(NULL, ss, f); + int faceIdx = (int)ccgSubSurf_getFaceFaceHandle(ss, f); + + if(!ssFromEditmesh) { + MFace origMFace; + dm->getFace(dm, faceIdx, &origMFace); + + mat_nr = origMFace.mat_nr; + flag = origMFace.flag; + } else { + EditFace *ef = ccgSubSurf_getFaceFaceHandle(ss, f); + mat_nr = ef->mat_nr; + flag = ef->flag; + } + + for(S = 0; S < numVerts; S++) { + FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight; + + for(y = 0; y < gridFaces; y++) { + for(x = 0; x < gridFaces; x++) { + mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0, + edgeSize, gridSize); + mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1, + edgeSize, gridSize); + mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1, + edgeSize, gridSize); + mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0, + edgeSize, gridSize); + mf->mat_nr = mat_nr; + mf->flag = flag; + + if(dm) { + int prevS = (S - 1 + numVerts) % numVerts; + int nextS = (S + 1) % numVerts; + int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3; + FaceVertWeight w; + + for(j = 0; j < 4; ++j) { + w[j][prevS] = (*weight)[j][0]; + w[j][S] = (*weight)[j][1]; + w[j][nextS] = (*weight)[j][2]; + w[j][otherS] = (*weight)[j][3]; + } + + DM_interp_face_data(dm, result, &faceIdx, NULL, + &w, 1, i); + weight++; + } + + if(uvf) { + TFace *tf = DM_get_face_data(result, i, + LAYERTYPE_TFACE); + float *newuv; + + newuv = getFaceUV(uvss, uvf, S, x + 0, y + 0, + edgeSize, gridSize); + tf->uv[0][0] = newuv[0]; tf->uv[0][1] = newuv[1]; + newuv = getFaceUV(uvss, uvf, S, x + 0, y + 1, + edgeSize, gridSize); + tf->uv[1][0] = newuv[0]; tf->uv[1][1] = newuv[1]; + newuv = getFaceUV(uvss, uvf, S, x + 1, y + 1, + edgeSize, gridSize); + tf->uv[2][0] = newuv[0]; tf->uv[2][1] = newuv[1]; + newuv = getFaceUV(uvss, uvf, S, x + 1, y + 0, + edgeSize, gridSize); + tf->uv[3][0] = newuv[0]; tf->uv[3][1] = newuv[1]; + } + + *origIndex = mapIndex; + ++mf; + ++origIndex; + i++; + } + } + } + } + + MEM_freeN(faceMap2); + MEM_freeN(edgeMap2); + MEM_freeN(vertMap2); + + MEM_freeN(tweight); + MEM_freeN(qweight); + + if(uvss) { + ccgSubSurf_free(uvss); + MEM_freeN(faceMap2Uv); + } + + CDDM_calc_normals(result); + + return result; +} + static void ss_sync_from_mesh(CCGSubSurf *ss, Mesh *me, DispListMesh *dlm, float (*vertexCos)[3], int useFlatSubdiv) { float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss); CCGVertHDL fVerts[4]; @@ -812,7 +1278,7 @@ static void ss_sync_from_mesh(CCGSubSurf *ss, Mesh *me, DispListMesh *dlm, float CCGVert *v; ccgSubSurf_syncVert(ss, (CCGVertHDL) i, vertexCos?vertexCos[i]:mvert[i].co, 0, &v); - if (!dlm || (mvert[i].flag&ME_VERT_STEPINDEX)) index++; + if (!dlm) index++; ((int*) ccgSubSurf_getVertUserData(ss, v))[1] = index; } @@ -824,7 +1290,7 @@ static void ss_sync_from_mesh(CCGSubSurf *ss, Mesh *me, DispListMesh *dlm, float ccgSubSurf_syncEdge(ss, (CCGEdgeHDL) i, (CCGVertHDL) med->v1, (CCGVertHDL) med->v2, crease, &e); - if (!dlm || (med->flag&ME_EDGE_STEPINDEX)) index++; + if (!dlm) index++; ((int*) ccgSubSurf_getEdgeUserData(ss, e))[1] = index; } } @@ -833,7 +1299,7 @@ static void ss_sync_from_mesh(CCGSubSurf *ss, Mesh *me, DispListMesh *dlm, float MFace *mf = &((MFace*) mface)[i]; CCGFace *f; - if (!dlm || (mf->flag&ME_FACE_STEPINDEX)) index++; + if (!dlm) index++; fVerts[0] = (CCGVertHDL) mf->v1; fVerts[1] = (CCGVertHDL) mf->v2; @@ -866,6 +1332,92 @@ static void ss_sync_from_mesh(CCGSubSurf *ss, Mesh *me, DispListMesh *dlm, float ccgSubSurf_processSync(ss); } +static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm, + float (*vertexCos)[3], int useFlatSubdiv) +{ + float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss); + CCGVertHDL fVerts[4]; + int totvert = dm->getNumVerts(dm); + int totedge = dm->getNumEdges(dm); + int totface = dm->getNumFaces(dm); + int i; + int *index; + MVert *mvert = dm->dupVertArray(dm); + MEdge *medge = dm->dupEdgeArray(dm); + MFace *mface = dm->dupFaceArray(dm); + MVert *mv; + MEdge *me; + MFace *mf; + + ccgSubSurf_initFullSync(ss); + + mv = mvert; + index = (int *)dm->getVertDataArray(dm, LAYERTYPE_ORIGINDEX); + for(i = 0; i < totvert; i++, mv++, index++) { + CCGVert *v; + + if(vertexCos) { + ccgSubSurf_syncVert(ss, (CCGVertHDL)i, vertexCos[i], 0, &v); + } else { + ccgSubSurf_syncVert(ss, (CCGVertHDL)i, mv->co, 0, &v); + } + + ((int*)ccgSubSurf_getVertUserData(ss, v))[1] = *index; + } + + me = medge; + index = (int *)dm->getEdgeDataArray(dm, LAYERTYPE_ORIGINDEX); + for(i = 0; i < totedge; i++, me++, index++) { + CCGEdge *e; + float crease; + + crease = useFlatSubdiv ? creaseFactor : + me->crease * creaseFactor / 255.0f; + + ccgSubSurf_syncEdge(ss, (CCGEdgeHDL)i, (CCGVertHDL)me->v1, + (CCGVertHDL)me->v2, crease, &e); + + ((int*)ccgSubSurf_getEdgeUserData(ss, e))[1] = *index; + } + + mf = mface; + index = (int *)dm->getFaceDataArray(dm, LAYERTYPE_ORIGINDEX); + for (i = 0; i < totface; i++, mf++, index++) { + CCGFace *f; + + fVerts[0] = (CCGVertHDL) mf->v1; + fVerts[1] = (CCGVertHDL) mf->v2; + fVerts[2] = (CCGVertHDL) mf->v3; + fVerts[3] = (CCGVertHDL) mf->v4; + + // 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, (CCGFaceHDL)i, fVerts[3] ? 4 : 3, + fVerts, &f) == eCCGError_InvalidValue) { + static int hasGivenError = 0; + + if(!hasGivenError) { + error("Unrecoverable error in SubSurf calculation," + " mesh is inconsistent."); + + hasGivenError = 1; + } + + return; + } + + ((int*)ccgSubSurf_getFaceUserData(ss, f))[1] = *index; + } + + ccgSubSurf_processSync(ss); + + MEM_freeN(mvert); + MEM_freeN(medge); + MEM_freeN(mface); +} + void ss_sync_from_editmesh(CCGSubSurf *ss, EditMesh *em, float (*vertCos)[3], int useFlatSubdiv) { float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss); @@ -974,11 +1526,445 @@ static int ccgDM_getNumVerts(DerivedMesh *dm) { return ccgSubSurf_getNumFinalVerts(ccgdm->ss); } +static int ccgDM_getNumEdges(DerivedMesh *dm) { + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + + return ccgSubSurf_getNumFinalEdges(ccgdm->ss); +} static int ccgDM_getNumFaces(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; return ccgSubSurf_getNumFinalFaces(ccgdm->ss); } + +static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int i; + + memset(mv, 0, sizeof(*mv)); + + if(vertNum < ccgdm->edgeMap[0].startVert) { + /* this vert comes from face data */ + int lastface = ccgSubSurf_getNumFaces(ss) - 1; + CCGFace *f; + int x, y, grid, numVerts; + int offset; + int gridSize = ccgSubSurf_getGridSize(ss); + int gridSideVerts; + int gridInternalVerts; + int gridSideEnd; + int gridInternalEnd; + + i = 0; + while(i < lastface && vertNum >= ccgdm->faceMap[i + 1].startVert) + ++i; + + f = ccgdm->faceMap[i].face; + numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + gridSideVerts = gridSize - 2; + gridInternalVerts = gridSideVerts * gridSideVerts; + + gridSideEnd = 1 + numVerts * gridSideVerts; + gridInternalEnd = gridSideEnd + numVerts * gridInternalVerts; + + offset = vertNum - ccgdm->faceMap[i].startVert; + if(offset < 1) { + VecCopyf(mv->co, ccgSubSurf_getFaceCenterData(ss, f)); + } else if(offset < gridSideEnd) { + offset -= 1; + grid = offset / gridSideVerts; + x = offset % gridSideVerts + 1; + VecCopyf(mv->co, ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x)); + } else if(offset < gridInternalEnd) { + offset -= gridSideEnd; + grid = offset / gridInternalVerts; + offset %= gridInternalVerts; + y = offset / gridSideVerts + 1; + x = offset % gridSideVerts + 1; + VecCopyf(mv->co, ccgSubSurf_getFaceGridData(ss, f, grid, x, y)); + } + } else if(vertNum < ccgdm->vertMap[0].startVert) { + /* this vert comes from edge data */ + CCGEdge *e; + int lastedge = ccgSubSurf_getNumEdges(ss) - 1; + int x; + + i = 0; + while(i < lastedge && vertNum >= ccgdm->edgeMap[i + 1].startVert) + ++i; + + e = ccgdm->edgeMap[i].edge; + + x = vertNum - ccgdm->edgeMap[i].startVert + 1; + VecCopyf(mv->co, ccgSubSurf_getEdgeData(ss, e, x)); + } else { + /* this vert comes from vert data */ + CCGVert *v; + i = vertNum - ccgdm->vertMap[0].startVert; + + v = ccgdm->vertMap[i].vert; + VecCopyf(mv->co, ccgSubSurf_getVertData(ss, v)); + } +} + +static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int i; + + memset(med, 0, sizeof(*med)); + + if(edgeNum < ccgdm->edgeMap[0].startEdge) { + /* this edge comes from face data */ + int lastface = ccgSubSurf_getNumFaces(ss) - 1; + CCGFace *f; + int x, y, grid, numVerts; + int offset; + int gridSize = ccgSubSurf_getGridSize(ss); + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int gridSideEdges; + int gridInternalEdges; + + i = 0; + while(i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge) + ++i; + + f = ccgdm->faceMap[i].face; + numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + gridSideEdges = gridSize - 1; + gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; + + offset = edgeNum - ccgdm->faceMap[i].startEdge; + grid = offset / (gridSideEdges + gridInternalEdges); + offset %= (gridSideEdges + gridInternalEdges); + + if(offset < gridSideEdges) { + x = offset; + med->v1 = getFaceIndex(ss, f, grid, x, 0, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, grid, x+1, 0, edgeSize, gridSize); + } else { + offset -= gridSideEdges; + x = (offset / 2) / gridSideEdges + 1; + y = (offset / 2) % gridSideEdges; + if(offset % 2 == 0) { + med->v1 = getFaceIndex(ss, f, grid, x, y, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, grid, x, y+1, edgeSize, gridSize); + } else { + med->v1 = getFaceIndex(ss, f, grid, y, x, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, grid, y+1, x, edgeSize, gridSize); + } + } + } else { + /* this vert comes from edge data */ + CCGEdge *e; + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int x; + unsigned int flags = 0; + + i = (edgeNum - ccgdm->edgeMap[0].startEdge) / (edgeSize - 1); + + e = ccgdm->edgeMap[i].edge; + + if(!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE; + + x = edgeNum - ccgdm->edgeMap[i].startEdge; + + med->v1 = getEdgeIndex(ss, e, x, edgeSize); + med->v2 = getEdgeIndex(ss, e, x+1, edgeSize); + + if(ccgdm->fromEditmesh) { + EditEdge *eed = ccgSubSurf_getEdgeEdgeHandle(ss, e); + + flags |= ME_EDGEDRAW | ME_EDGERENDER; + if(eed->seam) { + flags |= ME_SEAM; + } + if(eed->sharp) flags |= ME_SHARP; + } else if(ccgdm->dlm || ccgdm->me) { + int edgeIdx = (int) ccgSubSurf_getEdgeEdgeHandle(ss, e); + + if(edgeIdx!=-1) { + MEdge *medge = (ccgdm->dlm ? ccgdm->dlm->medge + : ccgdm->me->medge); + MEdge *origMed = &medge[edgeIdx]; + + if(ccgdm->dlm) { + flags |= origMed->flag; + } else { + flags |= (origMed->flag & (ME_SEAM | ME_SHARP)) + | ME_EDGEDRAW | ME_EDGERENDER; + } + } + } else { + flags |= ME_EDGEDRAW | ME_EDGERENDER; + } + + med->flag = flags; + } +} + +static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int gridSize = ccgSubSurf_getGridSize(ss); + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int gridSideEdges = gridSize - 1; + int gridFaces = gridSideEdges * gridSideEdges; + int i; + CCGFace *f; + int numVerts; + int offset; + int grid; + int x, y; + int lastface = ccgSubSurf_getNumFaces(ss) - 1; + int *faceFlags = dm->getFaceData(dm, faceNum, LAYERTYPE_FLAGS); + + memset(mf, 0, sizeof(*mf)); + + i = 0; + while(i < lastface && faceNum >= ccgdm->faceMap[i + 1].startFace) + ++i; + + f = ccgdm->faceMap[i].face; + numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + offset = faceNum - ccgdm->faceMap[i].startFace; + grid = offset / gridFaces; + offset %= gridFaces; + y = offset / gridSideEdges; + x = offset % gridSideEdges; + + mf->v1 = getFaceIndex(ss, f, grid, x+0, y+0, edgeSize, gridSize); + mf->v2 = getFaceIndex(ss, f, grid, x+0, y+1, edgeSize, gridSize); + mf->v3 = getFaceIndex(ss, f, grid, x+1, y+1, edgeSize, gridSize); + mf->v4 = getFaceIndex(ss, f, grid, x+1, y+0, edgeSize, gridSize); + + if(faceFlags) mf->flag = *faceFlags; + else mf->flag = ME_SMOOTH; +} + +static void ccgDM_getFinalVertArray(DerivedMesh *dm, MVert *mvert) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int index; + int totvert, totedge, totface; + int gridSize = ccgSubSurf_getGridSize(ss); + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int i = 0; + + totface = ccgSubSurf_getNumFaces(ss); + for(index = 0; index < totface; index++) { + CCGFace *f = ccgdm->faceMap[index].face; + int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + VecCopyf(mvert[i++].co, ccgSubSurf_getFaceCenterData(ss, f)); + + for(S = 0; S < numVerts; S++) { + for(x = 1; x < gridSize - 1; x++) { + VecCopyf(mvert[i++].co, + ccgSubSurf_getFaceGridEdgeData(ss, f, S, x)); + } + } + + for(S = 0; S < numVerts; S++) { + for(y = 1; y < gridSize - 1; y++) { + for(x = 1; x < gridSize - 1; x++) { + VecCopyf(mvert[i++].co, + ccgSubSurf_getFaceGridData(ss, f, S, x, y)); + } + } + } + } + + totedge = ccgSubSurf_getNumEdges(ss); + for(index = 0; index < totedge; index++) { + CCGEdge *e = ccgdm->edgeMap[index].edge; + int x; + + for(x = 1; x < edgeSize - 1; x++) { + VecCopyf(mvert[i++].co, ccgSubSurf_getEdgeData(ss, e, x)); + } + } + + totvert = ccgSubSurf_getNumVerts(ss); + for(index = 0; index < totvert; index++) { + CCGVert *v = ccgdm->vertMap[index].vert; + + VecCopyf(mvert[i].co, ccgSubSurf_getVertData(ss, v)); + + i++; + } +} + +static void ccgDM_getFinalEdgeArray(DerivedMesh *dm, MEdge *medge) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int index; + int totedge, totface; + int gridSize = ccgSubSurf_getGridSize(ss); + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int i = 0; + MEdge *origEdges = NULL; + + if(!ccgdm->fromEditmesh) { + if(ccgdm->dlm) origEdges = ccgdm->dlm->medge; + else if(ccgdm->me) origEdges = ccgdm->me->medge; + } + + totface = ccgSubSurf_getNumFaces(ss); + for(index = 0; index < totface; index++) { + CCGFace *f = ccgdm->faceMap[index].face; + int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + + for(S = 0; S < numVerts; S++) { + for(x = 0; x < gridSize - 1; x++) { + MEdge *med = &medge[i]; + + if(ccgdm->drawInteriorEdges) + med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize); + i++; + } + + for(x = 1; x < gridSize - 1; x++) { + for(y = 0; y < gridSize - 1; y++) { + MEdge *med; + + med = &medge[i]; + if(ccgdm->drawInteriorEdges) + med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, S, x, y, + edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, S, x, y + 1, + edgeSize, gridSize); + i++; + + med = &medge[i]; + if(ccgdm->drawInteriorEdges) + med->flag = ME_EDGEDRAW | ME_EDGERENDER; + med->v1 = getFaceIndex(ss, f, S, y, x, + edgeSize, gridSize); + med->v2 = getFaceIndex(ss, f, S, y + 1, x, + edgeSize, gridSize); + i++; + } + } + } + } + + totedge = ccgSubSurf_getNumEdges(ss); + for(index = 0; index < totedge; index++) { + CCGEdge *e = ccgdm->edgeMap[index].edge; + unsigned int flags = 0; + int x; + + if(!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE; + + if(ccgdm->fromEditmesh) { + EditEdge *eed = ccgSubSurf_getEdgeEdgeHandle(ss, e); + + flags |= ME_EDGEDRAW | ME_EDGERENDER; + if (eed->seam) { + flags |= ME_SEAM; + } + if(eed->sharp) flags |= ME_SHARP; + } else if(origEdges){ + int edgeIdx = (int)ccgSubSurf_getEdgeEdgeHandle(ss, e); + + if(edgeIdx != -1) { + MEdge *origMed = &origEdges[edgeIdx]; + + if(ccgdm->dlm) { + flags |= origMed->flag; + } else { + flags |= (origMed->flag & (ME_SEAM | ME_SHARP)) + | ME_EDGEDRAW | ME_EDGERENDER; + } + } + } else { + flags |= ME_EDGEDRAW | ME_EDGERENDER; + } + + for(x = 0; x < edgeSize - 1; x++) { + MEdge *med = &medge[i]; + med->v1 = getEdgeIndex(ss, e, x, edgeSize); + med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize); + med->flag = flags; + i++; + } + } +} + +static void ccgDM_getFinalFaceArray(DerivedMesh *dm, MFace *mface) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + CCGSubSurf *ss = ccgdm->ss; + int index; + int totface; + int gridSize = ccgSubSurf_getGridSize(ss); + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int i = 0; + MFace *origFaces = NULL; + int *faceFlags = dm->getFaceDataArray(dm, LAYERTYPE_FLAGS); + + if(!ccgdm->fromEditmesh) { + if(ccgdm->dlm) origFaces = ccgdm->dlm->mface; + else if(ccgdm->me) origFaces = ccgdm->me->mface; + } + + totface = ccgSubSurf_getNumFaces(ss); + for(index = 0; index < totface; index++) { + CCGFace *f = ccgdm->faceMap[index].face; + int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + int mat_nr = 0; + int flag = ME_SMOOTH; /* assume face is smooth by default */ + + if(!faceFlags) { + if(!ccgdm->fromEditmesh && origFaces) { + int origIdx = (int) ccgSubSurf_getFaceFaceHandle(ss, f); + MFace *origMFace = &origFaces[origIdx]; + + mat_nr = origMFace->mat_nr; + flag = origMFace->flag; + } else if(ccgdm->fromEditmesh) { + EditFace *ef = ccgSubSurf_getFaceFaceHandle(ss, f); + mat_nr = ef->mat_nr; + flag = ef->flag; + } + } + + for(S = 0; S < numVerts; S++) { + for(y = 0; y < gridSize - 1; y++) { + for(x = 0; x < gridSize - 1; x++) { + MFace *mf = &mface[i]; + mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0, + edgeSize, gridSize); + mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1, + edgeSize, gridSize); + mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1, + edgeSize, gridSize); + mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0, + edgeSize, gridSize); + mf->mat_nr = mat_nr; + if(faceFlags) mf->flag = faceFlags[i]; + else mf->flag = flag; + + i++; + } + } + } + } +} + static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; CCGSubSurf *ss = ccgdm->ss; @@ -1509,11 +2495,21 @@ 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); + int *faceFlags = dm->getFaceDataArray(dm, LAYERTYPE_FLAGS); for (i=0; !ccgFaceIterator_isStopped(fi); i++,ccgFaceIterator_next(fi)) { CCGFace *f = ccgFaceIterator_getCurrent(fi); int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f); - int drawSmooth = 1, index = ccgDM_getFaceMapIndex(ccgdm, ss, f); + int drawSmooth, index = ccgDM_getFaceMapIndex(ccgdm, ss, f); + int origIndex; + + if(ccgdm->fromEditmesh) { + origIndex = index; + } else { + origIndex = (int)ccgSubSurf_getFaceFaceHandle(ss, f); + } + if(faceFlags) drawSmooth = (*faceFlags & ME_SMOOTH); + else drawSmooth = 1; if (index!=-1 && (!setDrawOptions || setDrawOptions(userData, index, &drawSmooth))) { for (S=0; S<numVerts; S++) { @@ -1649,17 +2645,79 @@ static void ccgDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *us static void ccgDM_release(DerivedMesh *dm) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm; + DM_release(dm); + if (ccgdm->dlm) displistmesh_free(ccgdm->dlm); + MEM_freeN(ccgdm->vertMap); + MEM_freeN(ccgdm->edgeMap); + MEM_freeN(ccgdm->faceMap); MEM_freeN(ccgdm); } -static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int fromEditmesh, int drawInteriorEdges, int useSubsurfUv, Mesh *me, DispListMesh *dlm) { +static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int fromEditmesh, + int drawInteriorEdges, + int useSubsurfUv, Mesh *me, + DispListMesh *dlm, DerivedMesh *dm) +{ CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm"); + CCGVertIterator *vi; + CCGEdgeIterator *ei; + CCGFaceIterator *fi; + int index, totvert, totedge, totface; + int i; + int vertNum, edgeNum, faceNum; + int *vertOrigIndex, *edgeOrigIndex, *faceOrigIndex; + int *faceFlags; + int edgeSize; + int gridSize; + int gridFaces; + int gridSideVerts; + int gridInternalVerts; + int gridSideEdges; + int gridInternalEdges; + MVert *mvert = NULL; + MEdge *medge = NULL; + MFace *mface = NULL; + TFace *tface; + CCGSubSurf *uvss = NULL; + CCGFace **faceMap2Uv = NULL; + FaceVertWeight *qweight, *tweight; + + if(dm) { + DM_from_template(&ccgdm->dm, dm, ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + ccgSubSurf_getNumFinalFaces(ss)); + tface = dm->getFaceDataArray(dm, LAYERTYPE_TFACE); + DM_add_face_layer(&ccgdm->dm, LAYERTYPE_FLAGS, LAYERFLAG_NOCOPY, NULL); + } else { + DM_init(&ccgdm->dm, ccgSubSurf_getNumFinalVerts(ss), + ccgSubSurf_getNumFinalEdges(ss), + ccgSubSurf_getNumFinalFaces(ss)); + + if(dlm) tface = dlm->tface; + else if(me) tface = me->tface; + else tface = NULL; + } ccgdm->dm.getMinMax = ccgDM_getMinMax; ccgdm->dm.getNumVerts = ccgDM_getNumVerts; ccgdm->dm.getNumFaces = ccgDM_getNumFaces; + + ccgdm->dm.getNumEdges = ccgDM_getNumEdges; + ccgdm->dm.getVert = ccgDM_getFinalVert; + ccgdm->dm.getEdge = ccgDM_getFinalEdge; + ccgdm->dm.getFace = ccgDM_getFinalFace; + ccgdm->dm.getVertArray = ccgDM_getFinalVertArray; + ccgdm->dm.getEdgeArray = ccgDM_getFinalEdgeArray; + ccgdm->dm.getFaceArray = ccgDM_getFinalFaceArray; + ccgdm->dm.getVertData = DM_get_vert_data; + ccgdm->dm.getEdgeData = DM_get_edge_data; + ccgdm->dm.getFaceData = 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.getVertCos = ccgdm_getVertCos; ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert; ccgdm->dm.foreachMappedEdge = ccgDM_foreachMappedEdge; @@ -1687,6 +2745,323 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int fromEditmesh, int d ccgdm->me = me; ccgdm->dlm = dlm; + totvert = ccgSubSurf_getNumVerts(ss); + ccgdm->vertMap = MEM_mallocN(totvert * sizeof(*ccgdm->vertMap), "vertMap"); + vi = ccgSubSurf_getVertIterator(ss); + for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) { + CCGVert *v = ccgVertIterator_getCurrent(vi); + + if(fromEditmesh) { + ccgdm->vertMap[ccgDM_getVertMapIndex(ccgdm, ss, v)].vert = v; + } else { + ccgdm->vertMap[(int) ccgSubSurf_getVertVertHandle(ss, v)].vert = v; + } + } + ccgVertIterator_free(vi); + + totedge = ccgSubSurf_getNumEdges(ss); + ccgdm->edgeMap = MEM_mallocN(totedge * sizeof(*ccgdm->edgeMap), "edgeMap"); + ei = ccgSubSurf_getEdgeIterator(ss); + for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) { + CCGEdge *e = ccgEdgeIterator_getCurrent(ei); + + if(fromEditmesh) { + ccgdm->edgeMap[ccgDM_getEdgeMapIndex(ccgdm,ss,e)].edge = e; + } else { + ccgdm->edgeMap[(int) ccgSubSurf_getEdgeEdgeHandle(ss, e)].edge = e; + } + } + + totface = ccgSubSurf_getNumFaces(ss); + ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap"); + fi = ccgSubSurf_getFaceIterator(ss); + for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + + if(fromEditmesh) { + ccgdm->faceMap[ccgDM_getFaceMapIndex(ccgdm,ss,f)].face = f; + } else { + ccgdm->faceMap[(int) ccgSubSurf_getFaceFaceHandle(ss, f)].face = f; + } + } + ccgFaceIterator_free(fi); + + if(useSubsurfUv && tface) { + /* slightly dodgy hack to use current ss_sync_from_uv function */ + DispListMesh dlm; + + dlm.mface = dm->dupFaceArray(dm); + dlm.tface = tface; + dlm.mvert = dm->dupVertArray(dm); + dlm.totvert = dm->getNumVerts(dm); + dlm.totface = dm->getNumFaces(dm); + + /* not for editmesh currently */ + uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), + 0, 1, 0); + + if(ss_sync_from_uv(uvss, ss, NULL, &dlm)) { + faceMap2Uv = MEM_mallocN(totface * sizeof(*faceMap2Uv), + "facemapuv"); + + fi = ccgSubSurf_getFaceIterator(uvss); + for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { + CCGFace *f = ccgFaceIterator_getCurrent(fi); + faceMap2Uv[(int) ccgSubSurf_getFaceFaceHandle(uvss, f)] = f; + } + ccgFaceIterator_free(fi); + } + + MEM_freeN(dlm.mface); + MEM_freeN(dlm.mvert); + } + + edgeSize = ccgSubSurf_getEdgeSize(ss); + gridSize = ccgSubSurf_getGridSize(ss); + gridFaces = gridSize - 1; + gridSideVerts = gridSize - 2; + gridInternalVerts = gridSideVerts * gridSideVerts; + gridSideEdges = gridSize - 1; + gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; + + calc_ss_weights(gridFaces, &qweight, &tweight); + + vertNum = 0; + edgeNum = 0; + faceNum = 0; + + if(dm) { + mvert = dm->dupVertArray(dm); + medge = dm->dupEdgeArray(dm); + mface = dm->dupFaceArray(dm); + } else if(dlm) { + mvert = dlm->mvert; + medge = dlm->medge; + mface = dlm->mface; + } else if(me) { + mvert = me->mvert; + medge = me->medge; + mface = me->mface; + } + + vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, LAYERTYPE_ORIGINDEX); + edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, LAYERTYPE_ORIGINDEX); + faceOrigIndex = DM_get_face_data_layer(&ccgdm->dm, LAYERTYPE_ORIGINDEX); + + faceFlags = DM_get_face_data_layer(&ccgdm->dm, LAYERTYPE_FLAGS); + + for(index = 0; index < totface; ++index) { + CCGFace *f = ccgdm->faceMap[index].face; + CCGFace *uvf = faceMap2Uv ? faceMap2Uv[index] : NULL; + int numVerts = ccgSubSurf_getFaceNumVerts(ss, f); + int numFinalEdges = numVerts * (gridSideEdges + gridInternalEdges); + int mapIndex = ccgDM_getFaceMapIndex(ccgdm, ss, f); + int origIndex = (int)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; + ccgdm->faceMap[index].startFace = faceNum; + + /* set the face base vert */ + *((int*)ccgSubSurf_getFaceUserData(ss, f)) = vertNum; + + for(S = 0; S < numVerts; S++) { + CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S); + + if(fromEditmesh) + vertIdx[S] = ccgDM_getVertMapIndex(NULL, ss, v); + else + vertIdx[S] = (int)ccgSubSurf_getVertVertHandle(ss, v); + } + + DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, weight[0][0], + numVerts, vertNum); + *vertOrigIndex = ORIGINDEX_NONE; + ++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]; + 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); + *vertOrigIndex = ORIGINDEX_NONE; + ++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(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, &ccgdm->dm, vertIdx, w, + numVerts, vertNum); + *vertOrigIndex = ORIGINDEX_NONE; + ++vertOrigIndex; + ++vertNum; + } + } + } + + for(i = 0; i < numFinalEdges; ++i) + *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i, + LAYERTYPE_ORIGINDEX) = ORIGINDEX_NONE; + + 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; + + weight = (numVerts == 4) ? qweight : tweight; + + for(y = 0; y < gridFaces; y++) { + for(x = 0; x < gridFaces; x++) { + FaceVertWeight w; + int j; + + for(j = 0; j < 4; ++j) { + w[j][prevS] = (*weight)[j][0]; + w[j][S] = (*weight)[j][1]; + w[j][nextS] = (*weight)[j][2]; + w[j][otherS] = (*weight)[j][3]; + } + + DM_interp_face_data(dm, &ccgdm->dm, &origIndex, NULL, + &w, 1, faceNum); + weight++; + + if(uvf) { + TFace *tf = DM_get_face_data(&ccgdm->dm, faceNum, + LAYERTYPE_TFACE); + float *newuv; + + newuv = getFaceUV(uvss, uvf, S, x + 0, y + 0, + edgeSize, gridSize); + tf->uv[0][0] = newuv[0]; tf->uv[0][1] = newuv[1]; + newuv = getFaceUV(uvss, uvf, S, x + 0, y + 1, + edgeSize, gridSize); + tf->uv[1][0] = newuv[0]; tf->uv[1][1] = newuv[1]; + newuv = getFaceUV(uvss, uvf, S, x + 1, y + 1, + edgeSize, gridSize); + tf->uv[2][0] = newuv[0]; tf->uv[2][1] = newuv[1]; + newuv = getFaceUV(uvss, uvf, S, x + 1, y + 0, + edgeSize, gridSize); + tf->uv[3][0] = newuv[0]; tf->uv[3][1] = newuv[1]; + } + + *faceOrigIndex = mapIndex; + if(mface) + *faceFlags = mface[origIndex].flag; + else + *faceFlags = ME_SMOOTH; + + ++faceOrigIndex; + ++faceFlags; + ++faceNum; + } + } + } + + edgeNum += numFinalEdges; + } + + if(uvss) { + ccgSubSurf_free(uvss); + MEM_freeN(faceMap2Uv); + } + + for(index = 0; index < totedge; ++index) { + CCGEdge *e = ccgdm->edgeMap[index].edge; + int numFinalEdges = edgeSize - 1; + int mapIndex = ccgDM_getEdgeMapIndex(ccgdm, ss, e); + int x; + int vertIdx[2]; + + if(fromEditmesh) { + CCGVert *v; + v = ccgSubSurf_getEdgeVert0(ss, e); + vertIdx[0] = ccgDM_getVertMapIndex(NULL, ss, v); + v = ccgSubSurf_getEdgeVert1(ss, e); + vertIdx[1] = ccgDM_getVertMapIndex(NULL, ss, v); + } else { + CCGVert *v; + v = ccgSubSurf_getEdgeVert0(ss, e); + vertIdx[0] = (int)ccgSubSurf_getVertVertHandle(ss, v); + v = ccgSubSurf_getEdgeVert1(ss, e); + vertIdx[1] = (int)ccgSubSurf_getVertVertHandle(ss, v); + } + + ccgdm->edgeMap[index].startVert = vertNum; + ccgdm->edgeMap[index].startEdge = edgeNum; + + /* set the edge base vert */ + *((int*)ccgSubSurf_getEdgeUserData(ss, e)) = vertNum; + + 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, &ccgdm->dm, vertIdx, w, 2, vertNum); + *vertOrigIndex = ORIGINDEX_NONE; + ++vertOrigIndex; + ++vertNum; + } + + for(i = 0; i < numFinalEdges; ++i) + *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i, + LAYERTYPE_ORIGINDEX) = mapIndex; + + edgeNum += numFinalEdges; + } + + for(index = 0; index < totvert; ++index) { + CCGVert *v = ccgdm->vertMap[index].vert; + int mapIndex = ccgDM_getVertMapIndex(ccgdm, ccgdm->ss, v); + int vertIdx; + + if(fromEditmesh) + vertIdx = ccgDM_getVertMapIndex(NULL, ss, v); + else + vertIdx = (int)ccgSubSurf_getVertVertHandle(ss, v); + + ccgdm->vertMap[index].startVert = vertNum; + + /* set the vert base vert */ + *((int*) ccgSubSurf_getVertUserData(ss, v)) = vertNum; + + DM_copy_vert_data(dm, &ccgdm->dm, vertIdx, vertNum, 1); + *vertOrigIndex = mapIndex; + ++vertOrigIndex; + ++vertNum; + } + + if(dm) { + MEM_freeN(mvert); + MEM_freeN(medge); + MEM_freeN(mface); + } + + MEM_freeN(qweight); + MEM_freeN(tweight); + return ccgdm; } @@ -1700,7 +3075,7 @@ DerivedMesh *subsurf_make_derived_from_editmesh(EditMesh *em, SubsurfModifierDat smd->emCache = _getSubSurf(smd->emCache, smd->levels, useAging, 0, useSimple); ss_sync_from_editmesh(smd->emCache, em, vertCos, useSimple); - return (DerivedMesh*) getCCGDerivedMesh(smd->emCache, 1, drawInteriorEdges, 0, NULL, NULL); + return (DerivedMesh*) getCCGDerivedMesh(smd->emCache, 1, drawInteriorEdges, 0, NULL, NULL, NULL); } DerivedMesh *subsurf_make_derived_from_dlm_em(DispListMesh *dlm, SubsurfModifierData *smd, float (*vertCos)[3]) { @@ -1713,7 +3088,7 @@ DerivedMesh *subsurf_make_derived_from_dlm_em(DispListMesh *dlm, SubsurfModifier ss_sync_from_mesh(smd->emCache, NULL, dlm, vertCos, useSimple); - return (DerivedMesh*) getCCGDerivedMesh(smd->emCache, 0, drawInteriorEdges, useSubsurfUv, NULL, dlm); + return (DerivedMesh*) getCCGDerivedMesh(smd->emCache, 0, drawInteriorEdges, useSubsurfUv, NULL, dlm, NULL); } DerivedMesh *subsurf_make_derived_from_mesh(Mesh *me, DispListMesh *dlm, SubsurfModifierData *smd, int useRenderParams, float (*vertCos)[3], int isFinalCalc) { @@ -1757,7 +3132,7 @@ DerivedMesh *subsurf_make_derived_from_mesh(Mesh *me, DispListMesh *dlm, Subsurf ss_sync_from_mesh(ss, me, dlm, vertCos, useSimple); - return (DerivedMesh*) getCCGDerivedMesh(ss, 0, drawInteriorEdges, useSubsurfUv, me, dlm); + return (DerivedMesh*) getCCGDerivedMesh(ss, 0, drawInteriorEdges, useSubsurfUv, me, dlm, NULL); } else { if (smd->mCache && isFinalCalc) { ccgSubSurf_free(smd->mCache); @@ -1777,6 +3152,83 @@ DerivedMesh *subsurf_make_derived_from_mesh(Mesh *me, DispListMesh *dlm, Subsurf } } +struct DerivedMesh *subsurf_make_derived_from_derived( + struct DerivedMesh *dm, + struct SubsurfModifierData *smd, + int useRenderParams, float (*vertCos)[3], + int isFinalCalc, int editMode) +{ + int useSimple = smd->subdivType == ME_SIMPLE_SUBSURF; + int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr; + int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv; + int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges); + DerivedMesh *result; + + if(editMode) { + smd->emCache = _getSubSurf(smd->emCache, smd->levels, useAging, 0, + useSimple); + ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple); + + return (DerivedMesh *)getCCGDerivedMesh(smd->emCache, 0, + drawInteriorEdges, + useSubsurfUv, NULL, NULL, dm); + } else if(useRenderParams) { + /* Do not use cache in render mode. */ + CCGSubSurf *ss = _getSubSurf(NULL, smd->renderLevels, 0, 1, useSimple); + + ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); + + result = ss_to_cdderivedmesh(ss, 0, drawInteriorEdges, + useSubsurfUv, dm); + + ccgSubSurf_free(ss); + + return result; + } else { + int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental); + int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr; + CCGSubSurf *ss; + + /* It is quite possible there is a much better place to do this. It + * depends a bit on how rigourously we expect this function to never + * be called in editmode. In semi-theory we could share a single + * cache, but the handles used inside and outside editmode are not + * the same so we would need some way of converting them. Its probably + * not worth the effort. But then why am I even writing this long + * comment that no one will read? Hmmm. - zr + */ + if(smd->emCache) { + ccgSubSurf_free(smd->emCache); + smd->emCache = NULL; + } + + if(useIncremental && isFinalCalc) { + smd->mCache = ss = _getSubSurf(smd->mCache, smd->levels, + useAging, 0, useSimple); + + ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); + + return ss_to_cdderivedmesh(ss, 0, drawInteriorEdges, + useSubsurfUv, dm); + } else { + if (smd->mCache && isFinalCalc) { + ccgSubSurf_free(smd->mCache); + smd->mCache = NULL; + } + + ss = _getSubSurf(NULL, smd->levels, 0, 1, useSimple); + ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); + + result = ss_to_cdderivedmesh(ss, 0, drawInteriorEdges, + useSubsurfUv, dm); + + ccgSubSurf_free(ss); + + return result; + } + } +} + void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]) { /* Finds the subsurf limit positions for the verts in a mesh diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h index 2c8df6efd43..7b3515c5135 100644 --- a/source/blender/blenlib/BLI_editVert.h +++ b/source/blender/blenlib/BLI_editVert.h @@ -38,6 +38,8 @@ #ifndef BLI_EDITVERT_H #define BLI_EDITVERT_H +#include "DNA_mesh_types.h" + struct DerivedMesh; /* note; changing this also might affect the undo copy in editmesh.c */ @@ -97,7 +99,7 @@ typedef struct EditEdge float fp; } tmp; short f1, f2; /* short, f1 is (ab)used in subdiv */ - unsigned char f, h, dir, seam; + unsigned char f, h, dir, seam, sharp; float crease; short fast; /* only 0 or 1, for editmesh_fastmalloc */ short fgoni; /* index for fgon, for search */ diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h index 2e75420a1ff..9982047ec9e 100644 --- a/source/blender/blenlib/BLI_linklist.h +++ b/source/blender/blenlib/BLI_linklist.h @@ -39,7 +39,7 @@ struct MemArena; typedef void (*LinkNodeFreeFP)(void *link); -typedef void (*LinkNodeApplyFP)(void *link); +typedef void (*LinkNodeApplyFP)(void *link, void *userdata); struct LinkNode; typedef struct LinkNode { @@ -56,7 +56,7 @@ void BLI_linklist_append (struct LinkNode **listp, void *ptr); void BLI_linklist_prepend_arena (struct LinkNode **listp, void *ptr, struct MemArena *ma); void BLI_linklist_free (struct LinkNode *list, LinkNodeFreeFP freefunc); -void BLI_linklist_apply (struct LinkNode *list, LinkNodeApplyFP applyfunc); +void BLI_linklist_apply (struct LinkNode *list, LinkNodeApplyFP applyfunc, void *userdata); #endif diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c index 253d127db38..6bb828a44bf 100644 --- a/source/blender/blenlib/intern/BLI_linklist.c +++ b/source/blender/blenlib/intern/BLI_linklist.c @@ -113,7 +113,7 @@ void BLI_linklist_free(LinkNode *list, LinkNodeFreeFP freefunc) { } } -void BLI_linklist_apply(LinkNode *list, LinkNodeApplyFP applyfunc) { +void BLI_linklist_apply(LinkNode *list, LinkNodeApplyFP applyfunc, void *userdata) { for (; list; list= list->next) - applyfunc(list->link); + applyfunc(list->link, userdata); } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 87125c2130f..6176d01e967 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2290,15 +2290,16 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh) /* ************ READ OBJECT ***************** */ -static void lib_link_modifiers__linkModifiers(void *userData, Object *ob, Object **obpoin) +static void lib_link_modifiers__linkModifiers(void *userData, Object *ob, + ID **idpoin) { FileData *fd = userData; - *obpoin = newlibadr(fd, ob->id.lib, *obpoin); + *idpoin = newlibadr(fd, ob->id.lib, *idpoin); } static void lib_link_modifiers(FileData *fd, Object *ob) { - modifiers_foreachObjectLink(ob, lib_link_modifiers__linkModifiers, fd); + modifiers_foreachIDLink(ob, lib_link_modifiers__linkModifiers, fd); } static void lib_link_object(FileData *fd, Main *main) diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 691696f1c80..34c3cc904f1 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -80,7 +80,6 @@ typedef struct MSelect { #define ME_SPHERETEMP 4 #define ME_HIDE 16 #define ME_VERT_MERGED (1<<6) -#define ME_VERT_STEPINDEX (1<<7) /* medge->flag (1=SELECT)*/ #define ME_EDGEDRAW (1<<1) @@ -90,7 +89,7 @@ typedef struct MSelect { #define ME_EDGERENDER (1<<5) #define ME_LOOSEEDGE (1<<7) #define ME_SEAM_LAST (1<<8) -#define ME_EDGE_STEPINDEX (1<<15) +#define ME_SHARP (1<<9) /* puno = vertexnormal (mface) */ #define ME_FLIPV1 1 @@ -112,7 +111,6 @@ typedef struct MSelect { #define ME_SMOOTH 1 #define ME_FACE_SEL 2 /* flag ME_HIDE==16 is used here too */ -#define ME_FACE_STEPINDEX (1<<7) #endif /* mselect->type */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 24400996831..522d25c9d90 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -5,6 +5,8 @@ #ifndef DNA_MODIFIER_TYPES_H #define DNA_MODIFIER_TYPES_H +#define MODSTACK_DEBUG 1 + /* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE! */ typedef enum ModifierType { @@ -21,14 +23,13 @@ typedef enum ModifierType { eModifierType_Softbody, eModifierType_Boolean, eModifierType_Array, + eModifierType_EdgeSplit, + eModifierType_Displace, + eModifierType_UVProject, NUM_MODIFIER_TYPES } ModifierType; - /* These numerical values are explicitly chosen so that - * (mode&1) is true for realtime calc and (mode&2) is true - * for render calc. - */ typedef enum ModifierMode { eModifierMode_Realtime = (1<<0), eModifierMode_Render = (1<<1), @@ -147,6 +148,60 @@ typedef struct MirrorModifierData { /* MirrorModifierData->flag */ #define MOD_MIR_CLIPPING 1 +typedef struct EdgeSplitModifierData { + ModifierData modifier; + + float split_angle; /* angle above which edges should be split */ + int flags; +} EdgeSplitModifierData; + +/* EdgeSplitModifierData->flags */ +#define MOD_EDGESPLIT_FROMANGLE 1<<1 +#define MOD_EDGESPLIT_FROMFLAG 1<<2 + +typedef struct DisplaceModifierData { + ModifierData modifier; + + struct Tex *texture; + float strength; + int direction; + char defgrp_name[32]; + float midlevel; + int texmapping; + struct Object *map_object; +} DisplaceModifierData; + +/* DisplaceModifierData->direction */ +enum { + MOD_DISP_DIR_X, + MOD_DISP_DIR_Y, + MOD_DISP_DIR_Z, + MOD_DISP_DIR_NOR, +}; + +/* DisplaceModifierData->texmapping */ +enum { + MOD_DISP_MAP_LOCAL, + MOD_DISP_MAP_GLOBAL, + MOD_DISP_MAP_OBJECT, + MOD_DISP_MAP_UV, +}; + +typedef struct UVProjectModifierData { + ModifierData modifier; + + /* the objects which do the projecting */ + struct Object *projectors[10]; + struct Image *image; /* the image to project */ + int flags; + int num_projectors; +} UVProjectModifierData; + +#define MOD_UVPROJECT_MAXPROJECTORS 10 + +/* UVProjectModifierData->flags */ +#define MOD_UVPROJECT_ADDUVS 1<<0 + typedef struct DecimateModifierData { ModifierData modifier; diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c index 5ebb74f088e..10e03a690f9 100644 --- a/source/blender/python/api2_2x/Mesh.c +++ b/source/blender/python/api2_2x/Mesh.c @@ -2221,8 +2221,7 @@ static int MEdge_setFlag( BPy_MEdge * self, PyObject * value ) | ME_HIDE | ME_EDGERENDER | ME_LOOSEEDGE - | ME_SEAM_LAST - | ME_EDGE_STEPINDEX; + | ME_SEAM_LAST; MEdge *edge = MEdge_get_pointer( self ); if( !edge ) diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 8b7740ccf8c..08281dbd23d 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1156,6 +1156,7 @@ static void do_2d_mapping(MTex *mtex, float *t, VlakRen *vlr, float *dxt, float static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres) { + float tmpvec[3]; int retval=0; /* return value, int:0, col:1, nor:2, everything:3 */ texres->talpha= 0; /* is set when image texture returns alpha (considered premul) */ @@ -1200,35 +1201,44 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, case TEX_MUSGRAVE: /* newnoise: musgrave types */ - /* ton: added this, for Blender convention reason. scaling texvec here is so-so ... */ - VecMulf(texvec, 1.0/tex->noisesize); + /* ton: added this, for Blender convention reason. + * artificer: added the use of tmpvec to avoid scaling texvec + */ + VECCOPY(tmpvec, texvec); + VecMulf(tmpvec, 1.0/tex->noisesize); switch(tex->stype) { case TEX_MFRACTAL: case TEX_FBM: - retval= mg_mFractalOrfBmTex(tex, texvec, texres); + retval= mg_mFractalOrfBmTex(tex, tmpvec, texres); break; case TEX_RIDGEDMF: case TEX_HYBRIDMF: - retval= mg_ridgedOrHybridMFTex(tex, texvec, texres); + retval= mg_ridgedOrHybridMFTex(tex, tmpvec, texres); break; case TEX_HTERRAIN: - retval= mg_HTerrainTex(tex, texvec, texres); + retval= mg_HTerrainTex(tex, tmpvec, texres); break; } break; /* newnoise: voronoi type */ case TEX_VORONOI: - /* ton: added this, for Blender convention reason. scaling texvec here is so-so ... */ - VecMulf(texvec, 1.0/tex->noisesize); + /* ton: added this, for Blender convention reason. + * artificer: added the use of tmpvec to avoid scaling texvec + */ + VECCOPY(tmpvec, texvec); + VecMulf(tmpvec, 1.0/tex->noisesize); - retval= voronoiTex(tex, texvec, texres); + retval= voronoiTex(tex, tmpvec, texres); break; case TEX_DISTNOISE: - /* ton: added this, for Blender convention reason. scaling texvec here is so-so ... */ - VecMulf(texvec, 1.0/tex->noisesize); + /* ton: added this, for Blender convention reason. + * artificer: added the use of tmpvec to avoid scaling texvec + */ + VECCOPY(tmpvec, texvec); + VecMulf(tmpvec, 1.0/tex->noisesize); - retval= mg_distNoiseTex(tex, texvec, texres); + retval= mg_distNoiseTex(tex, tmpvec, texres); break; } diff --git a/source/blender/src/booleanops.c b/source/blender/src/booleanops.c index b38600d182b..8a2d6d4d7f9 100644 --- a/source/blender/src/booleanops.c +++ b/source/blender/src/booleanops.c @@ -46,8 +46,10 @@ #include "CSG_BooleanOps.h" #include "BKE_booleanops.h" +#include "BKE_cdderivedmesh.h" #include "BKE_depsgraph.h" #include "BKE_displist.h" +#include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_material.h" @@ -74,6 +76,12 @@ static void ConvertCSGDescriptorsToDLM( CSG_VertexIteratorDescriptor *vertex_it, float parinv[][4]); +static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh( + Object *ob, CSG_MeshPropertyDescriptor *props, + CSG_FaceIteratorDescriptor *face_it, + CSG_VertexIteratorDescriptor *vertex_it, + float parinv[][4]); + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -571,6 +579,196 @@ DispListMesh *NewBooleanMeshDLM(Object *ob, Object *ob_select, int int_op_type) return dlm; } +DerivedMesh *NewBooleanDerivedMesh(struct Object *ob, struct Object *ob_select, + int int_op_type) +{ + Mesh *me2 = get_mesh(ob_select); + Mesh *me = get_mesh(ob); + int free_tface1, free_tface2; + DerivedMesh *result; + + float inv_mat[4][4]; + int success = 0; + // build and fill new descriptors for these meshes + CSG_VertexIteratorDescriptor vd_1; + CSG_VertexIteratorDescriptor vd_2; + CSG_FaceIteratorDescriptor fd_1; + CSG_FaceIteratorDescriptor fd_2; + + CSG_MeshPropertyDescriptor mpd1, mpd2; + + // work out the operation they chose and pick the appropriate + // enum from the csg module. + + CSG_OperationType op_type; + + if(me == NULL || me2 == NULL) return 0; + + if(!me->totface || !me2->totface) return 0; + + success = 0; + + switch(int_op_type) { + case 1 : op_type = e_csg_intersection; break; + case 2 : op_type = e_csg_union; break; + case 3 : op_type = e_csg_difference; break; + case 4 : op_type = e_csg_classify; break; + default : op_type = e_csg_intersection; + } + + // Here is the section where we describe the properties of + // both meshes to the bsp module. + + if(me->mcol != NULL) { + // Then this mesh has vertex colors only + // well this is awkward because there is no equivalent + // test_index_mface just for vertex colors! + // as a temporary hack we can convert these vertex colors + // into tfaces do the operation and turn them back again. + + // create some memory for the tfaces. + me->tface = (TFace *)MEM_callocN(sizeof(TFace) * me->totface, + "BooleanOps_TempTFace"); + mcol_to_tface(me, 1); + free_tface1 = 1; + } else { + free_tface1 = 0; + } + + mpd1.user_face_vertex_data_size = 0; + mpd1.user_data_size = sizeof(FaceData); + + if(me->tface) { + mpd1.user_face_vertex_data_size = sizeof(FaceVertexData); + } + + // same for mesh2 + + if(me2->mcol != NULL) { + // create some memory for the tfaces. + me2->tface = (TFace *)MEM_callocN(sizeof(TFace) * me2->totface, + "BooleanOps_TempTFace"); + mcol_to_tface(me2, 1); + free_tface2 = 1; + } else { + free_tface2 = 0; + } + + mpd2.user_face_vertex_data_size = 0; + mpd2.user_data_size = sizeof(FaceData); + + if(me2->tface) { + mpd2.user_face_vertex_data_size = sizeof(FaceVertexData); + } + + // we map the final object back into object 1's (ob) + // local coordinate space. For this we need to compute + // the inverse transform from global to local. + + Mat4Invert(inv_mat, ob_select->obmat); + + // make a boolean operation; + { + CSG_BooleanOperation *bool_op = CSG_NewBooleanFunction(); + CSG_MeshPropertyDescriptor output_mpd = CSG_DescibeOperands(bool_op, + mpd1, mpd2); + // analyse the result and choose mesh descriptors accordingly + int output_type; + if(output_mpd. user_face_vertex_data_size) { + output_type = 1; + } else { + output_type = 0; + } + + BuildMeshDescriptors(ob, &fd_1, &vd_1); + BuildMeshDescriptors(ob_select, &fd_2, &vd_2); + + // perform the operation + + if(output_type == 0) { + success = CSG_PerformBooleanOperation(bool_op, op_type, + fd_1, vd_1, fd_2, vd_2, + InterpNoUserData); + } else { + success = CSG_PerformBooleanOperation(bool_op, op_type, + fd_1, vd_1, fd_2, vd_2, + InterpFaceVertexData); + } + + switch(success) { + case 1: + { + // descriptions of the output; + CSG_VertexIteratorDescriptor vd_o; + CSG_FaceIteratorDescriptor fd_o; + + CSG_OutputFaceDescriptor(bool_op, &fd_o); + CSG_OutputVertexDescriptor(bool_op, &vd_o); + + // iterate through results of operation and insert + // into new object + + result = ConvertCSGDescriptorsToDerivedMesh( + NULL, &output_mpd, + &fd_o, &vd_o, inv_mat); + + // free up the memory + + CSG_FreeVertexDescriptor(&vd_o); + CSG_FreeFaceDescriptor(&fd_o); + } + break; + case -1: + error("Selected meshes must have faces to perform " + "boolean operations"); + break; + case -2: + error("Both meshes must be closed"); + break; + default: + error("unknown internal error"); + break; + } + + CSG_FreeBooleanOperation(bool_op); + } + + // We may need to map back the tfaces to mcols here. + if(free_tface1) { + tface_to_mcol(me); + MEM_freeN(me->tface); + me->tface = NULL; + } + if(free_tface2) { + tface_to_mcol(me2); + MEM_freeN(me2->tface); + me2->tface = NULL; + } + + if(free_tface1 && free_tface2) { + // then we need to map the output tfaces into mcols + if(result && DM_get_vert_data(result, 0, LAYERTYPE_TFACE)) { + int i; + int maxFaces = result->getNumFaces(result); + + if(!DM_get_vert_data(result, 0, LAYERTYPE_MCOL)) + DM_add_vert_layer(result, LAYERTYPE_MCOL, 0, NULL); + + for(i = 0; i < maxFaces; ++i) { + MCol *mcol = DM_get_vert_data(result, i, LAYERTYPE_MCOL); + TFace *tface = DM_get_vert_data(result, i, LAYERTYPE_TFACE); + + memcpy(mcol, tface->col, sizeof(*mcol) * 4); + } + } + } + + FreeMeshDescriptors(&fd_1, &vd_1); + FreeMeshDescriptors(&fd_2, &vd_2); + + return result; +} + int NewBooleanMesh( struct Base * base, @@ -999,6 +1197,154 @@ ConvertCSGDescriptorsToDLM( } MEM_freeN(face.user_face_data); } + +static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh( + Object *ob, CSG_MeshPropertyDescriptor *props, + CSG_FaceIteratorDescriptor *face_it, + CSG_VertexIteratorDescriptor *vertex_it, + float parinv[][4]) +{ + FaceVertexData *user_face_vertex_data; + GHash *material_hash; + CSG_IVertex vert; + CSG_IFace face; + DerivedMesh *result; + int i; +#if 0 + MFace *mfaces; + TFace *tfaces; +#endif + int fi_insert_pos, nmaterials; + + // create some memory for the Iface according to output mesh props. + + // initialize the face structure for readback + + face.user_face_data = MEM_callocN(sizeof(FaceData),"BooleanOp_IFaceData"); + + if(props->user_face_vertex_data_size) { + user_face_vertex_data = MEM_callocN(sizeof(FaceVertexData) * 4, + "BooleanOp_IFaceData"); + face.user_face_vertex_data[0] = &user_face_vertex_data[0]; + face.user_face_vertex_data[1] = &user_face_vertex_data[1]; + face.user_face_vertex_data[2] = &user_face_vertex_data[2]; + face.user_face_vertex_data[3] = &user_face_vertex_data[3]; + } else { + user_face_vertex_data = NULL; + } + + // create memory for the vertex array. + + result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements); + + if(user_face_vertex_data) + DM_add_face_layer(result, LAYERTYPE_TFACE, 0, NULL); + + // step through the iterators. + + i = 0; + while(!vertex_it->Done(vertex_it->it)) { + MVert *insert_pos = CDDM_get_vert(result, i); + vertex_it->Fill(vertex_it->it, &vert); + + // map output vertex into insert_pos + // and transform at by parinv at the same time. + + VecMat4MulVecfl(insert_pos->co, parinv, vert.position); + + vertex_it->Step(vertex_it->it); + i++; + } + + // a hash table to remap materials to indices with + material_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + nmaterials = 0; + + fi_insert_pos = 0; + while(!face_it->Done(face_it->it)) { + MFace *mface = CDDM_get_face(result, fi_insert_pos); + FaceData *fdata; + + face_it->Fill(face_it->it, &face); + fdata = face.user_face_data; + + // cheat CSG never dumps out quads. + + if(face.vertex_number>3) { + // QUAD + mface->v1 = face.vertex_index[0]; + mface->v2 = face.vertex_index[1]; + mface->v3 = face.vertex_index[2]; + mface->v4 = face.vertex_index[3]; + } else { + // TRIANGLE + mface->v1 = face.vertex_index[0]; + mface->v2 = face.vertex_index[1]; + mface->v3 = face.vertex_index[2]; + mface->v4 = 0; + } + + mface->mat_nr = 0; + mface->flag = fdata->faceflag; + + /* HACK, perform material to index mapping using a general + * hash table, just tuck the int into a void *. + */ + + if(ob && !BLI_ghash_haskey(material_hash, fdata->material)) { + int matnr = nmaterials++; + BLI_ghash_insert(material_hash, fdata->material, (void*)matnr); + assign_material(ob, fdata->material, matnr + 1); + } + mface->mat_nr = (int)BLI_ghash_lookup(material_hash, fdata->material); + + // grab the vertex colors and texture cos and dump them into the tface. + + if(user_face_vertex_data) { + TFace *tface = DM_get_face_data(result, fi_insert_pos, + LAYERTYPE_TFACE); + + // copy all the tface settings back + tface->tpage = fdata->tpage; + tface->flag = fdata->flag; + tface->transp = fdata->transp; + tface->mode = fdata->mode; + tface->tile = fdata->tile; + + for(i = 0; i < 4; i++) { + FaceVertexData *fvdata = face.user_face_vertex_data[i]; + float *color = fvdata->color; + + tface->uv[i][0] = fvdata->uv[0]; + tface->uv[i][1] = fvdata->uv[1]; + tface->col[i] = + ((((unsigned int)floor(color[0] + 0.5f)) & 0xff) << 24) + | ((((unsigned int)floor(color[1] + 0.5f)) & 0xff) << 16) + | ((((unsigned int)floor(color[2] + 0.5f)) & 0xff) << 8) + | ((((unsigned int)floor(color[3] + 0.5f)) & 0xff) << 0); + } + + test_index_face(mface, NULL, tface, face.vertex_number); + } else { + test_index_face(mface, NULL, NULL, face.vertex_number); + } + + fi_insert_pos++; + face_it->Step(face_it->it); + } + + BLI_ghash_free(material_hash, NULL, NULL); + + CDDM_calc_edges(result); + + CDDM_calc_normals(result); + + // thats it! + if(user_face_vertex_data) MEM_freeN(user_face_vertex_data); + MEM_freeN(face.user_face_data); + + return result; +} void BuildMeshDescriptors( diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index c3e45f49123..ad066544442 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -765,27 +765,50 @@ static void modifiers_add(void *ob_v, int type) BIF_undo_push("Add modifier"); } +typedef struct MenuEntry { + char *name; + int ID; +} MenuEntry; + +static int menuEntry_compare_names(const void *entry1, const void *entry2) +{ + return strcmp(((MenuEntry *)entry1)->name, ((MenuEntry *)entry2)->name); +} + static uiBlock *modifiers_add_menu(void *ob_v) { Object *ob = ob_v; uiBlock *block; int i, yco=0; + int numEntries = 0; + MenuEntry entries[NUM_MODIFIER_TYPES]; - block= uiNewBlock(&curarea->uiblocks, "modifier_add_menu", UI_EMBOSSP, UI_HELV, curarea->win); + block= uiNewBlock(&curarea->uiblocks, "modifier_add_menu", + UI_EMBOSSP, UI_HELV, curarea->win); uiBlockSetButmFunc(block, modifiers_add, ob); for (i=eModifierType_None+1; i<NUM_MODIFIER_TYPES; i++) { ModifierTypeInfo *mti = modifierType_getInfo(i); - /* Only allow adding through appropriate other interfaces */ - if (ELEM(i, eModifierType_Softbody, eModifierType_Hook)) continue; - - if ( (mti->flags&eModifierTypeFlag_AcceptsCVs) || - (ob->type==OB_MESH && (mti->flags&eModifierTypeFlag_AcceptsMesh))) { - uiDefBut(block, BUTM, B_MODIFIER_RECALC, mti->name, 0, yco-=20, 160, 19, NULL, 0, 0, 1, i, ""); + /* Only allow adding through appropriate other interfaces */ + if(ELEM(i, eModifierType_Softbody, eModifierType_Hook)) continue; + + if((mti->flags&eModifierTypeFlag_AcceptsCVs) || + (ob->type==OB_MESH && (mti->flags&eModifierTypeFlag_AcceptsMesh))) { + entries[numEntries].name = mti->name; + entries[numEntries].ID = i; + + ++numEntries; } } - + + qsort(entries, numEntries, sizeof(*entries), menuEntry_compare_names); + + + for(i = 0; i < numEntries; ++i) + uiDefBut(block, BUTM, B_MODIFIER_RECALC, entries[i].name, + 0, yco -= 20, 160, 19, NULL, 0, 0, 1, entries[i].ID, ""); + uiTextBoundsBlock(block, 50); uiBlockSetDirection(block, UI_DOWN); @@ -943,12 +966,85 @@ static void modifier_testArmatureObj(char *name, ID **idpp) *idpp= 0; } +static void modifier_testTexture(char *name, ID **idpp) +{ + ID *id; + + for(id = G.main->tex.first; id; id = id->next) { + if(strcmp(name, id->name + 2) == 0) { + *idpp = id; + return; + } + } + *idpp = 0; +} + +static void modifier_testMaterial(char *name, ID **idpp) +{ + ID *id; + + for(id = G.main->mat.first; id; id = id->next) { + if(strcmp(name, id->name + 2) == 0) { + *idpp = id; + return; + } + } + *idpp = 0; +} + +static void modifier_testImage(char *name, ID **idpp) +{ + ID *id; + + for(id = G.main->image.first; id; id = id->next) { + if(strcmp(name, id->name + 2) == 0) { + *idpp = id; + return; + } + } + *idpp = 0; +} + +/* autocomplete callback for ID buttons */ +void autocomplete_image(char *str, void *arg_v) +{ + char truncate[40] = {0}; + + /* search if str matches the beginning of an ID struct */ + if(str[0]) { + ID *id; + + for(id = G.main->image.first; id; id = id->next) { + int a; + + for(a = 0; a < 24 - 2; a++) { + if(str[a] == 0 || str[a] != id->name[a + 2]) + break; + } + /* found a match */ + if(str[a] == 0) { + /* first match */ + if(truncate[0] == 0) + BLI_strncpy(truncate, id->name + 2, 24); + else { + /* remove from truncate what is not in bone->name */ + for(a = 0; a < 23; a++) { + if(truncate[a] != id->name[a]) + truncate[a] = 0; + } + } + } + } + if(truncate[0]) + BLI_strncpy(str, truncate, 24); + } +} + static void modifiers_applyModifier(void *obv, void *mdv) { Object *ob = obv; ModifierData *md = mdv; DerivedMesh *dm; - DispListMesh *dlm; Mesh *me = ob->data; int converted = 0; @@ -972,20 +1068,9 @@ static void modifiers_applyModifier(void *obv, void *mdv) return; } - dlm= dm->convertToDispListMesh(dm, 0); + DM_to_mesh(dm, me); + converted = 1; - if ((!me->tface || dlm->tface) || okee("Applying will delete mesh UVs and vertex colors")) { - if ((!me->mcol || dlm->mcol) || okee("Applying will delete mesh vertex colors")) { - if (dlm->totvert==me->totvert || okee("Applying will delete mesh sticky, keys, and vertex groups")) { - displistmesh_to_mesh(dlm, me); - converted = 1; - } - } - } - - if (!converted) { - displistmesh_free(dlm); - } dm->release(dm); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { @@ -1234,6 +1319,14 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco height = 86; } else if (md->type==eModifierType_Mirror) { height = 46; + } else if (md->type==eModifierType_EdgeSplit) { + height = 46; + } else if (md->type==eModifierType_Displace) { + DisplaceModifierData *dmd = (DisplaceModifierData *)md; + height = 134; + if(dmd->texmapping == MOD_DISP_MAP_OBJECT) height += 19; + } else if (md->type==eModifierType_UVProject) { + height = 67 + ((UVProjectModifierData *)md)->num_projectors * 19; } else if (md->type==eModifierType_Decimate) { height = 46; } else if (md->type==eModifierType_Wave) { @@ -1279,7 +1372,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco char subsurfmenu[]="Subsurf Type%t|Catmull-Clark%x0|Simple Subdiv.%x1"; uiDefButS(block, MENU, B_MODIFIER_RECALC, subsurfmenu, lx,(cy-=19),buttonWidth,19, &smd->subdivType, 0, 0, 0, 0, "Selects type of subdivision algorithm."); uiDefButS(block, NUM, B_MODIFIER_RECALC, "Levels:", lx, (cy-=19), buttonWidth,19, &smd->levels, 1, 6, 0, 0, "Number subdivisions to perform"); - uiDefButS(block, NUM, B_MODIFIER_RECALC, "Render Levels:", lx, (cy-=19), buttonWidth,19, &smd->renderLevels, 1, 6, 0, 0, "Number subdivisions to perform when rendering"); + uiDefButS(block, NUM, B_MODIFIER_REDRAW, "Render Levels:", lx, (cy-=19), buttonWidth,19, &smd->renderLevels, 1, 6, 0, 0, "Number subdivisions to perform when rendering"); /* Disabled until non-EM DerivedMesh implementation is complete */ @@ -1294,12 +1387,12 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco LatticeModifierData *lmd = (LatticeModifierData*) md; uiDefIDPoinBut(block, modifier_testLatticeObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &lmd->object, "Lattice object to deform with"); but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &lmd->name, 0.0, 31.0, 0, 0, "Vertex Group name"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)lmd->object); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob); } else if (md->type==eModifierType_Curve) { CurveModifierData *cmd = (CurveModifierData*) md; uiDefIDPoinBut(block, modifier_testCurveObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &cmd->object, "Curve object to deform with"); but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &cmd->name, 0.0, 31.0, 0, 0, "Vertex Group name"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)cmd->object); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob); } else if (md->type==eModifierType_Build) { BuildModifierData *bmd = (BuildModifierData*) md; uiDefButF(block, NUM, B_MODIFIER_RECALC, "Start:", lx, (cy-=19), buttonWidth,19, &bmd->start, 1.0, MAXFRAMEF, 100, 0, "Specify the start frame of the effect"); @@ -1313,6 +1406,86 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco uiDefButS(block, ROW, B_MODIFIER_RECALC, "Y", lx+20, cy, 20,19, &mmd->axis, 1, 1, 0, 0, "Specify the axis to mirror about"); uiDefButS(block, ROW, B_MODIFIER_RECALC, "Z", lx+40, cy, 20,19, &mmd->axis, 1, 2, 0, 0, "Specify the axis to mirror about"); uiDefButBitS(block, TOG, MOD_MIR_CLIPPING, B_MODIFIER_RECALC, "Do Clipping", lx+60, cy, buttonWidth-60,19, &mmd->flag, 1, 2, 0, 0, "Prevents during Transform vertices to go through Mirror"); + } else if (md->type==eModifierType_EdgeSplit) { + EdgeSplitModifierData *amd = (EdgeSplitModifierData*) md; + uiDefButF(block, NUM, B_MODIFIER_RECALC, "Split Angle:", + lx, (cy -= 19), buttonWidth, 19, &amd->split_angle, + 0.0, 180.0, 100, 2, + "Angle above which to split edges"); + uiDefButBitI(block, TOG, MOD_EDGESPLIT_FROMANGLE, + B_MODIFIER_RECALC, "From Angle", + lx, (cy-=19), buttonWidth/2, 19, + &amd->flags, 0, 0, 0, 0, + "Get edge sharpness from angle"); + uiDefButBitI(block, TOG, MOD_EDGESPLIT_FROMFLAG, + B_MODIFIER_RECALC, "From Flag", + lx + buttonWidth/2, cy, (buttonWidth + 1)/2, 19, + &amd->flags, 0, 0, 0, 0, + "Get edge sharpness from flag"); + } else if (md->type==eModifierType_Displace) { + DisplaceModifierData *dmd = (DisplaceModifierData*) md; + but = uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", + lx, (cy -= 19), buttonWidth, 19, + &dmd->defgrp_name, 0.0, 31.0, 0, 0, + "Name of vertex group to displace" + " (displace whole mesh if blank)"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob); + uiDefIDPoinBut(block, modifier_testTexture, ID_TE, B_CHANGEDEP, + "Texture: ", lx, (cy -= 19), buttonWidth, 19, + &dmd->texture, + "Texture to use as displacement input"); + uiDefButF(block, NUM, B_MODIFIER_RECALC, "Midlevel:", + lx, (cy -= 19), buttonWidth, 19, &dmd->midlevel, + 0, 1, 10, 3, + "Material value that gives no displacement"); + uiDefButF(block, NUM, B_MODIFIER_RECALC, "Strength:", + lx, (cy -= 19), buttonWidth, 19, &dmd->strength, + -1000, 1000, 10, 10, + "Strength of displacement"); + sprintf(str, "Direction%%t|Normal%%x%d|Z%%x%d|Y%%x%d|X%%x%d", + MOD_DISP_DIR_NOR, + MOD_DISP_DIR_Z, MOD_DISP_DIR_Y, MOD_DISP_DIR_X); + uiDefButI(block, MENU, B_MODIFIER_RECALC, str, + lx, (cy -= 19), buttonWidth, 19, &dmd->direction, + 0.0, 1.0, 0, 0, "Displace direction"); + sprintf(str, "Texture Coordinates%%t" + "|Local%%x%d|Global%%x%d|Object%%x%d|UV%%x%d", + MOD_DISP_MAP_LOCAL, MOD_DISP_MAP_GLOBAL, + MOD_DISP_MAP_OBJECT, MOD_DISP_MAP_UV); + uiDefButI(block, MENU, B_MODIFIER_RECALC, str, + lx, (cy -= 19), buttonWidth, 19, &dmd->texmapping, + 0.0, 1.0, 0, 0, + "Texture coordinates used for displacement input"); + if(dmd->texmapping == MOD_DISP_MAP_OBJECT) { + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP, + "Ob: ", lx, (cy -= 19), buttonWidth, 19, + &dmd->map_object, + "Object to get texture coordinates from"); + } + } else if (md->type==eModifierType_UVProject) { + UVProjectModifierData *umd = (UVProjectModifierData *) md; + int i; + uiDefButBitI(block, TOG, MOD_UVPROJECT_ADDUVS, + B_MODIFIER_RECALC, "Add UVs", + lx, (cy-=19), buttonWidth, 19, + &umd->flags, 0, 0, 0, 0, + "Add UV coordinates if missing"); + uiDefButI(block, NUM, B_MODIFIER_RECALC, "Projectors:", + lx, (cy -= 19), buttonWidth, 19, &umd->num_projectors, + 1, MOD_UVPROJECT_MAXPROJECTORS, 0, 0, + "Number of objects to use as projectors"); + for(i = 0; i < umd->num_projectors; ++i) { + uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP, + "Ob: ", lx, (cy -= 19), buttonWidth, 19, + &umd->projectors[i], + "Object to use as projector"); + } + uiDefIDPoinBut(block, modifier_testImage, ID_IM, B_CHANGEDEP, + "Image: ", lx, (cy -= 19), buttonWidth, 19, + &umd->image, + "Image to project (only faces with this image " + "will be altered"); + uiButSetCompleteFunc(but, autocomplete_image, (void *)ob); } else if (md->type==eModifierType_Decimate) { DecimateModifierData *dmd = (DecimateModifierData*) md; uiDefButF(block, NUM, B_MODIFIER_RECALC, "Ratio:", lx,(cy-=19),buttonWidth,19, &dmd->percent, 0.0, 1.0, 10, 0, "Defines the percentage of triangles to reduce to"); @@ -1340,7 +1513,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco uiDefIDPoinBut(block, modifier_testArmatureObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &amd->object, "Armature object to deform with"); uiDefButBitS(block, TOG, ARM_DEF_VGROUP, B_ARM_RECALCDATA, "Vert.Groups", lx,cy-=19,buttonWidth/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable VertexGroups defining deform"); - uiDefButBitS(block, TOG, ARM_DEF_ENVELOPE, B_ARM_RECALCDATA, "Envelopes", lx+buttonWidth/2,cy,buttonWidth/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable Bone Envelopes defining deform"); + uiDefButBitS(block, TOG, ARM_DEF_ENVELOPE, B_ARM_RECALCDATA, "Envelopes", lx+buttonWidth/2,cy,(buttonWidth + 1)/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable Bone Envelopes defining deform"); } else if (md->type==eModifierType_Hook) { HookModifierData *hmd = (HookModifierData*) md; @@ -1349,7 +1522,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &hmd->object, "Parent Object for hook, also recalculates and clears offset"); if(hmd->indexar==NULL) { but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &hmd->name, 0.0, 31.0, 0, 0, "Vertex Group name"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)hmd->object); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob); } uiBlockBeginAlign(block); but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Reset", lx, (cy-=19), 80,19, NULL, 0.0, 0.0, 0, 0, "Recalculate and clear offset (transform) of hook"); diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c index ee098b2ee7c..7149441093a 100644 --- a/source/blender/src/drawobject.c +++ b/source/blender/src/drawobject.c @@ -1370,7 +1370,6 @@ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *dra if (efa->h==0) { glColor4ubv(cols[(efa->f&SELECT)?1:0]); - *drawSmooth_r = (efa->flag&ME_SMOOTH); return 1; } else { return 0; @@ -1750,7 +1749,6 @@ static int draw_em_fancy__setFaceOpts(void *userData, int index, int *drawSmooth if (efa->h==0) { set_gl_material(efa->mat_nr+1); - *drawSmooth_r = efa->flag&ME_SMOOTH; return 1; } else { return 0; diff --git a/source/blender/src/editmesh.c b/source/blender/src/editmesh.c index 6c351a09dc4..72b118b56a2 100644 --- a/source/blender/src/editmesh.c +++ b/source/blender/src/editmesh.c @@ -286,6 +286,7 @@ EditEdge *addedgelist(EditVert *v1, EditVert *v2, EditEdge *example) rule is to do this with addedgelist call, before addfacelist */ if(example) { eed->crease= example->crease; + eed->sharp = example->sharp; eed->seam = example->seam; eed->h |= (example->h & EM_FGON); } @@ -858,6 +859,7 @@ void make_editMesh() eed->crease= ((float)medge->crease)/255.0; if(medge->flag & ME_SEAM) eed->seam= 1; + if(medge->flag & ME_SHARP) eed->sharp = 1; if(medge->flag & SELECT) eed->f |= SELECT; if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines! if(medge->flag & ME_HIDE) eed->h |= 1; @@ -1081,6 +1083,7 @@ void load_editMesh(void) medge->flag= (eed->f & SELECT) | ME_EDGERENDER; if(eed->f2<2) medge->flag |= ME_EDGEDRAW; if(eed->f2==0) medge->flag |= ME_LOOSEEDGE; + if(eed->sharp) medge->flag |= ME_SHARP; if(eed->seam) medge->flag |= ME_SEAM; if(eed->h & EM_FGON) medge->flag |= ME_FGON; // different defines yes if(eed->h & 1) medge->flag |= ME_HIDE; @@ -1782,7 +1785,7 @@ typedef struct EditVertC typedef struct EditEdgeC { int v1, v2; - unsigned char f, h, seam, pad; + unsigned char f, h, seam, sharp, pad; short crease, fgoni; } EditEdgeC; @@ -1888,6 +1891,7 @@ static void *editMesh_to_undoMesh(void) eedc->f= eed->f; eedc->h= eed->h; eedc->seam= eed->seam; + eedc->sharp= eed->sharp; eedc->crease= (short)(eed->crease*255.0); eedc->fgoni= eed->fgoni; eed->tmp.l = a; /*store index*/ @@ -1983,6 +1987,7 @@ static void undoMesh_to_editMesh(void *umv) 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.0; } diff --git a/source/blender/src/editmesh_mods.c b/source/blender/src/editmesh_mods.c index cf24bbd05a9..0416c31237a 100644 --- a/source/blender/src/editmesh_mods.c +++ b/source/blender/src/editmesh_mods.c @@ -2548,10 +2548,42 @@ void editmesh_mark_seam(int clear) allqueue(REDRAWVIEW3D, 0); } +void editmesh_mark_sharp(int set) +{ + EditMesh *em= G.editMesh; + EditEdge *eed; + +#if 0 + /* auto-enable sharp edge drawing */ + if(set) { + if(!(G.f & G_DRAWSEAMS)) { + G.f |= G_DRAWSEAMS; + allqueue(REDRAWBUTSEDIT, 0); + } + } +#endif + + if(set) { + 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; + } + } + + allqueue(REDRAWVIEW3D, 0); +} + void Edge_Menu() { short ret; - ret= pupmenu("Edge Specials%t|Mark Seam %x1|Clear Seam %x2|Rotate Edge CW%x3|Rotate Edge CCW%x4|Loopcut%x6|Edge Slide%x5|Edge Loop Select%x7|Edge Ring Select%x8|Loop to Region%x9|Region to Loop%x10"); + ret= pupmenu("Edge Specials%t|Mark Seam %x1|Clear Seam %x2|Rotate Edge CW%x3|Rotate Edge CCW%x4|Loopcut%x6|Edge Slide%x5|Edge Loop Select%x7|Edge Ring Select%x8|Loop to Region%x9|Region to Loop%x10|Mark Sharp%x11|Clear Sharp%x12"); switch(ret) { @@ -2587,6 +2619,16 @@ void Edge_Menu() { case 10: region_to_loop(); break; + case 11: + editmesh_mark_sharp(1); + BIF_undo_push("Mark Sharp"); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + break; + case 12: + editmesh_mark_sharp(0); + BIF_undo_push("Clear Sharp"); + DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); + break; } } diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index 5dd7bab5176..ede9d198b15 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -4312,9 +4312,11 @@ void make_local(int mode) BIF_undo_push("Make local"); } -static void adduplicate__forwardModifierLinks(void *userData, Object *ob, Object **obpoin) +static void adduplicate__forwardModifierLinks(void *userData, Object *ob, + ID **idpoin) { - ID_NEW(*obpoin); + /* this is copied from ID_NEW; it might be better to have a macro */ + if(*idpoin && (*idpoin)->newid) *idpoin = (*idpoin)->newid; } /* This function duplicated the current visible selection, its used by Duplicate and Linked Duplicate @@ -4543,7 +4545,8 @@ void adduplicate(int mode, int dupflag) relink_constraints(&chan->constraints); } } - modifiers_foreachObjectLink(base->object, adduplicate__forwardModifierLinks, NULL); + modifiers_foreachIDLink(base->object, + adduplicate__forwardModifierLinks, NULL); ID_NEW(base->object->parent); ID_NEW(base->object->track); diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp index 3645491412e..b291331c378 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.cpp +++ b/source/gameengine/Converter/BL_SkinDeformer.cpp @@ -175,7 +175,7 @@ void BL_SkinDeformer::Update(void) for (int v =0; v<m_bmesh->totvert; v++) VECCOPY(m_transverts[v], m_bmesh->mvert[v].co); - armature_deform_verts( par_arma, m_objMesh, m_transverts, m_bmesh->totvert, ARM_DEF_VGROUP ); + armature_deform_verts( par_arma, m_objMesh, NULL, m_transverts, m_bmesh->totvert, ARM_DEF_VGROUP ); RecalcNormals(); /* Update the current frame */ |