515 lines
11 KiB
C
515 lines
11 KiB
C
/**
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_screen_types.h"
|
|
#include "DNA_space_types.h"
|
|
|
|
#include "BKE_global.h"
|
|
#include "BKE_mesh.h"
|
|
#include "BKE_utildefines.h"
|
|
#include "BKE_customdata.h"
|
|
|
|
#include "BLI_arithb.h"
|
|
#include "BLI_edgehash.h"
|
|
#include "BLI_editVert.h"
|
|
|
|
#include "BIF_editsima.h"
|
|
#include "BIF_space.h"
|
|
#include "BIF_screen.h"
|
|
#include "BIF_editmesh.h"
|
|
|
|
#include "blendef.h"
|
|
#include "mydevice.h"
|
|
|
|
#include "BDR_unwrapper.h"
|
|
|
|
#include "PIL_time.h"
|
|
|
|
#include "parametrizer.h"
|
|
|
|
/* Set tface seams based on edge data, uses hash table to find seam edges. */
|
|
|
|
static void hash_add_face(EdgeHash *ehash, MFace *mf)
|
|
{
|
|
BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
|
|
BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
|
|
if(mf->v4) {
|
|
BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
|
|
BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
|
|
}
|
|
else
|
|
BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
|
|
}
|
|
|
|
void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
|
|
{
|
|
MFace *mf;
|
|
int a, doit=1, mark=0;
|
|
char *linkflag;
|
|
EdgeHash *ehash, *seamhash;
|
|
MEdge *med;
|
|
|
|
ehash= BLI_edgehash_new();
|
|
seamhash = BLI_edgehash_new();
|
|
linkflag= MEM_callocN(sizeof(char)*me->totface, "linkflaguv");
|
|
|
|
for(med=me->medge, a=0; a < me->totedge; a++, med++)
|
|
if(med->flag & ME_SEAM)
|
|
BLI_edgehash_insert(seamhash, med->v1, med->v2, NULL);
|
|
|
|
if (mode==0 || mode==1) {
|
|
/* only put face under cursor in array */
|
|
mf= ((MFace*)me->mface) + index;
|
|
hash_add_face(ehash, mf);
|
|
linkflag[index]= 1;
|
|
}
|
|
else {
|
|
/* fill array by selection */
|
|
mf= me->mface;
|
|
for(a=0; a<me->totface; a++, mf++) {
|
|
if(mf->flag & ME_HIDE);
|
|
else if(mf->flag & ME_FACE_SEL) {
|
|
hash_add_face(ehash, mf);
|
|
linkflag[a]= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
while(doit) {
|
|
doit= 0;
|
|
|
|
/* expand selection */
|
|
mf= me->mface;
|
|
for(a=0; a<me->totface; a++, mf++) {
|
|
if(mf->flag & ME_HIDE)
|
|
continue;
|
|
|
|
if(!linkflag[a]) {
|
|
mark= 0;
|
|
|
|
if(!BLI_edgehash_haskey(seamhash, mf->v1, mf->v2))
|
|
if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2))
|
|
mark= 1;
|
|
if(!BLI_edgehash_haskey(seamhash, mf->v2, mf->v3))
|
|
if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3))
|
|
mark= 1;
|
|
if(mf->v4) {
|
|
if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v4))
|
|
if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4))
|
|
mark= 1;
|
|
if(!BLI_edgehash_haskey(seamhash, mf->v4, mf->v1))
|
|
if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1))
|
|
mark= 1;
|
|
}
|
|
else if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v1))
|
|
if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1))
|
|
mark = 1;
|
|
|
|
if(mark) {
|
|
linkflag[a]= 1;
|
|
hash_add_face(ehash, mf);
|
|
doit= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
BLI_edgehash_free(ehash, NULL);
|
|
BLI_edgehash_free(seamhash, NULL);
|
|
|
|
if(mode==0 || mode==2) {
|
|
for(a=0, mf=me->mface; a<me->totface; a++, mf++)
|
|
if(linkflag[a])
|
|
mf->flag |= ME_FACE_SEL;
|
|
else
|
|
mf->flag &= ~ME_FACE_SEL;
|
|
}
|
|
else if(mode==1) {
|
|
for(a=0, mf=me->mface; a<me->totface; a++, mf++)
|
|
if(linkflag[a] && (mf->flag & ME_FACE_SEL))
|
|
break;
|
|
|
|
if (a<me->totface) {
|
|
for(a=0, mf=me->mface; a<me->totface; a++, mf++)
|
|
if(linkflag[a])
|
|
mf->flag &= ~ME_FACE_SEL;
|
|
}
|
|
else {
|
|
for(a=0, mf=me->mface; a<me->totface; a++, mf++)
|
|
if(linkflag[a])
|
|
mf->flag |= ME_FACE_SEL;
|
|
}
|
|
}
|
|
|
|
MEM_freeN(linkflag);
|
|
|
|
BIF_undo_push("Select linked UV face");
|
|
object_tface_flags_changed(OBACT, 0);
|
|
}
|
|
|
|
/* Parametrizer */
|
|
ParamHandle *construct_param_handle(EditMesh *em, short implicit, short fill, short sel)
|
|
{
|
|
int a;
|
|
MTFace *tf;
|
|
|
|
EditFace *efa;
|
|
EditEdge *eed;
|
|
EditVert *ev;
|
|
|
|
ParamHandle *handle;
|
|
|
|
handle = param_construct_begin();
|
|
|
|
if ((G.scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT)==0) {
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa = EM_get_actFace(1);
|
|
if (efa) {
|
|
float aspx, aspy;
|
|
MTFace *tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
image_final_aspect(tface->tpage, &aspx, &aspy);
|
|
|
|
if (aspx!=aspy)
|
|
param_aspect_ratio(handle, aspx, aspy);
|
|
}
|
|
}
|
|
|
|
/* we need the vert indicies */
|
|
for (ev= em->verts.first, a=0; ev; ev= ev->next, a++)
|
|
ev->tmp.l = a;
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
ParamKey key, vkeys[4];
|
|
ParamBool pin[4], select[4];
|
|
float *co[4];
|
|
float *uv[4];
|
|
int nverts;
|
|
|
|
if ((efa->h) || (sel && (efa->f & SELECT)==0))
|
|
continue;
|
|
|
|
tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
if (implicit &&
|
|
!( simaUVSel_Check(efa, tf, 0) ||
|
|
simaUVSel_Check(efa, tf, 1) ||
|
|
simaUVSel_Check(efa, tf, 2) ||
|
|
(efa->v4 && simaUVSel_Check(efa, tf, 3)) )
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
key = (ParamKey)efa;
|
|
vkeys[0] = (ParamKey)efa->v1->tmp.l;
|
|
vkeys[1] = (ParamKey)efa->v2->tmp.l;
|
|
vkeys[2] = (ParamKey)efa->v3->tmp.l;
|
|
|
|
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];
|
|
|
|
pin[0] = ((tf->unwrap & TF_PIN1) != 0);
|
|
pin[1] = ((tf->unwrap & TF_PIN2) != 0);
|
|
pin[2] = ((tf->unwrap & TF_PIN3) != 0);
|
|
|
|
select[0] = ((simaUVSel_Check(efa, tf, 0)) != 0);
|
|
select[1] = ((simaUVSel_Check(efa, tf, 1)) != 0);
|
|
select[2] = ((simaUVSel_Check(efa, tf, 2)) != 0);
|
|
|
|
if (efa->v4) {
|
|
vkeys[3] = (ParamKey)efa->v4->tmp.l;
|
|
co[3] = efa->v4->co;
|
|
uv[3] = tf->uv[3];
|
|
pin[3] = ((tf->unwrap & TF_PIN4) != 0);
|
|
select[3] = (simaUVSel_Check(efa, tf, 3) != 0);
|
|
nverts = 4;
|
|
}
|
|
else
|
|
nverts = 3;
|
|
|
|
param_face_add(handle, key, nverts, vkeys, co, uv, pin, select);
|
|
}
|
|
|
|
if (!implicit) {
|
|
for (eed= em->edges.first; eed; eed= eed->next) {
|
|
if(eed->seam) {
|
|
ParamKey vkeys[2];
|
|
vkeys[0] = (ParamKey)eed->v1->tmp.l;
|
|
vkeys[1] = (ParamKey)eed->v2->tmp.l;
|
|
param_edge_set_seam(handle, vkeys);
|
|
}
|
|
}
|
|
}
|
|
|
|
param_construct_end(handle, fill, implicit);
|
|
|
|
return handle;
|
|
}
|
|
|
|
|
|
extern int EM_texFaceCheck(void);
|
|
|
|
void unwrap_lscm(short seamcut)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
ParamHandle *handle;
|
|
short abf = G.scene->toolsettings->unwrapper == 1;
|
|
short fillholes = G.scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
|
|
|
|
/* add uvs if there not here */
|
|
if (!EM_texFaceCheck()) {
|
|
if (em && em->faces.first)
|
|
EM_add_data_layer(&em->fdata, CD_MTFACE);
|
|
|
|
if (!EM_texFaceCheck())
|
|
return;
|
|
|
|
if (G.sima && G.sima->image) /* this is a bit of a kludge, but assume they want the image on their mesh when UVs are added */
|
|
image_changed(G.sima, G.sima->image);
|
|
|
|
/* select new UV's */
|
|
if ((G.sima==0 || G.sima->flag & SI_SYNC_UVSEL)==0) {
|
|
EditFace *efa;
|
|
MTFace *tf;
|
|
for(efa=em->faces.first; efa; efa=efa->next) {
|
|
tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
simaFaceSel_Set(efa, tf);
|
|
}
|
|
}
|
|
}
|
|
|
|
handle = construct_param_handle(em, 0, fillholes, seamcut == 0);
|
|
|
|
param_lscm_begin(handle, PARAM_FALSE, abf);
|
|
param_lscm_solve(handle);
|
|
param_lscm_end(handle);
|
|
|
|
param_pack(handle);
|
|
|
|
param_flush(handle);
|
|
|
|
param_delete(handle);
|
|
|
|
if (!seamcut)
|
|
BIF_undo_push("UV unwrap");
|
|
|
|
object_uvs_changed(OBACT);
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
|
|
void minimize_stretch_tface_uv(void)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
ParamHandle *handle;
|
|
double lasttime;
|
|
short doit = 1, escape = 0, val, blend = 0;
|
|
unsigned short event = 0;
|
|
short fillholes = G.scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
|
|
|
|
if(!EM_texFaceCheck()) return;
|
|
|
|
handle = construct_param_handle(em, 1, fillholes, 1);
|
|
|
|
lasttime = PIL_check_seconds_timer();
|
|
|
|
param_stretch_begin(handle);
|
|
|
|
while (doit) {
|
|
param_stretch_iter(handle);
|
|
|
|
while (qtest()) {
|
|
event= extern_qread(&val);
|
|
|
|
if (val) {
|
|
switch (event) {
|
|
case ESCKEY:
|
|
escape = 1;
|
|
case RETKEY:
|
|
case PADENTER:
|
|
doit = 0;
|
|
break;
|
|
case PADPLUSKEY:
|
|
case WHEELUPMOUSE:
|
|
if (blend < 10) {
|
|
blend++;
|
|
param_stretch_blend(handle, blend*0.1f);
|
|
param_flush(handle);
|
|
lasttime = 0.0f;
|
|
}
|
|
break;
|
|
case PADMINUS:
|
|
case WHEELDOWNMOUSE:
|
|
if (blend > 0) {
|
|
blend--;
|
|
param_stretch_blend(handle, blend*0.1f);
|
|
param_flush(handle);
|
|
lasttime = 0.0f;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if ((event == LEFTMOUSE) || (event == RIGHTMOUSE)) {
|
|
escape = (event == RIGHTMOUSE);
|
|
doit = 0;
|
|
}
|
|
}
|
|
|
|
if (!doit)
|
|
break;
|
|
|
|
if (PIL_check_seconds_timer() - lasttime > 0.5) {
|
|
char str[100];
|
|
|
|
param_flush(handle);
|
|
|
|
sprintf(str, "Stretch minimize. Blend %.2f.", blend*0.1f);
|
|
headerprint(str);
|
|
|
|
lasttime = PIL_check_seconds_timer();
|
|
object_uvs_changed(OBACT);
|
|
if(G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
|
|
else force_draw(0);
|
|
}
|
|
}
|
|
|
|
if (escape)
|
|
param_flush_restore(handle);
|
|
else
|
|
param_flush(handle);
|
|
|
|
param_stretch_end(handle);
|
|
|
|
param_delete(handle);
|
|
|
|
BIF_undo_push("UV stretch minimize");
|
|
|
|
object_uvs_changed(OBACT);
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
|
|
void pack_charts_tface_uv(void)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
ParamHandle *handle;
|
|
|
|
if(!EM_texFaceCheck()) return;
|
|
|
|
handle = construct_param_handle(em, 1, 0, 1);
|
|
param_pack(handle);
|
|
param_flush(handle);
|
|
param_delete(handle);
|
|
|
|
BIF_undo_push("UV pack islands");
|
|
|
|
object_uvs_changed(OBACT);
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
|
|
|
|
void average_charts_tface_uv(void)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
ParamHandle *handle;
|
|
|
|
if(!EM_texFaceCheck()) return;
|
|
|
|
handle = construct_param_handle(em, 1, 0, 1);
|
|
param_average(handle);
|
|
param_flush(handle);
|
|
param_delete(handle);
|
|
|
|
BIF_undo_push("UV average island scale");
|
|
|
|
object_uvs_changed(OBACT);
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
|
|
/* LSCM live mode */
|
|
|
|
static ParamHandle *liveHandle = NULL;
|
|
|
|
void unwrap_lscm_live_begin(void)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
short abf = G.scene->toolsettings->unwrapper == 1;
|
|
short fillholes = G.scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
|
|
|
|
if(!EM_texFaceCheck()) return;
|
|
|
|
liveHandle = construct_param_handle(em, 0, fillholes, 1);
|
|
|
|
param_lscm_begin(liveHandle, PARAM_TRUE, abf);
|
|
}
|
|
|
|
void unwrap_lscm_live_re_solve(void)
|
|
{
|
|
if (liveHandle) {
|
|
param_lscm_solve(liveHandle);
|
|
param_flush(liveHandle);
|
|
}
|
|
}
|
|
|
|
void unwrap_lscm_live_end(short cancel)
|
|
{
|
|
if (liveHandle) {
|
|
param_lscm_end(liveHandle);
|
|
if (cancel)
|
|
param_flush_restore(liveHandle);
|
|
param_delete(liveHandle);
|
|
liveHandle = NULL;
|
|
}
|
|
}
|
|
|