Index: source/blender/editors/uvedit/uvedit_unwrap_ops.c |
=================================================================== |
--- source/blender/editors/uvedit/uvedit_unwrap_ops.c (.../https://svn.blender.org/svnroot/bf-blender/trunk/blender) (revision 43172) |
+++ source/blender/editors/uvedit/uvedit_unwrap_ops.c (working copy) |
@@ -40,6 +40,7 @@ |
#include "DNA_meshdata_types.h" |
#include "DNA_object_types.h" |
#include "DNA_scene_types.h" |
+#include "DNA_modifier_types.h" |
#include "BLI_math.h" |
#include "BLI_edgehash.h" |
@@ -47,12 +48,15 @@ |
#include "BLI_uvproject.h" |
#include "BLI_utildefines.h" |
+#include "BKE_cdderivedmesh.h" |
+#include "BKE_subsurf.h" |
#include "BKE_context.h" |
#include "BKE_customdata.h" |
#include "BKE_depsgraph.h" |
#include "BKE_image.h" |
#include "BKE_main.h" |
#include "BKE_mesh.h" |
+#include "BKE_report.h" |
#include "PIL_time.h" |
@@ -228,7 +232,7 @@ |
co[0] = efa->v1->co; |
co[1] = efa->v2->co; |
co[2] = efa->v3->co; |
- |
+ |
uv[0] = tf->uv[0]; |
uv[1] = tf->uv[1]; |
uv[2] = tf->uv[2]; |
@@ -271,6 +275,249 @@ |
return handle; |
} |
+ |
+static void get_TexFace_Attributes_from_Index(EditFace *editFace, MTFace *texFace, int index, float **uv, ParamBool *pin, ParamBool *select, Scene *scene) |
+{ |
+ if(editFace->v1->tmp.t == index){ |
+ *uv = texFace->uv[0]; |
+ *pin = ((texFace->unwrap & TF_PIN1) != 0); |
+ *select = (uvedit_uv_selected(scene, editFace, texFace, 0) != 0); |
+ } |
+ else if(editFace->v2->tmp.t == index){ |
+ *uv = texFace->uv[1]; |
+ *pin = ((texFace->unwrap & TF_PIN2) != 0); |
+ *select = (uvedit_uv_selected(scene, editFace, texFace, 1) != 0); |
+ } |
+ else if(editFace->v3->tmp.t == index){ |
+ *uv = texFace->uv[2]; |
+ *pin = ((texFace->unwrap & TF_PIN3) != 0); |
+ *select = (uvedit_uv_selected(scene, editFace, texFace, 2) != 0); |
+ } |
+ else if(editFace->v4 && editFace->v4->tmp.t == index){ |
+ *uv = texFace->uv[3]; |
+ *pin = ((texFace->unwrap & TF_PIN4) != 0); |
+ *select = (uvedit_uv_selected(scene, editFace, texFace, 3) != 0); |
+ } |
+} |
+ |
+ |
+ |
+/* unwrap handle initialization for subsurf aware-unwrapper. The many modifications required to make the original function(see above) |
+ * work justified the existence of a new function. */ |
+static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *editMesh, short implicit, short fill, short sel, short correct_aspect) |
+{ |
+ ParamHandle *handle; |
+ /* index pointers */ |
+ MFace *face; |
+ MEdge *edge; |
+ EditVert *editVert; |
+ MTFace *texface; |
+ EditFace *editFace, **editFaceTmp; |
+ EditEdge *editEdge, **editEdgeTmp; |
+ int i; |
+ |
+ /* modifier initialization data, will control what type of subdivision will happen*/ |
+ SubsurfModifierData smd = {{0}}; |
+ /* Used to hold subsurfed Mesh */ |
+ DerivedMesh *derivedMesh, *initialDerived; |
+ /* holds original indices for subsurfed mesh */ |
+ int *origVertIndices, *origFaceIndices, *origEdgeIndices; |
+ /* Holds vertices of subsurfed mesh */ |
+ MVert *subsurfedVerts; |
+ MEdge *subsurfedEdges; |
+ MFace *subsurfedFaces; |
+ MTFace *subsurfedTexfaces; |
+ /* number of vertices and faces for subsurfed mesh*/ |
+ int numOfEdges, numOfFaces; |
+ |
+ /* holds a map to editfaces for every subsurfed MFace. These will be used to get hidden/ selected flags etc. */ |
+ EditFace **faceMap; |
+ /* Mini container to hold all EditFaces so that they may be indexed easily and fast. */ |
+ EditFace **editFaceArray; |
+ /* similar to the above, we need a way to map edges to their original ones */ |
+ EditEdge **edgeMap; |
+ EditEdge **editEdgeArray; |
+ |
+ handle = param_construct_begin(); |
+ |
+ if(correct_aspect) { |
+ EditFace *eface = EM_get_actFace(editMesh, 1); |
+ |
+ if(eface) { |
+ float aspx, aspy; |
+ texface= CustomData_em_get(&editMesh->fdata, eface->data, CD_MTFACE); |
+ |
+ ED_image_uv_aspect(texface->tpage, &aspx, &aspy); |
+ |
+ if(aspx!=aspy) |
+ param_aspect_ratio(handle, aspx, aspy); |
+ } |
+ } |
+ |
+ /* number of subdivisions to perform */ |
+ smd.levels = scene->toolsettings->uv_subsurf_level; |
+ smd.subdivType = ME_CC_SUBSURF; |
+ |
+ initialDerived = CDDM_from_editmesh(editMesh, NULL); |
+ derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd, |
+ 0, NULL, 0, 0, 1); |
+ |
+ initialDerived->release(initialDerived); |
+ |
+ /* Store the derived Mesh in the handle to cleanup later. This avoids freed memory access and crashes */ |
+ param_set_subsurfed_mesh(handle, derivedMesh); |
+ |
+ /* get the derived data */ |
+ subsurfedVerts = derivedMesh->getVertArray(derivedMesh); |
+ subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh); |
+ subsurfedFaces = derivedMesh->getFaceArray(derivedMesh); |
+ |
+ origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX); |
+ origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX); |
+ origFaceIndices = derivedMesh->getFaceDataArray(derivedMesh, CD_ORIGINDEX); |
+ |
+ subsurfedTexfaces = derivedMesh->getFaceDataArray(derivedMesh, CD_MTFACE); |
+ |
+ numOfEdges = derivedMesh->getNumEdges(derivedMesh); |
+ numOfFaces = derivedMesh->getNumFaces(derivedMesh); |
+ |
+ faceMap = MEM_mallocN(numOfFaces*sizeof(EditFace *), "unwrap_edit_face_map"); |
+ editFaceArray = MEM_mallocN(editMesh->totface*sizeof(EditFace *), "unwrap_editFaceArray"); |
+ |
+ /* fill edit face array with edit faces */ |
+ for(editFace = editMesh->faces.first, editFaceTmp = editFaceArray; editFace; editFace= editFace->next, editFaceTmp++) { |
+ *editFaceTmp = editFace; |
+ } |
+ /* map subsurfed faces to original editFaces */ |
+ for(i = 0; i < numOfFaces; i++){ |
+ faceMap[i] = editFaceArray[origFaceIndices[i]]; |
+ } |
+ MEM_freeN(editFaceArray); |
+ |
+ edgeMap = MEM_mallocN(numOfEdges*sizeof(EditEdge *), "unwrap_edit_edge_map"); |
+ editEdgeArray = MEM_mallocN(editMesh->totedge*sizeof(EditEdge *), "unwrap_editEdgeArray"); |
+ |
+ /* fill edit edge array with edit edges */ |
+ for(editEdge = editMesh->edges.first, editEdgeTmp = editEdgeArray; editEdge; editEdge= editEdge->next, editEdgeTmp++) { |
+ *editEdgeTmp = editEdge; |
+ } |
+ /* map subsurfed edges to original editEdges */ |
+ for(i = 0; i < numOfEdges; i++){ |
+ /* not all edges correspond to an old edge */ |
+ edgeMap[i] = (origEdgeIndices[i] != -1)? |
+ editEdgeArray[origEdgeIndices[i]] : NULL; |
+ } |
+ MEM_freeN(editEdgeArray); |
+ |
+ /* we need the editvert indices too */ |
+ for(editVert = editMesh->verts.first, i=0; editVert; editVert = editVert->next, i++){ |
+ editVert->tmp.t = i; |
+ } |
+ |
+ /* Prepare and feed faces to the solver */ |
+ for(i = 0; i < numOfFaces; i++) { |
+ ParamKey key, vkeys[4]; |
+ ParamBool pin[4], select[4]; |
+ float *co[4]; |
+ float *uv[4]; |
+ EditFace *origFace = faceMap[i]; |
+ MTFace *origtexface = (MTFace *)CustomData_em_get(&editMesh->fdata, origFace->data, CD_MTFACE); |
+ |
+ |
+ face = subsurfedFaces+i; |
+ |
+ if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { |
+ if(origFace->h) { |
+ continue; |
+ } |
+ } |
+ else { |
+ if((origFace->h) || (sel && (origFace->f & SELECT)==0)) { |
+ continue; |
+ } |
+ } |
+ |
+ /* we need some original mesh data to calculate these parameters */ |
+ if(implicit && |
+ !( uvedit_uv_selected(scene, origFace, origtexface, 0) || |
+ uvedit_uv_selected(scene, origFace, origtexface, 1) || |
+ uvedit_uv_selected(scene, origFace, origtexface, 2) || |
+ (origFace->v4 && uvedit_uv_selected(scene, origFace, origtexface, 3)) ) |
+ ) { |
+ continue; |
+ } |
+ |
+ /* Now we feed the rest of the data from the subsurfed faces */ |
+ texface= subsurfedTexfaces+i; |
+ |
+ /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */ |
+ key = (ParamKey)face; |
+ vkeys[0] = (ParamKey)face->v1; |
+ vkeys[1] = (ParamKey)face->v2; |
+ vkeys[2] = (ParamKey)face->v3; |
+ vkeys[3] = (ParamKey)face->v4; |
+ |
+ co[0] = subsurfedVerts[face->v1].co; |
+ co[1] = subsurfedVerts[face->v2].co; |
+ co[2] = subsurfedVerts[face->v3].co; |
+ co[3] = subsurfedVerts[face->v4].co; |
+ |
+ /* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus |
+ * flushing the solution to the edit mesh. */ |
+ if(origVertIndices[face->v1] == ORIGINDEX_NONE){ |
+ uv[0] = texface->uv[0]; |
+ pin[0] = 0; |
+ select[0] = !!1; |
+ } |
+ else{ |
+ get_TexFace_Attributes_from_Index(origFace, origtexface, origVertIndices[face->v1], &uv[0], &pin[0], &select[0], scene); |
+ } |
+ if(origVertIndices[face->v2] == ORIGINDEX_NONE){ |
+ uv[1] = texface->uv[1]; |
+ pin[1] = 0; |
+ select[1] = !!1; |
+ } else{ |
+ get_TexFace_Attributes_from_Index(origFace, origtexface, origVertIndices[face->v2], &uv[1], &pin[1], &select[1], scene); |
+ } |
+ if(origVertIndices[face->v3] == ORIGINDEX_NONE){ |
+ uv[2] = texface->uv[2]; |
+ pin[2] = 0; |
+ select[2] = !!1; |
+ } else{ |
+ get_TexFace_Attributes_from_Index(origFace, origtexface, origVertIndices[face->v3], &uv[2], &pin[2], &select[2], scene); |
+ } |
+ if(origVertIndices[face->v4] == ORIGINDEX_NONE){ |
+ uv[3] = texface->uv[3]; |
+ pin[3] = 0; |
+ select[3] = !!1; |
+ } else{ |
+ get_TexFace_Attributes_from_Index(origFace, origtexface, origVertIndices[face->v4], &uv[3], &pin[3], &select[3], scene); |
+ } |
+ |
+ param_face_add(handle, key, 4, vkeys, co, uv, pin, select); |
+ } |
+ |
+ /* these are calculated from original mesh too */ |
+ if(!implicit) { |
+ for(edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) { |
+ if((edgeMap[i] != NULL) && edgeMap[i]->seam) { |
+ ParamKey vkeys[2]; |
+ vkeys[0] = (ParamKey)edge->v1; |
+ vkeys[1] = (ParamKey)edge->v2; |
+ param_edge_set_seam(handle, vkeys); |
+ } |
+ } |
+ } |
+ |
+ param_construct_end(handle, fill, implicit); |
+ |
+ /* cleanup */ |
+ MEM_freeN(faceMap); |
+ MEM_freeN(edgeMap); |
+ |
+ return handle; |
+} |
+ |
/* ******************** Minimize Stretch operator **************** */ |
typedef struct MinStretch { |
@@ -581,14 +828,19 @@ |
EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); |
short abf = scene->toolsettings->unwrapper == 0; |
short fillholes = scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES; |
+ short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF; |
if(!ED_uvedit_test(obedit)) { |
BKE_mesh_end_editmesh(obedit->data, em); |
return; |
} |
+ if(use_subsurf){ |
+ liveHandle = construct_param_handle_subsurfed(scene, em, 0, fillholes, 0, 1); |
+ } |
+ else{ |
+ liveHandle = construct_param_handle(scene, em, 0, fillholes, 0, 1); |
+ } |
- liveHandle = construct_param_handle(scene, em, 0, fillholes, 0, 1); |
- |
param_lscm_begin(liveHandle, PARAM_TRUE, abf); |
BKE_mesh_end_editmesh(obedit->data, em); |
} |
@@ -899,14 +1151,20 @@ |
/* assumes UV Map is checked, doesn't run update funcs */ |
void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel) |
{ |
- EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); |
ParamHandle *handle; |
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); |
const short fill_holes= scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES; |
const short correct_aspect= !(scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT); |
- short implicit= 0; |
+ const short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF; |
- handle= construct_param_handle(scene, em, implicit, fill_holes, sel, correct_aspect); |
+ if(use_subsurf){ |
+ handle = construct_param_handle_subsurfed(scene, em, 0, fill_holes, sel, correct_aspect); |
+ } |
+ else |
+ { |
+ handle= construct_param_handle(scene, em, 0, fill_holes, sel, correct_aspect); |
+ } |
param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0); |
param_lscm_solve(handle); |
@@ -929,6 +1187,8 @@ |
int method = RNA_enum_get(op->ptr, "method"); |
int fill_holes = RNA_boolean_get(op->ptr, "fill_holes"); |
int correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"); |
+ int use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data"); |
+ int subdivisionLevel = RNA_int_get(op->ptr, "uv_subsurf_level"); |
short implicit= 0; |
if(!uvedit_have_selection(scene, em, implicit)) { |
@@ -943,8 +1203,16 @@ |
return OPERATOR_CANCELLED; |
} |
+ if((fabs(obedit->size[0] - 1.0) > FLT_EPSILON) || (fabs(obedit->size[1] - 1.0) > FLT_EPSILON) || |
+ (fabs(obedit->size[2] - 1.0) > FLT_EPSILON) || (fabs(obedit->dscale[0] - 1.0) > FLT_EPSILON) || |
+ (fabs(obedit->dscale[1] - 1.0) > FLT_EPSILON) || (fabs(obedit->dscale[2] - 1.0) > FLT_EPSILON)){ |
+ BKE_report(op->reports, RPT_WARNING, "Object scale is not 1.0. Unwrap will operate on a non-scaled version of the mesh."); |
+ } |
+ |
/* remember last method for live unwrap */ |
scene->toolsettings->unwrapper = method; |
+ |
+ scene->toolsettings->uv_subsurf_level = subdivisionLevel; |
if(fill_holes) scene->toolsettings->uvcalc_flag |= UVCALC_FILLHOLES; |
else scene->toolsettings->uvcalc_flag &= ~UVCALC_FILLHOLES; |
@@ -952,6 +1220,9 @@ |
if(correct_aspect) scene->toolsettings->uvcalc_flag &= ~UVCALC_NO_ASPECT_CORRECT; |
else scene->toolsettings->uvcalc_flag |= UVCALC_NO_ASPECT_CORRECT; |
+ if(use_subsurf) scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF; |
+ else scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF; |
+ |
/* execute unwrap */ |
ED_unwrap_lscm(scene, obedit, TRUE); |
@@ -985,6 +1256,8 @@ |
"Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry"); |
RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect", |
"Map UVs taking image aspect ratio into account"); |
+ RNA_def_boolean(ot->srna, "use_subsurf_data", 0, "Use Subsurf Data", "Map UV's taking vertex position after subsurf into account"); |
+ RNA_def_int(ot->srna, "uv_subsurf_level", 1, 1, 6, "SubSurf Target", "Number of times to subdivide before calculating UV's", 1, 6); |
} |
/**************** Project From View operator **************/ |