Seam Cutting in Faceselect Mode:
- Mark Border Seam: mark edges on the border of face selection as seam. - Clear Seam: clears seams in selected faces. Hotkey: Ctrl+E - Alt+RMB Click: mark/clear edge as seam - Alt+Shift+RMB Click: mark/clear seams along the shortest/straightest path from last marked seam. The cost of the path also includes some measure of 'straightness' next to the typical distance to make things work more predicatble and edgeloop friendly. Note that this cuts a path from edge to edge, not vertex to vertex. That gives some nice control over the direction of the seam. Also includes: - Removed old LSCM code. - Fix updates glitches with DerivedMesh/Subsurf drawing in FaceSelect mode. Now there's a drawMappedFacesTex instead of drawFacesTex. - Minimize Stretch menu entry called Limit Stitch. - Removed the lasttface global, was being set before it was used anyway, so might as wel return from a function. - Moved some backbuf sampling code to drawview.c from editmesh, so it can be used by Faceselect and VPaint. - Use BLI_heap in parametrizer.c.
This commit is contained in:
@@ -47,7 +47,6 @@
|
||||
|
||||
struct MVert;
|
||||
struct Object;
|
||||
struct TFace;
|
||||
struct EditMesh;
|
||||
struct DispListMesh;
|
||||
struct ModifierData;
|
||||
@@ -144,7 +143,7 @@ struct DerivedMesh {
|
||||
/* Draw all faces uses TFace
|
||||
* o Drawing options too complicated to enumerate, look at code.
|
||||
*/
|
||||
void (*drawFacesTex)(DerivedMesh *dm, int (*setDrawOptions)(struct TFace *tf, int matnr));
|
||||
void (*drawMappedFacesTex)(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int matnr), void *userData);
|
||||
|
||||
/* Draw mapped faces (no color, or texture)
|
||||
* o Only if !setDrawOptions or setDrawOptions(userData, mapped-face-index, drawSmooth_r) returns true
|
||||
|
||||
@@ -366,7 +366,7 @@ static void meshDM_drawFacesColored(DerivedMesh *dm, int useTwoSide, unsigned ch
|
||||
glShadeModel(GL_FLAT);
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
static void meshDM_drawFacesTex(DerivedMesh *dm, int (*setDrawParams)(TFace *tf, int matnr))
|
||||
static void meshDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawParams)(void *userData, int index, int matnr), void *userData)
|
||||
{
|
||||
MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
|
||||
Mesh *me = mdm->me;
|
||||
@@ -382,7 +382,7 @@ static void meshDM_drawFacesTex(DerivedMesh *dm, int (*setDrawParams)(TFace *tf,
|
||||
int flag;
|
||||
unsigned char *cp= NULL;
|
||||
|
||||
flag = setDrawParams(tf, mf->mat_nr);
|
||||
flag = setDrawParams(userData, i, mf->mat_nr);
|
||||
|
||||
if (flag==0) {
|
||||
continue;
|
||||
@@ -535,7 +535,7 @@ static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3]
|
||||
|
||||
mdm->dm.drawFacesSolid = meshDM_drawFacesSolid;
|
||||
mdm->dm.drawFacesColored = meshDM_drawFacesColored;
|
||||
mdm->dm.drawFacesTex = meshDM_drawFacesTex;
|
||||
mdm->dm.drawMappedFacesTex = meshDM_drawMappedFacesTex;
|
||||
mdm->dm.drawMappedFaces = meshDM_drawMappedFaces;
|
||||
|
||||
mdm->dm.drawMappedEdges = meshDM_drawMappedEdges;
|
||||
@@ -1202,7 +1202,8 @@ static void ssDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned cha
|
||||
|
||||
#undef PASSVERT
|
||||
}
|
||||
static void ssDM_drawFacesTex(DerivedMesh *dm, int (*setDrawParams)(TFace *tf, int matnr))
|
||||
|
||||
static void ssDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawParams)(void *userData, int index, int matnr), void *userData)
|
||||
{
|
||||
SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
|
||||
DispListMesh *dlm = ssdm->dlm;
|
||||
@@ -1210,7 +1211,7 @@ static void ssDM_drawFacesTex(DerivedMesh *dm, int (*setDrawParams)(TFace *tf, i
|
||||
MFace *mface= dlm->mface;
|
||||
TFace *tface = dlm->tface;
|
||||
float *nors = dlm->nors;
|
||||
int a;
|
||||
int a, index=-1;
|
||||
|
||||
for (a=0; a<dlm->totface; a++) {
|
||||
MFace *mf= &mface[a];
|
||||
@@ -1218,7 +1219,9 @@ static void ssDM_drawFacesTex(DerivedMesh *dm, int (*setDrawParams)(TFace *tf, i
|
||||
int flag;
|
||||
unsigned char *cp= NULL;
|
||||
|
||||
flag = setDrawParams(tf, mf->mat_nr);
|
||||
if (mf->flag&ME_FACE_STEPINDEX) index++;
|
||||
|
||||
flag = setDrawParams(userData, index, mf->mat_nr);
|
||||
|
||||
if (flag==0) {
|
||||
continue;
|
||||
@@ -1401,7 +1404,7 @@ DerivedMesh *derivedmesh_from_displistmesh(DispListMesh *dlm, float (*vertexCos)
|
||||
|
||||
ssdm->dm.drawFacesSolid = ssDM_drawFacesSolid;
|
||||
ssdm->dm.drawFacesColored = ssDM_drawFacesColored;
|
||||
ssdm->dm.drawFacesTex = ssDM_drawFacesTex;
|
||||
ssdm->dm.drawMappedFacesTex = ssDM_drawMappedFacesTex;
|
||||
ssdm->dm.drawMappedFaces = ssDM_drawMappedFaces;
|
||||
|
||||
/* EM functions */
|
||||
@@ -1624,7 +1627,7 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, DerivedMesh **final_r)
|
||||
ModifierData *md;
|
||||
float (*deformedVerts)[3] = NULL;
|
||||
DerivedMesh *dm;
|
||||
int i, numVerts, cageIndex = modifiers_getCageIndex(ob, NULL);
|
||||
int i, numVerts = 0, cageIndex = modifiers_getCageIndex(ob, NULL);
|
||||
|
||||
modifiers_clearErrors(ob);
|
||||
|
||||
|
||||
@@ -1376,7 +1376,7 @@ static void ccgDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned ch
|
||||
|
||||
ccgFaceIterator_free(fi);
|
||||
}
|
||||
static void ccgDM_drawFacesTex(DerivedMesh *dm, int (*setDrawParams)(TFace *tf, int matnr)) {
|
||||
static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawParams)(void *userData, int index, int matnr), void *userData) {
|
||||
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
|
||||
CCGSubSurf *ss = ccgdm->ss;
|
||||
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
|
||||
@@ -1395,7 +1395,8 @@ static void ccgDM_drawFacesTex(DerivedMesh *dm, int (*setDrawParams)(TFace *tf,
|
||||
MFace *mf = &mface[index];
|
||||
TFace *tf = tface?&tface[index]:NULL;
|
||||
unsigned char *cp= NULL;
|
||||
int flag = setDrawParams(tf, mf->mat_nr);
|
||||
int findex = ccgDM_getFaceMapIndex(ccgdm, ss, f);
|
||||
int flag = (findex == -1)? 0: setDrawParams(userData, findex, mf->mat_nr);
|
||||
|
||||
if (flag==0) {
|
||||
continue;
|
||||
@@ -1662,7 +1663,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss, int fromEditmesh, int d
|
||||
ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges;
|
||||
ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid;
|
||||
ccgdm->dm.drawFacesColored = ccgDM_drawFacesColored;
|
||||
ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex;
|
||||
ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex;
|
||||
ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces;
|
||||
|
||||
ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
|
||||
|
||||
@@ -37,6 +37,7 @@ struct Image;
|
||||
struct TFace;
|
||||
struct Object;
|
||||
struct Mesh;
|
||||
struct EdgeHash;
|
||||
|
||||
/**
|
||||
* Enables or disable mipmapping for realtime images (textures).
|
||||
@@ -74,6 +75,7 @@ void free_all_realtime_images(void);
|
||||
void make_repbind(struct Image *ima);
|
||||
int set_tpage(struct TFace *tface);
|
||||
void draw_tface_mesh(struct Object *ob, struct Mesh *me, int dt);
|
||||
struct EdgeHash *get_tface_mesh_marked_edge_info(struct Mesh *me);
|
||||
void init_realtime_GL(void);
|
||||
|
||||
#endif /* BDR_DRAWMESH_H */
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
struct TFace;
|
||||
struct Mesh;
|
||||
|
||||
void set_lasttface(void);
|
||||
struct TFace *get_active_tface(void);
|
||||
void calculate_uv_map(unsigned short mapmode);
|
||||
void default_uv(float uv[][2], float size);
|
||||
void default_tface(struct TFace *tface);
|
||||
@@ -49,13 +49,13 @@ void selectswap_tface(void);
|
||||
void rotate_uv_tface(void);
|
||||
void mirror_uv_tface(void);
|
||||
void minmax_tface(float *min, float *max);
|
||||
int face_pick(struct Mesh *me, short x, short y, unsigned int *index);
|
||||
void face_select(void);
|
||||
void face_borderselect(void);
|
||||
void uv_autocalc_tface(void);
|
||||
void set_faceselect(void);
|
||||
void face_draw(void);
|
||||
void get_same_uv(void);
|
||||
void seam_mark_clear_tface(short mode);
|
||||
|
||||
#endif /* BDR_EDITFACE_H */
|
||||
|
||||
|
||||
@@ -36,8 +36,7 @@
|
||||
void set_seamtface(void); /* set TF_SEAM flags in tfaces */
|
||||
void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index);
|
||||
|
||||
void unwrap_lscm(void); /* unwrap faces selected in 3d view */
|
||||
void unwrap_lscm_new(void);
|
||||
void unwrap_lscm(short seamcut); /* unwrap faces selected in 3d view */
|
||||
void minimize_stretch_tface_uv(void); /* optimize faces selected in uv editor */
|
||||
void smooth_area_tface_uv(void);
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ struct Object;
|
||||
struct BGpic;
|
||||
struct rcti;
|
||||
struct ScrArea;
|
||||
struct ImBuf;
|
||||
|
||||
void setalpha_bgpic(struct BGpic *bgpic);
|
||||
void default_gl_light(void);
|
||||
@@ -52,6 +53,11 @@ void do_viewbuts(unsigned short event);
|
||||
void add_view3d_after(struct View3D *v3d, struct Base *base, int type);
|
||||
|
||||
void backdrawview3d(int test);
|
||||
void check_backbuf(void);
|
||||
unsigned int sample_backbuf(int x, int y);
|
||||
struct ImBuf *read_backbuf(short xmin, short ymin, short xmax, short ymax);
|
||||
unsigned int sample_backbuf_rect(short mval[2], int size, unsigned int min, unsigned int max, short *dist);;
|
||||
|
||||
void drawview3dspace(struct ScrArea *sa, void *spacedata);
|
||||
void drawview3d_render(struct View3D *v3d, int winx, int winy);
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ extern void do_latticebuts(unsigned short event);
|
||||
extern void do_fpaintbuts(unsigned short event);
|
||||
extern void do_cambuts(unsigned short event);
|
||||
extern void do_armbuts(unsigned short event);
|
||||
extern void do_uvautocalculationbuts(unsigned short event);
|
||||
|
||||
extern char *get_vertexgroup_menustr(struct Object *ob); // used in object buttons
|
||||
|
||||
@@ -113,11 +114,6 @@ extern void do_scriptbuts(unsigned short event);
|
||||
/* ipowindow */
|
||||
extern void do_ipobuts(unsigned short event); // drawipo.c (bad! ton)
|
||||
|
||||
/* uvautocalculation */
|
||||
void do_uvautocalculationbuts(unsigned short event);
|
||||
void get_uvautocalculationsettings(float *radius,float *cubesize, int *mapdir, int *mapalign);
|
||||
|
||||
|
||||
/* butspace.c */
|
||||
void test_meshpoin_but(char *name, struct ID **idpp);
|
||||
void test_obpoin_but(char *name, struct ID **idpp);
|
||||
|
||||
@@ -155,14 +155,14 @@ typedef struct Mesh {
|
||||
#define TF_SUB 3
|
||||
|
||||
/* tface->unwrap */
|
||||
#define TF_SEAM1 1
|
||||
#define TF_SEAM2 2
|
||||
#define TF_SEAM3 4
|
||||
#define TF_SEAM4 8
|
||||
#define TF_PIN1 16
|
||||
#define TF_PIN2 32
|
||||
#define TF_PIN3 64
|
||||
#define TF_PIN4 128
|
||||
#define TF_DEPRECATED1 1
|
||||
#define TF_DEPRECATED2 2
|
||||
#define TF_DEPRECATED3 4
|
||||
#define TF_DEPRECATED4 8
|
||||
#define TF_PIN1 16
|
||||
#define TF_PIN2 32
|
||||
#define TF_PIN3 64
|
||||
#define TF_PIN4 128
|
||||
|
||||
#define MESH_MAX_VERTS 2000000000L
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ typedef struct MSticky {
|
||||
// reserve 16 for ME_HIDE
|
||||
#define ME_EDGERENDER (1<<5)
|
||||
#define ME_LOOSEEDGE (1<<7)
|
||||
#define ME_SEAM_LAST (1<<8)
|
||||
#define ME_EDGE_STEPINDEX (1<<15)
|
||||
|
||||
/* puno = vertexnormal (mface) */
|
||||
|
||||
@@ -580,7 +580,7 @@ void do_butspace(unsigned short event)
|
||||
do_constraintbuts(event);
|
||||
}
|
||||
else if(event<=B_UVAUTOCALCBUTS) {
|
||||
do_uvautocalculationbuts(event);
|
||||
do_uvcalculationbuts(event);
|
||||
}
|
||||
else if(event<=B_EFFECTSBUTS) {
|
||||
do_effects_panels(event);
|
||||
|
||||
@@ -3540,7 +3540,8 @@ void do_fpaintbuts(unsigned short event)
|
||||
Mesh *me;
|
||||
Object *ob;
|
||||
bDeformGroup *defGroup;
|
||||
extern TFace *lasttface; /* caches info on tface bookkeeping ?*/
|
||||
TFace *activetf, *tf;
|
||||
int a;
|
||||
extern VPaint Gwp; /* from vpaint */
|
||||
|
||||
ob= OBACT;
|
||||
@@ -3555,42 +3556,37 @@ void do_fpaintbuts(unsigned short event)
|
||||
case B_COPY_TF_UV:
|
||||
case B_COPY_TF_COL:
|
||||
case B_COPY_TF_TEX:
|
||||
me= get_mesh(ob);
|
||||
if(me && me->tface) {
|
||||
/* extern TFace *lasttface; */
|
||||
TFace *tface= me->tface;
|
||||
int a= me->totface;
|
||||
me = get_mesh(OBACT);
|
||||
activetf = get_active_tface();
|
||||
|
||||
set_lasttface();
|
||||
if(lasttface) {
|
||||
|
||||
while(a--) {
|
||||
if(tface!=lasttface && (tface->flag & TF_SELECT)) {
|
||||
if(event==B_COPY_TF_MODE) {
|
||||
tface->mode= lasttface->mode;
|
||||
tface->transp= lasttface->transp;
|
||||
}
|
||||
else if(event==B_COPY_TF_UV) {
|
||||
memcpy(tface->uv, lasttface->uv, sizeof(tface->uv));
|
||||
tface->tpage= lasttface->tpage;
|
||||
tface->tile= lasttface->tile;
|
||||
|
||||
if(lasttface->mode & TF_TILES) tface->mode |= TF_TILES;
|
||||
else tface->mode &= ~TF_TILES;
|
||||
|
||||
}
|
||||
else if(event==B_COPY_TF_TEX) {
|
||||
tface->tpage= lasttface->tpage;
|
||||
tface->tile= lasttface->tile;
|
||||
|
||||
if(lasttface->mode & TF_TILES) tface->mode |= TF_TILES;
|
||||
else tface->mode &= ~TF_TILES;
|
||||
}
|
||||
else if(event==B_COPY_TF_COL) memcpy(tface->col, lasttface->col, sizeof(tface->col));
|
||||
if(me && activetf) {
|
||||
for (a=0, tf=me->tface; a < me->totface; a++, tf++) {
|
||||
if(tf!=activetf && (tf->flag & TF_SELECT)) {
|
||||
if(event==B_COPY_TF_MODE) {
|
||||
tf->mode= activetf->mode;
|
||||
tf->transp= activetf->transp;
|
||||
}
|
||||
tface++;
|
||||
else if(event==B_COPY_TF_UV) {
|
||||
memcpy(tf->uv, activetf->uv, sizeof(tf->uv));
|
||||
tf->tpage= activetf->tpage;
|
||||
tf->tile= activetf->tile;
|
||||
|
||||
if(activetf->mode & TF_TILES) tf->mode |= TF_TILES;
|
||||
else tf->mode &= ~TF_TILES;
|
||||
|
||||
}
|
||||
else if(event==B_COPY_TF_TEX) {
|
||||
tf->tpage= activetf->tpage;
|
||||
tf->tile= activetf->tile;
|
||||
|
||||
if(activetf->mode & TF_TILES) tf->mode |= TF_TILES;
|
||||
else tf->mode &= ~TF_TILES;
|
||||
}
|
||||
else if(event==B_COPY_TF_COL)
|
||||
memcpy(tf->col, activetf->col, sizeof(tf->col));
|
||||
}
|
||||
}
|
||||
|
||||
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
|
||||
do_shared_vertexcol(me);
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
@@ -3616,17 +3612,17 @@ void do_fpaintbuts(unsigned short event)
|
||||
break;
|
||||
|
||||
case B_TFACE_HALO:
|
||||
set_lasttface();
|
||||
if(lasttface) {
|
||||
lasttface->mode &= ~TF_BILLBOARD2;
|
||||
activetf = get_active_tface();
|
||||
if(activetf) {
|
||||
activetf->mode &= ~TF_BILLBOARD2;
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case B_TFACE_BILLB:
|
||||
set_lasttface();
|
||||
if(lasttface) {
|
||||
lasttface->mode &= ~TF_BILLBOARD;
|
||||
activetf = get_active_tface();
|
||||
if(activetf) {
|
||||
activetf->mode &= ~TF_BILLBOARD;
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
}
|
||||
break;
|
||||
@@ -3786,38 +3782,37 @@ static void editing_panel_mesh_texface(void)
|
||||
{
|
||||
extern VPaint Gvp; /* from vpaint */
|
||||
uiBlock *block;
|
||||
extern TFace *lasttface;
|
||||
TFace *tf;
|
||||
|
||||
block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_texface", UI_EMBOSS, UI_HELV, curarea->win);
|
||||
if(uiNewPanel(curarea, block, "Texture face", "Editing", 960, 0, 318, 204)==0) return;
|
||||
|
||||
set_lasttface(); // checks for ob type
|
||||
if(lasttface) {
|
||||
tf = get_active_tface();
|
||||
if(tf) {
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButBitS(block, TOG, TF_TEX, B_REDR_3D_IMA, "Tex", 600,160,60,19, &tf->mode, 0, 0, 0, 0, "Render face with texture");
|
||||
uiDefButBitS(block, TOG, TF_TILES, B_REDR_3D_IMA, "Tiles", 660,160,60,19, &tf->mode, 0, 0, 0, 0, "Use tilemode for face");
|
||||
uiDefButBitS(block, TOG, TF_LIGHT, REDRAWVIEW3D, "Light", 720,160,60,19, &tf->mode, 0, 0, 0, 0, "Use light for face");
|
||||
uiDefButBitS(block, TOG, TF_INVISIBLE, REDRAWVIEW3D, "Invisible",780,160,60,19, &tf->mode, 0, 0, 0, 0, "Make face invisible");
|
||||
uiDefButBitS(block, TOG, TF_DYNAMIC, REDRAWVIEW3D, "Collision", 840,160,60,19, &tf->mode, 0, 0, 0, 0, "Use face for collision detection");
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButBitS(block, TOG, TF_TEX, B_REDR_3D_IMA, "Tex", 600,160,60,19, &lasttface->mode, 0, 0, 0, 0, "Render face with texture");
|
||||
uiDefButBitS(block, TOG, TF_TILES, B_REDR_3D_IMA, "Tiles", 660,160,60,19, &lasttface->mode, 0, 0, 0, 0, "Use tilemode for face");
|
||||
uiDefButBitS(block, TOG, TF_LIGHT, REDRAWVIEW3D, "Light", 720,160,60,19, &lasttface->mode, 0, 0, 0, 0, "Use light for face");
|
||||
uiDefButBitS(block, TOG, TF_INVISIBLE, REDRAWVIEW3D, "Invisible",780,160,60,19, &lasttface->mode, 0, 0, 0, 0, "Make face invisible");
|
||||
uiDefButBitS(block, TOG, TF_DYNAMIC, REDRAWVIEW3D, "Collision", 840,160,60,19, &lasttface->mode, 0, 0, 0, 0, "Use face for collision detection");
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButBitS(block, TOG, TF_SHAREDCOL, REDRAWVIEW3D, "Shared", 600,135,60,19, &lasttface->mode, 0, 0, 0, 0, "Blend vertex colours across face when vertices are shared");
|
||||
uiDefButBitS(block, TOG, TF_TWOSIDE, REDRAWVIEW3D, "Twoside",660,135,60,19, &lasttface->mode, 0, 0, 0, 0, "Render face twosided");
|
||||
uiDefButBitS(block, TOG, TF_OBCOL, REDRAWVIEW3D, "ObColor",720,135,60,19, &lasttface->mode, 0, 0, 0, 0, "Use ObColor instead of vertex colours");
|
||||
uiDefButBitS(block, TOG, TF_SHAREDCOL, REDRAWVIEW3D, "Shared", 600,135,60,19, &tf->mode, 0, 0, 0, 0, "Blend vertex colours across face when vertices are shared");
|
||||
uiDefButBitS(block, TOG, TF_TWOSIDE, REDRAWVIEW3D, "Twoside",660,135,60,19, &tf->mode, 0, 0, 0, 0, "Render face twosided");
|
||||
uiDefButBitS(block, TOG, TF_OBCOL, REDRAWVIEW3D, "ObColor",720,135,60,19, &tf->mode, 0, 0, 0, 0, "Use ObColor instead of vertex colours");
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
|
||||
uiDefButBitS(block, TOG, TF_BILLBOARD, B_TFACE_HALO, "Halo", 600,110,60,19, &lasttface->mode, 0, 0, 0, 0, "Screen aligned billboard");
|
||||
uiDefButBitS(block, TOG, TF_BILLBOARD2, B_TFACE_BILLB, "Billboard",660,110,60,19, &lasttface->mode, 0, 0, 0, 0, "Billboard with Z-axis constraint");
|
||||
uiDefButBitS(block, TOG, TF_SHADOW, REDRAWVIEW3D, "Shadow", 720,110,60,19, &lasttface->mode, 0, 0, 0, 0, "Face is used for shadow");
|
||||
uiDefButBitS(block, TOG, TF_BMFONT, REDRAWVIEW3D, "Text", 780,110,60,19, &lasttface->mode, 0, 0, 0, 0, "Enable bitmap text on face");
|
||||
uiDefButBitS(block, TOG, TF_BILLBOARD, B_TFACE_HALO, "Halo", 600,110,60,19, &tf->mode, 0, 0, 0, 0, "Screen aligned billboard");
|
||||
uiDefButBitS(block, TOG, TF_BILLBOARD2, B_TFACE_BILLB, "Billboard",660,110,60,19, &tf->mode, 0, 0, 0, 0, "Billboard with Z-axis constraint");
|
||||
uiDefButBitS(block, TOG, TF_SHADOW, REDRAWVIEW3D, "Shadow", 720,110,60,19, &tf->mode, 0, 0, 0, 0, "Face is used for shadow");
|
||||
uiDefButBitS(block, TOG, TF_BMFONT, REDRAWVIEW3D, "Text", 780,110,60,19, &tf->mode, 0, 0, 0, 0, "Enable bitmap text on face");
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
uiBlockSetCol(block, TH_BUT_SETTING1);
|
||||
uiDefButC(block, ROW, REDRAWVIEW3D, "Opaque", 600,80,60,19, &lasttface->transp, 2.0, 0.0, 0, 0, "Render colour of textured face as colour");
|
||||
uiDefButC(block, ROW, REDRAWVIEW3D, "Add", 660,80,60,19, &lasttface->transp, 2.0, 1.0, 0, 0, "Render face transparent and add colour of face");
|
||||
uiDefButC(block, ROW, REDRAWVIEW3D, "Alpha", 720,80,60,19, &lasttface->transp, 2.0, 2.0, 0, 0, "Render polygon transparent, depending on alpha channel of the texture");
|
||||
uiDefButC(block, ROW, REDRAWVIEW3D, "Opaque", 600,80,60,19, &tf->transp, 2.0, 0.0, 0, 0, "Render colour of textured face as colour");
|
||||
uiDefButC(block, ROW, REDRAWVIEW3D, "Add", 660,80,60,19, &tf->transp, 2.0, 1.0, 0, 0, "Render face transparent and add colour of face");
|
||||
uiDefButC(block, ROW, REDRAWVIEW3D, "Alpha", 720,80,60,19, &tf->transp, 2.0, 2.0, 0, 0, "Render polygon transparent, depending on alpha channel of the texture");
|
||||
|
||||
uiBlockSetCol(block, TH_AUTO);
|
||||
|
||||
@@ -3832,29 +3827,9 @@ static void editing_panel_mesh_texface(void)
|
||||
}
|
||||
}
|
||||
|
||||
void do_uvautocalculationbuts(unsigned short event)
|
||||
void do_uvcalculationbuts(unsigned short event)
|
||||
{
|
||||
switch(event) {
|
||||
case B_UVAUTO_STD1:
|
||||
case B_UVAUTO_STD2:
|
||||
case B_UVAUTO_STD4:
|
||||
case B_UVAUTO_STD8:
|
||||
case B_UVAUTO_CUBE:
|
||||
calculate_uv_map(event);
|
||||
break;
|
||||
case B_UVAUTO_BOUNDS1:
|
||||
case B_UVAUTO_BOUNDS2:
|
||||
case B_UVAUTO_BOUNDS4:
|
||||
case B_UVAUTO_BOUNDS8:
|
||||
case B_UVAUTO_SPHERE:
|
||||
case B_UVAUTO_CYLINDER:
|
||||
case B_UVAUTO_WINDOW:
|
||||
if(select_area(SPACE_VIEW3D)) calculate_uv_map(event);
|
||||
break;
|
||||
case B_UVAUTO_UNWRAP:
|
||||
unwrap_lscm();
|
||||
break;
|
||||
}
|
||||
/* nothing to do here */
|
||||
}
|
||||
|
||||
static void editing_panel_mesh_uvautocalculation(void)
|
||||
@@ -3877,9 +3852,8 @@ static void editing_panel_mesh_uvautocalculation(void)
|
||||
row-= 4*butHB+butS;
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButS(block, MENU, REDRAWBUTSEDIT, "Unwrapper%t|Conformal%x0|Angle Based%x1|Conformal (Old)%x2",100,row,200,butH, &G.scene->toolsettings->unwrapper, 0, 0, 0, 0, "Unwrap method");
|
||||
if (G.scene->toolsettings->unwrapper != 2)
|
||||
uiDefButBitS(block, TOG, 1, B_NOP, "Fill Holes",100,row-butHB,200,butH,&G.scene->toolsettings->uvcalc_flag, 0, 0, 0, 0, "Fill holes to prevent internal overlaps");
|
||||
uiDefButS(block, MENU, REDRAWBUTSEDIT, "Unwrapper%t|Conformal%x0|Angle Based%x1",100,row,200,butH, &G.scene->toolsettings->unwrapper, 0, 0, 0, 0, "Unwrap method");
|
||||
uiDefButBitS(block, TOG, 1, B_NOP, "Fill Holes",100,row-butHB,200,butH,&G.scene->toolsettings->uvcalc_flag, 0, 0, 0, 0, "Fill holes to prevent internal overlaps");
|
||||
uiBlockEndAlign(block);
|
||||
row-= 2*butHB+butS;
|
||||
|
||||
|
||||
@@ -205,24 +205,24 @@ void calc_image_view(SpaceImage *sima, char mode)
|
||||
|
||||
void what_image(SpaceImage *sima)
|
||||
{
|
||||
extern TFace *lasttface; /* editface.c */
|
||||
TFace *activetf;
|
||||
Mesh *me;
|
||||
|
||||
if(sima->mode==SI_TEXTURE) {
|
||||
if(G.f & G_FACESELECT) {
|
||||
|
||||
sima->image= 0;
|
||||
me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
|
||||
set_lasttface();
|
||||
me= get_mesh(OBACT);
|
||||
activetf = get_active_tface();
|
||||
|
||||
if(me && me->tface && lasttface && lasttface->mode & TF_TEX) {
|
||||
sima->image= lasttface->tpage;
|
||||
if(me && me->tface && activetf && activetf->mode & TF_TEX) {
|
||||
sima->image= activetf->tpage;
|
||||
|
||||
if(sima->flag & SI_EDITTILE);
|
||||
else sima->curtile= lasttface->tile;
|
||||
else sima->curtile= activetf->tile;
|
||||
|
||||
if(sima->image) {
|
||||
if(lasttface->mode & TF_TILES)
|
||||
if(activetf->mode & TF_TILES)
|
||||
sima->image->tpageflag |= IMA_TILES;
|
||||
else sima->image->tpageflag &= ~IMA_TILES;
|
||||
}
|
||||
|
||||
@@ -515,7 +515,8 @@ static void get_marked_edge_info__orFlags(EdgeHash *eh, int v0, int v1, int flag
|
||||
flags_p = (int*) BLI_edgehash_lookup_p(eh, v0, v1);
|
||||
*flags_p |= flags;
|
||||
}
|
||||
static EdgeHash *get_marked_edge_info(Mesh *me)
|
||||
|
||||
EdgeHash *get_tface_mesh_marked_edge_info(Mesh *me)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new();
|
||||
int i;
|
||||
@@ -618,20 +619,25 @@ static int draw_tfaces3D__setActiveOpts(void *userData, int index)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static int draw_tfaces3D__drawFaceOpts(TFace *tface, int matnr)
|
||||
static int draw_tfaces3D__drawFaceOpts(void *userData, int index, int matnr)
|
||||
{
|
||||
if (tface && !(tface->flag&TF_HIDE) && (tface->flag&TF_SELECT)) {
|
||||
return 2; /* Don't set color */
|
||||
} else {
|
||||
Mesh *me = (Mesh*)userData;
|
||||
|
||||
if (me->tface) {
|
||||
TFace *tface = &me->tface[index];
|
||||
if (!(tface->flag&TF_HIDE) && (tface->flag&TF_SELECT))
|
||||
return 2; /* Don't set color */
|
||||
else
|
||||
return 0;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static void draw_tfaces3D(Object *ob, Mesh *me, DerivedMesh *dm)
|
||||
{
|
||||
struct { Mesh *me; EdgeHash *eh; } data;
|
||||
|
||||
data.me = me;
|
||||
data.eh = get_marked_edge_info(me);
|
||||
data.eh = get_tface_mesh_marked_edge_info(me);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
@@ -657,7 +663,7 @@ static void draw_tfaces3D(Object *ob, Mesh *me, DerivedMesh *dm)
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
BIF_ThemeColor4(TH_FACE_SELECT);
|
||||
|
||||
dm->drawFacesTex(dm, draw_tfaces3D__drawFaceOpts);
|
||||
dm->drawMappedFacesTex(dm, draw_tfaces3D__drawFaceOpts, (void*)me);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
@@ -838,8 +844,11 @@ static Object *g_draw_tface_mesh_ob = NULL;
|
||||
static int g_draw_tface_mesh_islight = 0;
|
||||
static int g_draw_tface_mesh_istex = 0;
|
||||
static unsigned char g_draw_tface_mesh_obcol[4];
|
||||
static int draw_tface_mesh__set_draw(TFace *tface, int matnr)
|
||||
static int draw_tface_mesh__set_draw(void *userData, int index, int matnr)
|
||||
{
|
||||
Mesh *me = (Mesh*)userData;
|
||||
TFace *tface = (me->tface)? &me->tface[index]: NULL;
|
||||
|
||||
if (tface && ((tface->flag&TF_HIDE) || (tface->mode&TF_INVISIBLE))) return 0;
|
||||
|
||||
if (set_draw_settings_cached(0, g_draw_tface_mesh_istex, tface, g_draw_tface_mesh_islight, g_draw_tface_mesh_ob, matnr, TF_TWOSIDE)) {
|
||||
@@ -901,7 +910,7 @@ void draw_tface_mesh(Object *ob, Mesh *me, int dt)
|
||||
int editing= (G.f & (G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT)) && (ob==((G.scene->basact) ? (G.scene->basact->object) : 0));
|
||||
int start, totface;
|
||||
|
||||
dm->drawFacesTex(dm, draw_tface_mesh__set_draw);
|
||||
dm->drawMappedFacesTex(dm, draw_tface_mesh__set_draw, (void*)me);
|
||||
|
||||
start = 0;
|
||||
totface = me->totface;
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_editVert.h"
|
||||
#include "BLI_edgehash.h"
|
||||
|
||||
#include "BKE_utildefines.h"
|
||||
#include "BKE_curve.h"
|
||||
@@ -4110,17 +4111,47 @@ static int bbs_mesh_solid__setDrawOpts(void *userData, int index, int *drawSmoot
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int bbs_mesh_wire__setDrawOpts(void *userData, int index)
|
||||
{
|
||||
struct { Mesh *me; EdgeHash *eh; int offset; } *data = userData;
|
||||
MEdge *med = data->me->medge + index;
|
||||
unsigned int flags = (int)BLI_edgehash_lookup(data->eh, med->v1, med->v2);
|
||||
|
||||
if (flags & 1) {
|
||||
set_framebuffer_index_color(data->offset+index);
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bbs_mesh_solid(Object *ob)
|
||||
{
|
||||
int dmNeedsFree;
|
||||
DerivedMesh *dm = mesh_get_derived_final(ob, &dmNeedsFree);
|
||||
Mesh *me = (Mesh*)ob->data;
|
||||
|
||||
glColor3ub(0, 0, 0);
|
||||
dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, ob->data, 0);
|
||||
|
||||
if (dmNeedsFree) {
|
||||
dm->release(dm);
|
||||
dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, me, 0);
|
||||
|
||||
/* draw edges for seam marking in faceselect mode, but not when painting,
|
||||
so that painting doesn't get interrupted on an edge */
|
||||
if ((G.f & G_FACESELECT) && !(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))) {
|
||||
struct { Mesh *me; EdgeHash *eh; int offset; } userData;
|
||||
|
||||
userData.me = me;
|
||||
userData.eh = get_tface_mesh_marked_edge_info(me);
|
||||
userData.offset = userData.me->totface+1;
|
||||
|
||||
bglPolygonOffset(1.0);
|
||||
dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOpts, (void*)&userData);
|
||||
bglPolygonOffset(0.0);
|
||||
|
||||
BLI_edgehash_free(userData.eh, NULL);
|
||||
}
|
||||
|
||||
if (dmNeedsFree)
|
||||
dm->release(dm);
|
||||
}
|
||||
|
||||
void draw_object_backbufsel(Object *ob)
|
||||
@@ -4145,7 +4176,7 @@ void draw_object_backbufsel(Object *ob)
|
||||
|
||||
// we draw edges always, for loop (select) tools
|
||||
em_wireoffs= bbs_mesh_wire(dm, em_solidoffs);
|
||||
|
||||
|
||||
if(G.scene->selectmode & SCE_SELECT_VERTEX)
|
||||
em_vertoffs= bbs_mesh_verts(dm, em_wireoffs);
|
||||
else em_vertoffs= em_wireoffs;
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "BMF_Api.h"
|
||||
|
||||
#include "IMB_imbuf_types.h"
|
||||
#include "IMB_imbuf.h"
|
||||
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
@@ -1054,7 +1055,143 @@ void backdrawview3d(int test)
|
||||
|
||||
}
|
||||
|
||||
void check_backbuf(void)
|
||||
{
|
||||
if(G.vd->flag & V3D_NEEDBACKBUFDRAW)
|
||||
backdrawview3d(0);
|
||||
}
|
||||
|
||||
/* samples a single pixel (copied from vpaint) */
|
||||
unsigned int sample_backbuf(int x, int y)
|
||||
{
|
||||
unsigned int col;
|
||||
|
||||
if(x>=curarea->winx || y>=curarea->winy) return 0;
|
||||
x+= curarea->winrct.xmin;
|
||||
y+= curarea->winrct.ymin;
|
||||
|
||||
check_backbuf(); // actually not needed for apple
|
||||
|
||||
#ifdef __APPLE__
|
||||
glReadBuffer(GL_AUX0);
|
||||
#endif
|
||||
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
|
||||
glReadBuffer(GL_BACK);
|
||||
|
||||
if(G.order==B_ENDIAN) SWITCH_INT(col);
|
||||
|
||||
return framebuffer_to_index(col);
|
||||
}
|
||||
|
||||
/* reads full rect, converts indices */
|
||||
ImBuf *read_backbuf(short xmin, short ymin, short xmax, short ymax)
|
||||
{
|
||||
unsigned int *dr, *rd;
|
||||
struct ImBuf *ibuf, *ibuf1;
|
||||
int a;
|
||||
short xminc, yminc, xmaxc, ymaxc, xs, ys;
|
||||
|
||||
/* clip */
|
||||
if(xmin<0) xminc= 0; else xminc= xmin;
|
||||
if(xmax>=curarea->winx) xmaxc= curarea->winx-1; else xmaxc= xmax;
|
||||
if(xminc > xmaxc) return NULL;
|
||||
|
||||
if(ymin<0) yminc= 0; else yminc= ymin;
|
||||
if(ymax>=curarea->winy) ymaxc= curarea->winy-1; else ymaxc= ymax;
|
||||
if(yminc > ymaxc) return NULL;
|
||||
|
||||
ibuf= IMB_allocImBuf((xmaxc-xminc+1),(ymaxc-yminc+1),32,IB_rect,0);
|
||||
|
||||
check_backbuf(); // actually not needed for apple
|
||||
|
||||
#ifdef __APPLE__
|
||||
glReadBuffer(GL_AUX0);
|
||||
#endif
|
||||
glReadPixels(curarea->winrct.xmin+xminc, curarea->winrct.ymin+yminc, (xmaxc-xminc+1), (ymaxc-yminc+1), GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
|
||||
glReadBuffer(GL_BACK);
|
||||
|
||||
if(G.order==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
|
||||
|
||||
a= (xmaxc-xminc+1)*(ymaxc-yminc+1);
|
||||
dr= ibuf->rect;
|
||||
while(a--) {
|
||||
if(*dr) *dr= framebuffer_to_index(*dr);
|
||||
dr++;
|
||||
}
|
||||
|
||||
/* put clipped result back, if needed */
|
||||
if(xminc==xmin && xmaxc==xmax && yminc==ymin && ymaxc==ymax) return ibuf;
|
||||
ibuf1= IMB_allocImBuf( (xmax-xmin+1),(ymax-ymin+1),32,IB_rect,0);
|
||||
rd= ibuf->rect;
|
||||
dr= ibuf1->rect;
|
||||
|
||||
for(ys= ymin; ys<=ymax; ys++) {
|
||||
for(xs= xmin; xs<=xmax; xs++, dr++) {
|
||||
if( xs>=xminc && xs<=xmaxc && ys>=yminc && ys<=ymaxc) {
|
||||
*dr= *rd;
|
||||
rd++;
|
||||
}
|
||||
}
|
||||
}
|
||||
IMB_freeImBuf(ibuf);
|
||||
return ibuf1;
|
||||
}
|
||||
|
||||
/* smart function to sample a rect spiralling outside, nice for backbuf selection */
|
||||
unsigned int sample_backbuf_rect(short mval[2], int size, unsigned int min, unsigned int max, short *dist)
|
||||
{
|
||||
struct ImBuf *buf;
|
||||
unsigned int *bufmin, *bufmax, *tbuf;
|
||||
int minx, miny;
|
||||
int a, b, rc, nr, amount, dirvec[4][2];
|
||||
short distance=0;
|
||||
unsigned int index = 0;
|
||||
|
||||
amount= (size-1)/2;
|
||||
|
||||
minx = mval[0]-(amount+1);
|
||||
miny = mval[1]-(amount+1);
|
||||
buf = read_backbuf(minx, miny, minx+size-1, miny+size-1);
|
||||
if (!buf) return 0;
|
||||
|
||||
rc= 0;
|
||||
|
||||
dirvec[0][0]= 1; dirvec[0][1]= 0;
|
||||
dirvec[1][0]= 0; dirvec[1][1]= -size;
|
||||
dirvec[2][0]= -1; dirvec[2][1]= 0;
|
||||
dirvec[3][0]= 0; dirvec[3][1]= size;
|
||||
|
||||
bufmin = buf->rect;
|
||||
tbuf = buf->rect;
|
||||
bufmax = buf->rect + size*size;
|
||||
tbuf+= amount*size+ amount;
|
||||
|
||||
for(nr=1; nr<=size; nr++) {
|
||||
|
||||
for(a=0; a<2; a++) {
|
||||
for(b=0; b<nr; b++, distance++) {
|
||||
if (*tbuf && *tbuf>=min && *tbuf<max) {
|
||||
*dist= (short) sqrt( (float)distance ); // XXX, this distance is wrong - zr
|
||||
index = *tbuf - min+1; // messy yah, but indices start at 1
|
||||
goto exit;
|
||||
}
|
||||
|
||||
tbuf+= (dirvec[rc][0]+dirvec[rc][1]);
|
||||
|
||||
if(tbuf<bufmin || tbuf>=bufmax) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
rc++;
|
||||
rc &= 3;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
IMB_freeImBuf(buf);
|
||||
return index;
|
||||
}
|
||||
|
||||
void drawname(Object *ob)
|
||||
{
|
||||
cpack(0x404040);
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_heap.h"
|
||||
#include "BLI_edgehash.h"
|
||||
|
||||
#include "MTC_matrixops.h"
|
||||
|
||||
@@ -91,7 +93,59 @@
|
||||
|
||||
#include "BDR_unwrapper.h"
|
||||
|
||||
TFace *lasttface=NULL;
|
||||
/* returns 0 if not found, otherwise 1 */
|
||||
static int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect)
|
||||
{
|
||||
if (!me->tface || me->totface==0)
|
||||
return 0;
|
||||
|
||||
if (G.vd->flag & V3D_NEEDBACKBUFDRAW) {
|
||||
check_backbuf();
|
||||
persp(PERSP_VIEW);
|
||||
}
|
||||
|
||||
if (rect) {
|
||||
/* sample rect to increase changes of selecting, so that when clicking
|
||||
on an edge in the backbuf, we can still select a face */
|
||||
short dist;
|
||||
*index = sample_backbuf_rect(mval, 3, 1, me->totface+1, &dist);
|
||||
}
|
||||
else
|
||||
/* sample only on the exact position */
|
||||
*index = sample_backbuf(mval[0], mval[1]);
|
||||
|
||||
if ((*index)<=0 || (*index)>(unsigned int)me->totface)
|
||||
return 0;
|
||||
|
||||
(*index)--;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* returns 0 if not found, otherwise 1 */
|
||||
static int facesel_edge_pick(Mesh *me, short *mval, unsigned int *index)
|
||||
{
|
||||
short dist;
|
||||
unsigned int min = me->totface + 1;
|
||||
unsigned int max = me->totface + me->totedge + 1;
|
||||
|
||||
if (me->totedge == 0)
|
||||
return 0;
|
||||
|
||||
if (G.vd->flag & V3D_NEEDBACKBUFDRAW) {
|
||||
check_backbuf();
|
||||
persp(PERSP_VIEW);
|
||||
}
|
||||
|
||||
*index = sample_backbuf_rect(mval, 50, min, max, &dist);
|
||||
|
||||
if (*index == 0)
|
||||
return 0;
|
||||
|
||||
(*index)--;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void uv_calc_center_vector(float *result, Object *ob, Mesh *me)
|
||||
{
|
||||
@@ -487,47 +541,32 @@ void calculate_uv_map(unsigned short mapmode)
|
||||
allqueue(REDRAWIMAGE, 0);
|
||||
}
|
||||
|
||||
void set_lasttface()
|
||||
TFace *get_active_tface()
|
||||
{
|
||||
Mesh *me;
|
||||
TFace *tface;
|
||||
TFace *tf;
|
||||
int a;
|
||||
|
||||
lasttface= 0;
|
||||
if(OBACT==NULL || OBACT->type!=OB_MESH) return;
|
||||
if(OBACT==NULL || OBACT->type!=OB_MESH)
|
||||
return NULL;
|
||||
|
||||
me= get_mesh(OBACT);
|
||||
if(me==0 || me->tface==0) return;
|
||||
if(me==0 || me->tface==0)
|
||||
return NULL;
|
||||
|
||||
tface= me->tface;
|
||||
a= me->totface;
|
||||
while(a--) {
|
||||
if(tface->flag & TF_ACTIVE) {
|
||||
lasttface= tface;
|
||||
return;
|
||||
}
|
||||
tface++;
|
||||
}
|
||||
for(a=0, tf=me->tface; a < me->totface; a++, tf++)
|
||||
if(tf->flag & TF_ACTIVE)
|
||||
return tf;
|
||||
|
||||
tface= me->tface;
|
||||
a= me->totface;
|
||||
while(a--) {
|
||||
if(tface->flag & TF_SELECT) {
|
||||
lasttface= tface;
|
||||
return;
|
||||
}
|
||||
tface++;
|
||||
}
|
||||
for(a=0, tf=me->tface; a < me->totface; a++, tf++)
|
||||
if(tf->flag & TF_SELECT)
|
||||
return tf;
|
||||
|
||||
tface= me->tface;
|
||||
a= me->totface;
|
||||
while(a--) {
|
||||
if((tface->flag & TF_HIDE)==0) {
|
||||
lasttface= tface;
|
||||
return;
|
||||
}
|
||||
tface++;
|
||||
}
|
||||
for(a=0, tf=me->tface; a < me->totface; a++, tf++)
|
||||
if((tf->flag & TF_HIDE)==0)
|
||||
return tf;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void default_uv(float uv[][2], float size)
|
||||
@@ -660,7 +699,7 @@ void select_linked_tfaces(int mode)
|
||||
error("The active object is not in this layer");
|
||||
|
||||
getmouseco_areawin(mval);
|
||||
if (!face_pick(me, mval[0], mval[1], &index)) return;
|
||||
if (!facesel_face_pick(me, mval, &index, 1)) return;
|
||||
}
|
||||
|
||||
select_linked_tfaces_with_seams(mode, me, index);
|
||||
@@ -910,55 +949,275 @@ void minmax_tface(float *min, float *max)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the face under the give position in screen coordinates.
|
||||
* Code extracted from face_select routine.
|
||||
* Question: why is all of the backbuffer drawn?
|
||||
* We're only interested in one pixel!
|
||||
* @author Maarten Gribnau
|
||||
* @param me the mesh with the faces to be picked
|
||||
* @param x the x-coordinate to pick at
|
||||
* @param y the y-coordinate to pick at
|
||||
* @param index the index of the face
|
||||
* @return 1 if found, 0 if none found
|
||||
*/
|
||||
int face_pick(Mesh *me, short x, short y, unsigned int *index)
|
||||
#define ME_SEAM_DONE ME_SEAM_LAST /* reuse this flag */
|
||||
|
||||
static float seam_cut_cost(Mesh *me, int e1, int e2, int vert)
|
||||
{
|
||||
unsigned int col;
|
||||
MVert *v = me->mvert + vert;
|
||||
MEdge *med1 = me->medge + e1, *med2 = me->medge + e2;
|
||||
MVert *v1 = me->mvert + ((med1->v1 == vert)? med1->v2: med1->v1);
|
||||
MVert *v2 = me->mvert + ((med2->v1 == vert)? med2->v2: med2->v1);
|
||||
float cost, d1[3], d2[3];
|
||||
|
||||
if (me==0 || me->tface==0)
|
||||
return 0;
|
||||
cost = VecLenf(v1->co, v->co);
|
||||
cost += VecLenf(v->co, v2->co);
|
||||
|
||||
/* Have OpenGL draw in the back buffer with color coded face indices */
|
||||
if (curarea->win_swap==WIN_EQUAL) {
|
||||
G.vd->flag |= V3D_NEEDBACKBUFDRAW;
|
||||
VecSubf(d1, v->co, v1->co);
|
||||
VecSubf(d2, v2->co, v->co);
|
||||
|
||||
cost = cost + 0.5f*cost*(2.0f - fabs(d1[0]*d2[0] + d1[1]*d2[1] + d1[2]*d2[2]));
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
static void seam_add_adjacent(Mesh *me, Heap *heap, int mednum, int vertnum, int *nedges, int *edges, int *prevedge, float *cost)
|
||||
{
|
||||
int startadj, endadj = nedges[vertnum+1];
|
||||
|
||||
for (startadj = nedges[vertnum]; startadj < endadj; startadj++) {
|
||||
int adjnum = edges[startadj];
|
||||
MEdge *medadj = me->medge + adjnum;
|
||||
float newcost;
|
||||
|
||||
if (medadj->flag & ME_SEAM_DONE)
|
||||
continue;
|
||||
|
||||
newcost = cost[mednum] + seam_cut_cost(me, mednum, adjnum, vertnum);
|
||||
|
||||
if (cost[adjnum] > newcost) {
|
||||
cost[adjnum] = newcost;
|
||||
prevedge[adjnum] = mednum;
|
||||
BLI_heap_insert(heap, newcost, (void*)adjnum);
|
||||
}
|
||||
}
|
||||
if (G.vd->flag & V3D_NEEDBACKBUFDRAW) {
|
||||
backdrawview3d(0);
|
||||
persp(PERSP_VIEW);
|
||||
}
|
||||
/* Read the pixel under the cursor */
|
||||
#ifdef __APPLE__
|
||||
glReadBuffer(GL_AUX0);
|
||||
#endif
|
||||
glReadPixels(x+curarea->winrct.xmin, y+curarea->winrct.ymin, 1, 1,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, &col);
|
||||
glReadBuffer(GL_BACK);
|
||||
}
|
||||
|
||||
/* Unbelievable! */
|
||||
if (G.order==B_ENDIAN) {
|
||||
SWITCH_INT(col);
|
||||
}
|
||||
/* Convert the color back to a face index */
|
||||
*index = framebuffer_to_index(col);
|
||||
if (col==0 || (*index)<=0 || (*index)>(unsigned) me->totface)
|
||||
return 0;
|
||||
static int seam_shortest_path(Mesh *me, int source, int target)
|
||||
{
|
||||
Heap *heap;
|
||||
EdgeHash *ehash;
|
||||
float *cost;
|
||||
MEdge *med;
|
||||
int a, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
|
||||
TFace *tf;
|
||||
MFace *mf;
|
||||
|
||||
(*index)--;
|
||||
/* mark hidden edges as done, so we don't use them */
|
||||
ehash = BLI_edgehash_new();
|
||||
|
||||
for (a=0, mf=me->mface, tf=me->tface; a<me->totface; a++, tf++, mf++) {
|
||||
if (!(tf->flag & TF_HIDE)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
for (a=0, med=me->medge; a<me->totedge; a++, med++)
|
||||
if (!BLI_edgehash_haskey(ehash, med->v1, med->v2))
|
||||
med->flag |= ME_SEAM_DONE;
|
||||
|
||||
BLI_edgehash_free(ehash, NULL);
|
||||
|
||||
/* alloc */
|
||||
nedges = MEM_callocN(sizeof(*nedges)*me->totvert+1, "SeamPathNEdges");
|
||||
edges = MEM_mallocN(sizeof(*edges)*me->totedge*2, "SeamPathEdges");
|
||||
prevedge = MEM_mallocN(sizeof(*prevedge)*me->totedge, "SeamPathPrevious");
|
||||
cost = MEM_mallocN(sizeof(*cost)*me->totedge, "SeamPathCost");
|
||||
|
||||
/* count edges, compute adjacent edges offsets and fill adjacent edges */
|
||||
for (a=0, med=me->medge; a<me->totedge; a++, med++) {
|
||||
nedges[med->v1+1]++;
|
||||
nedges[med->v2+1]++;
|
||||
}
|
||||
|
||||
for (a=1; a<me->totvert; a++) {
|
||||
int newswap = nedges[a+1];
|
||||
nedges[a+1] = nedgeswap + nedges[a];
|
||||
nedgeswap = newswap;
|
||||
}
|
||||
nedges[0] = nedges[1] = 0;
|
||||
|
||||
for (a=0, med=me->medge; a<me->totedge; a++, med++) {
|
||||
edges[nedges[med->v1+1]++] = a;
|
||||
edges[nedges[med->v2+1]++] = a;
|
||||
|
||||
cost[a] = 1e20f;
|
||||
prevedge[a] = -1;
|
||||
}
|
||||
|
||||
/* regular dijkstra shortest path, but over edges instead of vertices */
|
||||
heap = BLI_heap_new();
|
||||
BLI_heap_insert(heap, 0.0f, (void*)source);
|
||||
cost[source] = 0.0f;
|
||||
|
||||
while (!BLI_heap_empty(heap)) {
|
||||
mednum = (int)BLI_heap_popmin(heap);
|
||||
med = me->medge + mednum;
|
||||
|
||||
if (mednum == target)
|
||||
break;
|
||||
|
||||
if (med->flag & ME_SEAM_DONE)
|
||||
continue;
|
||||
|
||||
med->flag |= ME_SEAM_DONE;
|
||||
|
||||
seam_add_adjacent(me, heap, mednum, med->v1, nedges, edges, prevedge, cost);
|
||||
seam_add_adjacent(me, heap, mednum, med->v2, nedges, edges, prevedge, cost);
|
||||
}
|
||||
|
||||
MEM_freeN(nedges);
|
||||
MEM_freeN(edges);
|
||||
MEM_freeN(cost);
|
||||
BLI_heap_free(heap, NULL);
|
||||
|
||||
for (a=0, med=me->medge; a<me->totedge; a++, med++)
|
||||
med->flag &= ~ME_SEAM_DONE;
|
||||
|
||||
if (mednum != target) {
|
||||
MEM_freeN(prevedge);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* follow path back to source and mark as seam */
|
||||
if (mednum == target) {
|
||||
short allseams = 1;
|
||||
|
||||
mednum = target;
|
||||
do {
|
||||
med = me->medge + mednum;
|
||||
if (!(med->flag & ME_SEAM)) {
|
||||
allseams = 0;
|
||||
break;
|
||||
}
|
||||
mednum = prevedge[mednum];
|
||||
} while (mednum != source);
|
||||
|
||||
mednum = target;
|
||||
do {
|
||||
med = me->medge + mednum;
|
||||
if (allseams)
|
||||
med->flag &= ~ME_SEAM;
|
||||
else
|
||||
med->flag |= ME_SEAM;
|
||||
mednum = prevedge[mednum];
|
||||
} while (mednum != -1);
|
||||
}
|
||||
|
||||
MEM_freeN(prevedge);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void seam_select(Mesh *me, short *mval, short path)
|
||||
{
|
||||
unsigned int index = 0;
|
||||
MEdge *medge, *med;
|
||||
int a, lastindex = -1;
|
||||
|
||||
if (!facesel_edge_pick(me, mval, &index))
|
||||
return;
|
||||
|
||||
for (a=0, med=me->medge; a<me->totedge; a++, med++) {
|
||||
if (med->flag & ME_SEAM_LAST) {
|
||||
lastindex = a;
|
||||
med->flag &= ~ME_SEAM_LAST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
medge = me->medge + index;
|
||||
if (!path || (lastindex == -1) || (index == lastindex) ||
|
||||
!seam_shortest_path(me, lastindex, index))
|
||||
medge->flag ^= ME_SEAM;
|
||||
medge->flag |= ME_SEAM_LAST;
|
||||
|
||||
G.f |= G_DRAWSEAMS;
|
||||
|
||||
if (G.rt == 8)
|
||||
unwrap_lscm(1);
|
||||
|
||||
BIF_undo_push("Mark Seam");
|
||||
|
||||
object_tface_flags_changed(OBACT, 1);
|
||||
}
|
||||
|
||||
void seam_edgehash_insert_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 seam_mark_clear_tface(short mode)
|
||||
{
|
||||
Mesh *me;
|
||||
TFace *tf;
|
||||
MFace *mf;
|
||||
MEdge *med;
|
||||
int a;
|
||||
|
||||
me= get_mesh(OBACT);
|
||||
if(me==0 || me->tface==0 || me->totface==0) return;
|
||||
|
||||
if (mode == 0)
|
||||
mode = pupmenu("Seams%t|Mark Border Seam %x1|Clear Seam %x2");
|
||||
|
||||
if (mode != 1 && mode != 2)
|
||||
return;
|
||||
|
||||
if (mode == 2) {
|
||||
EdgeHash *ehash = BLI_edgehash_new();
|
||||
|
||||
for (a=0, mf=me->mface, tf=me->tface; a<me->totface; a++, tf++, mf++)
|
||||
if (!(tf->flag & TF_HIDE) && (tf->flag & TF_SELECT))
|
||||
seam_edgehash_insert_face(ehash, mf);
|
||||
|
||||
for (a=0, med=me->medge; a<me->totedge; a++, med++)
|
||||
if (BLI_edgehash_haskey(ehash, med->v1, med->v2))
|
||||
med->flag &= ~ME_SEAM;
|
||||
|
||||
BLI_edgehash_free(ehash, NULL);
|
||||
}
|
||||
else {
|
||||
/* mark edges that are on both selected and deselected faces */
|
||||
EdgeHash *ehash1 = BLI_edgehash_new();
|
||||
EdgeHash *ehash2 = BLI_edgehash_new();
|
||||
|
||||
for (a=0, mf=me->mface, tf=me->tface; a<me->totface; a++, tf++, mf++) {
|
||||
if ((tf->flag & TF_HIDE) || !(tf->flag & TF_SELECT))
|
||||
seam_edgehash_insert_face(ehash1, mf);
|
||||
else
|
||||
seam_edgehash_insert_face(ehash2, mf);
|
||||
}
|
||||
|
||||
for (a=0, med=me->medge; a<me->totedge; a++, med++)
|
||||
if (BLI_edgehash_haskey(ehash1, med->v1, med->v2) &&
|
||||
BLI_edgehash_haskey(ehash2, med->v1, med->v2))
|
||||
med->flag |= ME_SEAM;
|
||||
|
||||
BLI_edgehash_free(ehash1, NULL);
|
||||
BLI_edgehash_free(ehash2, NULL);
|
||||
}
|
||||
|
||||
if (G.rt == 8)
|
||||
unwrap_lscm(1);
|
||||
|
||||
BIF_undo_push("Mark Seam");
|
||||
|
||||
object_tface_flags_changed(OBACT, 1);
|
||||
}
|
||||
|
||||
void face_select()
|
||||
{
|
||||
Object *ob;
|
||||
@@ -975,7 +1234,13 @@ void face_select()
|
||||
}
|
||||
me = get_mesh(ob);
|
||||
getmouseco_areawin(mval);
|
||||
if (!face_pick(me, mval[0], mval[1], &index)) return;
|
||||
|
||||
if (G.qual & LR_ALTKEY) {
|
||||
seam_select(me, mval, (G.qual & LR_SHIFTKEY) != 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!facesel_face_pick(me, mval, &index, 1)) return;
|
||||
|
||||
tsel= (((TFace*)me->tface)+index);
|
||||
msel= (((MFace*)me->mface)+index);
|
||||
@@ -1003,8 +1268,6 @@ void face_select()
|
||||
}
|
||||
else tsel->flag |= TF_SELECT;
|
||||
|
||||
lasttface = tsel;
|
||||
|
||||
/* image window redraw */
|
||||
|
||||
BIF_undo_push("Select UV face");
|
||||
@@ -1149,7 +1412,7 @@ void uv_autocalc_tface()
|
||||
case UV_WINDOW_MAPPING:
|
||||
calculate_uv_map(B_UVAUTO_WINDOW); break;
|
||||
case UV_UNWRAP_MAPPING:
|
||||
unwrap_lscm(); break;
|
||||
unwrap_lscm(0); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1176,10 +1439,6 @@ void set_faceselect() /* toggle */
|
||||
|
||||
if(G.f & G_FACESELECT) {
|
||||
setcursor_space(SPACE_VIEW3D, CURSOR_FACESEL);
|
||||
if(me) {
|
||||
set_lasttface();
|
||||
set_seamtface(); /* set TF_SEAM flags in tface */
|
||||
}
|
||||
BIF_undo_push("Set UV Faceselect");
|
||||
}
|
||||
else if((G.f & (G_WEIGHTPAINT|G_VERTEXPAINT|G_TEXTUREPAINT))==0) {
|
||||
@@ -1497,7 +1756,7 @@ void face_draw()
|
||||
if ((xy[0] != xy_old[0]) || (xy[1] != xy_old[1])) {
|
||||
|
||||
/* Get face to draw on */
|
||||
if (!face_pick(me, xy[0], xy[1], &face_index)) face = NULL;
|
||||
if (!facesel_face_pick(me, xy, &face_index, 0)) face = NULL;
|
||||
else face = (((TFace*)me->tface)+face_index);
|
||||
|
||||
/* Check if this is another face. */
|
||||
|
||||
@@ -123,145 +123,6 @@ void EM_select_mirrored(void)
|
||||
|
||||
unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0; // set in drawobject.c ... for colorindices
|
||||
|
||||
static void check_backbuf(void)
|
||||
{
|
||||
if(G.vd->flag & V3D_NEEDBACKBUFDRAW) {
|
||||
backdrawview3d(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* samples a single pixel (copied from vpaint) */
|
||||
static unsigned int sample_backbuf(int x, int y)
|
||||
{
|
||||
unsigned int col;
|
||||
|
||||
if(x>=curarea->winx || y>=curarea->winy) return 0;
|
||||
x+= curarea->winrct.xmin;
|
||||
y+= curarea->winrct.ymin;
|
||||
|
||||
check_backbuf(); // actually not needed for apple
|
||||
|
||||
#ifdef __APPLE__
|
||||
glReadBuffer(GL_AUX0);
|
||||
#endif
|
||||
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
|
||||
glReadBuffer(GL_BACK);
|
||||
|
||||
if(G.order==B_ENDIAN) SWITCH_INT(col);
|
||||
|
||||
return framebuffer_to_index(col);
|
||||
}
|
||||
|
||||
/* reads full rect, converts indices */
|
||||
struct ImBuf *read_backbuf(short xmin, short ymin, short xmax, short ymax)
|
||||
{
|
||||
unsigned int *dr, *rd;
|
||||
struct ImBuf *ibuf, *ibuf1;
|
||||
int a;
|
||||
short xminc, yminc, xmaxc, ymaxc, xs, ys;
|
||||
|
||||
/* clip */
|
||||
if(xmin<0) xminc= 0; else xminc= xmin;
|
||||
if(xmax>=curarea->winx) xmaxc= curarea->winx-1; else xmaxc= xmax;
|
||||
if(xminc > xmaxc) return NULL;
|
||||
|
||||
if(ymin<0) yminc= 0; else yminc= ymin;
|
||||
if(ymax>=curarea->winy) ymaxc= curarea->winy-1; else ymaxc= ymax;
|
||||
if(yminc > ymaxc) return NULL;
|
||||
|
||||
ibuf= IMB_allocImBuf((xmaxc-xminc+1),(ymaxc-yminc+1),32,IB_rect,0);
|
||||
|
||||
check_backbuf(); // actually not needed for apple
|
||||
|
||||
#ifdef __APPLE__
|
||||
glReadBuffer(GL_AUX0);
|
||||
#endif
|
||||
glReadPixels(curarea->winrct.xmin+xminc, curarea->winrct.ymin+yminc, (xmaxc-xminc+1), (ymaxc-yminc+1), GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
|
||||
glReadBuffer(GL_BACK);
|
||||
|
||||
if(G.order==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
|
||||
|
||||
a= (xmaxc-xminc+1)*(ymaxc-yminc+1);
|
||||
dr= ibuf->rect;
|
||||
while(a--) {
|
||||
if(*dr) *dr= framebuffer_to_index(*dr);
|
||||
dr++;
|
||||
}
|
||||
|
||||
/* put clipped result back, if needed */
|
||||
if(xminc==xmin && xmaxc==xmax && yminc==ymin && ymaxc==ymax) return ibuf;
|
||||
ibuf1= IMB_allocImBuf( (xmax-xmin+1),(ymax-ymin+1),32,IB_rect,0);
|
||||
rd= ibuf->rect;
|
||||
dr= ibuf1->rect;
|
||||
|
||||
for(ys= ymin; ys<=ymax; ys++) {
|
||||
for(xs= xmin; xs<=xmax; xs++, dr++) {
|
||||
if( xs>=xminc && xs<=xmaxc && ys>=yminc && ys<=ymaxc) {
|
||||
*dr= *rd;
|
||||
rd++;
|
||||
}
|
||||
}
|
||||
}
|
||||
IMB_freeImBuf(ibuf);
|
||||
return ibuf1;
|
||||
}
|
||||
|
||||
|
||||
/* smart function to sample a rect spiralling outside, nice for backbuf selection */
|
||||
static unsigned int sample_backbuf_rect(short mval[2], int size, unsigned int min, unsigned int max, short *dist)
|
||||
{
|
||||
struct ImBuf *buf;
|
||||
unsigned int *bufmin, *bufmax, *tbuf;
|
||||
int minx, miny;
|
||||
int a, b, rc, nr, amount, dirvec[4][2];
|
||||
short distance=0;
|
||||
unsigned int index = 0;
|
||||
|
||||
amount= (size-1)/2;
|
||||
|
||||
minx = mval[0]-(amount+1);
|
||||
miny = mval[1]-(amount+1);
|
||||
buf = read_backbuf(minx, miny, minx+size-1, miny+size-1);
|
||||
if (!buf) return 0;
|
||||
|
||||
rc= 0;
|
||||
|
||||
dirvec[0][0]= 1; dirvec[0][1]= 0;
|
||||
dirvec[1][0]= 0; dirvec[1][1]= -size;
|
||||
dirvec[2][0]= -1; dirvec[2][1]= 0;
|
||||
dirvec[3][0]= 0; dirvec[3][1]= size;
|
||||
|
||||
bufmin = buf->rect;
|
||||
tbuf = buf->rect;
|
||||
bufmax = buf->rect + size*size;
|
||||
tbuf+= amount*size+ amount;
|
||||
|
||||
for(nr=1; nr<=size; nr++) {
|
||||
|
||||
for(a=0; a<2; a++) {
|
||||
for(b=0; b<nr; b++, distance++) {
|
||||
if (*tbuf && *tbuf>=min && *tbuf<max) {
|
||||
*dist= (short) sqrt( (float)distance ); // XXX, this distance is wrong - zr
|
||||
index = *tbuf - min+1; // messy yah, but indices start at 1
|
||||
goto exit;
|
||||
}
|
||||
|
||||
tbuf+= (dirvec[rc][0]+dirvec[rc][1]);
|
||||
|
||||
if(tbuf<bufmin || tbuf>=bufmax) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
rc++;
|
||||
rc &= 3;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
IMB_freeImBuf(buf);
|
||||
return index;
|
||||
}
|
||||
|
||||
/* facilities for border select and circle select */
|
||||
static char *selbuf= NULL;
|
||||
|
||||
|
||||
@@ -1504,10 +1504,8 @@ void exit_editmode(int freedata) /* freedata==0 at render, 1= freedata, 2= do un
|
||||
|
||||
if(freedata) free_editMesh(G.editMesh);
|
||||
|
||||
if(G.f & G_FACESELECT) {
|
||||
set_seamtface();
|
||||
if(G.f & G_FACESELECT)
|
||||
allqueue(REDRAWIMAGE, 0);
|
||||
}
|
||||
if(G.f & G_WEIGHTPAINT)
|
||||
mesh_octree_table(G.obedit, NULL, 'e');
|
||||
}
|
||||
|
||||
@@ -1029,7 +1029,7 @@ static void do_image_uvsmenu(void *arg, int event)
|
||||
pin_tface_uv(0);
|
||||
break;
|
||||
case 10:
|
||||
unwrap_lscm();
|
||||
unwrap_lscm(0);
|
||||
break;
|
||||
case 11:
|
||||
if(G.sima->flag & SI_LIVE_UNWRAP) G.sima->flag &= ~SI_LIVE_UNWRAP;
|
||||
@@ -1072,7 +1072,7 @@ static uiBlock *image_uvsmenu(void *arg_unused)
|
||||
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Minimize Stretch|Ctrl V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Minimize Stretch|Ctrl V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 12, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Limit Stitch...|Shift V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Stitch|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
|
||||
uiDefIconTextBlockBut(block, image_uvs_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
|
||||
|
||||
@@ -3574,55 +3574,56 @@ static uiBlock *view3d_paintmenu(void *arg_unused)
|
||||
|
||||
static void do_view3d_facesel_propertiesmenu(void *arg, int event)
|
||||
{
|
||||
extern TFace *lasttface;
|
||||
set_lasttface();
|
||||
|
||||
switch(event) {
|
||||
case 0: /* textured */
|
||||
lasttface->mode ^= TF_TEX;
|
||||
break;
|
||||
case 1: /* tiled*/
|
||||
lasttface->mode ^= TF_TILES;
|
||||
break;
|
||||
case 2: /* light */
|
||||
lasttface->mode ^= TF_LIGHT;
|
||||
break;
|
||||
case 3: /* invisible */
|
||||
lasttface->mode ^= TF_INVISIBLE;
|
||||
break;
|
||||
case 4: /* collision */
|
||||
lasttface->mode ^= TF_DYNAMIC;
|
||||
break;
|
||||
case 5: /* shared vertex colors */
|
||||
lasttface->mode ^= TF_SHAREDCOL;
|
||||
break;
|
||||
case 6: /* two sided */
|
||||
lasttface->mode ^= TF_TWOSIDE;
|
||||
break;
|
||||
case 7: /* use object color */
|
||||
lasttface->mode ^= TF_OBCOL;
|
||||
break;
|
||||
case 8: /* halo */
|
||||
lasttface->mode ^= TF_BILLBOARD;
|
||||
break;
|
||||
case 9: /* billboard */
|
||||
lasttface->mode ^= TF_BILLBOARD2;
|
||||
break;
|
||||
case 10: /* shadow */
|
||||
lasttface->mode ^= TF_SHADOW;
|
||||
break;
|
||||
case 11: /* text */
|
||||
lasttface->mode ^= TF_BMFONT;
|
||||
break;
|
||||
case 12: /* opaque blend mode */
|
||||
lasttface->transp = TF_SOLID;
|
||||
break;
|
||||
case 13: /* additive blend mode */
|
||||
lasttface->transp |= TF_ADD;
|
||||
break;
|
||||
case 14: /* alpha blend mode */
|
||||
lasttface->transp = TF_ALPHA;
|
||||
break;
|
||||
TFace *tf = get_active_tface();
|
||||
|
||||
if (tf) {
|
||||
switch(event) {
|
||||
case 0: /* textured */
|
||||
tf->mode ^= TF_TEX;
|
||||
break;
|
||||
case 1: /* tiled*/
|
||||
tf->mode ^= TF_TILES;
|
||||
break;
|
||||
case 2: /* light */
|
||||
tf->mode ^= TF_LIGHT;
|
||||
break;
|
||||
case 3: /* invisible */
|
||||
tf->mode ^= TF_INVISIBLE;
|
||||
break;
|
||||
case 4: /* collision */
|
||||
tf->mode ^= TF_DYNAMIC;
|
||||
break;
|
||||
case 5: /* shared vertex colors */
|
||||
tf->mode ^= TF_SHAREDCOL;
|
||||
break;
|
||||
case 6: /* two sided */
|
||||
tf->mode ^= TF_TWOSIDE;
|
||||
break;
|
||||
case 7: /* use object color */
|
||||
tf->mode ^= TF_OBCOL;
|
||||
break;
|
||||
case 8: /* halo */
|
||||
tf->mode ^= TF_BILLBOARD;
|
||||
break;
|
||||
case 9: /* billboard */
|
||||
tf->mode ^= TF_BILLBOARD2;
|
||||
break;
|
||||
case 10: /* shadow */
|
||||
tf->mode ^= TF_SHADOW;
|
||||
break;
|
||||
case 11: /* text */
|
||||
tf->mode ^= TF_BMFONT;
|
||||
break;
|
||||
case 12: /* opaque blend mode */
|
||||
tf->transp = TF_SOLID;
|
||||
break;
|
||||
case 13: /* additive blend mode */
|
||||
tf->transp |= TF_ADD;
|
||||
break;
|
||||
case 14: /* alpha blend mode */
|
||||
tf->transp = TF_ALPHA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
allqueue(REDRAWBUTSEDIT, 0);
|
||||
@@ -3630,61 +3631,60 @@ static void do_view3d_facesel_propertiesmenu(void *arg, int event)
|
||||
|
||||
static uiBlock *view3d_facesel_propertiesmenu(void *arg_unused)
|
||||
{
|
||||
extern TFace *lasttface;
|
||||
TFace *tf = get_active_tface();
|
||||
uiBlock *block;
|
||||
short yco = 20, menuwidth = 120;
|
||||
|
||||
/* to display ticks/crosses depending on face properties */
|
||||
set_lasttface();
|
||||
/* display ticks/crosses depending on active tface properties */
|
||||
|
||||
block= uiNewBlock(&curarea->uiblocks, "view3d_facesel_propertiesmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
|
||||
uiBlockSetButmFunc(block, do_view3d_facesel_propertiesmenu, NULL);
|
||||
|
||||
if (lasttface->mode & TF_TEX) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Textured", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
|
||||
if (tf->mode & TF_TEX) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Textured", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Textured", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
if (lasttface->mode & TF_TILES) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Tiled", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
|
||||
if (tf->mode & TF_TILES) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Tiled", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Tiled", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
|
||||
|
||||
if (lasttface->mode & TF_LIGHT) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Light", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
|
||||
if (tf->mode & TF_LIGHT) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Light", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Light", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
|
||||
|
||||
if (lasttface->mode & TF_INVISIBLE) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Invisible", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
|
||||
if (tf->mode & TF_INVISIBLE) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Invisible", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Invisible", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
|
||||
|
||||
if (lasttface->mode & TF_DYNAMIC) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Collision", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
|
||||
if (tf->mode & TF_DYNAMIC) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Collision", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Collision", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
|
||||
|
||||
if (lasttface->mode & TF_SHAREDCOL) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Shared Vertex Colors", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
|
||||
if (tf->mode & TF_SHAREDCOL) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Shared Vertex Colors", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Shared Vertex Colors", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
|
||||
|
||||
if (lasttface->mode & TF_TWOSIDE) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Two Sided", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
|
||||
if (tf->mode & TF_TWOSIDE) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Two Sided", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Two Sided", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
|
||||
|
||||
if (lasttface->mode & TF_OBCOL) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Use Object Color", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
|
||||
if (tf->mode & TF_OBCOL) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Use Object Color", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Use Object Color", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
|
||||
|
||||
if (lasttface->mode & TF_BILLBOARD) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Halo", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
|
||||
if (tf->mode & TF_BILLBOARD) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Halo", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Halo", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
|
||||
|
||||
if (lasttface->mode & TF_BILLBOARD2) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Billboard", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
|
||||
if (tf->mode & TF_BILLBOARD2) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Billboard", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Billboard", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
|
||||
|
||||
if (lasttface->mode & TF_SHADOW) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Shadow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
|
||||
if (tf->mode & TF_SHADOW) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Shadow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Shadow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
|
||||
|
||||
if (lasttface->mode & TF_BMFONT) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Text", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 11, "");
|
||||
if (tf->mode & TF_BMFONT) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Text", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 11, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Text", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 11, "");
|
||||
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
if (lasttface->transp == TF_SOLID) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Opaque Blend Mode", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 12, "");
|
||||
if (tf->transp == TF_SOLID) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Opaque Blend Mode", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 12, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Opaque Blend Mode", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 12, "");
|
||||
|
||||
if (lasttface->transp == TF_ADD) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Additive Blend Mode", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 13, "");
|
||||
if (tf->transp == TF_ADD) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Additive Blend Mode", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 13, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Additive Blend Mode", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 13, "");
|
||||
|
||||
if (lasttface->transp == TF_ALPHA) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Alpha Blend Mode", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 14, "");
|
||||
if (tf->transp == TF_ALPHA) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Alpha Blend Mode", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 14, "");
|
||||
else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Alpha Blend Mode", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 14, "");
|
||||
|
||||
uiBlockSetDirection(block, UI_RIGHT);
|
||||
@@ -3731,44 +3731,36 @@ static void do_view3d_faceselmenu(void *arg, int event)
|
||||
{
|
||||
/* code copied from buttons.c :(
|
||||
would be nice if it was split up into functions */
|
||||
Mesh *me=NULL;
|
||||
Object *ob=NULL;
|
||||
extern TFace *lasttface; /* caches info on tface bookkeeping ?*/
|
||||
TFace *tface;
|
||||
Mesh *me;
|
||||
TFace *tf, *activetf;
|
||||
int a;
|
||||
|
||||
switch(event) {
|
||||
case 0: /* copy draw mode */
|
||||
case 1: /* copy UVs */
|
||||
case 2: /* copy vertex colors */
|
||||
ob= OBACT;
|
||||
if(ob==0) return;
|
||||
me= get_mesh(ob);
|
||||
if(!(me && me->tface)) return;
|
||||
me= get_mesh(OBACT);
|
||||
activetf = get_active_tface();
|
||||
|
||||
tface= me->tface;
|
||||
a= me->totface;
|
||||
set_lasttface();
|
||||
if(lasttface) {
|
||||
|
||||
while(a--) {
|
||||
if(tface!=lasttface && (tface->flag & TF_SELECT)) {
|
||||
if (me && activetf) {
|
||||
for (a=0, tf=me->tface; a < me->totface; a++, tf++) {
|
||||
if(tf!=activetf && (tf->flag & TF_SELECT)) {
|
||||
if(event==0) {
|
||||
tface->mode= lasttface->mode;
|
||||
tface->transp= lasttface->transp;
|
||||
tf->mode= activetf->mode;
|
||||
tf->transp= activetf->transp;
|
||||
} else if(event==1) {
|
||||
memcpy(tface->uv, lasttface->uv, sizeof(tface->uv));
|
||||
tface->tpage= lasttface->tpage;
|
||||
tface->tile= lasttface->tile;
|
||||
memcpy(tf->uv, activetf->uv, sizeof(tf->uv));
|
||||
tf->tpage= activetf->tpage;
|
||||
tf->tile= activetf->tile;
|
||||
|
||||
if(lasttface->mode & TF_TILES) tface->mode |= TF_TILES;
|
||||
else tface->mode &= ~TF_TILES;
|
||||
if(activetf->mode & TF_TILES) tf->mode |= TF_TILES;
|
||||
else tf->mode &= ~TF_TILES;
|
||||
|
||||
} else if(event==2)
|
||||
memcpy(tface->col, lasttface->col, sizeof(tface->col));
|
||||
memcpy(tf->col, activetf->col, sizeof(tf->col));
|
||||
}
|
||||
tface++;
|
||||
}
|
||||
|
||||
do_shared_vertexcol(me);
|
||||
}
|
||||
break;
|
||||
@@ -3784,7 +3776,12 @@ static void do_view3d_faceselmenu(void *arg, int event)
|
||||
case 9: /* mirror UVs */
|
||||
mirror_uv_tface();
|
||||
break;
|
||||
|
||||
case 10: /* mark border seam */
|
||||
seam_mark_clear_tface(1);
|
||||
break;
|
||||
case 11: /* clear seam */
|
||||
seam_mark_clear_tface(2);
|
||||
break;
|
||||
}
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
allqueue(REDRAWIMAGE, 0);
|
||||
@@ -3795,8 +3792,6 @@ static uiBlock *view3d_faceselmenu(void *arg_unused)
|
||||
uiBlock *block;
|
||||
short yco= 0, menuwidth=120;
|
||||
|
||||
set_lasttface();
|
||||
|
||||
block= uiNewBlock(&curarea->uiblocks, "view3d_faceselmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
|
||||
uiBlockSetButmFunc(block, do_view3d_faceselmenu, NULL);
|
||||
|
||||
@@ -3817,6 +3812,11 @@ static uiBlock *view3d_faceselmenu(void *arg_unused)
|
||||
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Seam|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mark Border Seam|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
|
||||
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
uiDefIconTextBlockBut(block, view3d_facesel_showhidemenu, NULL, ICON_RIGHTARROW_THIN, "Show/Hide Faces", 0, yco-=20, 120, 19, "");
|
||||
|
||||
if(curarea->headertype==HEADERTOP) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_arithb.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_heap.h"
|
||||
|
||||
#include "BKE_utildefines.h"
|
||||
|
||||
@@ -129,148 +130,6 @@ static PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link)
|
||||
return link;
|
||||
}
|
||||
|
||||
/* Heap */
|
||||
|
||||
#define PHEAP_PARENT(i) ((i-1)>>1)
|
||||
#define PHEAP_LEFT(i) ((i<<1)+1)
|
||||
#define PHEAP_RIGHT(i) ((i<<1)+2)
|
||||
#define PHEAP_COMPARE(a, b) (a->value < b->value)
|
||||
#define PHEAP_EQUALS(a, b) (a->value == b->value)
|
||||
#define PHEAP_SWAP(heap, i, j) \
|
||||
{ SWAP(int, heap->tree[i]->index, heap->tree[j]->index); \
|
||||
SWAP(PHeapLink*, heap->tree[i], heap->tree[j]); }
|
||||
|
||||
static void pheap_down(PHeap *heap, int i)
|
||||
{
|
||||
while (P_TRUE) {
|
||||
int size = heap->size, smallest;
|
||||
int l = PHEAP_LEFT(i);
|
||||
int r = PHEAP_RIGHT(i);
|
||||
|
||||
smallest = ((l < size) && PHEAP_COMPARE(heap->tree[l], heap->tree[i]))? l: i;
|
||||
|
||||
if ((r < size) && PHEAP_COMPARE(heap->tree[r], heap->tree[smallest]))
|
||||
smallest = r;
|
||||
|
||||
if (smallest == i)
|
||||
break;
|
||||
|
||||
PHEAP_SWAP(heap, i, smallest);
|
||||
i = smallest;
|
||||
}
|
||||
}
|
||||
|
||||
static void pheap_up(PHeap *heap, int i)
|
||||
{
|
||||
while (i > 0) {
|
||||
int p = PHEAP_PARENT(i);
|
||||
|
||||
if (PHEAP_COMPARE(heap->tree[p], heap->tree[i]))
|
||||
break;
|
||||
|
||||
PHEAP_SWAP(heap, p, i);
|
||||
i = p;
|
||||
}
|
||||
}
|
||||
|
||||
static PHeap *pheap_new()
|
||||
{
|
||||
PHeap *heap = (PHeap*)MEM_callocN(sizeof(PHeap), "PHeap");
|
||||
heap->bufsize = 1;
|
||||
heap->tree = (PHeapLink**)MEM_mallocN(sizeof(PHeapLink*), "PHeapTree");
|
||||
heap->arena = BLI_memarena_new(1<<16);
|
||||
|
||||
return heap;
|
||||
}
|
||||
|
||||
static void pheap_delete(PHeap *heap)
|
||||
{
|
||||
MEM_freeN(heap->tree);
|
||||
BLI_memarena_free(heap->arena);
|
||||
MEM_freeN(heap);
|
||||
}
|
||||
|
||||
static PHeapLink *pheap_insert(PHeap *heap, float value, void *ptr)
|
||||
{
|
||||
PHeapLink *link;
|
||||
|
||||
if ((heap->size + 1) > heap->bufsize) {
|
||||
int newsize = heap->bufsize*2;
|
||||
|
||||
PHeapLink **ntree = (PHeapLink**)MEM_mallocN(newsize*sizeof(PHeapLink*), "PHeapTree");
|
||||
memcpy(ntree, heap->tree, sizeof(PHeapLink*)*heap->size);
|
||||
MEM_freeN(heap->tree);
|
||||
|
||||
heap->tree = ntree;
|
||||
heap->bufsize = newsize;
|
||||
}
|
||||
|
||||
param_assert(heap->size < heap->bufsize);
|
||||
|
||||
if (heap->freelinks) {
|
||||
link = heap->freelinks;
|
||||
heap->freelinks = (PHeapLink*)(((PHeapLink*)heap->freelinks)->ptr);
|
||||
}
|
||||
else
|
||||
link = (PHeapLink*)BLI_memarena_alloc(heap->arena, sizeof *link);
|
||||
link->value = value;
|
||||
link->ptr = ptr;
|
||||
link->index = heap->size;
|
||||
|
||||
heap->tree[link->index] = link;
|
||||
|
||||
heap->size++;
|
||||
|
||||
pheap_up(heap, heap->size-1);
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int pheap_empty(PHeap *heap)
|
||||
{
|
||||
return (heap->size == 0);
|
||||
}
|
||||
|
||||
static PHeapLink *pheap_toplink(PHeap *heap)
|
||||
{
|
||||
return heap->tree[0];
|
||||
}
|
||||
#endif
|
||||
|
||||
static void *pheap_popmin(PHeap *heap)
|
||||
{
|
||||
void *ptr = heap->tree[0]->ptr;
|
||||
|
||||
heap->tree[0]->ptr = heap->freelinks;
|
||||
heap->freelinks = heap->tree[0];
|
||||
|
||||
if (heap->size == 1)
|
||||
heap->size--;
|
||||
else {
|
||||
PHEAP_SWAP(heap, 0, heap->size-1);
|
||||
heap->size--;
|
||||
|
||||
pheap_down(heap, 0);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void pheap_remove(PHeap *heap, PHeapLink *link)
|
||||
{
|
||||
int i = link->index;
|
||||
|
||||
while (i > 0) {
|
||||
int p = PHEAP_PARENT(i);
|
||||
|
||||
PHEAP_SWAP(heap, p, i);
|
||||
i = p;
|
||||
}
|
||||
|
||||
pheap_popmin(heap);
|
||||
}
|
||||
|
||||
/* Geometry */
|
||||
|
||||
static float p_vec_angle_cos(float *v1, float *v2, float *v3)
|
||||
@@ -1110,13 +969,13 @@ static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges)
|
||||
PEdge *e, *e1, *e2;
|
||||
PHashKey vkeys[3];
|
||||
PFace *f;
|
||||
struct PHeap *heap = pheap_new(nedges);
|
||||
struct Heap *heap = BLI_heap_new();
|
||||
float angle;
|
||||
|
||||
e = be;
|
||||
do {
|
||||
angle = p_edge_boundary_angle(e);
|
||||
e->u.heaplink = pheap_insert(heap, angle, e);
|
||||
e->u.heaplink = BLI_heap_insert(heap, angle, e);
|
||||
|
||||
e = p_boundary_edge_next(e);
|
||||
} while(e != be);
|
||||
@@ -1127,20 +986,20 @@ static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges)
|
||||
e->pair = be;
|
||||
be->pair = e;
|
||||
|
||||
pheap_remove(heap, e->u.heaplink);
|
||||
pheap_remove(heap, be->u.heaplink);
|
||||
BLI_heap_remove(heap, e->u.heaplink);
|
||||
BLI_heap_remove(heap, be->u.heaplink);
|
||||
}
|
||||
else {
|
||||
while (nedges > 2) {
|
||||
PEdge *ne, *ne1, *ne2;
|
||||
|
||||
e = (PEdge*)pheap_popmin(heap);
|
||||
e = (PEdge*)BLI_heap_popmin(heap);
|
||||
|
||||
e1 = p_boundary_edge_prev(e);
|
||||
e2 = p_boundary_edge_next(e);
|
||||
|
||||
pheap_remove(heap, e1->u.heaplink);
|
||||
pheap_remove(heap, e2->u.heaplink);
|
||||
BLI_heap_remove(heap, e1->u.heaplink);
|
||||
BLI_heap_remove(heap, e2->u.heaplink);
|
||||
e->u.heaplink = e1->u.heaplink = e2->u.heaplink = NULL;
|
||||
|
||||
e->flag |= PEDGE_FILLED;
|
||||
@@ -1175,15 +1034,15 @@ static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges)
|
||||
else {
|
||||
ne2->vert->edge = ne2;
|
||||
|
||||
ne2->u.heaplink = pheap_insert(heap, p_edge_boundary_angle(ne2), ne2);
|
||||
e2->u.heaplink = pheap_insert(heap, p_edge_boundary_angle(e2), e2);
|
||||
ne2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(ne2), ne2);
|
||||
e2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(e2), e2);
|
||||
}
|
||||
|
||||
nedges--;
|
||||
}
|
||||
}
|
||||
|
||||
pheap_delete(heap);
|
||||
BLI_heap_free(heap, NULL);
|
||||
}
|
||||
|
||||
static void p_chart_fill_boundaries(PChart *chart, PEdge *outer)
|
||||
@@ -2008,7 +1867,7 @@ static void p_chart_simplify_compute(PChart *chart)
|
||||
collapsed may then be view as stacks, where the next collapse/split
|
||||
is at the top of the respective lists. */
|
||||
|
||||
PHeap *heap = pheap_new();
|
||||
Heap *heap = BLI_heap_new();
|
||||
PVert *v, **wheelverts;
|
||||
PEdge *collapsededges = NULL, *e;
|
||||
int nwheelverts, i, ncollapsed = 0;
|
||||
@@ -2023,7 +1882,7 @@ static void p_chart_simplify_compute(PChart *chart)
|
||||
p_collapse_cost_vertex(v, &cost, &e);
|
||||
|
||||
if (e)
|
||||
v->u.heaplink = pheap_insert(heap, cost, e);
|
||||
v->u.heaplink = BLI_heap_insert(heap, cost, e);
|
||||
else
|
||||
v->u.heaplink = NULL;
|
||||
}
|
||||
@@ -2032,12 +1891,12 @@ static void p_chart_simplify_compute(PChart *chart)
|
||||
e->u.nextcollapse = NULL;
|
||||
|
||||
/* pop edge collapse out of heap one by one */
|
||||
while (!pheap_empty(heap)) {
|
||||
while (!BLI_heap_empty(heap)) {
|
||||
if (ncollapsed == NCOLLAPSE)
|
||||
break;
|
||||
|
||||
PHeapLink *link = pheap_toplink(heap);
|
||||
PEdge *edge = (PEdge*)pheap_popmin(heap), *pair = edge->pair;
|
||||
HeapNode *link = BLI_heap_top(heap);
|
||||
PEdge *edge = (PEdge*)BLI_heap_popmin(heap), *pair = edge->pair;
|
||||
PVert *oldv, *keepv;
|
||||
PEdge *wheele, *nexte;
|
||||
|
||||
@@ -2081,21 +1940,21 @@ static void p_chart_simplify_compute(PChart *chart)
|
||||
v = wheelverts[i];
|
||||
|
||||
if (v->u.heaplink) {
|
||||
pheap_remove(heap, v->u.heaplink);
|
||||
BLI_heap_remove(heap, v->u.heaplink);
|
||||
v->u.heaplink = NULL;
|
||||
}
|
||||
|
||||
p_collapse_cost_vertex(v, &cost, &collapse);
|
||||
|
||||
if (collapse)
|
||||
v->u.heaplink = pheap_insert(heap, cost, collapse);
|
||||
v->u.heaplink = BLI_heap_insert(heap, cost, collapse);
|
||||
}
|
||||
|
||||
ncollapsed++;
|
||||
}
|
||||
|
||||
MEM_freeN(wheelverts);
|
||||
pheap_delete(heap);
|
||||
BLI_heap_free(heap, NULL);
|
||||
|
||||
p_chart_post_collapse_flush(chart, collapsededges);
|
||||
}
|
||||
|
||||
@@ -51,23 +51,6 @@ struct PFace;
|
||||
struct PChart;
|
||||
struct PHandle;
|
||||
|
||||
/* Heap */
|
||||
|
||||
typedef struct PHeapLink {
|
||||
void *ptr;
|
||||
float value;
|
||||
int index;
|
||||
} PHeapLink;
|
||||
|
||||
typedef struct PHeap {
|
||||
unsigned int size;
|
||||
unsigned int bufsize;
|
||||
MemArena *arena;
|
||||
PHeapLink *freelinks;
|
||||
PHeapLink *links;
|
||||
PHeapLink **tree;
|
||||
} PHeap;
|
||||
|
||||
/* Simplices */
|
||||
|
||||
typedef struct PVert {
|
||||
@@ -77,7 +60,7 @@ typedef struct PVert {
|
||||
PHashKey key; /* construct */
|
||||
int id; /* abf/lscm matrix index */
|
||||
float distortion; /* area smoothing */
|
||||
PHeapLink *heaplink; /* edge collapsing */
|
||||
HeapNode *heaplink; /* edge collapsing */
|
||||
} u;
|
||||
|
||||
struct PEdge *edge;
|
||||
@@ -93,7 +76,7 @@ typedef struct PEdge {
|
||||
union PEdgeUnion {
|
||||
PHashKey key; /* construct */
|
||||
int id; /* abf matrix index */
|
||||
PHeapLink *heaplink; /* fill holes */
|
||||
HeapNode *heaplink; /* fill holes */
|
||||
struct PEdge *nextcollapse; /* simplification */
|
||||
} u;
|
||||
|
||||
|
||||
@@ -1265,6 +1265,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
else if (G.qual==LR_CTRLKEY) {
|
||||
if(G.obedit && G.obedit->type==OB_MESH)
|
||||
Edge_Menu();
|
||||
else if (G.f & G_FACESELECT)
|
||||
seam_mark_clear_tface(0);
|
||||
}
|
||||
else if (G.qual==LR_SHIFTKEY) {
|
||||
if (G.obedit && G.obedit->type==OB_MESH) {
|
||||
@@ -3992,7 +3994,7 @@ static void winqreadimagespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
break;
|
||||
case EKEY :
|
||||
if(okee("Unwrap"))
|
||||
unwrap_lscm();
|
||||
unwrap_lscm(0);
|
||||
break;
|
||||
case GKEY:
|
||||
if((G.qual==0) && is_uv_tface_editing_allowed()) {
|
||||
|
||||
@@ -60,49 +60,13 @@
|
||||
#include "blendef.h"
|
||||
#include "mydevice.h"
|
||||
|
||||
#include "ONL_opennl.h"
|
||||
#include "BDR_unwrapper.h"
|
||||
|
||||
#include "PIL_time.h"
|
||||
|
||||
#include "parametrizer.h"
|
||||
|
||||
/* Implementation Least Squares Conformal Maps parameterization, based on
|
||||
* chapter 2 of:
|
||||
* Bruno Levy, Sylvain Petitjean, Nicolas Ray, Jerome Maillot. Least Squares
|
||||
* Conformal Maps for Automatic Texture Atlas Generation. In Siggraph 2002,
|
||||
* July 2002.
|
||||
*/
|
||||
|
||||
/* Data structure defines */
|
||||
#define LSCM_SEAM1 1
|
||||
#define LSCM_SEAM2 2
|
||||
#define LSCM_INDEXED 4
|
||||
#define LSCM_PINNED 8
|
||||
|
||||
/* LscmVert = One UV */
|
||||
typedef struct LscmVert {
|
||||
int v, v1, v2; /* vertex indices */
|
||||
int index; /* index in solver */
|
||||
short tf_index; /* index in tface (0, 1, 2 or 3) */
|
||||
short flag; /* see above LSCM constants */
|
||||
TFace *tf; /* original tface */
|
||||
} LscmVert;
|
||||
|
||||
/* QuickSort helper function, sort by vertex id */
|
||||
static int comp_lscmvert(const void *u1, const void *u2)
|
||||
{
|
||||
LscmVert *v1, *v2;
|
||||
|
||||
v1= *((LscmVert**)u1);
|
||||
v2= *((LscmVert**)u2);
|
||||
|
||||
if (v1->v > v2->v) return 1;
|
||||
else if (v1->v < v2->v) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Hashed edge table utility */
|
||||
/* Set tface seams based on edge data, uses hash table to find seam edges. */
|
||||
|
||||
static void hash_add_face(EdgeHash *ehash, MFace *mf)
|
||||
{
|
||||
@@ -116,1149 +80,23 @@ static void hash_add_face(EdgeHash *ehash, MFace *mf)
|
||||
BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
|
||||
}
|
||||
|
||||
/* divide selected faces in groups, based on seams. note that group numbering
|
||||
starts at 1 */
|
||||
static int make_seam_groups(Mesh *me, int **seamgroups)
|
||||
{
|
||||
int a, b, gid;
|
||||
TFace *tf, *tface;
|
||||
MFace *mf, *mface;
|
||||
int *gf, *gface, *groups;
|
||||
EdgeHash *ehash;
|
||||
int doit, mark;
|
||||
|
||||
if(!me || !me->tface) return 0;
|
||||
|
||||
groups= (int*)MEM_callocN(sizeof(int)*me->totface, "SeamGroups");
|
||||
|
||||
ehash= BLI_edgehash_new();
|
||||
|
||||
mface= (MFace*)me->mface;
|
||||
tface= (TFace*)me->tface;
|
||||
gface= groups;
|
||||
gid= 0;
|
||||
for(b=me->totface; b>0; b--, mface++, tface++, gface++) {
|
||||
if(!(tface->flag & TF_SELECT) || *gface!=0) continue;
|
||||
|
||||
if(gid != 0)
|
||||
BLI_edgehash_clear(ehash, NULL);
|
||||
|
||||
gid++;
|
||||
*gface= gid;
|
||||
mark= 0;
|
||||
doit= 1;
|
||||
|
||||
|
||||
while(doit) {
|
||||
doit= 0;
|
||||
|
||||
/* select connected: fill array */
|
||||
tf= tface;
|
||||
mf= mface;
|
||||
gf= gface;
|
||||
a= b;
|
||||
while(a--) {
|
||||
if(tf->flag & TF_HIDE);
|
||||
else if(tf->flag & TF_SELECT && *gf==gid) {
|
||||
hash_add_face(ehash, mf);
|
||||
}
|
||||
tf++; mf++; gf++;
|
||||
}
|
||||
|
||||
/* select the faces using array
|
||||
* consider faces connected when they share one non-seam edge */
|
||||
tf= tface;
|
||||
mf= mface;
|
||||
gf= gface;
|
||||
a= b;
|
||||
while(a--) {
|
||||
if(tf->flag & TF_HIDE);
|
||||
else if(tf->flag & TF_SELECT && *gf==0) {
|
||||
mark= 0;
|
||||
|
||||
if(!(tf->unwrap & TF_SEAM1))
|
||||
if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2))
|
||||
mark= 1;
|
||||
if(!(tf->unwrap & TF_SEAM2))
|
||||
if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3))
|
||||
mark= 1;
|
||||
if(!(tf->unwrap & TF_SEAM3)) {
|
||||
if(mf->v4) {
|
||||
if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4))
|
||||
mark= 1;
|
||||
}
|
||||
else if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1))
|
||||
mark= 1;
|
||||
}
|
||||
if(mf->v4 && !(tf->unwrap & TF_SEAM4))
|
||||
if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1))
|
||||
mark= 1;
|
||||
|
||||
if(mark) {
|
||||
*gf= gid;
|
||||
doit= 1;
|
||||
}
|
||||
}
|
||||
tf++; mf++; gf++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_edgehash_free(ehash, NULL);
|
||||
*seamgroups= groups;
|
||||
|
||||
return gid;
|
||||
}
|
||||
|
||||
static void lscm_rotate_vert(int a, LscmVert **sortvert, int v2, int index)
|
||||
{
|
||||
LscmVert **sv, *v;
|
||||
int found, b;
|
||||
|
||||
/* starting from edge sortvert->v,v2, rotate around vertex and set
|
||||
* index until a seam or an already marked tri is encountered */
|
||||
found = 1;
|
||||
|
||||
while(found) {
|
||||
found= 0;
|
||||
sv=sortvert;
|
||||
|
||||
for(b=a; b>0 && ((*sv)->v == (*sortvert)->v) && !found; b--, sv++) {
|
||||
v= *sv;
|
||||
|
||||
if(v->flag & LSCM_INDEXED);
|
||||
else if(v->v1 == v2) {
|
||||
v2= v->v2;
|
||||
|
||||
if(v->flag & LSCM_SEAM1) break;
|
||||
|
||||
v->index= index;
|
||||
v->flag |= LSCM_INDEXED;
|
||||
found= 1;
|
||||
break;
|
||||
}
|
||||
else if(v->v2==v2) {
|
||||
v2= v->v1;
|
||||
|
||||
if(v->flag & LSCM_SEAM2) break;
|
||||
|
||||
v->index= index;
|
||||
v->flag |= LSCM_INDEXED;
|
||||
found= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int lscm_vertex_set_index(int a, LscmVert **sortvert, int totindex)
|
||||
{
|
||||
LscmVert **sv, *v;
|
||||
int index, b;
|
||||
|
||||
/* rotate over 'wheel' of faces around vertex, incrementing the index
|
||||
everytime we meet a seam, or no next connected face is found.
|
||||
repeat this until we have and id for all verts.
|
||||
if mesh is non-manifold, non-manifold edges will be cut randomly */
|
||||
|
||||
index= totindex;
|
||||
sv= sortvert;
|
||||
|
||||
for(b=a; b>0 && ((*sv)->v == (*sortvert)->v); b--, sv++) {
|
||||
v= *sv;
|
||||
|
||||
if(v->flag & LSCM_INDEXED) continue;
|
||||
|
||||
v->index= index;
|
||||
v->flag |= LSCM_INDEXED;
|
||||
|
||||
lscm_rotate_vert(b, sv, v->v1, index);
|
||||
lscm_rotate_vert(b, sv, v->v2, index);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static int lscm_set_indices(LscmVert **sortvert, int totvert)
|
||||
{
|
||||
LscmVert *v, **sv;
|
||||
int a, lastvert, totindex;
|
||||
|
||||
totindex= 0;
|
||||
lastvert= -1;
|
||||
sv= sortvert;
|
||||
|
||||
for(a=totvert; a>0; a--, sv++) {
|
||||
v= *sv;
|
||||
if(v->v != lastvert) {
|
||||
totindex= lscm_vertex_set_index(a, sv, totindex);
|
||||
lastvert= v->v;
|
||||
}
|
||||
}
|
||||
|
||||
return totindex;
|
||||
}
|
||||
|
||||
static void lscm_normalize(float *co, float *center, float radius)
|
||||
{
|
||||
/* normalize relative to complete surface */
|
||||
VecSubf(co, co, center);
|
||||
VecMulf(co, (float)1.0/radius);
|
||||
}
|
||||
|
||||
static void lscm_add_triangle(float *v1, float *v2, float *v3, int vid1, int vid2, int vid3, float *center, float radius)
|
||||
{
|
||||
float x[3], y[3], z[3], sub[3], z1[2], z2[2];
|
||||
int id0[2], id1[2], id2[2];
|
||||
|
||||
/* project 3d triangle
|
||||
* edge length is lost, as this algorithm is angle based */
|
||||
lscm_normalize(v1, center, radius);
|
||||
lscm_normalize(v2, center, radius);
|
||||
lscm_normalize(v3, center, radius);
|
||||
|
||||
VecSubf(x, v2, v1);
|
||||
Normalise(x);
|
||||
|
||||
VecSubf(sub, v3, v1);
|
||||
Crossf(z, x, sub);
|
||||
Normalise(z);
|
||||
|
||||
Crossf(y, z, x);
|
||||
|
||||
/* reduce to two 2d vectors */
|
||||
VecSubf(sub, v2, v1);
|
||||
z1[0]= Normalise(sub);
|
||||
z1[1]= 0;
|
||||
|
||||
VecSubf(sub, v3, v1);
|
||||
z2[0]= Inpf(sub, x);
|
||||
z2[1]= Inpf(sub, y);
|
||||
|
||||
/* split id's up for u and v
|
||||
id = u, id + 1 = v */
|
||||
id0[0]= 2*vid1;
|
||||
id0[1]= 2*vid1 + 1;
|
||||
id1[0]= 2*vid2;
|
||||
id1[1]= 2*vid2 + 1;
|
||||
id2[0]= 2*vid3;
|
||||
id2[1]= 2*vid3 + 1;
|
||||
|
||||
/* The LSCM Equation:
|
||||
* ------------------
|
||||
* (u,v) are the uv coords we are looking for -> complex number u + i*v
|
||||
* (x,y) are the above calculated local coords -> complex number x + i*y
|
||||
* Uk = uk + i*vk
|
||||
* Zk = xk + i*yk (= zk[0] + i*zk[1] in the code)
|
||||
*
|
||||
* That makes the equation:
|
||||
* (Z1 - Z0)(U2 - U0) = (Z2 - Z0)(U1 - U0)
|
||||
*
|
||||
* x0, y0 and y1 were made zero by projecting the triangle:
|
||||
* (x1 + i*y1)(u2 + i*v2 - u0 - i*v0) = (x2 + i*y2)(u1 + i*v1 - u0 - i*v0)
|
||||
*
|
||||
* this gives the following coefficients:
|
||||
* u0 * ((-x1 + x2) + i*(y2))
|
||||
* v0 * ((-y2) + i*(-x1 + x2))
|
||||
* u1 * ((-x2) + i*(-y2))
|
||||
* v1 * ((y2) + i*(-x2))
|
||||
* u2 * (x1)
|
||||
* v2 * (i*(x1))
|
||||
*/
|
||||
|
||||
/* real part */
|
||||
nlBegin(NL_ROW);
|
||||
nlCoefficient(id0[0], -z1[0] + z2[0]);
|
||||
nlCoefficient(id0[1], -z2[1] );
|
||||
nlCoefficient(id1[0], -z2[0] );
|
||||
nlCoefficient(id1[1], z2[1] );
|
||||
nlCoefficient(id2[0], z1[0] );
|
||||
nlEnd(NL_ROW);
|
||||
|
||||
/* imaginary part */
|
||||
nlBegin(NL_ROW);
|
||||
nlCoefficient(id0[0], z2[1] );
|
||||
nlCoefficient(id0[1], -z1[0] + z2[0]);
|
||||
nlCoefficient(id1[0], -z2[1] );
|
||||
nlCoefficient(id1[1], -z2[0] );
|
||||
nlCoefficient(id2[1], z1[0] );
|
||||
nlEnd(NL_ROW);
|
||||
}
|
||||
|
||||
static float lscm_angle_cos(float *v1, float *v2, float *v3)
|
||||
{
|
||||
float vec1[3], vec2[3];
|
||||
|
||||
VecSubf(vec1, v2, v1);
|
||||
VecSubf(vec2, v3, v1);
|
||||
Normalise(vec1);
|
||||
Normalise(vec2);
|
||||
|
||||
return vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2];
|
||||
}
|
||||
|
||||
static int lscm_build_vertex_data(Mesh *me, int *groups, int gid, LscmVert **lscm_vertices, LscmVert ***sort_vertices)
|
||||
{
|
||||
MVert *mv;
|
||||
MFace *mf;
|
||||
TFace *tf;
|
||||
int *gf, totvert, a;
|
||||
LscmVert *lscmvert, **sortvert;
|
||||
LscmVert *v1, *v2, *v3, **sv1, **sv2, **sv3;
|
||||
float a1, a2;
|
||||
|
||||
/* determine size for malloc */
|
||||
totvert= 0;
|
||||
mv = me->mvert;
|
||||
mf= me->mface;
|
||||
tf= me->tface;
|
||||
gf= groups;
|
||||
a1 = a2 = 0;
|
||||
|
||||
for(a=me->totface; a>0; a--) {
|
||||
if(*gf==gid) {
|
||||
|
||||
totvert += 3;
|
||||
if(mf->v4) totvert +=3;
|
||||
}
|
||||
tf++; mf++; gf++;
|
||||
}
|
||||
|
||||
/* a list per face vertices */
|
||||
lscmvert= (LscmVert*)MEM_mallocN(sizeof(LscmVert)*totvert,"LscmVerts");
|
||||
/* the above list sorted by vertex id */
|
||||
sortvert= (LscmVert**)MEM_mallocN(sizeof(LscmVert*)*totvert, "LscmVSort");
|
||||
|
||||
/* actually build the list (including virtual triangulation) */
|
||||
mf= me->mface;
|
||||
tf= me->tface;
|
||||
gf= groups;
|
||||
|
||||
v1= lscmvert;
|
||||
v2= lscmvert + 1;
|
||||
v3= lscmvert + 2;
|
||||
|
||||
sv1= sortvert;
|
||||
sv2= sortvert + 1;
|
||||
sv3= sortvert + 2;
|
||||
|
||||
/* warning: ugly code :) */
|
||||
for(a=me->totface; a>0; a--) {
|
||||
if(*gf==gid) {
|
||||
/* determine triangulation direction, to avoid degenerate
|
||||
triangles (small cos = degenerate). */
|
||||
if(mf->v4) {
|
||||
a1 = lscm_angle_cos((mv+mf->v1)->co, (mv+mf->v2)->co, (mv+mf->v3)->co);
|
||||
a1 += lscm_angle_cos((mv+mf->v2)->co, (mv+mf->v1)->co, (mv+mf->v3)->co);
|
||||
a1 += lscm_angle_cos((mv+mf->v3)->co, (mv+mf->v1)->co, (mv+mf->v2)->co);
|
||||
|
||||
a2 = lscm_angle_cos((mv+mf->v1)->co, (mv+mf->v2)->co, (mv+mf->v4)->co);
|
||||
a2 += lscm_angle_cos((mv+mf->v2)->co, (mv+mf->v1)->co, (mv+mf->v4)->co);
|
||||
a2 += lscm_angle_cos((mv+mf->v4)->co, (mv+mf->v1)->co, (mv+mf->v2)->co);
|
||||
}
|
||||
|
||||
a1 = 0.0; a2 = 1.0;
|
||||
|
||||
if(!mf->v4 || a1 > a2) {
|
||||
v1->v= mf->v1;
|
||||
v2->v= mf->v2;
|
||||
v3->v= mf->v3;
|
||||
|
||||
v1->tf_index= 0;
|
||||
v2->tf_index= 1;
|
||||
v3->tf_index= 2;
|
||||
|
||||
v1->flag= v2->flag= v3->flag= 0;
|
||||
|
||||
v1->v1= v2->v;
|
||||
v1->v2= v3->v;
|
||||
|
||||
v2->v1= v1->v;
|
||||
v2->v2= v3->v;
|
||||
|
||||
v3->v1= v1->v;
|
||||
v3->v2= v2->v;
|
||||
|
||||
v1->tf= v2->tf= v3->tf= tf;
|
||||
|
||||
*sv1= v1;
|
||||
*sv2= v2;
|
||||
*sv3= v3;
|
||||
|
||||
if(tf->unwrap & TF_SEAM1) {
|
||||
v1->flag |= LSCM_SEAM1;
|
||||
v2->flag |= LSCM_SEAM1;
|
||||
}
|
||||
|
||||
if(tf->unwrap & TF_SEAM2) {
|
||||
v2->flag |= LSCM_SEAM2;
|
||||
v3->flag |= LSCM_SEAM2;
|
||||
}
|
||||
|
||||
if(!mf->v4 && tf->unwrap & TF_SEAM3) {
|
||||
v1->flag |= LSCM_SEAM2;
|
||||
v3->flag |= LSCM_SEAM1;
|
||||
}
|
||||
|
||||
v1 += 3; v2 += 3; v3 += 3;
|
||||
sv1 += 3; sv2 += 3; sv3 += 3;
|
||||
}
|
||||
|
||||
if(mf->v4 && a1 > a2) {
|
||||
v1->v= mf->v1;
|
||||
v2->v= mf->v3;
|
||||
v3->v= mf->v4;
|
||||
|
||||
v1->tf_index= 0;
|
||||
v2->tf_index= 2;
|
||||
v3->tf_index= 3;
|
||||
|
||||
v1->flag= v2->flag= v3->flag= 0;
|
||||
|
||||
v1->v1= v2->v;
|
||||
v1->v2= v3->v;
|
||||
|
||||
v2->v1= v3->v;
|
||||
v2->v2= v1->v;
|
||||
|
||||
v3->v1= v1->v;
|
||||
v3->v2= v2->v;
|
||||
|
||||
v1->tf= v2->tf= v3->tf= tf;
|
||||
|
||||
*sv1= v1;
|
||||
*sv2= v2;
|
||||
*sv3= v3;
|
||||
|
||||
if(tf->unwrap & TF_SEAM3) {
|
||||
v2->flag |= LSCM_SEAM1;
|
||||
v3->flag |= LSCM_SEAM2;
|
||||
}
|
||||
|
||||
if(tf->unwrap & TF_SEAM4) {
|
||||
v1->flag |= LSCM_SEAM2;
|
||||
v3->flag |= LSCM_SEAM1;
|
||||
}
|
||||
|
||||
v1 += 3; v2 += 3; v3 += 3;
|
||||
sv1 += 3; sv2 += 3; sv3 += 3;
|
||||
}
|
||||
|
||||
if(mf->v4 && a1 <= a2) {
|
||||
v1->v= mf->v1;
|
||||
v2->v= mf->v2;
|
||||
v3->v= mf->v4;
|
||||
|
||||
v1->tf_index= 0;
|
||||
v2->tf_index= 1;
|
||||
v3->tf_index= 3;
|
||||
|
||||
v1->flag= v2->flag= v3->flag= 0;
|
||||
|
||||
v1->v1= v2->v;
|
||||
v1->v2= v3->v;
|
||||
|
||||
v2->v1= v1->v;
|
||||
v2->v2= v3->v;
|
||||
|
||||
v3->v1= v1->v;
|
||||
v3->v2= v2->v;
|
||||
|
||||
v1->tf= v2->tf= v3->tf= tf;
|
||||
|
||||
*sv1= v1;
|
||||
*sv2= v2;
|
||||
*sv3= v3;
|
||||
|
||||
if(tf->unwrap & TF_SEAM1) {
|
||||
v1->flag |= LSCM_SEAM1;
|
||||
v2->flag |= LSCM_SEAM1;
|
||||
}
|
||||
|
||||
if(tf->unwrap & TF_SEAM4) {
|
||||
v1->flag |= LSCM_SEAM2;
|
||||
v3->flag |= LSCM_SEAM1;
|
||||
}
|
||||
|
||||
v1 += 3; v2 += 3; v3 += 3;
|
||||
sv1 += 3; sv2 += 3; sv3 += 3;
|
||||
|
||||
/* -- */
|
||||
|
||||
v1->v= mf->v2;
|
||||
v2->v= mf->v3;
|
||||
v3->v= mf->v4;
|
||||
|
||||
v1->tf_index= 1;
|
||||
v2->tf_index= 2;
|
||||
v3->tf_index= 3;
|
||||
|
||||
v1->flag= v2->flag= v3->flag= 0;
|
||||
|
||||
v1->v1= v2->v;
|
||||
v1->v2= v3->v;
|
||||
|
||||
v2->v1= v1->v;
|
||||
v2->v2= v3->v;
|
||||
|
||||
v3->v1= v1->v;
|
||||
v3->v2= v2->v;
|
||||
|
||||
v1->tf= v2->tf= v3->tf= tf;
|
||||
|
||||
*sv1= v1;
|
||||
*sv2= v2;
|
||||
*sv3= v3;
|
||||
|
||||
if(tf->unwrap & TF_SEAM2) {
|
||||
v1->flag |= LSCM_SEAM1;
|
||||
v2->flag |= LSCM_SEAM1;
|
||||
}
|
||||
|
||||
if(tf->unwrap & TF_SEAM3) {
|
||||
v2->flag |= LSCM_SEAM2;
|
||||
v3->flag |= LSCM_SEAM2;
|
||||
}
|
||||
|
||||
v1 += 3; v2 += 3; v3 += 3;
|
||||
sv1 += 3; sv2 += 3; sv3 += 3;
|
||||
}
|
||||
|
||||
}
|
||||
tf++; mf++; gf++;
|
||||
}
|
||||
|
||||
/* sort by vertex id */
|
||||
qsort(sortvert, totvert, sizeof(LscmVert*), comp_lscmvert);
|
||||
|
||||
*lscm_vertices= lscmvert;
|
||||
*sort_vertices= sortvert;
|
||||
return totvert;
|
||||
}
|
||||
|
||||
static void lscm_min_max_cent_rad(Mesh *me, LscmVert **sortvert, int totvert, float *min, float *max, float *center, float *radius)
|
||||
{
|
||||
MVert *mv= me->mvert;
|
||||
LscmVert *v, **sv;
|
||||
int a, lastvert, vertcount;
|
||||
float *co, sub[3];
|
||||
|
||||
/* find min, max and center */
|
||||
center[0]= center[1]= center[2]= 0.0;
|
||||
INIT_MINMAX(min, max);
|
||||
|
||||
vertcount= 0;
|
||||
lastvert= -1;
|
||||
sv= sortvert;
|
||||
|
||||
for(a=totvert; a>0; a--, sv++) {
|
||||
v= *sv;
|
||||
if(v->v != lastvert) {
|
||||
co= (mv+v->v)->co;
|
||||
|
||||
VecAddf(center, center, (mv+v->v)->co);
|
||||
DO_MINMAX(co, min, max);
|
||||
|
||||
vertcount++;
|
||||
lastvert= v->v;
|
||||
}
|
||||
}
|
||||
|
||||
VecMulf(center, (float)1.0/(float)vertcount);
|
||||
|
||||
/* find radius */
|
||||
VecSubf(sub, center, max);
|
||||
*radius= Normalise(sub);
|
||||
|
||||
if(*radius < 1e-20)
|
||||
*radius= 1.0;
|
||||
}
|
||||
|
||||
static void lscm_projection_axes(float *min, float *max, float *p1, float *p2)
|
||||
{
|
||||
float dx, dy, dz;
|
||||
|
||||
dx= max[0] - min[0];
|
||||
dy= max[1] - min[1];
|
||||
dz= max[2] - min[2];
|
||||
|
||||
p1[0]= p1[1]= p1[2]= 0.0;
|
||||
p2[0]= p2[1]= p2[2]= 0.0;
|
||||
|
||||
if(dx < dy && dx < dz) {
|
||||
if(dy > dz) p1[1]= p2[2]= 1.0; /* y, z */
|
||||
else p1[2]= p2[1]= 1.0; /* z, y */
|
||||
}
|
||||
else if(dy < dx && dy < dz) {
|
||||
if(dx > dz) p1[0]= p2[2]= 1.0; /* x, z */
|
||||
else p1[2]= p2[0]= 1.0; /* z, x */
|
||||
}
|
||||
else {
|
||||
if(dx > dy) p1[0]= p2[1]= 1.0; /* x, y */
|
||||
else p1[1]= p2[0]= 1.0; /* y, x */
|
||||
}
|
||||
}
|
||||
|
||||
static void lscm_set_initial_solution(Mesh *me, LscmVert **sortvert, int totvert, float *p1, float *p2, int *vertex_min, int *vertex_max)
|
||||
{
|
||||
float umin, umax, *uv, *co;
|
||||
int vmin, vmax, a;
|
||||
LscmVert **sv, *v;
|
||||
MVert *mv= me->mvert;
|
||||
|
||||
umin= 1.0e30;
|
||||
umax= -1.0e30;
|
||||
|
||||
vmin= 0;
|
||||
vmax= 2;
|
||||
|
||||
sv= sortvert;
|
||||
|
||||
for(a=totvert; a>0; a--, sv++) {
|
||||
v= *sv;
|
||||
co= (mv+v->v)->co;
|
||||
uv= v->tf->uv[v->tf_index];
|
||||
|
||||
uv[0]= Inpf(co, p1);
|
||||
uv[1]= Inpf(co, p2);
|
||||
|
||||
if(uv[0] < umin) {
|
||||
vmin= v->index;
|
||||
umin= uv[0];
|
||||
}
|
||||
if(uv[0] > umax) {
|
||||
vmax= v->index;
|
||||
umax= uv[0];
|
||||
}
|
||||
|
||||
nlSetVariable(2*v->index, uv[0]);
|
||||
nlSetVariable(2*v->index + 1, uv[1]);
|
||||
}
|
||||
|
||||
*vertex_min= vmin;
|
||||
*vertex_max= vmax;
|
||||
}
|
||||
|
||||
static void lscm_set_pinned_solution(Mesh *me, LscmVert **sortvert, int totvert, int *pinned)
|
||||
{
|
||||
float min[2], max[2], *uv, *co;
|
||||
int a, pin;
|
||||
LscmVert **sv, *v;
|
||||
MVert *mv= me->mvert;
|
||||
|
||||
INIT_MINMAX2(min, max);
|
||||
*pinned= 0;
|
||||
|
||||
sv= sortvert;
|
||||
|
||||
for(a=totvert; a>0; a--, sv++) {
|
||||
v= *sv;
|
||||
co= (mv+v->v)->co;
|
||||
uv= v->tf->uv[v->tf_index];
|
||||
|
||||
pin = ((v->tf->unwrap & TF_PIN1) && (v->tf_index == 0)) ||
|
||||
((v->tf->unwrap & TF_PIN2) && (v->tf_index == 1)) ||
|
||||
((v->tf->unwrap & TF_PIN3) && (v->tf_index == 2)) ||
|
||||
((v->tf->unwrap & TF_PIN4) && (v->tf_index == 3));
|
||||
|
||||
nlSetVariable(2*v->index, uv[0]);
|
||||
nlSetVariable(2*v->index + 1, uv[1]);
|
||||
|
||||
if(pin){
|
||||
DO_MINMAX2(uv, min, max);
|
||||
|
||||
*pinned += 1;
|
||||
|
||||
nlLockVariable(2*v->index);
|
||||
nlLockVariable(2*v->index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (*pinned){
|
||||
/* abuse umax vmax for caculating euclidian distance */
|
||||
max[0] -= min[0];
|
||||
max[1] -= min[1];
|
||||
|
||||
/* check for degenerated pinning box */
|
||||
if (((max[0]*max[0])+(max[1]*max[1])) < 1e-10)
|
||||
*pinned = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void lscm_build_matrix(Mesh *me, LscmVert *lscmvert, int *groups, int gid, float *center, float radius)
|
||||
{
|
||||
MVert *mv= me->mvert;
|
||||
MFace *mf;
|
||||
TFace *tf;
|
||||
int *gf, a, id1, id2, id3;
|
||||
LscmVert *v;
|
||||
float co1[3], co2[3], co3[3];
|
||||
|
||||
nlBegin(NL_MATRIX);
|
||||
|
||||
mf= me->mface;
|
||||
tf= me->tface;
|
||||
gf= groups;
|
||||
v= lscmvert;
|
||||
|
||||
for(a=me->totface; a>0; a--) {
|
||||
if(*gf==gid) {
|
||||
VecCopyf(co1, (mv+v->v)->co);
|
||||
id1= v->index; v++;
|
||||
VecCopyf(co2, (mv+v->v)->co);
|
||||
id2= v->index; v++;
|
||||
VecCopyf(co3, (mv+v->v)->co);
|
||||
id3= v->index; v++;
|
||||
lscm_add_triangle(co1, co2, co3, id1, id2, id3, center, radius);
|
||||
|
||||
if(mf->v4) {
|
||||
VecCopyf(co1, (mv+v->v)->co);
|
||||
id1= v->index; v++;
|
||||
VecCopyf(co2, (mv+v->v)->co);
|
||||
id2= v->index; v++;
|
||||
VecCopyf(co3, (mv+v->v)->co);
|
||||
id3= v->index; v++;
|
||||
lscm_add_triangle(co1, co2, co3, id1, id2, id3, center, radius);
|
||||
}
|
||||
}
|
||||
tf++; mf++; gf++;
|
||||
}
|
||||
|
||||
nlEnd(NL_MATRIX);
|
||||
}
|
||||
|
||||
static void lscm_load_solution(Mesh *me, LscmVert *lscmvert, int *groups, int gid)
|
||||
{
|
||||
MFace *mf;
|
||||
TFace *tf;
|
||||
int *gf, a, b;
|
||||
LscmVert *v;
|
||||
float *uv;
|
||||
|
||||
mf= me->mface;
|
||||
tf= me->tface;
|
||||
gf= groups;
|
||||
v= lscmvert;
|
||||
|
||||
for(a=me->totface; a>0; a--) {
|
||||
if(*gf==gid) {
|
||||
|
||||
if(mf->v4) b= 6;
|
||||
else b=3;
|
||||
|
||||
/* index= u, index + 1= v */
|
||||
while(b > 0) {
|
||||
uv= v->tf->uv[v->tf_index];
|
||||
|
||||
uv[0]= nlGetVariable(2*v->index);
|
||||
uv[1]= nlGetVariable(2*v->index + 1);
|
||||
|
||||
v++;
|
||||
b--;
|
||||
}
|
||||
}
|
||||
tf++; mf++; gf++;
|
||||
}
|
||||
}
|
||||
|
||||
static int unwrap_lscm_face_group(Mesh *me, int *groups, int gid)
|
||||
{
|
||||
LscmVert *lscmvert, **sortvert;
|
||||
int totindex, totvert, vmin, vmax,pinned;
|
||||
float min[3], max[3], center[3], radius, p1[3], p2[3];
|
||||
|
||||
/* build the data structures */
|
||||
totvert= lscm_build_vertex_data(me, groups, gid, &lscmvert, &sortvert);
|
||||
|
||||
/* calculate min, max, center and radius */
|
||||
lscm_min_max_cent_rad(me, sortvert, totvert, min, max, center, &radius);
|
||||
|
||||
/* index distinct vertices */
|
||||
totindex= lscm_set_indices(sortvert, totvert);
|
||||
|
||||
/* create solver */
|
||||
nlNewContext();
|
||||
nlSolverParameteri(NL_NB_VARIABLES, 2*totindex);
|
||||
nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
|
||||
|
||||
nlBegin(NL_SYSTEM);
|
||||
|
||||
/* find axes for projecting initial solutions on */
|
||||
lscm_projection_axes(min, max, p1, p2);
|
||||
/* see if pinned data is avail and set on fly */
|
||||
lscm_set_pinned_solution(me, sortvert, totvert, &pinned);
|
||||
|
||||
if(pinned < 0); /* really small pinned uv's: won't see difference anyway */
|
||||
else {
|
||||
/* auto pinning */
|
||||
if(pinned < 2)
|
||||
{
|
||||
/* set initial solution and locate two extrema vertices to pin */
|
||||
lscm_set_initial_solution(me,sortvert,totvert,p1,p2,&vmin,&vmax);
|
||||
|
||||
/* pin 2 uv's */
|
||||
nlLockVariable(2*vmin);
|
||||
nlLockVariable(2*vmin + 1);
|
||||
nlLockVariable(2*vmax);
|
||||
nlLockVariable(2*vmax + 1);
|
||||
}
|
||||
|
||||
/* add triangles to the solver */
|
||||
lscm_build_matrix(me, lscmvert, groups, gid, center, radius);
|
||||
|
||||
nlEnd(NL_SYSTEM);
|
||||
|
||||
/* LSCM solver magic! */
|
||||
nlSolve(NULL, NL_FALSE);
|
||||
|
||||
/* load new uv's: will be projected uv's if solving failed */
|
||||
lscm_load_solution(me, lscmvert, groups, gid);
|
||||
}
|
||||
|
||||
nlDeleteContext(nlGetCurrent());
|
||||
MEM_freeN(lscmvert);
|
||||
MEM_freeN(sortvert);
|
||||
return (pinned);
|
||||
}
|
||||
|
||||
static void seam_group_bbox(Mesh *me, int *groups, int gid, float *min, float *max)
|
||||
{
|
||||
MFace *mf;
|
||||
TFace *tf;
|
||||
int *gf, a;
|
||||
|
||||
INIT_MINMAX2(min, max);
|
||||
|
||||
mf= me->mface;
|
||||
tf= me->tface;
|
||||
gf= groups;
|
||||
|
||||
for(a=me->totface; a>0; a--) {
|
||||
if((gid!=0 && *gf==gid) || (gid==0 && *gf)) {
|
||||
|
||||
DO_MINMAX2(tf->uv[0], min, max)
|
||||
DO_MINMAX2(tf->uv[1], min, max)
|
||||
DO_MINMAX2(tf->uv[2], min, max)
|
||||
|
||||
if(mf->v4) {
|
||||
DO_MINMAX2(tf->uv[3], min, max)
|
||||
}
|
||||
}
|
||||
tf++; mf++; gf++;
|
||||
}
|
||||
}
|
||||
|
||||
static void seam_group_scale(Mesh *me, int *groups, int gid, float scale)
|
||||
{
|
||||
MFace *mf;
|
||||
TFace *tf;
|
||||
int *gf, a;
|
||||
|
||||
mf= me->mface;
|
||||
tf= me->tface;
|
||||
gf= groups;
|
||||
|
||||
for(a=me->totface; a>0; a--) {
|
||||
if((gid!=0 && *gf==gid) || (gid==0 && *gf)) {
|
||||
|
||||
Vec2Mulf(tf->uv[0], scale);
|
||||
Vec2Mulf(tf->uv[1], scale);
|
||||
Vec2Mulf(tf->uv[2], scale);
|
||||
if(mf->v4) Vec2Mulf(tf->uv[3], scale);
|
||||
}
|
||||
tf++; mf++; gf++;
|
||||
}
|
||||
}
|
||||
|
||||
static void seam_group_move(Mesh *me, int *groups, int gid, float add[2])
|
||||
{
|
||||
MFace *mf;
|
||||
TFace *tf;
|
||||
int *gf, a;
|
||||
|
||||
mf= me->mface;
|
||||
tf= me->tface;
|
||||
gf= groups;
|
||||
|
||||
for(a=me->totface; a>0; a--) {
|
||||
if((gid!=0 && *gf==gid) || (gid==0 && *gf)) {
|
||||
|
||||
Vec2Addf(tf->uv[0], tf->uv[0], add);
|
||||
Vec2Addf(tf->uv[1], tf->uv[1], add);
|
||||
Vec2Addf(tf->uv[2], tf->uv[2], add);
|
||||
if(mf->v4) Vec2Addf(tf->uv[3], tf->uv[3], add);
|
||||
}
|
||||
tf++; mf++; gf++;
|
||||
}
|
||||
}
|
||||
|
||||
/* put group withing (0,0)->(1,1) boundbox */
|
||||
static void seam_group_normalize(Mesh *me, int *groups, int gid)
|
||||
{
|
||||
float min[2], max[2], sx, sy, scale, add[2];
|
||||
|
||||
seam_group_bbox(me, groups, gid, min, max);
|
||||
|
||||
sx= (max[0]-min[0]);
|
||||
sy= (max[1]-min[1]);
|
||||
|
||||
scale= MAX2(sx, sy);
|
||||
scale= (1.0/scale);
|
||||
|
||||
add[0]= -min[0];
|
||||
add[1]= -min[1];
|
||||
|
||||
seam_group_move(me, groups, gid, add);
|
||||
seam_group_scale(me, groups, gid, scale);
|
||||
}
|
||||
|
||||
/* get scale relative to mesh */
|
||||
static float seam_group_relative_scale(Mesh *me, int *groups, int gid)
|
||||
{
|
||||
MVert *mv= me->mvert;
|
||||
MFace *mf;
|
||||
TFace *tf;
|
||||
int *gf, a;
|
||||
float len_xyz, len_uv;
|
||||
|
||||
len_xyz= 0.0;
|
||||
len_uv= 0.0;
|
||||
mf= me->mface;
|
||||
tf= me->tface;
|
||||
gf= groups;
|
||||
|
||||
for(a=me->totface; a>0; a--) {
|
||||
if(*gf==gid) {
|
||||
|
||||
len_uv += Vec2Lenf(tf->uv[0], tf->uv[1]);
|
||||
len_xyz += VecLenf((mv+mf->v1)->co, (mv+mf->v2)->co);
|
||||
|
||||
len_uv += Vec2Lenf(tf->uv[1], tf->uv[2]);
|
||||
len_xyz += VecLenf((mv+mf->v2)->co, (mv+mf->v3)->co);
|
||||
|
||||
if(mf->v4) {
|
||||
|
||||
len_uv += Vec2Lenf(tf->uv[2], tf->uv[3]);
|
||||
len_xyz += VecLenf((mv+mf->v3)->co, (mv+mf->v4)->co);
|
||||
|
||||
len_uv += Vec2Lenf(tf->uv[3], tf->uv[0]);
|
||||
len_xyz += VecLenf((mv+mf->v4)->co, (mv+mf->v1)->co);
|
||||
}
|
||||
else {
|
||||
len_uv += Vec2Lenf(tf->uv[2], tf->uv[0]);
|
||||
len_xyz += VecLenf((mv+mf->v3)->co, (mv+mf->v1)->co);
|
||||
}
|
||||
}
|
||||
tf++; mf++; gf++;
|
||||
}
|
||||
|
||||
return (len_uv/len_xyz);
|
||||
}
|
||||
|
||||
/* very primitive packing */
|
||||
static void pack_seam_groups(Mesh *me, int *groups, int totgroup)
|
||||
{
|
||||
float *groupscale, minscale, scale, add[2], groupw;
|
||||
float dx, dy, packx, packy, min[2], max[2], rowh;
|
||||
int a;
|
||||
|
||||
groupscale = (float*)MEM_mallocN(sizeof(float)*totgroup, "SeamGroupScale");
|
||||
|
||||
minscale= 1e30;
|
||||
|
||||
for(a=0; a<totgroup; a++) {
|
||||
groupscale[a]= seam_group_relative_scale(me, groups, a+1);
|
||||
minscale= MIN2(groupscale[a], minscale);
|
||||
}
|
||||
|
||||
packx= packy= 0.0;
|
||||
rowh= 0.0;
|
||||
groupw= 1.0/sqrt(totgroup);
|
||||
|
||||
for(a=0; a<totgroup; a++) {
|
||||
|
||||
/* scale so all groups have the same size relative to the mesh */
|
||||
scale = minscale/groupscale[a];
|
||||
scale *= groupw;
|
||||
|
||||
seam_group_bbox(me, groups, a+1, min, max);
|
||||
dx= (max[0]-min[0])*scale;
|
||||
dy= (max[1]-min[1])*scale;
|
||||
|
||||
/* for padding */
|
||||
dx += 0.01;
|
||||
dy += 0.01;
|
||||
|
||||
add[0]= add[1]= 0.0;
|
||||
|
||||
if(dx > 1.0) {
|
||||
add[0]= 0.0;
|
||||
add[1]= packy;
|
||||
|
||||
packy += dy;
|
||||
packx= 0.0;
|
||||
rowh= 0.0;
|
||||
}
|
||||
else if(dx <= (1.0-packx)) {
|
||||
add[0]= packx;
|
||||
add[1]= packy;
|
||||
|
||||
packx += dx;
|
||||
rowh= MAX2(rowh, dy);
|
||||
}
|
||||
else {
|
||||
packy += rowh;
|
||||
packx= dx;
|
||||
rowh= dy;
|
||||
|
||||
add[0]= 0.0;
|
||||
add[1]= packy;
|
||||
}
|
||||
|
||||
/* for padding */
|
||||
add[0] += 0.005;
|
||||
add[1] += 0.005;
|
||||
|
||||
seam_group_scale(me, groups, a+1, scale);
|
||||
seam_group_move(me, groups, a+1, add);
|
||||
}
|
||||
|
||||
MEM_freeN(groupscale);
|
||||
|
||||
seam_group_normalize(me, groups, 0);
|
||||
seam_group_scale(me, groups, 0, 0.98);
|
||||
add[0]= add[1]= 0.01;
|
||||
seam_group_move(me, groups, 0, add);
|
||||
}
|
||||
|
||||
void unwrap_lscm(void)
|
||||
{
|
||||
int dopack = 1;
|
||||
int res;
|
||||
Mesh *me;
|
||||
int totgroup, *groups=NULL, a;
|
||||
|
||||
if (G.scene->toolsettings->unwrapper != 2) {
|
||||
unwrap_lscm_new();
|
||||
return;
|
||||
}
|
||||
|
||||
me= get_mesh(OBACT);
|
||||
if(me==0 || me->tface==0) return;
|
||||
|
||||
totgroup= make_seam_groups(me, &groups);
|
||||
|
||||
if(totgroup==0) return;
|
||||
|
||||
for(a=totgroup; a>0; a--) {
|
||||
res= unwrap_lscm_face_group(me, groups, a);
|
||||
if((res < 3) && (res > -1)) {
|
||||
seam_group_normalize(me, groups, a);
|
||||
}
|
||||
else {
|
||||
dopack = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(dopack) pack_seam_groups(me, groups, totgroup);
|
||||
|
||||
MEM_freeN(groups);
|
||||
|
||||
BIF_undo_push("UV lscm unwrap");
|
||||
|
||||
object_uvs_changed(OBACT);
|
||||
|
||||
allqueue(REDRAWVIEW3D, 0);
|
||||
allqueue(REDRAWIMAGE, 0);
|
||||
}
|
||||
|
||||
/* note; to make it quick work, brecht/jens: you can make it nice later! (ton) */
|
||||
void unwrap_lscm_live(void)
|
||||
{
|
||||
int dopack = 1;
|
||||
int res;
|
||||
Mesh *me;
|
||||
int totgroup, *groups=NULL, a;
|
||||
|
||||
me= get_mesh(OBACT);
|
||||
if(me==0 || me->tface==0) return;
|
||||
|
||||
totgroup= make_seam_groups(me, &groups);
|
||||
|
||||
if(totgroup==0) return;
|
||||
|
||||
for(a=totgroup; a>0; a--) {
|
||||
res= unwrap_lscm_face_group(me, groups, a);
|
||||
if((res < 3) && (res > -1)) {
|
||||
seam_group_normalize(me, groups, a);
|
||||
}
|
||||
else {
|
||||
dopack = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(dopack) pack_seam_groups(me, groups, totgroup);
|
||||
|
||||
MEM_freeN(groups);
|
||||
|
||||
}
|
||||
|
||||
/* Set tface seams based on edge data, uses hash table to find seam edges. */
|
||||
|
||||
void set_seamtface()
|
||||
{
|
||||
Mesh *me;
|
||||
EdgeHash *ehash;
|
||||
int a;
|
||||
MFace *mf;
|
||||
TFace *tf;
|
||||
MEdge *medge;
|
||||
|
||||
me= get_mesh(OBACT);
|
||||
if(!me || !me->tface || !(G.f & G_FACESELECT)) return;
|
||||
|
||||
ehash= BLI_edgehash_new();
|
||||
|
||||
for(medge=me->medge, a=me->totedge; a>0; a--, medge++)
|
||||
if(medge->flag & ME_SEAM)
|
||||
BLI_edgehash_insert(ehash, medge->v1, medge->v2, NULL);
|
||||
|
||||
mf= me->mface;
|
||||
tf= me->tface;
|
||||
for(a=me->totface; a>0; a--, mf++, tf++) {
|
||||
tf->unwrap &= ~(TF_SEAM1|TF_SEAM2|TF_SEAM3|TF_SEAM4);
|
||||
|
||||
if(!ehash) continue;
|
||||
|
||||
if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2)) tf->unwrap |= TF_SEAM1;
|
||||
if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3)) tf->unwrap |= TF_SEAM2;
|
||||
|
||||
if(mf->v4) {
|
||||
if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4)) tf->unwrap |= TF_SEAM3;
|
||||
if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1)) tf->unwrap |= TF_SEAM4;
|
||||
}
|
||||
else if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1)) tf->unwrap |= TF_SEAM3;
|
||||
}
|
||||
|
||||
BLI_edgehash_free(ehash, NULL);
|
||||
}
|
||||
|
||||
void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
|
||||
{
|
||||
TFace *tf;
|
||||
MFace *mf;
|
||||
int a, doit=1, mark=0;
|
||||
char *linkflag;
|
||||
EdgeHash *ehash;
|
||||
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;
|
||||
@@ -1285,27 +123,29 @@ void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
|
||||
tf= me->tface;
|
||||
mf= me->mface;
|
||||
for(a=0; a<me->totface; a++, tf++, mf++) {
|
||||
if(tf->flag & TF_HIDE);
|
||||
else if(!linkflag[a]) {
|
||||
if(tf->flag & TF_HIDE)
|
||||
continue;
|
||||
|
||||
if(!linkflag[a]) {
|
||||
mark= 0;
|
||||
|
||||
if(!(tf->unwrap & TF_SEAM1))
|
||||
if(!BLI_edgehash_haskey(seamhash, mf->v1, mf->v2))
|
||||
if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2))
|
||||
mark= 1;
|
||||
if(!(tf->unwrap & TF_SEAM2))
|
||||
if(!BLI_edgehash_haskey(seamhash, mf->v2, mf->v3))
|
||||
if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3))
|
||||
mark= 1;
|
||||
if(!(tf->unwrap & TF_SEAM3)) {
|
||||
if(mf->v4) {
|
||||
if(mf->v4) {
|
||||
if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v4))
|
||||
if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4))
|
||||
mark= 1;
|
||||
}
|
||||
else if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1))
|
||||
mark= 1;
|
||||
if(!BLI_edgehash_haskey(seamhash, mf->v4, mf->v1))
|
||||
if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1))
|
||||
mark= 1;
|
||||
}
|
||||
if(mf->v4 && !(tf->unwrap & TF_SEAM4))
|
||||
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;
|
||||
@@ -1317,6 +157,9 @@ void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
|
||||
|
||||
}
|
||||
|
||||
BLI_edgehash_free(ehash, NULL);
|
||||
BLI_edgehash_free(seamhash, NULL);
|
||||
|
||||
if(mode==0 || mode==2) {
|
||||
for(a=0, tf=me->tface; a<me->totface; a++, tf++)
|
||||
if(linkflag[a])
|
||||
@@ -1341,7 +184,6 @@ void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
|
||||
}
|
||||
}
|
||||
|
||||
BLI_edgehash_free(ehash, NULL);
|
||||
MEM_freeN(linkflag);
|
||||
|
||||
BIF_undo_push("Select linked UV face");
|
||||
@@ -1350,7 +192,7 @@ void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
|
||||
|
||||
/* Parametrizer */
|
||||
|
||||
ParamHandle *construct_param_handle(Mesh *me, short implicit, short fill)
|
||||
ParamHandle *construct_param_handle(Mesh *me, short implicit, short fill, short sel)
|
||||
{
|
||||
int a;
|
||||
TFace *tf;
|
||||
@@ -1371,7 +213,10 @@ ParamHandle *construct_param_handle(Mesh *me, short implicit, short fill)
|
||||
float *uv[4];
|
||||
int nverts;
|
||||
|
||||
if ((tf->flag & TF_HIDE) || !(tf->flag & TF_SELECT))
|
||||
if (tf->flag & TF_HIDE)
|
||||
continue;
|
||||
|
||||
if (sel && !(tf->flag & TF_SELECT))
|
||||
continue;
|
||||
|
||||
if (implicit && !(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)))
|
||||
@@ -1429,7 +274,7 @@ ParamHandle *construct_param_handle(Mesh *me, short implicit, short fill)
|
||||
return handle;
|
||||
}
|
||||
|
||||
void unwrap_lscm_new(void)
|
||||
void unwrap_lscm(short seamcut)
|
||||
{
|
||||
Mesh *me;
|
||||
ParamHandle *handle;
|
||||
@@ -1439,7 +284,7 @@ void unwrap_lscm_new(void)
|
||||
me= get_mesh(OBACT);
|
||||
if(me==0 || me->tface==0) return;
|
||||
|
||||
handle = construct_param_handle(me, 0, fillholes);
|
||||
handle = construct_param_handle(me, 0, fillholes, seamcut == 0);
|
||||
|
||||
param_lscm_begin(handle, PARAM_FALSE, abf);
|
||||
param_lscm_solve(handle);
|
||||
@@ -1451,7 +296,8 @@ void unwrap_lscm_new(void)
|
||||
|
||||
param_delete(handle);
|
||||
|
||||
BIF_undo_push("UV unwrap");
|
||||
if (!seamcut)
|
||||
BIF_undo_push("UV unwrap");
|
||||
|
||||
object_uvs_changed(OBACT);
|
||||
|
||||
@@ -1471,7 +317,7 @@ void minimize_stretch_tface_uv(void)
|
||||
me = get_mesh(OBACT);
|
||||
if(me==0 || me->tface==0) return;
|
||||
|
||||
handle = construct_param_handle(me, 1, fillholes);
|
||||
handle = construct_param_handle(me, 1, fillholes, 1);
|
||||
|
||||
lasttime = PIL_check_seconds_timer();
|
||||
|
||||
@@ -1561,7 +407,7 @@ void smooth_area_tface_uv(void)
|
||||
me = get_mesh(OBACT);
|
||||
if(me==0 || me->tface==0) return;
|
||||
|
||||
handle = construct_param_handle(me, 1, fillholes);
|
||||
handle = construct_param_handle(me, 1, fillholes, 1);
|
||||
param_smooth_area(handle);
|
||||
param_flush(handle);
|
||||
param_delete(handle);
|
||||
@@ -1584,24 +430,16 @@ void unwrap_lscm_live_begin(void)
|
||||
short abf = G.scene->toolsettings->unwrapper == 1;
|
||||
short fillholes = G.scene->toolsettings->uvcalc_flag & 1;
|
||||
|
||||
if (G.scene->toolsettings->unwrapper == 2)
|
||||
return;
|
||||
|
||||
me= get_mesh(OBACT);
|
||||
if(me==0 || me->tface==0) return;
|
||||
|
||||
liveHandle = construct_param_handle(me, 0, fillholes);
|
||||
liveHandle = construct_param_handle(me, 0, fillholes, 1);
|
||||
|
||||
param_lscm_begin(liveHandle, PARAM_TRUE, abf);
|
||||
}
|
||||
|
||||
void unwrap_lscm_live_re_solve(void)
|
||||
{
|
||||
if (G.scene->toolsettings->unwrapper == 2) {
|
||||
unwrap_lscm();
|
||||
return;
|
||||
}
|
||||
|
||||
if (liveHandle) {
|
||||
param_lscm_solve(liveHandle);
|
||||
param_flush(liveHandle);
|
||||
@@ -1610,9 +448,6 @@ void unwrap_lscm_live_re_solve(void)
|
||||
|
||||
void unwrap_lscm_live_end(short cancel)
|
||||
{
|
||||
if (G.scene->toolsettings->unwrapper == 2)
|
||||
return;
|
||||
|
||||
if (liveHandle) {
|
||||
param_lscm_end(liveHandle);
|
||||
if (cancel)
|
||||
|
||||
@@ -571,6 +571,8 @@ void viewmove(int mode)
|
||||
VECCOPY(obofs, ofs);
|
||||
}
|
||||
}
|
||||
else
|
||||
ofs[0] = ofs[1] = ofs[2] = 0.0f;
|
||||
|
||||
reverse= 1.0f;
|
||||
if (G.vd->persmat[2][1] < 0.0f)
|
||||
|
||||
@@ -652,26 +652,6 @@ static int sample_backbuf_area(int x, int y, float size)
|
||||
return tot;
|
||||
}
|
||||
|
||||
static unsigned int sample_backbuf(int x, int y)
|
||||
{
|
||||
unsigned int col;
|
||||
|
||||
if(x>=curarea->winx || y>=curarea->winy) return 0;
|
||||
|
||||
x+= curarea->winrct.xmin;
|
||||
y+= curarea->winrct.ymin;
|
||||
|
||||
#ifdef __APPLE__
|
||||
glReadBuffer(GL_AUX0);
|
||||
#endif
|
||||
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
|
||||
glReadBuffer(GL_BACK);
|
||||
|
||||
if(G.order==B_ENDIAN) SWITCH_INT(col);
|
||||
|
||||
return framebuffer_to_index(col);
|
||||
}
|
||||
|
||||
static int calc_vp_alpha_dl(VPaint *vp, float *vert_nor, short *mval)
|
||||
{
|
||||
float fac, dx, dy;
|
||||
|
||||
Reference in New Issue
Block a user