Orange branch commit.

This commit adds new underlying uv unwrapper code, intended to be
more extensible. At the moment this has a re-implementation of LSCM.
This has not been activated yet, since it doesn't add anything new.

What's new is the stretch minimize tool from tuhopuu. It works by
selecting some some uv's in the uv editor window, and then pressing
ctrl+V. The uv's on the boundary stay fixed.

More stuff will follow as I port it over & fix it.
This commit is contained in:
Brecht Van Lommel 2005-12-01 02:09:21 +00:00
parent 1eab492c4b
commit d6feeb6b22
9 changed files with 2996 additions and 797 deletions

@ -89,10 +89,6 @@ typedef void* NLContext;
#define NL_SYMMETRIC 0x106 #define NL_SYMMETRIC 0x106
#define NL_ERROR 0x108 #define NL_ERROR 0x108
/* Enable / Disable */
#define NL_NORMALIZE_ROWS 0x400
/* Row parameters */ /* Row parameters */
#define NL_RIGHT_HAND_SIDE 0x500 #define NL_RIGHT_HAND_SIDE 0x500
@ -142,7 +138,9 @@ void nlRightHandSideAdd(NLuint index, NLfloat value);
/* Solve */ /* Solve */
NLboolean nlSolve(void); void nlPrintMatrix(void);
NLboolean nlSolve();
NLboolean nlSolveAdvanced(NLint *permutation, NLboolean solveAgain);
#ifdef __cplusplus #ifdef __cplusplus
} }

File diff suppressed because it is too large Load Diff

@ -37,6 +37,7 @@ void set_seamtface(void); /* set TF_SEAM flags in tfaces */
void unwrap_lscm(void); /* unwrap selected tfaces */ void unwrap_lscm(void); /* unwrap selected tfaces */
void unwrap_lscm_live(void); /* unwrap selected tfaces (for live mode, with no undo pushes) */ void unwrap_lscm_live(void); /* unwrap selected tfaces (for live mode, with no undo pushes) */
void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index); void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index);
void minimize_stretch_tface_uv(void);
#endif /* BDR_UNWRAPPER_H */ #endif /* BDR_UNWRAPPER_H */

@ -1013,6 +1013,9 @@ static void do_image_uvsmenu(void *arg, int event)
if(G.sima->flag & SI_LSCM_LIVE) G.sima->flag &= ~SI_LSCM_LIVE; if(G.sima->flag & SI_LSCM_LIVE) G.sima->flag &= ~SI_LSCM_LIVE;
else G.sima->flag |= SI_LSCM_LIVE; else G.sima->flag |= SI_LSCM_LIVE;
break; break;
case 12:
minimize_stretch_tface_uv();
break;
} }
} }
@ -1047,6 +1050,7 @@ static uiBlock *image_uvsmenu(void *arg_unused)
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); 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, "Limit Stitch...|Shift V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, ""); 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, ""); 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, ""); uiDefIconTextBlockBut(block, image_uvs_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");

File diff suppressed because it is too large Load Diff

@ -0,0 +1,73 @@
#ifndef __PARAMETRIZER_H__
#define __PARAMETRIZER_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef void ParamHandle; /* handle to a set of charts */
typedef long ParamKey; /* (hash) key for identifying verts and faces */
typedef enum ParamBool {
PARAM_TRUE = 1,
PARAM_FALSE = 0
} ParamBool;
/* Chart construction:
-------------------
- faces and seams may only be added between construct_{begin|end}
- the pointers to co and uv are stored, rather than being copied
- vertices are implicitly created
- in construct_end the mesh will be split up according to the seams
- the resulting charts must be:
- manifold, connected, open (at least one boundary loop)
- output will be written to the uv pointers
*/
ParamHandle *param_construct_begin();
void param_face_add(ParamHandle *handle,
ParamKey key,
int nverts,
ParamKey *vkeys,
float **co,
float **uv,
ParamBool *pin,
ParamBool *select);
void param_edge_set_seam(ParamHandle *handle,
ParamKey *vkeys);
void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl);
void param_delete(ParamHandle *chart);
/* Least Squares Conformal Maps:
-----------------------------
- charts with less than two pinned vertices are assigned 2 pins
- lscm is divided in three steps:
- begin: compute matrix and it's factorization (expensive)
- solve using pinned coordinates (cheap)
- end: clean up
- uv coordinates are allowed to change within begin/end, for
quick re-solving
*/
void param_lscm_begin(ParamHandle *handle);
void param_lscm_solve(ParamHandle *handle);
void param_lscm_end(ParamHandle *handle);
/* Stretch */
void param_stretch_begin(ParamHandle *handle);
void param_stretch_iter(ParamHandle *handle);
void param_stretch_end(ParamHandle *handle, ParamBool restore);
/* Packing */
void param_pack(ParamHandle *handle);
#ifdef __cplusplus
}
#endif
#endif /*__PARAMETRIZER_H__*/

@ -0,0 +1,186 @@
#ifndef __PARAMETRIZER_INTERN_H__
#define __PARAMETRIZER_INTERN_H__
/* Hash:
-----
- insert only
- elements are all stored in a flat linked list
*/
typedef long PHashKey;
typedef struct PHashLink {
struct PHashLink *next;
PHashKey key;
} PHashLink;
typedef struct PHash {
PHashLink *first;
PHashLink **buckets;
int size, cursize, cursize_id;
} PHash;
PHash *phash_new(int sizehint);
void phash_delete_with_links(PHash *ph);
void phash_delete(PHash *ph);
int phash_size(PHash *ph);
void phash_insert(PHash *ph, PHashLink *link);
PHashLink *phash_lookup(PHash *ph, PHashKey key);
PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link);
#if 0
#define param_assert(condition)
#define param_warning(message);
#else
#define param_assert(condition) \
if (!(condition)) \
{ printf("Assertion %s:%d\n", __FILE__, __LINE__); abort(); }
#define param_warning(message) \
{ printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);
#endif
typedef enum PBool {
P_TRUE = 1,
P_FALSE = 0
} PBool;
struct PVert;
struct PEdge;
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;
PHeapLink *links;
PHeapLink **tree;
} PHeap;
/* Simplices */
typedef struct PVert {
struct PVertLink {
struct PVert *next;
PHashKey key;
} link;
struct PEdge *edge;
float *co;
float uv[2];
int flag;
union PVertUnion {
int index; /* lscm matrix index */
float distortion; /* area smoothing */
} u;
} PVert;
typedef struct PEdge {
struct PEdgeLink {
struct PEdge *next;
PHashKey key;
} link;
struct PVert *vert;
struct PEdge *pair;
struct PEdge *next;
struct PFace *face;
float *orig_uv, old_uv[2];
int flag;
union PEdgeUnion {
PHeapLink *heaplink;
} u;
} PEdge;
typedef struct PFace {
struct PFaceLink {
struct PFace *next;
PHashKey key;
} link;
struct PEdge *edge;
int flag;
union PFaceUnion {
int chart; /* chart construction */
float area3d; /* stretch */
} u;
} PFace;
enum PVertFlag {
PVERT_PIN = 1,
PVERT_SELECT = 2
};
enum PEdgeFlag {
PEDGE_SEAM = 1,
PEDGE_VERTEX_SPLIT = 2,
PEDGE_PIN = 4,
PEDGE_SELECT = 8,
PEDGE_DONE = 16,
PEDGE_FILLED = 32
};
/* for flipping faces */
#define PEDGE_VERTEX_FLAGS (PEDGE_PIN)
enum PFaceFlag {
PFACE_CONNECTED = 1,
PFACE_FILLED = 2
};
/* Chart */
typedef struct PChart {
PHash *verts;
PHash *edges;
PHash *faces;
union PChartUnion {
struct PChartLscm {
NLContext context;
float *abf_alpha;
PVert *singlepin;
PVert *pin1, *pin2;
} lscm;
struct PChartPack {
float rescale;
float size[2], trans[2];
} pack;
} u;
struct PHandle *handle;
} PChart;
enum PHandleState {
PHANDLE_STATE_ALLOCATED,
PHANDLE_STATE_CONSTRUCTED,
PHANDLE_STATE_LSCM,
PHANDLE_STATE_STRETCH,
};
typedef struct PHandle {
PChart *construction_chart;
PChart **charts;
int ncharts;
enum PHandleState state;
MemArena *arena;
PBool implicit;
RNG *rng;
} PHandle;
#endif /*__PARAMETRIZER_INTERN_H__*/

@ -3867,8 +3867,7 @@ static void winqreadimagespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
sample_vpaint(); sample_vpaint();
break; break;
case AKEY: case AKEY:
if((G.qual==0)) select_swap_tface_uv();
select_swap_tface_uv();
break; break;
case BKEY: case BKEY:
if(G.qual==LR_SHIFTKEY) if(G.qual==LR_SHIFTKEY)
@ -3956,6 +3955,8 @@ static void winqreadimagespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
stitch_uv_tface(0); stitch_uv_tface(0);
else if(G.qual==LR_SHIFTKEY) else if(G.qual==LR_SHIFTKEY)
stitch_uv_tface(1); stitch_uv_tface(1);
else if(G.qual==LR_CTRLKEY)
minimize_stretch_tface_uv();
break; break;
case WKEY: case WKEY:
weld_align_menu_tface_uv(); weld_align_menu_tface_uv();

@ -43,6 +43,8 @@
#include "DNA_mesh_types.h" #include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h" #include "DNA_meshdata_types.h"
#include "DNA_scene_types.h" #include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "BKE_global.h" #include "BKE_global.h"
#include "BKE_mesh.h" #include "BKE_mesh.h"
@ -53,6 +55,7 @@
#include "BIF_editsima.h" #include "BIF_editsima.h"
#include "BIF_space.h" #include "BIF_space.h"
#include "BIF_screen.h"
#include "blendef.h" #include "blendef.h"
#include "mydevice.h" #include "mydevice.h"
@ -60,6 +63,10 @@
#include "ONL_opennl.h" #include "ONL_opennl.h"
#include "BDR_unwrapper.h" #include "BDR_unwrapper.h"
#include "PIL_time.h"
#include "parametrizer.h"
/* Implementation Least Squares Conformal Maps parameterization, based on /* Implementation Least Squares Conformal Maps parameterization, based on
* chapter 2 of: * chapter 2 of:
* Bruno Levy, Sylvain Petitjean, Nicolas Ray, Jerome Maillot. Least Squares * Bruno Levy, Sylvain Petitjean, Nicolas Ray, Jerome Maillot. Least Squares
@ -903,9 +910,9 @@ static int unwrap_lscm_face_group(Mesh *me, int *groups, int gid)
lscm_build_matrix(me, lscmvert, groups, gid, center, radius); lscm_build_matrix(me, lscmvert, groups, gid, center, radius);
nlEnd(NL_SYSTEM); nlEnd(NL_SYSTEM);
/* LSCM solver magic! */ /* LSCM solver magic! */
nlSolve(); nlSolve(NULL, NL_FALSE);
/* load new uv's: will be projected uv's if solving failed */ /* load new uv's: will be projected uv's if solving failed */
lscm_load_solution(me, lscmvert, groups, gid); lscm_load_solution(me, lscmvert, groups, gid);
@ -1336,3 +1343,162 @@ void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
object_tface_flags_changed(OBACT, 0); object_tface_flags_changed(OBACT, 0);
} }
/* Parametrizer */
ParamHandle *construct_param_handle(Mesh *me, short implicit, short fill)
{
int a;
TFace *tf;
MFace *mf;
MVert *mv;
MEdge *medge;
ParamHandle *handle;
handle = param_construct_begin();
mv= me->mvert;
mf= me->mface;
tf= me->tface;
for (a=0; a<me->totface; a++, mf++, tf++) {
ParamKey key, vkeys[4];
ParamBool pin[4], select[4];
float *co[4];
float *uv[4];
int nverts;
if ((tf->flag & TF_HIDE) || !(tf->flag & TF_SELECT))
continue;
if (implicit && !(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)))
continue;
key = (ParamKey)mf;
vkeys[0] = (ParamKey)mf->v1;
vkeys[1] = (ParamKey)mf->v2;
vkeys[2] = (ParamKey)mf->v3;
co[0] = (mv+mf->v1)->co;
co[1] = (mv+mf->v2)->co;
co[2] = (mv+mf->v3)->co;
uv[0] = tf->uv[0];
uv[1] = tf->uv[1];
uv[2] = tf->uv[2];
pin[0] = ((tf->flag & TF_PIN1) != 0);
pin[1] = ((tf->flag & TF_PIN2) != 0);
pin[2] = ((tf->flag & TF_PIN3) != 0);
select[0] = ((tf->flag & TF_SEL1) != 0);
select[1] = ((tf->flag & TF_SEL2) != 0);
select[2] = ((tf->flag & TF_SEL3) != 0);
if (mf->v4) {
vkeys[3] = (ParamKey)mf->v4;
co[3] = (mv+mf->v4)->co;
uv[3] = tf->uv[3];
pin[3] = ((tf->flag & TF_PIN4) != 0);
select[3] = ((tf->flag & TF_SEL4) != 0);
nverts = 4;
}
else
nverts = 3;
param_face_add(handle, key, nverts, vkeys, co, uv, pin, select);
}
if (!implicit) {
for(medge=me->medge, a=me->totedge; a>0; a--, medge++) {
if(medge->flag & ME_SEAM) {
ParamKey vkeys[2];
vkeys[0] = (ParamKey)medge->v1;
vkeys[1] = (ParamKey)medge->v2;
param_edge_set_seam(handle, vkeys);
}
}
}
param_construct_end(handle, fill, implicit);
return handle;
}
#if 0
void unwrap_lscm(void)
{
Mesh *me;
ParamHandle *handle;
me= get_mesh(OBACT);
if(me==0 || me->tface==0) return;
handle = construct_param_handle(me, 0, 1);
param_lscm_begin(handle);
param_lscm_solve(handle);
param_lscm_end(handle);
param_pack(handle);
param_delete(handle);
BIF_undo_push("UV lscm unwrap");
object_uvs_changed(OBACT);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWIMAGE, 0);
}
#endif
void minimize_stretch_tface_uv(void)
{
Mesh *me;
ParamHandle *handle;
double lasttime;
short doit = 1, val;
unsigned short event = 0;
me = get_mesh(OBACT);
if(me==0 || me->tface==0) return;
handle = construct_param_handle(me, 1, 0);
lasttime = PIL_check_seconds_timer();
param_stretch_begin(handle);
while (doit) {
param_stretch_iter(handle);
while (qtest()) {
event= extern_qread(&val);
if (val && (event==ESCKEY || event==RETKEY || event==PADENTER))
doit = 0;
}
if (!doit)
break;
if (PIL_check_seconds_timer() - lasttime > 0.5) {
headerprint("Enter to finish. Escape to cancel.");
lasttime = PIL_check_seconds_timer();
if(G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
else force_draw(0);
}
}
param_stretch_end(handle, event==ESCKEY);
param_delete(handle);
BIF_undo_push("UV stretch minimize");
object_uvs_changed(OBACT);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWIMAGE, 0);
}