Texture Paint Add Simple UVs:

Add simple uvs now does a cube unwrap and pack operation. Result is not
optimal by far but it should not result in crashes and it will be quite
usable for simple cases.
This commit is contained in:
Antonis Ryakiotakis 2014-10-31 14:37:36 +01:00
parent 46c11c7b7d
commit a6a3989617
11 changed files with 168 additions and 48 deletions

View File

@ -794,7 +794,7 @@ class VIEW3D_PT_imapaint_tools_missing(Panel, View3DPaintPanel):
col.separator()
col.label("Missing UVs", icon='INFO')
col.label("Unwrap the mesh in edit mode or generate a simple UVs")
col.operator("mesh.uv_texture_add", text="Add Simple UVs")
col.operator("paint.add_simple_uvs")
if toolsettings.mode == 'MATERIAL':
if toolsettings.missing_materials:

View File

@ -267,6 +267,7 @@ void ED_mesh_vertices_remove(struct Mesh *mesh, struct ReportList *reports, int
void ED_mesh_calc_tessface(struct Mesh *mesh);
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, int calc_edges, int calc_tessface);
void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name);
int ED_mesh_uv_texture_add(struct Mesh *me, const char *name, const bool active_set);
bool ED_mesh_uv_texture_remove_index(struct Mesh *me, const int n);
bool ED_mesh_uv_texture_remove_active(struct Mesh *me);

View File

@ -31,6 +31,7 @@
#define __ED_UVEDIT_H__
struct ARegionType;
struct BMesh;
struct BMEditMesh;
struct BMFace;
struct BMLoop;
@ -52,6 +53,7 @@ void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
void ED_uvedit_assign_image(struct Main *bmain, struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma);
bool ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]);
void ED_uvedit_select_all(struct BMesh *bm);
bool ED_object_get_active_image(struct Object *ob, int mat_nr,
struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree);
@ -98,10 +100,13 @@ void ED_uvedit_live_unwrap_re_solve(void);
void ED_uvedit_live_unwrap_end(short cancel);
void ED_uvedit_live_unwrap(struct Scene *scene, struct Object *obedit);
void ED_uvedit_pack_islands(struct Scene *scene, struct Object *ob, struct BMesh *bm, bool selected, bool correct_aspect, bool do_rotate);
void ED_uvedit_cube_project_unwrap(struct Object *ob, struct BMesh *bm, float cube_size, bool use_select);
/* single call up unwrap using scene settings, used for edge tag unwrapping */
void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel);
/* uvedit_draw.c */
void draw_image_cursor(struct ARegion *ar, const float cursor[2]);
void draw_uvedit_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit, struct Object *obact);

View File

@ -336,6 +336,26 @@ int ED_mesh_uv_texture_add(Mesh *me, const char *name, const bool active_set)
return layernum_dst;
}
void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name)
{
BMEditMesh *em;
int layernum_dst;
if (me->edit_btmesh) {
em = me->edit_btmesh;
layernum_dst = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
if (layernum_dst == 0)
ED_mesh_uv_texture_add(me, name, true);
}
else {
layernum_dst = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
if (layernum_dst == 0)
ED_mesh_uv_texture_add(me, name, true);
}
}
bool ED_mesh_uv_texture_remove_index(Mesh *me, const int n)
{
CustomData *pdata = GET_CD_DATA(me, pdata), *ldata = GET_CD_DATA(me, ldata);

View File

@ -105,6 +105,9 @@
#include "IMB_colormanagement.h"
#include "bmesh.h"
//#include "bmesh_tools.h"
#include "paint_intern.h"
/* Defines and Structs */
@ -5233,9 +5236,9 @@ static int texture_paint_delete_texture_paint_slot_exec(bContext *C, wmOperator
BKE_texpaint_slot_refresh_cache(scene, ma);
DAG_id_tag_update(&ma->id, 0);
WM_event_add_notifier(C, NC_MATERIAL, CTX_data_scene(C));
WM_event_add_notifier(C, NC_MATERIAL, ma);
/* we need a notifier for data change since we change the displayed modifier uvs */
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
return OPERATOR_FINISHED;
}
@ -5254,3 +5257,64 @@ void PAINT_OT_delete_texture_paint_slot(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op))
{
/* no checks here, poll function does them for us */
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
Mesh *me = ob->data;
bool synch_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
/* turn synch selection off, since we are not in edit mode we need to ensure only the uv flags are tested */
scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION;
ED_mesh_uv_texture_ensure(me, NULL);
BM_mesh_bm_from_me(bm, me, true, false, 0);
/* select all uv loops first - pack parameters needs this to make sure charts are registered */
ED_uvedit_select_all(bm);
ED_uvedit_cube_project_unwrap(ob, bm, 1.0, false);
/* set the margin really quickly before the packing operation*/
scene->toolsettings->uvcalc_margin = 0.001f;
ED_uvedit_pack_islands(scene, ob, bm, false, false, true);
BM_mesh_bm_to_me(bm, me, false);
BM_mesh_free(bm);
if (synch_selection)
scene->toolsettings->uv_flag |= UV_SYNC_SELECTION;
DAG_id_tag_update(ob->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene);
return OPERATOR_FINISHED;
}
static int add_simple_uvs_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
if (!ob || ob->type != OB_MESH || ob->mode != OB_MODE_TEXTURE_PAINT)
return false;
return true;
}
void PAINT_OT_add_simple_uvs(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add simple UVs";
ot->description = "Add cube map uvs on mesh";
ot->idname = "PAINT_OT_add_simple_uvs";
/* api callbacks */
ot->exec = add_simple_uvs_exec;
ot->poll = add_simple_uvs_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}

View File

@ -184,6 +184,7 @@ void PAINT_OT_image_from_view(struct wmOperatorType *ot);
void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_delete_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
/* uv sculpting */
int uv_sculpt_poll(struct bContext *C);

View File

@ -1085,6 +1085,7 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_brush_colors_flip);
WM_operatortype_append(PAINT_OT_add_texture_paint_slot);
WM_operatortype_append(PAINT_OT_delete_texture_paint_slot);
WM_operatortype_append(PAINT_OT_add_simple_uvs);
/* weight */
WM_operatortype_append(PAINT_OT_weight_paint_toggle);

View File

@ -41,6 +41,7 @@ struct SpaceImage;
struct UvElementMap;
struct wmOperatorType;
struct BMEditMesh;
struct BMesh;
struct BMFace;
struct BMLoop;
struct BMEdge;
@ -71,7 +72,7 @@ void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditM
/* utility tool functions */
void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit);
void uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMEditMesh *em, float *aspx, float *aspy);
void uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy);
/* operators */

View File

@ -668,6 +668,24 @@ bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2],
return changed;
}
/* Be careful when using this, it bypasses all synchronization options */
void ED_uvedit_select_all(BMesh *bm)
{
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv->flag |= MLOOPUV_VERTSEL;
}
}
}
static bool ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);

View File

@ -1660,7 +1660,7 @@ static int stitch_init(bContext *C, wmOperator *op)
return 0;
}
uvedit_get_aspect(scene, obedit, em, &aspx, &aspy);
uvedit_get_aspect(scene, obedit, em->bm, &aspx, &aspy);
state->aspect = aspx / aspy;
/* Entirely possible if redoing last operator that static island is bigger than total number of islands.

View File

@ -190,21 +190,21 @@ static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, bool implicit)
return false;
}
void uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, float *aspy)
void uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, float *aspy)
{
bool sloppy = true;
bool selected = false;
BMFace *efa;
Image *ima;
efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
efa = BM_mesh_active_face_get(bm, sloppy, selected);
if (efa) {
if (BKE_scene_use_new_shading_nodes(scene)) {
ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
}
else {
MTexPoly *tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
MTexPoly *tf = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY);
ima = tf->tpage;
}
@ -247,11 +247,10 @@ static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene,
param_face_add(handle, key, i, vkeys, co, uv, pin, select, efa->no);
}
static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMEditMesh *em,
static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
const bool implicit, const bool fill, const bool sel,
const bool correct_aspect)
{
BMesh *bm = em->bm;
ParamHandle *handle;
BMFace *efa;
BMLoop *l;
@ -262,20 +261,19 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMEditMesh
handle = param_construct_begin();
if (correct_aspect) {
float aspx, aspy;
uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
if (aspx != aspy)
param_aspect_ratio(handle, aspx, aspy);
}
/* we need the vert indices */
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
BM_mesh_elem_index_ensure(bm, BM_VERT);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || (sel && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
continue;
@ -299,7 +297,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMEditMesh
}
if (!implicit) {
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
ParamKey vkeys[2];
vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
@ -378,7 +376,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
if (correct_aspect) {
float aspx, aspy;
uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
if (aspx != aspy)
param_aspect_ratio(handle, aspx, aspy);
@ -522,7 +520,7 @@ static bool minimize_stretch_init(bContext *C, wmOperator *op)
ms->blend = RNA_float_get(op->ptr, "blend");
ms->iterations = RNA_int_get(op->ptr, "iterations");
ms->i = 0;
ms->handle = construct_param_handle(scene, obedit, em, implicit, fill_holes, 1, 1);
ms->handle = construct_param_handle(scene, obedit, em->bm, implicit, fill_holes, 1, 1);
ms->lasttime = PIL_check_seconds_timer();
param_stretch_begin(ms->handle);
@ -701,16 +699,23 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/* ******************** Pack Islands operator **************** */
void ED_uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm, bool selected, bool correct_aspect, bool do_rotate)
{
ParamHandle *handle;
handle = construct_param_handle(scene, ob, bm, true, false, selected, correct_aspect);
param_pack(handle, scene->toolsettings->uvcalc_margin, do_rotate);
param_flush(handle);
param_delete(handle);
}
static int pack_islands_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
ParamHandle *handle;
bool implicit = true;
bool do_rotate = RNA_boolean_get(op->ptr, "rotate");
if (!uvedit_have_selection(scene, em, implicit)) {
if (!uvedit_have_selection(scene, em, true)) {
return OPERATOR_CANCELLED;
}
@ -719,10 +724,7 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
else
RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
handle = construct_param_handle(scene, obedit, em, implicit, 0, 1, 1);
param_pack(handle, scene->toolsettings->uvcalc_margin, do_rotate);
param_flush(handle);
param_delete(handle);
ED_uvedit_pack_islands(scene, obedit, em->bm, true, true, do_rotate);
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
@ -762,7 +764,7 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
handle = construct_param_handle(scene, obedit, em, implicit, 0, 1, 1);
handle = construct_param_handle(scene, obedit, em->bm, implicit, 0, 1, 1);
param_average(handle);
param_flush(handle);
param_delete(handle);
@ -807,7 +809,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
if (use_subsurf)
liveHandle = construct_param_handle_subsurfed(scene, obedit, em, fillholes, false, true);
else
liveHandle = construct_param_handle(scene, obedit, em, false, fillholes, false, true);
liveHandle = construct_param_handle(scene, obedit, em->bm, false, fillholes, false, true);
param_lscm_begin(liveHandle, PARAM_TRUE, abf);
}
@ -1008,7 +1010,7 @@ static void correct_uv_aspect(Scene *scene, Object *ob, BMEditMesh *em)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
if (aspx == aspy)
return;
@ -1072,7 +1074,7 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper
if (scale_to_bounds) {
INIT_MINMAX2(min, max);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
continue;
@ -1082,7 +1084,7 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper
minmax_v2v2_v2(min, max, luv->uv);
}
}
/* rescale UV to be in 1/1 */
dx = (max[0] - min[0]);
dy = (max[1] - min[1]);
@ -1098,7 +1100,7 @@ static void uv_map_clip_correct(Scene *scene, Object *ob, BMEditMesh *em, wmOper
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
luv->uv[0] = (luv->uv[0] - min[0]) * dx;
luv->uv[1] = (luv->uv[1] - min[1]) * dy;
}
@ -1136,7 +1138,7 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
if (use_subsurf)
handle = construct_param_handle_subsurfed(scene, obedit, em, fill_holes, sel, correct_aspect);
else
handle = construct_param_handle(scene, obedit, em, false, fill_holes, sel, correct_aspect);
handle = construct_param_handle(scene, obedit, em->bm, false, fill_holes, sel, correct_aspect);
param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
param_lscm_solve(handle);
@ -1599,39 +1601,30 @@ void UV_OT_cylinder_project(wmOperatorType *ot)
/******************* Cube Project operator ****************/
static int cube_project_exec(bContext *C, wmOperator *op)
void ED_uvedit_cube_project_unwrap(Object *ob, BMesh *bm, float cube_size, bool use_select)
{
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
/* MTexPoly *tf; */ /* UNUSED */
MLoopUV *luv;
float cube_size, *loc, dx, dy;
float *loc, dx, dy;
int cox, coy;
int cd_loop_uv_offset;
/* add uvs if they don't exist yet */
if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
return OPERATOR_CANCELLED;
}
cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
loc = obedit->obmat[3];
cube_size = RNA_float_get(op->ptr, "cube_size");
loc = ob->obmat[3];
/* choose x,y,z axis for projection depending on the largest normal
* component, but clusters all together around the center of map. */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
int first = 1;
/* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT))
continue;
axis_dominant_v3(&cox, &coy, efa->no);
@ -1642,19 +1635,35 @@ static int cube_project_exec(bContext *C, wmOperator *op)
luv->uv[0] = 0.5f + 0.5f * cube_size * (loc[cox] + l->v->co[cox]);
luv->uv[1] = 0.5f + 0.5f * cube_size * (loc[coy] + l->v->co[coy]);
if (first) {
dx = floor(luv->uv[0]);
dy = floor(luv->uv[1]);
first = 0;
}
luv->uv[0] -= dx;
luv->uv[1] -= dy;
}
}
}
static int cube_project_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
float cube_size = RNA_float_get(op->ptr, "cube_size");
/* add uvs if they don't exist yet */
if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
return OPERATOR_CANCELLED;
}
ED_uvedit_cube_project_unwrap(obedit, em->bm, cube_size, true);
uv_map_clip_correct(scene, obedit, em, op);
DAG_id_tag_update(obedit->data, 0);