2858 lines
72 KiB
C
2858 lines
72 KiB
C
/**
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifndef WIN32
|
|
#include <unistd.h>
|
|
#else
|
|
#include <io.h>
|
|
#endif
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_arithb.h"
|
|
#include "BLI_editVert.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
#include "IMB_imbuf.h"
|
|
|
|
#include "DNA_image_types.h"
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_node_types.h"
|
|
#include "DNA_object_types.h" // only for uvedit_selectionCB() (struct Object)
|
|
#include "DNA_packedFile_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_space_types.h"
|
|
#include "DNA_screen_types.h"
|
|
#include "DNA_texture_types.h"
|
|
#include "DNA_userdef_types.h"
|
|
#include "DNA_view3d_types.h"
|
|
|
|
#include "BKE_colortools.h"
|
|
#include "BKE_depsgraph.h"
|
|
#include "BKE_displist.h"
|
|
#include "BKE_image.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_library.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_mesh.h"
|
|
#include "BKE_node.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_packedFile.h"
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BIF_gl.h"
|
|
#include "BIF_glutil.h"
|
|
#include "BIF_imasel.h"
|
|
#include "BIF_interface.h"
|
|
#include "BIF_drawimage.h"
|
|
#include "BIF_editview.h"
|
|
#include "BIF_editsima.h"
|
|
#include "BIF_mywindow.h"
|
|
#include "BIF_previewrender.h"
|
|
#include "BIF_screen.h"
|
|
#include "BIF_space.h"
|
|
#include "BIF_toolbox.h"
|
|
#include "BIF_transform.h"
|
|
#include "BIF_writeimage.h"
|
|
#include "BIF_editmesh.h"
|
|
|
|
#include "BSE_drawipo.h"
|
|
#include "BSE_edit.h"
|
|
#include "BSE_filesel.h"
|
|
#include "BSE_node.h"
|
|
#include "BSE_trans_types.h"
|
|
|
|
#include "BDR_editobject.h"
|
|
#include "BDR_unwrapper.h"
|
|
|
|
#include "BMF_Api.h"
|
|
|
|
#include "RE_pipeline.h"
|
|
|
|
#include "blendef.h"
|
|
#include "multires.h"
|
|
#include "mydevice.h"
|
|
#include "editmesh.h"
|
|
|
|
/* local prototypes */
|
|
void sel_uvco_inside_radius(short , EditFace *efa, MTFace *, int , float *, float *, short);
|
|
void uvedit_selectionCB(short , Object *, short *, float ); /* used in edit.c*/
|
|
|
|
void object_uvs_changed(Object *ob)
|
|
{
|
|
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
|
|
void object_tface_flags_changed(Object *ob, int updateButtons)
|
|
{
|
|
if (updateButtons) allqueue(REDRAWBUTSEDIT, 0);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
|
|
int is_uv_tface_editing_allowed_silent(void)
|
|
{
|
|
if(!EM_texFaceCheck()) return 0;
|
|
if(G.sima->mode!=SI_TEXTURE) return 0;
|
|
if(multires_level1_test()) return 0;
|
|
return 1;
|
|
}
|
|
|
|
int is_uv_tface_editing_allowed(void)
|
|
{
|
|
if(!G.obedit) error("Enter Edit Mode to perform this action");
|
|
|
|
return is_uv_tface_editing_allowed_silent();
|
|
}
|
|
|
|
void get_connected_limit_tface_uv(float *limit)
|
|
{
|
|
ImBuf *ibuf= imagewindow_get_ibuf(G.sima);
|
|
if(ibuf && ibuf->x > 0 && ibuf->y > 0) {
|
|
limit[0]= 0.05/(float)ibuf->x;
|
|
limit[1]= 0.05/(float)ibuf->y;
|
|
}
|
|
else
|
|
limit[0]= limit[1]= 0.05/256.0;
|
|
}
|
|
|
|
void be_square_tface_uv(EditMesh *em)
|
|
{
|
|
EditFace *efa;
|
|
MTFace *tface;
|
|
/* if 1 vertex selected: doit (with the selected vertex) */
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
if (efa->v4) {
|
|
tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if (simaUVSel_Check(efa, tface, 0)) {
|
|
if( tface->uv[1][0] == tface->uv[2][0] ) {
|
|
tface->uv[1][1]= tface->uv[0][1];
|
|
tface->uv[3][0]= tface->uv[0][0];
|
|
}
|
|
else {
|
|
tface->uv[1][0]= tface->uv[0][0];
|
|
tface->uv[3][1]= tface->uv[0][1];
|
|
}
|
|
|
|
}
|
|
if (simaUVSel_Check(efa, tface, 1)) {
|
|
if( tface->uv[2][1] == tface->uv[3][1] ) {
|
|
tface->uv[2][0]= tface->uv[1][0];
|
|
tface->uv[0][1]= tface->uv[1][1];
|
|
}
|
|
else {
|
|
tface->uv[2][1]= tface->uv[1][1];
|
|
tface->uv[0][0]= tface->uv[1][0];
|
|
}
|
|
|
|
}
|
|
if (simaUVSel_Check(efa, tface, 2)) {
|
|
if( tface->uv[3][0] == tface->uv[0][0] ) {
|
|
tface->uv[3][1]= tface->uv[2][1];
|
|
tface->uv[1][0]= tface->uv[2][0];
|
|
}
|
|
else {
|
|
tface->uv[3][0]= tface->uv[2][0];
|
|
tface->uv[1][1]= tface->uv[2][1];
|
|
}
|
|
}
|
|
if (simaUVSel_Check(efa, tface, 3)) {
|
|
if( tface->uv[0][1] == tface->uv[1][1] ) {
|
|
tface->uv[0][0]= tface->uv[3][0];
|
|
tface->uv[2][1]= tface->uv[3][1];
|
|
}
|
|
else {
|
|
tface->uv[0][1]= tface->uv[3][1];
|
|
tface->uv[2][0]= tface->uv[3][0];
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void transform_aspect_ratio_tface_uv(float *aspx, float *aspy)
|
|
{
|
|
int w, h;
|
|
float xuser_asp, yuser_asp;
|
|
|
|
if(G.sima && G.sima->image) {
|
|
image_pixel_aspect(G.sima->image, &xuser_asp, &yuser_asp);
|
|
|
|
transform_width_height_tface_uv(&w, &h);
|
|
*aspx= (float)w/256.0f * xuser_asp;
|
|
*aspy= (float)h/256.0f * yuser_asp;
|
|
}
|
|
else {
|
|
*aspx= 1.0f;
|
|
*aspy= 1.0f;
|
|
}
|
|
}
|
|
|
|
void transform_width_height_tface_uv(int *width, int *height)
|
|
{
|
|
ImBuf *ibuf= imagewindow_get_ibuf(G.sima);
|
|
|
|
if(ibuf) {
|
|
*width= ibuf->x;
|
|
*height= ibuf->y;
|
|
}
|
|
else {
|
|
*width= 256;
|
|
*height= 256;
|
|
}
|
|
}
|
|
|
|
void mirrormenu_tface_uv(void)
|
|
{
|
|
float mat[3][3];
|
|
short mode= 0;
|
|
|
|
Mat3One(mat);
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return;
|
|
|
|
mode= pupmenu("Mirror%t|X Axis%x1|Y Axis%x2|");
|
|
|
|
if(mode==-1) return;
|
|
|
|
if (mode == 1) {
|
|
initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
|
|
BIF_setSingleAxisConstraint(mat[0], " on X axis");
|
|
Transform();
|
|
}
|
|
else {
|
|
initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
|
|
BIF_setSingleAxisConstraint(mat[1], " on Y axis");
|
|
Transform();
|
|
}
|
|
|
|
BIF_undo_push("Mirror UV");
|
|
}
|
|
|
|
void weld_align_tface_uv(char tool)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tface;
|
|
float cent[2], min[2], max[2];
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return;
|
|
|
|
INIT_MINMAX2(min, max);
|
|
|
|
if(tool == 'a') {
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if (simaUVSel_Check(efa, tface, 0))
|
|
DO_MINMAX2(tface->uv[0], min, max)
|
|
if (simaUVSel_Check(efa, tface, 1))
|
|
DO_MINMAX2(tface->uv[1], min, max)
|
|
if (simaUVSel_Check(efa, tface, 2))
|
|
DO_MINMAX2(tface->uv[2], min, max)
|
|
if (efa->v4 && simaUVSel_Check(efa, tface, 3))
|
|
DO_MINMAX2(tface->uv[3], min, max)
|
|
}
|
|
}
|
|
|
|
tool= (max[0]-min[0] >= max[1]-min[1])? 'y': 'x';
|
|
}
|
|
|
|
cent_tface_uv(cent, 0);
|
|
|
|
if(tool == 'x' || tool == 'w') {
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if (simaUVSel_Check(efa, tface, 0))
|
|
tface->uv[0][0]= cent[0];
|
|
if (simaUVSel_Check(efa, tface, 1))
|
|
tface->uv[1][0]= cent[0];
|
|
if (simaUVSel_Check(efa, tface, 2))
|
|
tface->uv[2][0]= cent[0];
|
|
if (efa->v4 && simaUVSel_Check(efa, tface, 3))
|
|
tface->uv[3][0]= cent[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
if(tool == 'y' || tool == 'w') {
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if (simaUVSel_Check(efa, tface, 0))
|
|
tface->uv[0][1]= cent[1];
|
|
if (simaUVSel_Check(efa, tface, 1))
|
|
tface->uv[1][1]= cent[1];
|
|
if (simaUVSel_Check(efa, tface, 2))
|
|
tface->uv[2][1]= cent[1];
|
|
if (efa->v4 && simaUVSel_Check(efa, tface, 3))
|
|
tface->uv[3][1]= cent[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
object_uvs_changed(OBACT);
|
|
}
|
|
|
|
// just for averaging UV's
|
|
typedef struct UVVertAverage {
|
|
float uv[2];
|
|
int count;
|
|
} UVVertAverage;
|
|
|
|
void stitch_vert_uv_tface(void)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
EditVert *eve;
|
|
MTFace *tface;
|
|
int count;
|
|
UVVertAverage *uv_average, *uvav;
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return;
|
|
|
|
// index and count verts
|
|
for (count=0, eve=em->verts.first; eve; count++, eve= eve->next) {
|
|
eve->tmp.l = count;
|
|
}
|
|
|
|
uv_average = MEM_callocN(sizeof(UVVertAverage) * count, "Stitch");
|
|
|
|
// gather uv averages per vert
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if (simaUVSel_Check(efa, tface, 0)) {
|
|
uvav = uv_average + efa->v1->tmp.l;
|
|
uvav->count++;
|
|
uvav->uv[0] += tface->uv[0][0];
|
|
uvav->uv[1] += tface->uv[0][1];
|
|
}
|
|
if (simaUVSel_Check(efa, tface, 1)) {
|
|
uvav = uv_average + efa->v2->tmp.l;
|
|
uvav->count++;
|
|
uvav->uv[0] += tface->uv[1][0];
|
|
uvav->uv[1] += tface->uv[1][1];
|
|
}
|
|
if (simaUVSel_Check(efa, tface, 2)) {
|
|
uvav = uv_average + efa->v3->tmp.l;
|
|
uvav->count++;
|
|
uvav->uv[0] += tface->uv[2][0];
|
|
uvav->uv[1] += tface->uv[2][1];
|
|
}
|
|
if (efa->v4 && simaUVSel_Check(efa, tface, 3)) {
|
|
uvav = uv_average + efa->v4->tmp.l;
|
|
uvav->count++;
|
|
uvav->uv[0] += tface->uv[3][0];
|
|
uvav->uv[1] += tface->uv[3][1];
|
|
}
|
|
}
|
|
}
|
|
|
|
// apply uv welding
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if (simaUVSel_Check(efa, tface, 0)) {
|
|
uvav = uv_average + efa->v1->tmp.l;
|
|
tface->uv[0][0] = uvav->uv[0]/uvav->count;
|
|
tface->uv[0][1] = uvav->uv[1]/uvav->count;
|
|
}
|
|
if (simaUVSel_Check(efa, tface, 1)) {
|
|
uvav = uv_average + efa->v2->tmp.l;
|
|
tface->uv[1][0] = uvav->uv[0]/uvav->count;
|
|
tface->uv[1][1] = uvav->uv[1]/uvav->count;
|
|
}
|
|
if (simaUVSel_Check(efa, tface, 2)) {
|
|
uvav = uv_average + efa->v3->tmp.l;
|
|
tface->uv[2][0] = uvav->uv[0]/uvav->count;
|
|
tface->uv[2][1] = uvav->uv[1]/uvav->count;
|
|
}
|
|
if (efa->v4 && simaUVSel_Check(efa, tface, 3)) {
|
|
uvav = uv_average + efa->v4->tmp.l;
|
|
tface->uv[3][0] = uvav->uv[0]/uvav->count;
|
|
tface->uv[3][1] = uvav->uv[1]/uvav->count;
|
|
}
|
|
}
|
|
}
|
|
MEM_freeN(uv_average);
|
|
object_uvs_changed(OBACT);
|
|
}
|
|
|
|
void weld_align_menu_tface_uv(void)
|
|
{
|
|
short mode= 0;
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return;
|
|
|
|
mode= pupmenu("Weld/Align%t|Weld%x1|Align Auto%x2|Align X%x3|Align Y%x4");
|
|
|
|
if(mode==-1) return;
|
|
if(mode==1) weld_align_tface_uv('w');
|
|
else if(mode==2) weld_align_tface_uv('a');
|
|
else if(mode==3) weld_align_tface_uv('x');
|
|
else if(mode==4) weld_align_tface_uv('y');
|
|
|
|
if(mode==1) BIF_undo_push("Weld UV");
|
|
else if(ELEM3(mode, 2, 3, 4)) BIF_undo_push("Align UV");
|
|
}
|
|
|
|
void select_invert_tface_uv(void)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tface;
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return;
|
|
|
|
if (G.sima->flag & SI_SYNC_UVSEL) {
|
|
/* Warning, this is not that good (calling editmode stuff from UV),
|
|
TODO look into changing it */
|
|
selectswap_mesh();
|
|
return;
|
|
} else {
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
tface->flag ^= TF_SEL1;
|
|
tface->flag ^= TF_SEL2;
|
|
tface->flag ^= TF_SEL3;
|
|
if(efa->v4) tface->flag ^= TF_SEL4;
|
|
}
|
|
}
|
|
}
|
|
BIF_undo_push("Select Inverse UV");
|
|
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
|
|
void select_swap_tface_uv(void)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tface;
|
|
int sel=0;
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return;
|
|
|
|
if (G.sima->flag & SI_SYNC_UVSEL) {
|
|
deselectall_mesh();
|
|
return;
|
|
} else {
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if(tface->flag & (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4)) {
|
|
sel= 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if(efa->v4) {
|
|
if(sel) tface->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
|
|
else tface->flag |= (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
|
|
}
|
|
else {
|
|
if(sel) tface->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
|
|
else tface->flag |= (TF_SEL1+TF_SEL2+TF_SEL3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
BIF_undo_push("Select swap");
|
|
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
|
|
static int msel_hit(float *limit, unsigned int *hitarray, unsigned int vertexid, float **uv, float *uv2, int sticky)
|
|
{
|
|
int i;
|
|
for(i=0; i< 4; i++) {
|
|
if(hitarray[i] == vertexid) {
|
|
if(sticky == 2) {
|
|
if(fabs(uv[i][0]-uv2[0]) < limit[0] &&
|
|
fabs(uv[i][1]-uv2[1]) < limit[1])
|
|
return 1;
|
|
}
|
|
else return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void find_nearest_uv_edge(MTFace **nearesttf, EditFace **nearestefa, int *nearestedge)
|
|
{
|
|
EditMesh *em= G.editMesh;
|
|
MTFace *tf;
|
|
EditFace *efa;
|
|
float mvalf[2], v1[2], v2[2];
|
|
int i, nverts, mindist, dist, uval1[2], uval2[2];
|
|
short mval[2];
|
|
|
|
getmouseco_areawin(mval);
|
|
mvalf[0]= mval[0];
|
|
mvalf[1]= mval[1];
|
|
|
|
mindist= 0x7FFFFFF;
|
|
*nearesttf= NULL;
|
|
*nearestefa= NULL;
|
|
*nearestedge= 0;
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if(simaFaceDraw_Check(efa, tf)) {
|
|
nverts= efa->v4? 4: 3;
|
|
for(i=0; i<nverts; i++) {
|
|
uvco_to_areaco_noclip(tf->uv[i], uval1);
|
|
uvco_to_areaco_noclip(tf->uv[(i+1)%nverts], uval2);
|
|
|
|
v1[0]= uval1[0];
|
|
v1[1]= uval1[1];
|
|
v2[0]= uval2[0];
|
|
v2[1]= uval2[1];
|
|
|
|
dist= PdistVL2Dfl(mvalf, v1, v2);
|
|
if (dist < mindist) {
|
|
*nearesttf= tf;
|
|
*nearestefa= efa;
|
|
*nearestedge= i;
|
|
mindist= dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void find_nearest_tface(MTFace **nearesttf, EditFace **nearestefa)
|
|
{
|
|
EditMesh *em= G.editMesh;
|
|
MTFace *tf;
|
|
EditFace *efa;
|
|
int i, nverts, mindist, dist, fcenter[2], uval[2];
|
|
short mval[2];
|
|
|
|
getmouseco_areawin(mval);
|
|
|
|
mindist= 0x7FFFFFF;
|
|
*nearesttf= NULL;
|
|
*nearestefa= NULL;
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tf)) {
|
|
fcenter[0]= fcenter[1]= 0;
|
|
nverts= efa->v4? 4: 3;
|
|
for(i=0; i<nverts; i++) {
|
|
uvco_to_areaco_noclip(tf->uv[i], uval);
|
|
fcenter[0] += uval[0];
|
|
fcenter[1] += uval[1];
|
|
}
|
|
|
|
fcenter[0] /= nverts;
|
|
fcenter[1] /= nverts;
|
|
|
|
dist= abs(mval[0]- fcenter[0])+ abs(mval[1]- fcenter[1]);
|
|
if (dist < mindist) {
|
|
*nearesttf= tf;
|
|
*nearestefa= efa;
|
|
mindist= dist;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int nearest_uv_between(MTFace *tf, int nverts, int id, short *mval, int *uval)
|
|
{
|
|
float m[3], v1[3], v2[3], c1, c2;
|
|
int id1, id2;
|
|
|
|
id1= (id+nverts-1)%nverts;
|
|
id2= (id+nverts+1)%nverts;
|
|
|
|
m[0] = (float)(mval[0]-uval[0]);
|
|
m[1] = (float)(mval[1]-uval[1]);
|
|
Vec2Subf(v1, tf->uv[id1], tf->uv[id]);
|
|
Vec2Subf(v2, tf->uv[id2], tf->uv[id]);
|
|
|
|
/* m and v2 on same side of v-v1? */
|
|
c1= v1[0]*m[1] - v1[1]*m[0];
|
|
c2= v1[0]*v2[1] - v1[1]*v2[0];
|
|
|
|
if (c1*c2 < 0.0f)
|
|
return 0;
|
|
|
|
/* m and v1 on same side of v-v2? */
|
|
c1= v2[0]*m[1] - v2[1]*m[0];
|
|
c2= v2[0]*v1[1] - v2[1]*v1[0];
|
|
|
|
return (c1*c2 >= 0.0f);
|
|
}
|
|
|
|
void find_nearest_uv(MTFace **nearesttf, EditFace **nearestefa, unsigned int *nearestv, int *nearestuv)
|
|
{
|
|
EditMesh *em= G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tf;
|
|
int i, nverts, mindist, dist, uval[2];
|
|
short mval[2];
|
|
|
|
getmouseco_areawin(mval);
|
|
|
|
mindist= 0x7FFFFFF;
|
|
if (nearesttf) *nearesttf= NULL;
|
|
if (nearestefa) *nearestefa= NULL;
|
|
|
|
if (nearestv) {
|
|
EditVert *ev;
|
|
for (i=0, ev=em->verts.first; ev; ev = ev->next, i++)
|
|
ev->tmp.l = i;
|
|
}
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tf)) {
|
|
nverts= efa->v4? 4: 3;
|
|
for(i=0; i<nverts; i++) {
|
|
uvco_to_areaco_noclip(tf->uv[i], uval);
|
|
dist= abs(mval[0]-uval[0]) + abs(mval[1]-uval[1]);
|
|
|
|
if (simaUVSel_Check(efa, tf, i))
|
|
dist += 5;
|
|
|
|
if(dist<=mindist) {
|
|
if(dist==mindist)
|
|
if (!nearest_uv_between(tf, nverts, i, mval, uval))
|
|
continue;
|
|
|
|
mindist= dist;
|
|
*nearestuv= i;
|
|
|
|
if (nearesttf) *nearesttf= tf;
|
|
if (nearestefa) *nearestefa= efa;
|
|
if (nearestv) {
|
|
if (i==0) *nearestv= efa->v1->tmp.l;
|
|
else if (i==1) *nearestv= efa->v2->tmp.l;
|
|
else if (i==2) *nearestv= efa->v3->tmp.l;
|
|
else *nearestv= efa->v4->tmp.l;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void mouse_select_sima(void)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tf, *nearesttf;
|
|
EditFace *nearestefa=NULL;
|
|
int a, selectsticky, edgeloop, actface, nearestuv, nearestedge, i, shift, island=0;
|
|
char sticky= 0;
|
|
int flush = 0; /* 0 == dont flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
|
|
unsigned int hitv[4], nearestv;
|
|
float *hituv[4], limit[2];
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return;
|
|
|
|
get_connected_limit_tface_uv(limit);
|
|
|
|
edgeloop= G.qual & LR_ALTKEY;
|
|
shift= G.qual & LR_SHIFTKEY;
|
|
|
|
if (G.sima->flag & SI_SYNC_UVSEL) {
|
|
/* copy from mesh */
|
|
if (G.scene->selectmode == SCE_SELECT_FACE) {
|
|
actface= 1;
|
|
sticky= 0;
|
|
} else {
|
|
actface= G.scene->selectmode & SCE_SELECT_FACE;
|
|
sticky= 2;
|
|
}
|
|
} else {
|
|
/* normal operation */
|
|
actface= G.sima->selectmode == SI_SELECT_FACE;
|
|
island= G.sima->selectmode == SI_SELECT_ISLAND;
|
|
|
|
switch(G.sima->sticky) {
|
|
case SI_STICKY_LOC:
|
|
sticky=2;
|
|
break;
|
|
case SI_STICKY_DISABLE:
|
|
sticky=0;
|
|
break;
|
|
case SI_STICKY_VERTEX:
|
|
if(G.qual & LR_CTRLKEY) {
|
|
sticky=0;
|
|
} else {
|
|
sticky=1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(edgeloop) {
|
|
find_nearest_uv_edge(&nearesttf, &nearestefa, &nearestedge);
|
|
if(nearesttf==NULL)
|
|
return;
|
|
|
|
select_edgeloop_tface_uv(nearestefa, nearestedge, shift, &flush);
|
|
}
|
|
else if(actface) {
|
|
find_nearest_tface(&nearesttf, &nearestefa);
|
|
if(nearesttf==NULL)
|
|
return;
|
|
|
|
EM_set_actFace(nearestefa);
|
|
|
|
for (i=0; i<4; i++)
|
|
hituv[i]= nearesttf->uv[i];
|
|
|
|
hitv[0]= nearestefa->v1->tmp.l;
|
|
hitv[1]= nearestefa->v2->tmp.l;
|
|
hitv[2]= nearestefa->v3->tmp.l;
|
|
|
|
if (nearestefa->v4) hitv[3]= nearestefa->v4->tmp.l;
|
|
else hitv[3]= 0xFFFFFFFF;
|
|
}
|
|
else if (island) {
|
|
|
|
}
|
|
else {
|
|
find_nearest_uv(&nearesttf, &nearestefa, &nearestv, &nearestuv);
|
|
if(nearesttf==NULL)
|
|
return;
|
|
|
|
if(sticky) {
|
|
for(i=0; i<4; i++)
|
|
hitv[i]= 0xFFFFFFFF;
|
|
hitv[nearestuv]= nearestv;
|
|
hituv[nearestuv]= nearesttf->uv[nearestuv];
|
|
}
|
|
}
|
|
|
|
if (island) {
|
|
if(shift) select_linked_tface_uv(1);
|
|
else select_linked_tface_uv(0);
|
|
}
|
|
else if(!edgeloop && shift) {
|
|
/* (de)select face */
|
|
if(actface) {
|
|
if(simaFaceSel_Check(nearestefa, nearesttf)) {
|
|
simaFaceSel_UnSet(nearestefa, nearesttf);
|
|
selectsticky= 0;
|
|
}
|
|
else {
|
|
simaFaceSel_Set(nearestefa, nearesttf);
|
|
selectsticky= 1;
|
|
}
|
|
flush = -1;
|
|
}
|
|
/* (de)select uv node */
|
|
else {
|
|
if (simaUVSel_Check(nearestefa, nearesttf, nearestuv)) {
|
|
simaUVSel_UnSet(nearestefa, nearesttf, nearestuv);
|
|
selectsticky= 0;
|
|
}
|
|
else {
|
|
simaUVSel_Set(nearestefa, nearesttf, nearestuv);
|
|
selectsticky= 1;
|
|
}
|
|
flush = 1;
|
|
}
|
|
|
|
/* (de)select sticky uv nodes */
|
|
if(sticky || actface) {
|
|
EditVert *ev;
|
|
|
|
for (a=0, ev=em->verts.first; ev; ev = ev->next, a++)
|
|
ev->tmp.l = a;
|
|
|
|
/* deselect */
|
|
if(selectsticky==0) {
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tf)) {
|
|
/*if(nearesttf && tf!=nearesttf) tf->flag &=~ TF_ACTIVE;*/ /* TODO - deal with editmesh active face */
|
|
if (!sticky) continue;
|
|
|
|
if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
|
|
simaUVSel_UnSet(efa, tf, 0);
|
|
if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
|
|
simaUVSel_UnSet(efa, tf, 1);
|
|
if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
|
|
simaUVSel_UnSet(efa, tf, 2);
|
|
if (efa->v4)
|
|
if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
|
|
simaUVSel_UnSet(efa, tf, 3);
|
|
}
|
|
}
|
|
flush = -1;
|
|
}
|
|
/* select */
|
|
else {
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tf)) {
|
|
if (!sticky) continue;
|
|
if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
|
|
simaUVSel_Set(efa, tf, 0);
|
|
if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
|
|
simaUVSel_Set(efa, tf, 1);
|
|
if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
|
|
simaUVSel_Set(efa, tf, 2);
|
|
if (efa->v4)
|
|
if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
|
|
simaUVSel_Set(efa, tf, 3);
|
|
}
|
|
}
|
|
|
|
if (actface)
|
|
EM_set_actFace(nearestefa);
|
|
|
|
flush = 1;
|
|
}
|
|
}
|
|
}
|
|
else if(!edgeloop) {
|
|
/* select face and deselect other faces */
|
|
if(actface) {
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
simaFaceSel_UnSet(efa, tf);
|
|
}
|
|
if(nearesttf) {
|
|
simaFaceSel_Set(nearestefa, nearesttf);
|
|
EM_set_actFace(nearestefa);
|
|
}
|
|
|
|
}
|
|
|
|
/* deselect uvs, and select sticky uvs */
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tf)) {
|
|
if(!actface) simaFaceSel_UnSet(efa, tf);
|
|
if(!sticky) continue;
|
|
|
|
if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
|
|
simaUVSel_Set(efa, tf, 0);
|
|
if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
|
|
simaUVSel_Set(efa, tf, 1);
|
|
if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
|
|
simaUVSel_Set(efa, tf, 2);
|
|
if(efa->v4)
|
|
if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
|
|
simaUVSel_Set(efa, tf, 3);
|
|
flush= 1;
|
|
}
|
|
}
|
|
|
|
if(!actface) {
|
|
simaUVSel_Set(nearestefa, nearesttf, nearestuv);
|
|
flush= 1;
|
|
}
|
|
}
|
|
|
|
force_draw(1);
|
|
|
|
if (G.sima->flag & SI_SYNC_UVSEL) {
|
|
/* flush for mesh selection */
|
|
if (G.scene->selectmode != SCE_SELECT_FACE) {
|
|
if (flush==1) EM_select_flush();
|
|
else if (flush==-1) EM_deselect_flush();
|
|
}
|
|
allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */
|
|
}
|
|
|
|
BIF_undo_push("Select UV");
|
|
rightmouse_transform();
|
|
}
|
|
|
|
void borderselect_sima(short whichuvs)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tface;
|
|
rcti rect;
|
|
rctf rectf;
|
|
int val, ok = 1;
|
|
short mval[2], select;
|
|
|
|
if( is_uv_tface_editing_allowed()==0) return;
|
|
|
|
val= get_border(&rect, 3);
|
|
select = (val==LEFTMOUSE) ? 1 : 0;
|
|
|
|
if(val) {
|
|
mval[0]= rect.xmin;
|
|
mval[1]= rect.ymin;
|
|
areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
|
|
mval[0]= rect.xmax;
|
|
mval[1]= rect.ymax;
|
|
areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
|
|
|
|
if (draw_uvs_face_check() && whichuvs != UV_SELECT_PINNED) {
|
|
float cent[2];
|
|
ok = 0;
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
/* assume not touched */
|
|
efa->tmp.l = 0;
|
|
tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
uv_center(tface->uv, cent, (void *)efa->v4);
|
|
if(BLI_in_rctf(&rectf, cent[0], cent[1])) {
|
|
efa->tmp.l = ok = 1;
|
|
}
|
|
}
|
|
}
|
|
/* (de)selects all tagged faces and deals with sticky modes */
|
|
if (ok)
|
|
uvface_setsel__internal(select);
|
|
} else {
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if (whichuvs == UV_SELECT_ALL || (G.sima->flag & SI_SYNC_UVSEL) ) {
|
|
/* SI_SYNC_UVSEL - cant do pinned selection */
|
|
if(BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
|
|
if(select) simaUVSel_Set(efa, tface, 0);
|
|
else simaUVSel_UnSet(efa, tface, 0);
|
|
}
|
|
if(BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
|
|
if(select) simaUVSel_Set(efa, tface, 1);
|
|
else simaUVSel_UnSet(efa, tface, 1);
|
|
}
|
|
if(BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
|
|
if(select) simaUVSel_Set(efa, tface, 2);
|
|
else simaUVSel_UnSet(efa, tface, 2);
|
|
}
|
|
if(efa->v4 && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
|
|
if(select) simaUVSel_Set(efa, tface, 3);
|
|
else simaUVSel_UnSet(efa, tface, 3);
|
|
}
|
|
} else if (whichuvs == UV_SELECT_PINNED) {
|
|
if ((tface->unwrap & TF_PIN1) &&
|
|
BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
|
|
|
|
if(select) simaUVSel_Set(efa, tface, 0);
|
|
else simaUVSel_UnSet(efa, tface, 0);
|
|
}
|
|
if ((tface->unwrap & TF_PIN2) &&
|
|
BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
|
|
|
|
if(select) simaUVSel_Set(efa, tface, 1);
|
|
else simaUVSel_UnSet(efa, tface, 1);
|
|
}
|
|
if ((tface->unwrap & TF_PIN3) &&
|
|
BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
|
|
|
|
if(select) simaUVSel_Set(efa, tface, 2);
|
|
else simaUVSel_UnSet(efa, tface, 2);
|
|
}
|
|
if ((efa->v4) && (tface->unwrap & TF_PIN4) && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
|
|
if(select) simaUVSel_Set(efa, tface, 3);
|
|
else simaUVSel_UnSet(efa, tface, 3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (ok) {
|
|
/* make sure newly selected vert selection is updated*/
|
|
if (G.sima->flag & SI_SYNC_UVSEL) {
|
|
if (G.scene->selectmode != SCE_SELECT_FACE) {
|
|
if (select) EM_select_flush();
|
|
else EM_deselect_flush();
|
|
}
|
|
}
|
|
allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */
|
|
|
|
BIF_undo_push("Border select UV");
|
|
scrarea_queue_winredraw(curarea);
|
|
}
|
|
}
|
|
}
|
|
|
|
int snap_uv_sel_to_curs(void)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tface;
|
|
short change = 0;
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if (simaUVSel_Check(efa, tface, 0)) VECCOPY2D(tface->uv[0], G.v2d->cursor);
|
|
if (simaUVSel_Check(efa, tface, 1)) VECCOPY2D(tface->uv[1], G.v2d->cursor);
|
|
if (simaUVSel_Check(efa, tface, 2)) VECCOPY2D(tface->uv[2], G.v2d->cursor);
|
|
if (efa->v4)
|
|
if (simaUVSel_Check(efa, tface, 3)) VECCOPY2D(tface->uv[3], G.v2d->cursor);
|
|
change = 1;
|
|
}
|
|
}
|
|
return change;
|
|
}
|
|
|
|
int snap_uv_sel_to_adj_unsel(void)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
EditVert *eve;
|
|
MTFace *tface;
|
|
short change = 0;
|
|
int count = 0;
|
|
float *coords;
|
|
short *usercount, users;
|
|
|
|
/* set all verts to -1 : an unused index*/
|
|
for (eve= em->verts.first; eve; eve= eve->next)
|
|
eve->tmp.l=-1;
|
|
|
|
/* index every vert that has a selected UV using it, but only once so as to
|
|
* get unique indicies and to count how much to malloc */
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if (simaUVSel_Check(efa, tface, 0) && efa->v1->tmp.l==-1) efa->v1->tmp.l= count++;
|
|
if (simaUVSel_Check(efa, tface, 1) && efa->v2->tmp.l==-1) efa->v2->tmp.l= count++;
|
|
if (simaUVSel_Check(efa, tface, 2) && efa->v3->tmp.l==-1) efa->v3->tmp.l= count++;
|
|
if (efa->v4)
|
|
if (simaUVSel_Check(efa, tface, 3) && efa->v4->tmp.l==-1) efa->v4->tmp.l= count++;
|
|
change = 1;
|
|
|
|
/* optional speedup */
|
|
efa->tmp.p = tface;
|
|
} else {
|
|
efa->tmp.p = NULL;
|
|
}
|
|
}
|
|
|
|
coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords");
|
|
usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts");
|
|
|
|
/* add all UV coords from visible, unselected UV coords as well as counting them to average later */
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
// if (simaFaceDraw_Check(efa, tface)) {
|
|
if ((tface=(MTFace *)efa->tmp.p)) {
|
|
|
|
/* is this an unselected UV we can snap to? */
|
|
if (efa->v1->tmp.l >= 0 && (!simaUVSel_Check(efa, tface, 0))) {
|
|
coords[efa->v1->tmp.l*2] += tface->uv[0][0];
|
|
coords[(efa->v1->tmp.l*2)+1] += tface->uv[0][1];
|
|
usercount[efa->v1->tmp.l]++;
|
|
change = 1;
|
|
}
|
|
if (efa->v2->tmp.l >= 0 && (!simaUVSel_Check(efa, tface, 1))) {
|
|
coords[efa->v2->tmp.l*2] += tface->uv[1][0];
|
|
coords[(efa->v2->tmp.l*2)+1] += tface->uv[1][1];
|
|
usercount[efa->v2->tmp.l]++;
|
|
change = 1;
|
|
}
|
|
if (efa->v3->tmp.l >= 0 && (!simaUVSel_Check(efa, tface, 2))) {
|
|
coords[efa->v3->tmp.l*2] += tface->uv[2][0];
|
|
coords[(efa->v3->tmp.l*2)+1] += tface->uv[2][1];
|
|
usercount[efa->v3->tmp.l]++;
|
|
change = 1;
|
|
}
|
|
|
|
if (efa->v4) {
|
|
if (efa->v4->tmp.l >= 0 && (!simaUVSel_Check(efa, tface, 3))) {
|
|
coords[efa->v4->tmp.l*2] += tface->uv[3][0];
|
|
coords[(efa->v4->tmp.l*2)+1] += tface->uv[3][1];
|
|
usercount[efa->v4->tmp.l]++;
|
|
change = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* no other verts selected, bail out */
|
|
if (!change) {
|
|
MEM_freeN(coords);
|
|
MEM_freeN(usercount);
|
|
return change;
|
|
}
|
|
|
|
/* copy the averaged unselected UVs back to the selected UVs */
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
// if (simaFaceDraw_Check(efa, tface)) {
|
|
if ((tface=(MTFace *)efa->tmp.p)) {
|
|
|
|
if ( simaUVSel_Check(efa, tface, 0) &&
|
|
efa->v1->tmp.l >= 0 &&
|
|
(users = usercount[efa->v1->tmp.l])
|
|
) {
|
|
tface->uv[0][0] = coords[efa->v1->tmp.l*2] / users;
|
|
tface->uv[0][1] = coords[(efa->v1->tmp.l*2)+1] / users;
|
|
}
|
|
|
|
if ( simaUVSel_Check(efa, tface, 1) &&
|
|
efa->v2->tmp.l >= 0 &&
|
|
(users = usercount[efa->v2->tmp.l])
|
|
) {
|
|
tface->uv[1][0] = coords[efa->v2->tmp.l*2] / users;
|
|
tface->uv[1][1] = coords[(efa->v2->tmp.l*2)+1] / users;
|
|
}
|
|
|
|
if ( simaUVSel_Check(efa, tface, 2) &&
|
|
efa->v3->tmp.l >= 0 &&
|
|
(users = usercount[efa->v3->tmp.l])
|
|
) {
|
|
tface->uv[2][0] = coords[efa->v3->tmp.l*2] / users;
|
|
tface->uv[2][1] = coords[(efa->v3->tmp.l*2)+1] / users;
|
|
}
|
|
|
|
if (efa->v4) {
|
|
if ( simaUVSel_Check(efa, tface, 3) &&
|
|
efa->v4->tmp.l >= 0 &&
|
|
(users = usercount[efa->v4->tmp.l])
|
|
) {
|
|
tface->uv[3][0] = coords[efa->v4->tmp.l*2] / users;
|
|
tface->uv[3][1] = coords[(efa->v4->tmp.l*2)+1] / users;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MEM_freeN(coords);
|
|
MEM_freeN(usercount);
|
|
return change;
|
|
}
|
|
|
|
void snap_coord_to_pixel(float *uvco, float w, float h)
|
|
{
|
|
uvco[0] = ((float) ((int)((uvco[0]*w) + 0.5))) / w;
|
|
uvco[1] = ((float) ((int)((uvco[1]*h) + 0.5))) / h;
|
|
}
|
|
|
|
int snap_uv_sel_to_pixels(void) /* warning, sanity checks must alredy be done */
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tface;
|
|
int wi, hi;
|
|
float w, h;
|
|
short change = 0;
|
|
|
|
transform_width_height_tface_uv(&wi, &hi);
|
|
w = (float)wi;
|
|
h = (float)hi;
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if (simaUVSel_Check(efa, tface, 0)) snap_coord_to_pixel(tface->uv[0], w, h);
|
|
if (simaUVSel_Check(efa, tface, 1)) snap_coord_to_pixel(tface->uv[1], w, h);
|
|
if (simaUVSel_Check(efa, tface, 2)) snap_coord_to_pixel(tface->uv[2], w, h);
|
|
if (efa->v4)
|
|
if (simaUVSel_Check(efa, tface, 3)) snap_coord_to_pixel(tface->uv[3], w, h);
|
|
change = 1;
|
|
}
|
|
}
|
|
return change;
|
|
}
|
|
|
|
void snap_uv_curs_to_pixels(void)
|
|
{
|
|
int wi, hi;
|
|
float w, h;
|
|
|
|
transform_width_height_tface_uv(&wi, &hi);
|
|
w = (float)wi;
|
|
h = (float)hi;
|
|
snap_coord_to_pixel(G.v2d->cursor, w, h);
|
|
}
|
|
|
|
int snap_uv_curs_to_sel(void)
|
|
{
|
|
if( is_uv_tface_editing_allowed()==0 ) return 0;
|
|
return cent_tface_uv(G.v2d->cursor, 0);
|
|
}
|
|
|
|
void snap_menu_sima(void)
|
|
{
|
|
short event;
|
|
if( is_uv_tface_editing_allowed()==0 || !G.v2d) return; /* !G.v2d should never happen */
|
|
|
|
event = pupmenu("Snap %t|Selection -> Pixels%x1|Selection -> Cursor%x2|Selection -> Adjacent Unselected%x3|Cursor -> Selection%x4|Cursor -> Pixel%x5");
|
|
switch (event) {
|
|
case 1:
|
|
if (snap_uv_sel_to_pixels()) {
|
|
BIF_undo_push("Snap UV Selection to Pixels");
|
|
object_uvs_changed(OBACT);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (snap_uv_sel_to_curs()) {
|
|
BIF_undo_push("Snap UV Selection to Cursor");
|
|
object_uvs_changed(OBACT);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (snap_uv_sel_to_adj_unsel()) {
|
|
BIF_undo_push("Snap UV Selection to Cursor");
|
|
object_uvs_changed(OBACT);
|
|
}
|
|
break;
|
|
case 4:
|
|
if (snap_uv_curs_to_sel())
|
|
allqueue(REDRAWIMAGE, 0);
|
|
break;
|
|
case 5:
|
|
snap_uv_curs_to_pixels();
|
|
scrarea_queue_winredraw(curarea);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/** This is an ugly function to set the Tface selection flags depending
|
|
* on whether its UV coordinates are inside the normalized
|
|
* area with radius rad and offset offset. These coordinates must be
|
|
* normalized to 1.0
|
|
* Just for readability...
|
|
*/
|
|
|
|
void sel_uvco_inside_radius(short sel, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, short select_index)
|
|
{
|
|
// normalized ellipse: ell[0] = scaleX,
|
|
// [1] = scaleY
|
|
|
|
float *uv = tface->uv[index];
|
|
float x, y, r2;
|
|
|
|
x = (uv[0] - offset[0]) * ell[0];
|
|
y = (uv[1] - offset[1]) * ell[1];
|
|
|
|
r2 = x * x + y * y;
|
|
if (r2 < 1.0) {
|
|
if (sel == LEFTMOUSE) simaUVSel_Set(efa, tface, select_index);
|
|
else simaUVSel_UnSet(efa, tface, select_index);
|
|
}
|
|
}
|
|
|
|
// see below:
|
|
/** gets image dimensions of the 2D view 'v' */
|
|
static void getSpaceImageDimension(SpaceImage *sima, float *xy)
|
|
{
|
|
ImBuf *ibuf= imagewindow_get_ibuf(G.sima);
|
|
|
|
if (ibuf) {
|
|
xy[0] = ibuf->x * sima->zoom;
|
|
xy[1] = ibuf->y * sima->zoom;
|
|
} else {
|
|
xy[0] = 256 * sima->zoom;
|
|
xy[1] = 256 * sima->zoom;
|
|
}
|
|
}
|
|
|
|
/** Callback function called by circle_selectCB to enable
|
|
* brush select in UV editor.
|
|
*/
|
|
|
|
void uvedit_selectionCB(short selecting, Object *editobj, short *mval, float rad)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
float offset[2];
|
|
MTFace *tface;
|
|
float ellipse[2]; // we need to deal with ellipses, as
|
|
// non square textures require for circle
|
|
// selection. this ellipse is normalized; r = 1.0
|
|
|
|
getSpaceImageDimension(curarea->spacedata.first, ellipse);
|
|
ellipse[0] /= rad;
|
|
ellipse[1] /= rad;
|
|
|
|
areamouseco_to_ipoco(G.v2d, mval, &offset[0], &offset[1]);
|
|
|
|
if (selecting) {
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
sel_uvco_inside_radius(selecting, efa, tface, 0, offset, ellipse, 0);
|
|
sel_uvco_inside_radius(selecting, efa, tface, 1, offset, ellipse, 1);
|
|
sel_uvco_inside_radius(selecting, efa, tface, 2, offset, ellipse, 2);
|
|
if (efa->v4)
|
|
sel_uvco_inside_radius(selecting, efa, tface, 3, offset, ellipse, 3);
|
|
}
|
|
|
|
if(G.f & G_DRAWFACES) { /* full redraw only if necessary */
|
|
draw_sel_circle(0, 0, 0, 0, 0); /* signal */
|
|
force_draw(0);
|
|
}
|
|
else { /* force_draw() is no good here... */
|
|
glDrawBuffer(GL_FRONT);
|
|
draw_uvs_sima();
|
|
bglFlush();
|
|
glDrawBuffer(GL_BACK);
|
|
}
|
|
|
|
|
|
if (selecting == LEFTMOUSE) EM_select_flush();
|
|
else EM_deselect_flush();
|
|
|
|
if (G.sima->lock && (G.sima->flag & SI_SYNC_UVSEL))
|
|
force_draw_plus(SPACE_VIEW3D, 0);
|
|
}
|
|
}
|
|
|
|
|
|
void mouseco_to_curtile(void)
|
|
{
|
|
float fx, fy;
|
|
short mval[2];
|
|
|
|
if( is_uv_tface_editing_allowed()==0) return;
|
|
|
|
if(G.sima->image && G.sima->image->tpageflag & IMA_TILES) {
|
|
|
|
G.sima->flag |= SI_EDITTILE;
|
|
|
|
while(get_mbut()&L_MOUSE) {
|
|
|
|
calc_image_view(G.sima, 'f');
|
|
|
|
getmouseco_areawin(mval);
|
|
areamouseco_to_ipoco(G.v2d, mval, &fx, &fy);
|
|
|
|
if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
|
|
|
|
fx= (fx)*G.sima->image->xrep;
|
|
fy= (fy)*G.sima->image->yrep;
|
|
|
|
mval[0]= fx;
|
|
mval[1]= fy;
|
|
|
|
G.sima->curtile= mval[1]*G.sima->image->xrep + mval[0];
|
|
}
|
|
|
|
scrarea_do_windraw(curarea);
|
|
screen_swapbuffers();
|
|
}
|
|
|
|
G.sima->flag &= ~SI_EDITTILE;
|
|
|
|
image_set_tile(G.sima, 2);
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
scrarea_queue_winredraw(curarea);
|
|
}
|
|
}
|
|
|
|
/* Could be used for other 2D views also */
|
|
void mouseco_to_cursor_sima(void)
|
|
{
|
|
short mval[2];
|
|
getmouseco_areawin(mval);
|
|
areamouseco_to_ipoco(G.v2d, mval, &G.v2d->cursor[0], &G.v2d->cursor[1]);
|
|
scrarea_queue_winredraw(curarea);
|
|
}
|
|
|
|
void stitch_limit_uv_tface(void)
|
|
{
|
|
MTFace *tf;
|
|
int a, vtot;
|
|
float newuv[2], limit[2], pixellimit;
|
|
UvMapVert *vlist, *iterv;
|
|
EditMesh *em = G.editMesh;
|
|
EditVert *ev;
|
|
EditFace *efa;
|
|
|
|
struct UvVertMap *vmap;
|
|
|
|
|
|
if(is_uv_tface_editing_allowed()==0)
|
|
return;
|
|
if(G.sima->flag & SI_SYNC_UVSEL) {
|
|
error("Can't stitch when Sync Mesh Selection is enabled");
|
|
return;
|
|
}
|
|
|
|
pixellimit= 20.0f;
|
|
add_numbut(0, NUM|FLO, "Limit:", 0.1, 1000.0, &pixellimit, NULL);
|
|
if (!do_clever_numbuts("Stitch UVs", 1, REDRAW))
|
|
return;
|
|
|
|
if(G.sima->image) {
|
|
ImBuf *ibuf= imagewindow_get_ibuf(G.sima);
|
|
|
|
if(ibuf && ibuf->x > 0 && ibuf->y > 0) {
|
|
limit[0]= pixellimit/(float)ibuf->x;
|
|
limit[1]= pixellimit/(float)ibuf->y;
|
|
}
|
|
else
|
|
limit[0]= limit[1]= pixellimit/256.0;
|
|
}
|
|
else
|
|
limit[0]= limit[1]= pixellimit/256.0;
|
|
|
|
/*vmap= make_uv_vert_map(me->mface, tf, me->totface, me->totvert, 1, limit);*/
|
|
EM_init_index_arrays(0, 0, 1);
|
|
vmap= make_uv_vert_map_EM(1, 0, limit);
|
|
if(vmap == NULL)
|
|
return;
|
|
|
|
for(a=0, ev= em->verts.first; ev; a++, ev= ev->next) {
|
|
vlist= get_uv_map_vert_EM(vmap, a);
|
|
|
|
while(vlist) {
|
|
newuv[0]= 0; newuv[1]= 0;
|
|
vtot= 0;
|
|
|
|
for(iterv=vlist; iterv; iterv=iterv->next) {
|
|
if((iterv != vlist) && iterv->separate)
|
|
break;
|
|
efa = EM_get_face_for_index(iterv->f);
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
if (tf->flag & TF_SEL_MASK(iterv->tfindex)) {
|
|
newuv[0] += tf->uv[iterv->tfindex][0];
|
|
newuv[1] += tf->uv[iterv->tfindex][1];
|
|
vtot++;
|
|
}
|
|
}
|
|
|
|
if (vtot > 1) {
|
|
newuv[0] /= vtot; newuv[1] /= vtot;
|
|
|
|
for(iterv=vlist; iterv; iterv=iterv->next) {
|
|
if((iterv != vlist) && iterv->separate)
|
|
break;
|
|
efa = EM_get_face_for_index(iterv->f);
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (tf->flag & TF_SEL_MASK(iterv->tfindex)) {
|
|
tf->uv[iterv->tfindex][0]= newuv[0];
|
|
tf->uv[iterv->tfindex][1]= newuv[1];
|
|
}
|
|
}
|
|
}
|
|
vlist= iterv;
|
|
}
|
|
}
|
|
|
|
free_uv_vert_map_EM(vmap);
|
|
EM_free_index_arrays();
|
|
|
|
if(G.sima->flag & SI_BE_SQUARE) be_square_tface_uv(em);
|
|
|
|
BIF_undo_push("Stitch UV");
|
|
|
|
object_uvs_changed(OBACT);
|
|
}
|
|
|
|
void select_linked_tface_uv(int mode) /* TODO */
|
|
{
|
|
EditMesh *em= G.editMesh;
|
|
EditFace *efa, *nearestefa=NULL;
|
|
MTFace *tf, *nearesttf=NULL;
|
|
UvVertMap *vmap;
|
|
UvMapVert *vlist, *iterv, *startv;
|
|
unsigned int *stack, stacksize= 0, nearestv;
|
|
char *flag;
|
|
int a, nearestuv, i, nverts, j;
|
|
float limit[2];
|
|
if(is_uv_tface_editing_allowed()==0)
|
|
return;
|
|
|
|
if(G.sima->flag & SI_SYNC_UVSEL) {
|
|
error("Can't select linked when Sync Mesh Selection is enabled");
|
|
return;
|
|
}
|
|
|
|
if (mode == 2) {
|
|
nearesttf= NULL;
|
|
nearestuv= 0;
|
|
}
|
|
if (mode!=2) {
|
|
find_nearest_uv(&nearesttf, &nearestefa, &nearestv, &nearestuv);
|
|
if(nearesttf==NULL)
|
|
return;
|
|
}
|
|
|
|
get_connected_limit_tface_uv(limit);
|
|
vmap= make_uv_vert_map_EM(1, 1, limit);
|
|
if(vmap == NULL)
|
|
return;
|
|
|
|
stack= MEM_mallocN(sizeof(*stack)* BLI_countlist(&em->faces), "UvLinkStack");
|
|
flag= MEM_callocN(sizeof(*flag)*BLI_countlist(&em->faces), "UvLinkFlag");
|
|
|
|
if (mode == 2) {
|
|
for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tf)) {
|
|
if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) {
|
|
stack[stacksize]= a;
|
|
stacksize++;
|
|
flag[a]= 1;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if(tf == nearesttf) {
|
|
stack[stacksize]= a;
|
|
stacksize++;
|
|
flag[a]= 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
while(stacksize > 0) {
|
|
stacksize--;
|
|
a= stack[stacksize];
|
|
|
|
for (j=0, efa= em->faces.first; efa; efa= efa->next, j++) {
|
|
if (j==a) {
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
nverts= efa->v4? 4: 3;
|
|
|
|
for(i=0; i<nverts; i++) {
|
|
/* make_uv_vert_map_EM sets verts tmp.l to the indicies */
|
|
vlist= get_uv_map_vert_EM(vmap, (*(&efa->v1 + i))->tmp.l);
|
|
|
|
startv= vlist;
|
|
|
|
for(iterv=vlist; iterv; iterv=iterv->next) {
|
|
if(iterv->separate)
|
|
startv= iterv;
|
|
if(iterv->f == a)
|
|
break;
|
|
}
|
|
|
|
for(iterv=startv; iterv; iterv=iterv->next) {
|
|
if((startv != iterv) && (iterv->separate))
|
|
break;
|
|
else if(!flag[iterv->f]) {
|
|
flag[iterv->f]= 1;
|
|
stack[stacksize]= iterv->f;;
|
|
stacksize++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(mode==0 || mode==2) {
|
|
for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if(flag[a])
|
|
tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
|
|
else
|
|
tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
|
|
}
|
|
}
|
|
else if(mode==1) {
|
|
for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
|
|
if(flag[a]) {
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (efa->v4) {
|
|
if((tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)))
|
|
break;
|
|
}
|
|
else if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (efa) {
|
|
for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
|
|
if(flag[a]) {
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
|
|
if(flag[a]) {
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MEM_freeN(stack);
|
|
MEM_freeN(flag);
|
|
free_uv_vert_map_EM(vmap);
|
|
|
|
BIF_undo_push("Select linked UV");
|
|
scrarea_queue_winredraw(curarea);
|
|
}
|
|
|
|
void unlink_selection(void)
|
|
{
|
|
EditMesh *em= G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tface;
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return;
|
|
|
|
if(G.sima->flag & SI_SYNC_UVSEL) {
|
|
error("Can't select unlinked when Sync Mesh Selection is enabled");
|
|
return;
|
|
}
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if(efa->v4) {
|
|
if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))
|
|
tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
|
|
} else {
|
|
if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
|
|
tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3);
|
|
}
|
|
}
|
|
}
|
|
|
|
BIF_undo_push("Unlink UV selection");
|
|
scrarea_queue_winredraw(curarea);
|
|
}
|
|
|
|
/* this function sets the selection on tagged faces
|
|
* This is needed because setting the selection on a face is done in
|
|
* a number of places but it also needs to respect the sticky modes
|
|
* for the UV verts - dealing with the sticky modes is best done in a seperate function
|
|
*
|
|
* de-selects faces that have been tagged on efa->tmp.l
|
|
*/
|
|
void uvface_setsel__internal(short select)
|
|
{
|
|
|
|
/* All functions calling this should call
|
|
* draw_uvs_face_check()
|
|
*/
|
|
|
|
|
|
/* selecting UV Faces with some modes requires us to change
|
|
* the selection in other faces (depending on the stickt mode)
|
|
*
|
|
* This only needs to be done when the Mesh is not used for selection
|
|
* (So for sticky modes - vertex or location based)
|
|
* */
|
|
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tf;
|
|
int nverts, i;
|
|
|
|
if ((G.sima->flag & SI_SYNC_UVSEL)==0 && G.sima->sticky == SI_STICKY_VERTEX) {
|
|
/* tag all verts as untouched,
|
|
* then touch the ones that have a face center in the loop
|
|
* and select all MTFace UV's that use a touched vert */
|
|
|
|
EditVert *eve;
|
|
|
|
for (eve= em->verts.first; eve; eve= eve->next)
|
|
eve->tmp.l = 0;
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
if (efa->tmp.l) {
|
|
if (efa->v4) {
|
|
efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= efa->v4->tmp.l=1;
|
|
} else {
|
|
efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= 1;
|
|
}
|
|
}
|
|
}
|
|
/* now select tagged verts */
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
nverts= efa->v4? 4: 3;
|
|
for(i=0; i<nverts; i++) {
|
|
if ((*(&efa->v1 + i))->tmp.l) {
|
|
if (select) {
|
|
simaUVSel_Set(efa, tf, i);
|
|
} else {
|
|
simaUVSel_UnSet(efa, tf, i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if ((G.sima->flag & SI_SYNC_UVSEL)==0 && G.sima->sticky == SI_STICKY_LOC) {
|
|
EditFace *efa_vlist;
|
|
MTFace *tf_vlist;
|
|
UvMapVert *vlist, *start_vlist=NULL, *vlist_iter;
|
|
struct UvVertMap *vmap;
|
|
float limit[2];
|
|
int efa_index;
|
|
//EditVert *eve; /* removed vert counting for now */
|
|
//int a;
|
|
|
|
get_connected_limit_tface_uv(limit);
|
|
|
|
EM_init_index_arrays(0, 0, 1);
|
|
vmap= make_uv_vert_map_EM(0, 0, limit);
|
|
|
|
/* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */
|
|
/*for (a=0, eve= em->verts.first; eve; a++, eve= eve->next)
|
|
eve->tmp.l = a; */
|
|
|
|
if(vmap == NULL)
|
|
return;
|
|
|
|
for (efa_index=0, efa= em->faces.first; efa; efa_index++, efa= efa->next) {
|
|
if (efa->tmp.l) {
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
nverts= efa->v4? 4: 3;
|
|
for(i=0; i<nverts; i++) {
|
|
if (select) {
|
|
simaUVSel_Set(efa, tf, i);
|
|
} else {
|
|
simaUVSel_UnSet(efa, tf, i);
|
|
}
|
|
|
|
vlist= vlist_iter= get_uv_map_vert_EM(vmap, (*(&efa->v1 + i))->tmp.l);
|
|
|
|
while (vlist_iter) {
|
|
if (vlist_iter->separate)
|
|
start_vlist = vlist_iter;
|
|
|
|
if (efa_index == vlist_iter->f) {
|
|
break;
|
|
}
|
|
vlist_iter = vlist_iter->next;
|
|
}
|
|
|
|
vlist_iter = start_vlist;
|
|
while (vlist_iter) {
|
|
|
|
if (vlist_iter != start_vlist && vlist_iter->separate)
|
|
break;
|
|
|
|
if (efa_index != vlist_iter->f) {
|
|
efa_vlist = EM_get_face_for_index(vlist_iter->f);
|
|
tf_vlist = CustomData_em_get(&em->fdata, efa_vlist->data, CD_MTFACE);
|
|
|
|
if (select) {
|
|
simaUVSel_Set(efa_vlist, tf_vlist, vlist_iter->tfindex);
|
|
} else {
|
|
simaUVSel_UnSet(efa_vlist, tf_vlist, vlist_iter->tfindex);
|
|
}
|
|
}
|
|
vlist_iter = vlist_iter->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
EM_free_index_arrays();
|
|
free_uv_vert_map_EM(vmap);
|
|
|
|
} else { /* SI_STICKY_DISABLE or G.sima->flag & SI_SYNC_UVSEL */
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
if (efa->tmp.l) {
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (select) {
|
|
simaFaceSel_Set(efa, tf);
|
|
} else {
|
|
simaFaceSel_UnSet(efa, tf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void pin_tface_uv(int mode)
|
|
{
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tface;
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return;
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if(mode ==1) {
|
|
if(simaUVSel_Check(efa, tface, 0)) tface->unwrap |= TF_PIN1;
|
|
if(simaUVSel_Check(efa, tface, 1)) tface->unwrap |= TF_PIN2;
|
|
if(simaUVSel_Check(efa, tface, 2)) tface->unwrap |= TF_PIN3;
|
|
if(efa->v4)
|
|
if(simaUVSel_Check(efa, tface, 3)) tface->unwrap |= TF_PIN4;
|
|
}
|
|
else if (mode ==0) {
|
|
if(simaUVSel_Check(efa, tface, 0)) tface->unwrap &= ~TF_PIN1;
|
|
if(simaUVSel_Check(efa, tface, 1)) tface->unwrap &= ~TF_PIN2;
|
|
if(simaUVSel_Check(efa, tface, 2)) tface->unwrap &= ~TF_PIN3;
|
|
if(efa->v4)
|
|
if(simaUVSel_Check(efa, tface, 3)) tface->unwrap &= ~TF_PIN4;
|
|
}
|
|
}
|
|
}
|
|
|
|
BIF_undo_push("Pin UV");
|
|
scrarea_queue_winredraw(curarea);
|
|
}
|
|
|
|
void select_pinned_tface_uv(void)
|
|
{
|
|
EditMesh *em= G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tface;
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return;
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tface)) {
|
|
if (tface->unwrap & TF_PIN1) simaUVSel_Set(efa, tface, 0);
|
|
if (tface->unwrap & TF_PIN2) simaUVSel_Set(efa, tface, 1);
|
|
if (tface->unwrap & TF_PIN3) simaUVSel_Set(efa, tface, 2);
|
|
if(efa->v4) {
|
|
if (tface->unwrap & TF_PIN4) simaUVSel_Set(efa, tface, 3);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (G.sima->flag & SI_SYNC_UVSEL) {
|
|
allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */
|
|
}
|
|
|
|
BIF_undo_push("Select Pinned UVs");
|
|
scrarea_queue_winredraw(curarea);
|
|
}
|
|
|
|
/* UV edge loop select, follows same rules as editmesh */
|
|
|
|
static void uv_vertex_loop_flag(UvMapVert *first)
|
|
{
|
|
UvMapVert *iterv;
|
|
int count= 0;
|
|
|
|
for(iterv=first; iterv; iterv=iterv->next) {
|
|
if(iterv->separate && iterv!=first)
|
|
break;
|
|
|
|
count++;
|
|
}
|
|
|
|
if(count < 5)
|
|
first->flag= 1;
|
|
}
|
|
|
|
static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a)
|
|
{
|
|
UvMapVert *iterv, *first;
|
|
|
|
first= get_uv_map_vert_EM(vmap, (*(&efa->v1 + a))->tmp.l);
|
|
|
|
for(iterv=first; iterv; iterv=iterv->next) {
|
|
if(iterv->separate)
|
|
first= iterv;
|
|
if(iterv->f == efa->tmp.l)
|
|
return first;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
|
|
{
|
|
UvMapVert *iterv1, *iterv2;
|
|
EditFace *efa;
|
|
int tot = 0;
|
|
|
|
/* count number of faces this edge has */
|
|
for(iterv1=first1; iterv1; iterv1=iterv1->next) {
|
|
if(iterv1->separate && iterv1 != first1)
|
|
break;
|
|
|
|
for(iterv2=first2; iterv2; iterv2=iterv2->next) {
|
|
if(iterv2->separate && iterv2 != first2)
|
|
break;
|
|
|
|
if(iterv1->f == iterv2->f) {
|
|
/* if face already tagged, don't do this edge */
|
|
efa= EM_get_face_for_index(iterv1->f);
|
|
if(efa->f1)
|
|
return 0;
|
|
|
|
tot++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(*totface == 0) /* start edge */
|
|
*totface= tot;
|
|
else if(tot != *totface) /* check for same number of faces as start edge */
|
|
return 0;
|
|
|
|
/* tag the faces */
|
|
for(iterv1=first1; iterv1; iterv1=iterv1->next) {
|
|
if(iterv1->separate && iterv1 != first1)
|
|
break;
|
|
|
|
for(iterv2=first2; iterv2; iterv2=iterv2->next) {
|
|
if(iterv2->separate && iterv2 != first2)
|
|
break;
|
|
|
|
if(iterv1->f == iterv2->f) {
|
|
efa= EM_get_face_for_index(iterv1->f);
|
|
efa->f1= 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void select_edgeloop_tface_uv(EditFace *startefa, int starta, int shift, int *flush)
|
|
{
|
|
EditMesh *em= G.editMesh;
|
|
EditVert *eve;
|
|
EditFace *efa;
|
|
MTFace *tface;
|
|
UvVertMap *vmap;
|
|
UvMapVert *iterv1, *iterv2;
|
|
float limit[2];
|
|
int a, count, looking, nverts, starttotface, select;
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return;
|
|
|
|
/* setup */
|
|
EM_init_index_arrays(0, 0, 1);
|
|
|
|
get_connected_limit_tface_uv(limit);
|
|
vmap= make_uv_vert_map_EM(0, 0, limit);
|
|
|
|
for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
|
|
eve->tmp.l = count;
|
|
|
|
for(count=0, efa= em->faces.first; efa; count++, efa= efa->next) {
|
|
if(!shift) {
|
|
tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
simaFaceSel_UnSet(efa, tface);
|
|
}
|
|
|
|
efa->tmp.l= count;
|
|
efa->f1= 0;
|
|
}
|
|
|
|
/* set flags for first face and verts */
|
|
nverts= (startefa->v4)? 4: 3;
|
|
iterv1= uv_vertex_map_get(vmap, startefa, starta);
|
|
iterv2= uv_vertex_map_get(vmap, startefa, (starta+1)%nverts);
|
|
uv_vertex_loop_flag(iterv1);
|
|
uv_vertex_loop_flag(iterv2);
|
|
|
|
starttotface= 0;
|
|
uv_edge_tag_faces(iterv1, iterv2, &starttotface);
|
|
|
|
/* sorry, first edge isnt even ok */
|
|
if(iterv1->flag==0 && iterv2->flag==0) looking= 0;
|
|
else looking= 1;
|
|
|
|
/* iterate */
|
|
while(looking) {
|
|
looking= 0;
|
|
|
|
/* find correct valence edges which are not tagged yet, but connect to tagged one */
|
|
for(efa= em->faces.first; efa; efa=efa->next) {
|
|
tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
if(!efa->f1 && simaFaceDraw_Check(efa, tface)) {
|
|
nverts= (efa->v4)? 4: 3;
|
|
for(a=0; a<nverts; a++) {
|
|
/* check face not hidden and not tagged */
|
|
iterv1= uv_vertex_map_get(vmap, efa, a);
|
|
iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts);
|
|
|
|
/* check if vertex is tagged and has right valence */
|
|
if(iterv1->flag || iterv2->flag) {
|
|
if(uv_edge_tag_faces(iterv1, iterv2, &starttotface)) {
|
|
looking= 1;
|
|
efa->f1= 1;
|
|
|
|
uv_vertex_loop_flag(iterv1);
|
|
uv_vertex_loop_flag(iterv2);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* do the actual select/deselect */
|
|
nverts= (startefa->v4)? 4: 3;
|
|
iterv1= uv_vertex_map_get(vmap, startefa, starta);
|
|
iterv2= uv_vertex_map_get(vmap, startefa, (starta+1)%nverts);
|
|
iterv1->flag= 1;
|
|
iterv2->flag= 1;
|
|
|
|
if(shift) {
|
|
tface= CustomData_em_get(&em->fdata, startefa->data, CD_MTFACE);
|
|
if(simaUVSel_Check(startefa, tface, starta) && simaUVSel_Check(startefa, tface, starta))
|
|
select= 0;
|
|
else
|
|
select= 1;
|
|
}
|
|
else
|
|
select= 1;
|
|
|
|
if(select) *flush= 1;
|
|
else *flush= -1;
|
|
|
|
for(efa= em->faces.first; efa; efa=efa->next) {
|
|
tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
nverts= (efa->v4)? 4: 3;
|
|
for(a=0; a<nverts; a++) {
|
|
iterv1= uv_vertex_map_get(vmap, efa, a);
|
|
|
|
if(iterv1->flag) {
|
|
if(select) simaUVSel_Set(efa, tface, a);
|
|
else simaUVSel_UnSet(efa, tface, a);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* cleanup */
|
|
free_uv_vert_map_EM(vmap);
|
|
EM_free_index_arrays();
|
|
}
|
|
|
|
int minmax_tface_uv(float *min, float *max)
|
|
{
|
|
EditMesh *em= G.editMesh;
|
|
EditFace *efa;
|
|
MTFace *tf;
|
|
int sel;
|
|
|
|
if( is_uv_tface_editing_allowed()==0 ) return 0;
|
|
|
|
INIT_MINMAX2(min, max);
|
|
|
|
sel= 0;
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tf)) {
|
|
if (simaUVSel_Check(efa, tf, 0)) { DO_MINMAX2(tf->uv[0], min, max); sel = 1; }
|
|
if (simaUVSel_Check(efa, tf, 1)) { DO_MINMAX2(tf->uv[1], min, max); sel = 1; }
|
|
if (simaUVSel_Check(efa, tf, 2)) { DO_MINMAX2(tf->uv[2], min, max); sel = 1; }
|
|
if (efa->v4 && (simaUVSel_Check(efa, tf, 3))) { DO_MINMAX2(tf->uv[3], min, max); sel = 1; }
|
|
}
|
|
}
|
|
return sel;
|
|
}
|
|
|
|
int cent_tface_uv(float *cent, int mode)
|
|
{
|
|
float min[2], max[2];
|
|
short change= 0;
|
|
|
|
if (mode==0) {
|
|
if (minmax_tface_uv(min, max))
|
|
change = 1;
|
|
|
|
} else if (mode==1) {
|
|
EditFace *efa;
|
|
MTFace *tf;
|
|
INIT_MINMAX2(min, max);
|
|
|
|
for (efa= G.editMesh->faces.first; efa; efa= efa->next) {
|
|
tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
|
|
if (simaFaceDraw_Check(efa, tf)) {
|
|
if (simaUVSel_Check(efa, tf, 0)) { DO_MINMAX2(tf->uv[0], min, max); change= 1;}
|
|
if (simaUVSel_Check(efa, tf, 1)) { DO_MINMAX2(tf->uv[1], min, max); change= 1;}
|
|
if (simaUVSel_Check(efa, tf, 2)) { DO_MINMAX2(tf->uv[2], min, max); change= 1;}
|
|
if (efa->v4 && (simaUVSel_Check(efa, tf, 3))) { DO_MINMAX2(tf->uv[3], min, max); change= 1;}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (change) {
|
|
cent[0]= (min[0]+max[0])/2.0;
|
|
cent[1]= (min[1]+max[1])/2.0;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void sima_show_info(int channels, int x, int y, char *cp, float *fp, int *zp, float *zpf)
|
|
{
|
|
short ofs;
|
|
char str[256];
|
|
|
|
ofs= sprintf(str, "X: %d Y: %d ", x, y);
|
|
if(cp)
|
|
ofs+= sprintf(str+ofs, "| R: %d G: %d B: %d A: %d ", cp[0], cp[1], cp[2], cp[3]);
|
|
if(fp) {
|
|
if(channels==4)
|
|
ofs+= sprintf(str+ofs, "| R: %.3f G: %.3f B: %.3f A: %.3f ", fp[0], fp[1], fp[2], fp[3]);
|
|
else if(channels==1)
|
|
ofs+= sprintf(str+ofs, "| Val: %.3f ", fp[0]);
|
|
else if(channels==3)
|
|
ofs+= sprintf(str+ofs, "| R: %.3f G: %.3f B: %.3f ", fp[0], fp[1], fp[2]);
|
|
}
|
|
if(zp)
|
|
ofs+= sprintf(str+ofs, "| Z: %.4f ", 0.5+0.5*( ((float)*zp)/(float)0x7fffffff));
|
|
if(zpf)
|
|
ofs+= sprintf(str+ofs, "| Z: %.3f ", *zpf);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
|
glEnable(GL_BLEND);
|
|
|
|
glColor4f(.0,.0,.0,.25);
|
|
glRectf(0.0, 0.0, curarea->winx, 30.0);
|
|
glDisable(GL_BLEND);
|
|
|
|
glColor3ub(255, 255, 255);
|
|
glRasterPos2i(10, 10);
|
|
|
|
BMF_DrawString(G.fonts, str);
|
|
|
|
}
|
|
|
|
void sima_sample_color(void)
|
|
{
|
|
ImBuf *ibuf= imagewindow_get_ibuf(G.sima);
|
|
float fx, fy;
|
|
short mval[2], mvalo[2], firsttime=1;
|
|
|
|
if(ibuf==NULL)
|
|
return;
|
|
|
|
calc_image_view(G.sima, 'f');
|
|
getmouseco_areawin(mvalo);
|
|
|
|
while(get_mbut() & L_MOUSE) {
|
|
|
|
getmouseco_areawin(mval);
|
|
if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
|
|
firsttime= 0;
|
|
areamouseco_to_ipoco(G.v2d, mval, &fx, &fy);
|
|
|
|
if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
|
|
float *fp= NULL, *zpf= NULL;
|
|
float vec[3];
|
|
int *zp= NULL;
|
|
char *cp= NULL;
|
|
|
|
int x= (int) (fx*ibuf->x);
|
|
int y= (int) (fy*ibuf->y);
|
|
|
|
if(x>=ibuf->x) x= ibuf->x-1;
|
|
if(y>=ibuf->y) y= ibuf->y-1;
|
|
|
|
if(ibuf->rect)
|
|
cp= (char *)(ibuf->rect + y*ibuf->x + x);
|
|
if(ibuf->zbuf)
|
|
zp= ibuf->zbuf + y*ibuf->x + x;
|
|
if(ibuf->zbuf_float)
|
|
zpf= ibuf->zbuf_float + y*ibuf->x + x;
|
|
if(ibuf->rect_float)
|
|
fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
|
|
|
|
if(fp==NULL) {
|
|
fp= vec;
|
|
vec[0]= (float)cp[0]/255.0f;
|
|
vec[1]= (float)cp[1]/255.0f;
|
|
vec[2]= (float)cp[2]/255.0f;
|
|
}
|
|
|
|
if(G.sima->cumap) {
|
|
|
|
if(ibuf->channels==4) {
|
|
if(G.qual & LR_CTRLKEY) {
|
|
curvemapping_set_black_white(G.sima->cumap, NULL, fp);
|
|
curvemapping_do_ibuf(G.sima->cumap, ibuf);
|
|
}
|
|
else if(G.qual & LR_SHIFTKEY) {
|
|
curvemapping_set_black_white(G.sima->cumap, fp, NULL);
|
|
curvemapping_do_ibuf(G.sima->cumap, ibuf);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
ScrArea *sa, *cur= curarea;
|
|
|
|
node_curvemap_sample(fp); /* sends global to node editor */
|
|
for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
|
|
if(sa->spacetype==SPACE_NODE) {
|
|
areawinset(sa->win);
|
|
scrarea_do_windraw(sa);
|
|
}
|
|
}
|
|
node_curvemap_sample(NULL); /* clears global in node editor */
|
|
curarea= cur;
|
|
}
|
|
|
|
areawinset(curarea->win);
|
|
scrarea_do_windraw(curarea);
|
|
myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
|
|
glLoadIdentity();
|
|
|
|
sima_show_info(ibuf->channels, x, y, cp, (ibuf->rect_float)?fp:NULL, zp, zpf);
|
|
|
|
screen_swapbuffers();
|
|
|
|
}
|
|
}
|
|
BIF_wait_for_statechange();
|
|
}
|
|
|
|
scrarea_queue_winredraw(curarea);
|
|
|
|
}
|
|
|
|
/* Image functions */
|
|
|
|
static void load_image_filesel(char *str) /* called from fileselect */
|
|
{
|
|
Image *ima= NULL;
|
|
|
|
ima= BKE_add_image_file(str);
|
|
if(ima) {
|
|
BKE_image_signal(ima, &G.sima->iuser, IMA_SIGNAL_RELOAD);
|
|
image_changed(G.sima, ima);
|
|
}
|
|
BIF_undo_push("Load image UV");
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
|
|
static void replace_image_filesel(char *str) /* called from fileselect */
|
|
{
|
|
if (!G.sima->image)
|
|
return;
|
|
|
|
strncpy(G.sima->image->name, str, sizeof(G.sima->image->name)-1); /* we cant do much if the str is longer then 240 :/ */
|
|
BKE_image_signal(G.sima->image, &G.sima->iuser, IMA_SIGNAL_RELOAD);
|
|
BIF_undo_push("Replace image UV");
|
|
allqueue(REDRAWIMAGE, 0);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
|
|
|
|
static void save_image_doit(char *name)
|
|
{
|
|
Image *ima= G.sima->image;
|
|
ImBuf *ibuf= imagewindow_get_ibuf(G.sima);
|
|
int len;
|
|
char str[FILE_MAXDIR+FILE_MAXFILE];
|
|
|
|
if (ibuf) {
|
|
BLI_strncpy(str, name, sizeof(str));
|
|
|
|
BLI_convertstringcode(str, G.sce);
|
|
BLI_convertstringframe(str, G.scene->r.cfra);
|
|
|
|
|
|
if(G.scene->r.scemode & R_EXTENSION) {
|
|
BKE_add_image_extension(str, G.sima->imtypenr);
|
|
BKE_add_image_extension(name, G.sima->imtypenr);
|
|
}
|
|
|
|
if (saveover(str)) {
|
|
|
|
/* enforce user setting for RGB or RGBA, but skip BW */
|
|
if(G.scene->r.planes==32)
|
|
ibuf->depth= 32;
|
|
else if(G.scene->r.planes==24)
|
|
ibuf->depth= 24;
|
|
|
|
waitcursor(1);
|
|
if(G.sima->imtypenr==R_MULTILAYER) {
|
|
RenderResult *rr= BKE_image_get_renderresult(ima);
|
|
if(rr) {
|
|
RE_WriteRenderResult(rr, str, G.scene->r.quality);
|
|
|
|
BLI_strncpy(ima->name, name, sizeof(ima->name));
|
|
BLI_strncpy(ibuf->name, str, sizeof(ibuf->name));
|
|
|
|
/* should be function? nevertheless, saving only happens here */
|
|
for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next)
|
|
ibuf->userflags &= ~IB_BITMAPDIRTY;
|
|
|
|
}
|
|
else error("Did not write, no Multilayer Image");
|
|
}
|
|
else if (BKE_write_ibuf(ibuf, str, G.sima->imtypenr, G.scene->r.subimtype, G.scene->r.quality)) {
|
|
BLI_strncpy(ima->name, name, sizeof(ima->name));
|
|
BLI_strncpy(ibuf->name, str, sizeof(ibuf->name));
|
|
|
|
ibuf->userflags &= ~IB_BITMAPDIRTY;
|
|
|
|
/* change type? */
|
|
if( ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
|
|
ima->source= IMA_SRC_FILE;
|
|
ima->type= IMA_TYPE_IMAGE;
|
|
}
|
|
if(ima->type==IMA_TYPE_R_RESULT)
|
|
ima->type= IMA_TYPE_IMAGE;
|
|
|
|
/* name image as how we saved it */
|
|
len= strlen(str);
|
|
while (len > 0 && str[len - 1] != '/' && str[len - 1] != '\\') len--;
|
|
rename_id(&ima->id, str+len);
|
|
}
|
|
else {
|
|
error("Couldn't write image: %s", str);
|
|
}
|
|
|
|
allqueue(REDRAWHEADERS, 0);
|
|
allqueue(REDRAWBUTSSHADING, 0);
|
|
|
|
waitcursor(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void open_image_sima(short imageselect)
|
|
{
|
|
char name[FILE_MAXDIR+FILE_MAXFILE];
|
|
|
|
if(G.sima->image)
|
|
strcpy(name, G.sima->image->name);
|
|
else
|
|
strcpy(name, U.textudir);
|
|
|
|
if(imageselect)
|
|
activate_imageselect(FILE_SPECIAL, "Open Image", name, load_image_filesel);
|
|
else
|
|
activate_fileselect(FILE_SPECIAL, "Open Image", name, load_image_filesel);
|
|
}
|
|
|
|
void replace_image_sima(short imageselect)
|
|
{
|
|
char name[FILE_MAXDIR+FILE_MAXFILE];
|
|
|
|
if(G.sima->image)
|
|
strcpy(name, G.sima->image->name);
|
|
else
|
|
strcpy(name, U.textudir);
|
|
|
|
if(imageselect)
|
|
activate_imageselect(FILE_SPECIAL, "Replace Image", name, replace_image_filesel);
|
|
else
|
|
activate_fileselect(FILE_SPECIAL, "Replace Image", name, replace_image_filesel);
|
|
}
|
|
|
|
|
|
static char *filesel_imagetype_string(Image *ima)
|
|
{
|
|
char *strp, *str= MEM_callocN(14*32, "menu for filesel");
|
|
|
|
strp= str;
|
|
str += sprintf(str, "Save Image as: %%t|");
|
|
str += sprintf(str, "Targa %%x%d|", R_TARGA);
|
|
str += sprintf(str, "Targa Raw %%x%d|", R_RAWTGA);
|
|
str += sprintf(str, "PNG %%x%d|", R_PNG);
|
|
str += sprintf(str, "BMP %%x%d|", R_BMP);
|
|
str += sprintf(str, "Jpeg %%x%d|", R_JPEG90);
|
|
str += sprintf(str, "Iris %%x%d|", R_IRIS);
|
|
if(G.have_libtiff)
|
|
str += sprintf(str, "Tiff %%x%d|", R_TIFF);
|
|
str += sprintf(str, "Radiance HDR %%x%d|", R_RADHDR);
|
|
str += sprintf(str, "Cineon %%x%d|", R_CINEON);
|
|
str += sprintf(str, "DPX %%x%d|", R_DPX);
|
|
#ifdef WITH_OPENEXR
|
|
str += sprintf(str, "OpenEXR %%x%d|", R_OPENEXR);
|
|
/* saving sequences of multilayer won't work, they copy buffers */
|
|
if(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER);
|
|
else str += sprintf(str, "MultiLayer %%x%d|", R_MULTILAYER);
|
|
#endif
|
|
return strp;
|
|
}
|
|
|
|
/* always opens fileselect */
|
|
void save_as_image_sima(void)
|
|
{
|
|
Image *ima = G.sima->image;
|
|
ImBuf *ibuf= imagewindow_get_ibuf(G.sima);
|
|
char name[FILE_MAXDIR+FILE_MAXFILE];
|
|
|
|
if (ima) {
|
|
strcpy(name, ima->name);
|
|
|
|
if (ibuf) {
|
|
char *strp;
|
|
|
|
strp= filesel_imagetype_string(ima);
|
|
|
|
/* cant save multilayer sequence, ima->rr isn't valid for a specific frame */
|
|
if(ima->rr && !(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER))
|
|
G.sima->imtypenr= R_MULTILAYER;
|
|
else if(ima->type==IMA_TYPE_R_RESULT)
|
|
G.sima->imtypenr= G.scene->r.imtype;
|
|
else G.sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
|
|
|
|
activate_fileselect_menu(FILE_SPECIAL, "Save Image", name, strp, &G.sima->imtypenr, save_image_doit);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if exists, saves over without fileselect */
|
|
void save_image_sima(void)
|
|
{
|
|
Image *ima = G.sima->image;
|
|
ImBuf *ibuf= imagewindow_get_ibuf(G.sima);
|
|
char name[FILE_MAXDIR+FILE_MAXFILE];
|
|
|
|
if (ima) {
|
|
strcpy(name, ima->name);
|
|
|
|
if (ibuf) {
|
|
if (BLI_exists(ibuf->name)) {
|
|
if(BKE_image_get_renderresult(ima))
|
|
G.sima->imtypenr= R_MULTILAYER;
|
|
else
|
|
G.sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
|
|
|
|
save_image_doit(ibuf->name);
|
|
}
|
|
else
|
|
save_as_image_sima();
|
|
}
|
|
}
|
|
}
|
|
|
|
void save_image_sequence_sima(void)
|
|
{
|
|
ImBuf *ibuf;
|
|
int tot= 0;
|
|
char di[FILE_MAX], fi[FILE_MAX];
|
|
|
|
if(G.sima->image==NULL)
|
|
return;
|
|
if(G.sima->image->source!=IMA_SRC_SEQUENCE)
|
|
return;
|
|
if(G.sima->image->type==IMA_TYPE_MULTILAYER) {
|
|
error("Cannot save Multilayer Sequences");
|
|
return;
|
|
}
|
|
|
|
/* get total */
|
|
for(ibuf= G.sima->image->ibufs.first; ibuf; ibuf= ibuf->next)
|
|
if(ibuf->userflags & IB_BITMAPDIRTY)
|
|
tot++;
|
|
|
|
if(tot==0) {
|
|
notice("No Images have been changed");
|
|
return;
|
|
}
|
|
/* get a filename for menu */
|
|
for(ibuf= G.sima->image->ibufs.first; ibuf; ibuf= ibuf->next)
|
|
if(ibuf->userflags & IB_BITMAPDIRTY)
|
|
break;
|
|
|
|
BLI_strncpy(di, ibuf->name, FILE_MAX);
|
|
BLI_splitdirstring(di, fi);
|
|
|
|
sprintf(fi, "%d Image(s) will be saved in %s", tot, di);
|
|
if(okee(fi)) {
|
|
|
|
for(ibuf= G.sima->image->ibufs.first; ibuf; ibuf= ibuf->next) {
|
|
if(ibuf->userflags & IB_BITMAPDIRTY) {
|
|
char name[FILE_MAX];
|
|
BLI_strncpy(name, ibuf->name, sizeof(name));
|
|
|
|
BLI_convertstringcode(name, G.sce);
|
|
|
|
if(0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
|
|
error("Could not write image", name);
|
|
break;
|
|
}
|
|
printf("Saved: %s\n", ibuf->name);
|
|
ibuf->userflags &= ~IB_BITMAPDIRTY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void reload_image_sima(void)
|
|
{
|
|
if (G.sima ) {
|
|
BKE_image_signal(G.sima->image, &G.sima->iuser, IMA_SIGNAL_RELOAD);
|
|
/* image_changed(G.sima, 0); - do we really need this? */
|
|
}
|
|
|
|
allqueue(REDRAWIMAGE, 0);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
BIF_preview_changed(ID_TE);
|
|
}
|
|
|
|
void new_image_sima(void)
|
|
{
|
|
static int width= 1024, height= 1024;
|
|
static short uvtestgrid= 0;
|
|
static int floatbuf=0;
|
|
static float color[] = {0, 0, 0, 1};
|
|
char name[22];
|
|
Image *ima;
|
|
|
|
strcpy(name, "Untitled");
|
|
|
|
add_numbut(0, TEX, "Name:", 0, 21, name, NULL);
|
|
add_numbut(1, NUM|INT, "Width:", 1, 16384, &width, NULL);
|
|
add_numbut(2, NUM|INT, "Height:", 1, 16384, &height, NULL);
|
|
add_numbut(3, COL, "", 0, 0, &color, NULL);
|
|
add_numbut(4, NUM|FLO, "Alpha:", 0.0, 1.0, &color[3], NULL);
|
|
add_numbut(5, TOG|SHO, "UV Test Grid", 0, 0, &uvtestgrid, NULL);
|
|
add_numbut(6, TOG|INT, "32 bit Float", 0, 0, &floatbuf, NULL);
|
|
if (!do_clever_numbuts("New Image", 7, REDRAW))
|
|
return;
|
|
|
|
ima = BKE_add_image_size(width, height, name, floatbuf, uvtestgrid, color);
|
|
image_changed(G.sima, ima);
|
|
BKE_image_signal(G.sima->image, &G.sima->iuser, IMA_SIGNAL_USER_NEW_IMAGE);
|
|
BIF_undo_push("Add image");
|
|
|
|
allqueue(REDRAWIMAGE, 0);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
|
|
void pack_image_sima()
|
|
{
|
|
Image *ima = G.sima->image;
|
|
|
|
if (ima) {
|
|
if(ima->source!=IMA_SRC_SEQUENCE && ima->source!=IMA_SRC_MOVIE) {
|
|
if (ima->packedfile) {
|
|
if (G.fileflags & G_AUTOPACK)
|
|
if (okee("Disable AutoPack?"))
|
|
G.fileflags &= ~G_AUTOPACK;
|
|
|
|
if ((G.fileflags & G_AUTOPACK) == 0) {
|
|
unpackImage(ima, PF_ASK);
|
|
BIF_undo_push("Unpack image");
|
|
}
|
|
}
|
|
else {
|
|
ImBuf *ibuf= imagewindow_get_ibuf(G.sima);
|
|
if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY)) {
|
|
if(okee("Can't pack painted image. Use Repack as PNG?"))
|
|
BKE_image_memorypack(ima);
|
|
}
|
|
else {
|
|
ima->packedfile = newPackedFile(ima->name);
|
|
BIF_undo_push("Pack image");
|
|
}
|
|
}
|
|
|
|
allqueue(REDRAWBUTSSHADING, 0);
|
|
allqueue(REDRAWHEADERS, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */
|
|
void BIF_image_update_frame(void)
|
|
{
|
|
Tex *tex;
|
|
|
|
/* texture users */
|
|
for(tex= G.main->tex.first; tex; tex= tex->id.next) {
|
|
if(tex->type==TEX_IMAGE && tex->ima)
|
|
if(ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
|
|
if(tex->iuser.flag & IMA_ANIM_ALWAYS)
|
|
BKE_image_user_calc_imanr(&tex->iuser, G.scene->r.cfra, 0);
|
|
|
|
}
|
|
/* image window, compo node users */
|
|
if(G.curscreen) {
|
|
ScrArea *sa;
|
|
for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
|
|
if(sa->spacetype==SPACE_VIEW3D) {
|
|
View3D *v3d= sa->spacedata.first;
|
|
if(v3d->bgpic)
|
|
if(v3d->bgpic->iuser.flag & IMA_ANIM_ALWAYS)
|
|
BKE_image_user_calc_imanr(&v3d->bgpic->iuser, G.scene->r.cfra, 0);
|
|
}
|
|
else if(sa->spacetype==SPACE_IMAGE) {
|
|
SpaceImage *sima= sa->spacedata.first;
|
|
if(sima->iuser.flag & IMA_ANIM_ALWAYS)
|
|
BKE_image_user_calc_imanr(&sima->iuser, G.scene->r.cfra, 0);
|
|
}
|
|
else if(sa->spacetype==SPACE_NODE) {
|
|
SpaceNode *snode= sa->spacedata.first;
|
|
if((snode->treetype==NTREE_COMPOSIT) && (snode->nodetree)) {
|
|
bNode *node;
|
|
for(node= snode->nodetree->nodes.first; node; node= node->next) {
|
|
if(node->id && node->type==CMP_NODE_IMAGE) {
|
|
Image *ima= (Image *)node->id;
|
|
ImageUser *iuser= node->storage;
|
|
if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
|
|
if(iuser->flag & IMA_ANIM_ALWAYS)
|
|
BKE_image_user_calc_imanr(iuser, G.scene->r.cfra, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extern int EM_texFaceCheck(void); /* from editmesh.c */
|
|
/* called to assign images to UV faces */
|
|
void image_changed(SpaceImage *sima, Image *image)
|
|
{
|
|
MTFace *tface;
|
|
EditMesh *em = G.editMesh;
|
|
EditFace *efa;
|
|
ImBuf *ibuf = NULL;
|
|
short change = 0;
|
|
|
|
if(image==NULL) {
|
|
sima->flag &= ~SI_DRAWTOOL;
|
|
} else {
|
|
ibuf = BKE_image_get_ibuf(image, NULL);
|
|
}
|
|
|
|
if(sima->mode!=SI_TEXTURE)
|
|
return;
|
|
|
|
/* skip assigning these procedural images... */
|
|
if(image && (image->type==IMA_TYPE_R_RESULT || image->type==IMA_TYPE_COMPOSITE)) {
|
|
return;
|
|
} else if ((G.obedit) &&
|
|
(G.obedit->type == OB_MESH) &&
|
|
(G.editMesh) &&
|
|
(G.editMesh->faces.first)
|
|
) {
|
|
|
|
/* Add a UV layer if there is none, editmode only */
|
|
if ( !CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE) ) {
|
|
EM_add_data_layer(&em->fdata, CD_MTFACE);
|
|
CustomData_set_layer_active(&em->fdata, CD_MTFACE, 0); /* always zero because we have no other UV layers */
|
|
change = 1; /* so we update the object, incase no faces are selected */
|
|
|
|
/* BIF_undo_push("New UV Texture"); - undo should be done by whatever changes the image */
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWBUTSEDIT, 0);
|
|
}
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
if (efa->h==0 && efa->f & SELECT) {
|
|
if (image) {
|
|
tface->tpage= image;
|
|
tface->mode |= TF_TEX;
|
|
|
|
if(image->tpageflag & IMA_TILES) tface->mode |= TF_TILES;
|
|
else tface->mode &= ~TF_TILES;
|
|
|
|
if(image->id.us==0) id_us_plus(&image->id);
|
|
else id_lib_extern(&image->id);
|
|
#if 0 /* GE People dont like us messing with their face modes */
|
|
if (tface->transp==TF_ADD) {} /* they obviously know what they are doing! - leave as is */
|
|
else if (ibuf && ibuf->depth == 32) tface->transp = TF_ALPHA;
|
|
else tface->transp = TF_SOLID;
|
|
#endif
|
|
} else {
|
|
tface->tpage= NULL;
|
|
tface->mode &= ~TF_TEX;
|
|
#if 0
|
|
tface->transp = TF_SOLID;
|
|
#endif
|
|
}
|
|
change = 1;
|
|
}
|
|
}
|
|
}
|
|
/* change the space image after because simaFaceDraw_Check uses the space image
|
|
* to check if the face is displayed in UV-localview */
|
|
sima->image = image;
|
|
|
|
if (change)
|
|
object_uvs_changed(OBACT);
|
|
|
|
allqueue(REDRAWBUTSEDIT, 0);
|
|
}
|
|
|
|
void image_pixel_aspect(Image *image, float *x, float *y)
|
|
{
|
|
*x = *y = 1.0;
|
|
|
|
if( (image == NULL) ||
|
|
(image->type == IMA_TYPE_R_RESULT) ||
|
|
(image->type == IMA_TYPE_COMPOSITE) ||
|
|
(image->tpageflag & IMA_TILES) ||
|
|
(image->aspx==0.0 || image->aspy==0.0)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
/* x is always 1 */
|
|
*y = image->aspy / image->aspx;
|
|
}
|
|
|
|
void image_final_aspect(Image *image, float *x, float *y)
|
|
{
|
|
*x = *y = 1.0;
|
|
|
|
if( (image == NULL) ||
|
|
(image->type == IMA_TYPE_R_RESULT) ||
|
|
(image->type == IMA_TYPE_COMPOSITE) ||
|
|
(image->tpageflag & IMA_TILES) ||
|
|
(image->aspx==0.0 || image->aspy==0.0)
|
|
) {
|
|
return;
|
|
} else {
|
|
ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
|
|
if (ibuf && ibuf->x && ibuf->y) {
|
|
*y = (image->aspy * ibuf->y) / (image->aspx * ibuf->x);
|
|
} else {
|
|
/* x is always 1 */
|
|
*y = image->aspy / image->aspx;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Face selection tests - Keep these together */
|
|
|
|
/* this checks weather a face is drarn without the local image check */
|
|
int simaFaceDraw_Check_nolocal( EditFace *efa )
|
|
{
|
|
if (G.sima && G.sima->flag & SI_SYNC_UVSEL) {
|
|
return (efa->h==0);
|
|
} else {
|
|
return (efa->h==0 && efa->f & SELECT);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int simaFaceDraw_Check( EditFace *efa, MTFace *tf )
|
|
{
|
|
if (G.sima && G.sima->flag & SI_LOCAL_UV) {
|
|
if (tf->tpage==G.sima->image) {
|
|
return simaFaceDraw_Check_nolocal(efa);
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else {
|
|
return simaFaceDraw_Check_nolocal(efa);
|
|
}
|
|
}
|
|
|
|
int simaFaceSel_Check( struct EditFace *efa, struct MTFace *tf )
|
|
{
|
|
if (G.sima && G.sima->flag & SI_SYNC_UVSEL) {
|
|
return (efa->f & SELECT);
|
|
} else {
|
|
return (!(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&(!efa->v4 || tf->flag & TF_SEL4));
|
|
}
|
|
}
|
|
|
|
void simaFaceSel_Set( struct EditFace *efa, struct MTFace *tf )
|
|
{
|
|
if (G.sima && G.sima->flag & SI_SYNC_UVSEL) {
|
|
EM_select_face(efa, 1);
|
|
} else {
|
|
tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
|
|
}
|
|
}
|
|
|
|
void simaFaceSel_UnSet( struct EditFace *efa, struct MTFace *tf )
|
|
{
|
|
if (G.sima && G.sima->flag & SI_SYNC_UVSEL) {
|
|
EM_select_face(efa, 0);
|
|
} else {
|
|
tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
|
|
}
|
|
}
|
|
|
|
int simaUVSel_Check( struct EditFace *efa, struct MTFace *tf, int i)
|
|
{
|
|
if (G.sima && G.sima->flag & SI_SYNC_UVSEL) {
|
|
if (G.scene->selectmode == SCE_SELECT_FACE) {
|
|
return efa->f & SELECT;
|
|
} else {
|
|
return (*(&efa->v1 + i))->f & SELECT;
|
|
}
|
|
} else {
|
|
return tf->flag & TF_SEL_MASK(i);
|
|
}
|
|
}
|
|
|
|
void simaUVSel_Set( struct EditFace *efa, struct MTFace *tf, int i)
|
|
{
|
|
if (G.sima && G.sima->flag & SI_SYNC_UVSEL) {
|
|
if (G.scene->selectmode == SCE_SELECT_FACE) {
|
|
EM_select_face(efa, 1);
|
|
} else {
|
|
(*(&efa->v1 + i))->f |= SELECT;
|
|
}
|
|
} else {
|
|
tf->flag |= TF_SEL_MASK(i);
|
|
}
|
|
}
|
|
|
|
void simaUVSel_UnSet( struct EditFace *efa, struct MTFace *tf, int i)
|
|
{
|
|
if (G.sima && G.sima->flag & SI_SYNC_UVSEL) {
|
|
if (G.scene->selectmode == SCE_SELECT_FACE) {
|
|
EM_select_face(efa, 0);
|
|
} else {
|
|
(*(&efa->v1 + i))->f &= ~SELECT;
|
|
}
|
|
} else {
|
|
tf->flag &= ~TF_SEL_MASK(i);
|
|
}
|
|
}
|
|
|