2008-12-30 13:16:14 +00:00
|
|
|
/**
|
|
|
|
* $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.
|
|
|
|
*
|
|
|
|
* Contributor(s): Blender Foundation, Campbell Barton
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BLI_arithb.h"
|
|
|
|
#include "BLI_heap.h"
|
|
|
|
#include "BLI_edgehash.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_object_types.h"
|
|
|
|
#include "DNA_space_types.h"
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_view3d_types.h"
|
|
|
|
|
|
|
|
#include "BKE_brush.h"
|
|
|
|
#include "BKE_customdata.h"
|
|
|
|
#include "BKE_depsgraph.h"
|
|
|
|
#include "BKE_DerivedMesh.h"
|
|
|
|
#include "BKE_displist.h"
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_mesh.h"
|
|
|
|
#include "BKE_object.h"
|
|
|
|
#include "BKE_texture.h"
|
|
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BKE_customdata.h"
|
|
|
|
|
|
|
|
#include "BIF_gl.h"
|
|
|
|
#include "BIF_glutil.h"
|
|
|
|
|
|
|
|
#include "GPU_draw.h"
|
|
|
|
|
|
|
|
#ifndef DISABLE_PYTHON
|
|
|
|
//#include "BPY_extern.h"
|
|
|
|
//#include "BPY_menus.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "ED_mesh.h"
|
|
|
|
#include "ED_object.h"
|
2009-01-05 15:19:31 +00:00
|
|
|
#include "ED_view3d.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
/* own include */
|
2009-01-01 13:15:35 +00:00
|
|
|
#include "mesh_intern.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Pupmenu codes: */
|
|
|
|
#define UV_CUBE_MAPPING 2
|
|
|
|
#define UV_CYL_MAPPING 3
|
|
|
|
#define UV_SPHERE_MAPPING 4
|
|
|
|
#define UV_BOUNDS_MAPPING 5
|
|
|
|
#define UV_RESET_MAPPING 6
|
|
|
|
#define UV_WINDOW_MAPPING 7
|
|
|
|
#define UV_UNWRAP_MAPPING 8
|
|
|
|
#define UV_CYL_EX 32
|
|
|
|
#define UV_SPHERE_EX 34
|
|
|
|
|
|
|
|
/* Some macro tricks to make pupmenu construction look nicer :-)
|
|
|
|
Sorry, just did it for fun. */
|
|
|
|
|
|
|
|
#define _STR(x) " " #x
|
|
|
|
#define STRING(x) _STR(x)
|
|
|
|
|
|
|
|
#define MENUSTRING(string, code) string " %x" STRING(code)
|
|
|
|
#define MENUTITLE(string) string " %t|"
|
|
|
|
|
|
|
|
/* ***************** XXX **************** */
|
|
|
|
static int sample_backbuf_rect() {return 0;}
|
|
|
|
static int sample_backbuf() {return 0;}
|
|
|
|
static void BIF_undo_push() {}
|
|
|
|
static void error() {}
|
|
|
|
static int pupmenu() {return 0;}
|
|
|
|
/* ***************** XXX **************** */
|
|
|
|
|
|
|
|
|
|
|
|
/* returns 0 if not found, otherwise 1 */
|
|
|
|
int facesel_face_pick(View3D *v3d, Mesh *me, short *mval, unsigned int *index, short rect)
|
|
|
|
{
|
|
|
|
if (!me || me->totface==0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (v3d->flag & V3D_NEEDBACKBUFDRAW) {
|
|
|
|
// XXX drawview.c! check_backbuf();
|
|
|
|
// XXX persp(PERSP_VIEW);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rect) {
|
|
|
|
/* sample rect to increase changes of selecting, so that when clicking
|
|
|
|
on an edge in the backbuf, we can still select a face */
|
|
|
|
int dist;
|
|
|
|
*index = sample_backbuf_rect(mval, 3, 1, me->totface+1, &dist,0,NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/* sample only on the exact position */
|
|
|
|
*index = sample_backbuf(mval[0], mval[1]);
|
|
|
|
|
|
|
|
if ((*index)<=0 || (*index)>(unsigned int)me->totface)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
(*index)--;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* only operates on the edit object - this is all thats needed at the moment */
|
|
|
|
static void uv_calc_center_vector(Scene *scene, View3D *v3d, float *result, Object *ob, EditMesh *em)
|
|
|
|
{
|
|
|
|
float min[3], max[3], *cursx;
|
|
|
|
|
|
|
|
EditFace *efa;
|
|
|
|
switch (v3d->around)
|
|
|
|
{
|
|
|
|
case V3D_CENTER: /* bounding box center */
|
|
|
|
min[0]= min[1]= min[2]= 1e20f;
|
|
|
|
max[0]= max[1]= max[2]= -1e20f;
|
|
|
|
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
DO_MINMAX(efa->v1->co, min, max);
|
|
|
|
DO_MINMAX(efa->v2->co, min, max);
|
|
|
|
DO_MINMAX(efa->v3->co, min, max);
|
|
|
|
if(efa->v4) DO_MINMAX(efa->v4->co, min, max);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VecMidf(result, min, max);
|
|
|
|
break;
|
|
|
|
case V3D_CURSOR: /*cursor center*/
|
|
|
|
cursx= give_cursor(scene, v3d);
|
|
|
|
/* shift to objects world */
|
|
|
|
result[0]= cursx[0]-ob->obmat[3][0];
|
|
|
|
result[1]= cursx[1]-ob->obmat[3][1];
|
|
|
|
result[2]= cursx[2]-ob->obmat[3][2];
|
|
|
|
break;
|
|
|
|
case V3D_LOCAL: /*object center*/
|
|
|
|
case V3D_CENTROID: /* multiple objects centers, only one object here*/
|
|
|
|
default:
|
|
|
|
result[0]= result[1]= result[2]= 0.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
static void uv_calc_map_matrix(float result[][4], RegionView3D *rv3d, Object *ob, float upangledeg, float sideangledeg, float radius)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
|
|
|
|
float sideangle= 0.0, upangle= 0.0;
|
|
|
|
int k;
|
|
|
|
|
|
|
|
/* get rotation of the current view matrix */
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
Mat4CpyMat4(viewmatrix, rv3d->viewmat);
|
2008-12-30 13:16:14 +00:00
|
|
|
/* but shifting */
|
|
|
|
for( k= 0; k< 4; k++) viewmatrix[3][k] =0.0;
|
|
|
|
|
|
|
|
/* get rotation of the current object matrix */
|
|
|
|
Mat4CpyMat4(rotobj,ob->obmat);
|
|
|
|
/* but shifting */
|
|
|
|
for( k= 0; k< 4; k++) rotobj[3][k] =0.0;
|
|
|
|
|
|
|
|
Mat4Clr(*rotup);
|
|
|
|
Mat4Clr(*rotside);
|
|
|
|
|
|
|
|
/* compensate front/side.. against opengl x,y,z world definition */
|
|
|
|
/* this is "kanonen gegen spatzen", a few plus minus 1 will do here */
|
|
|
|
/* i wanted to keep the reason here, so we're rotating*/
|
|
|
|
sideangle= M_PI * (sideangledeg + 180.0) /180.0;
|
|
|
|
rotside[0][0]= (float)cos(sideangle);
|
|
|
|
rotside[0][1]= -(float)sin(sideangle);
|
|
|
|
rotside[1][0]= (float)sin(sideangle);
|
|
|
|
rotside[1][1]= (float)cos(sideangle);
|
|
|
|
rotside[2][2]= 1.0f;
|
|
|
|
|
|
|
|
upangle= M_PI * upangledeg /180.0;
|
|
|
|
rotup[1][1]= (float)cos(upangle)/radius;
|
|
|
|
rotup[1][2]= -(float)sin(upangle)/radius;
|
|
|
|
rotup[2][1]= (float)sin(upangle)/radius;
|
|
|
|
rotup[2][2]= (float)cos(upangle)/radius;
|
|
|
|
rotup[0][0]= (float)1.0/radius;
|
|
|
|
|
|
|
|
/* calculate transforms*/
|
|
|
|
Mat4MulSerie(result,rotup,rotside,viewmatrix,rotobj,NULL,NULL,NULL,NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void uv_calc_shift_project(ARegion *ar, View3D *v3d, float *target, float *shift, float rotmat[][4], int projectionmode, float *source, float *min, float *max)
|
|
|
|
{
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
RegionView3D *rv3d= ar->regiondata;
|
2008-12-30 13:16:14 +00:00
|
|
|
float pv[3];
|
|
|
|
|
|
|
|
VecSubf(pv, source, shift);
|
|
|
|
Mat4MulVecfl(rotmat, pv);
|
|
|
|
|
|
|
|
switch(projectionmode) {
|
|
|
|
case B_UVAUTO_CYLINDER:
|
|
|
|
tubemap(pv[0], pv[1], pv[2], &target[0],&target[1]);
|
|
|
|
/* split line is always zero */
|
|
|
|
if (target[0] >= 1.0f) target[0] -= 1.0f;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case B_UVAUTO_SPHERE:
|
|
|
|
spheremap(pv[0], pv[1], pv[2], &target[0],&target[1]);
|
|
|
|
/* split line is always zero */
|
|
|
|
if (target[0] >= 1.0f) target[0] -= 1.0f;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: /* ortho special case for BOUNDS */
|
|
|
|
target[0] = -pv[0];
|
|
|
|
target[1] = pv[2];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
{
|
|
|
|
/* very special case for FROM WINDOW */
|
|
|
|
float pv4[4], dx, dy, x= 0.0, y= 0.0;
|
|
|
|
|
|
|
|
dx= ar->winx;
|
|
|
|
dy= ar->winy;
|
|
|
|
|
|
|
|
VecCopyf(pv4, source);
|
|
|
|
pv4[3] = 1.0;
|
|
|
|
|
|
|
|
/* rotmat is the object matrix in this case */
|
|
|
|
Mat4MulVec4fl(rotmat, pv4);
|
|
|
|
|
|
|
|
/* almost project_short */
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
Mat4MulVec4fl(rv3d->persmat, pv4);
|
2008-12-30 13:16:14 +00:00
|
|
|
if (fabs(pv4[3]) > 0.00001) { /* avoid division by zero */
|
|
|
|
target[0] = dx/2.0 + (dx/2.0)*pv4[0]/pv4[3];
|
|
|
|
target[1] = dy/2.0 + (dy/2.0)*pv4[1]/pv4[3];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* scaling is lost but give a valid result */
|
|
|
|
target[0] = dx/2.0 + (dx/2.0)*pv4[0];
|
|
|
|
target[1] = dy/2.0 + (dy/2.0)*pv4[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* v3d->persmat seems to do this funky scaling */
|
|
|
|
if(dx > dy) {
|
|
|
|
y= (dx-dy)/2.0;
|
|
|
|
dy = dx;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
x= (dy-dx)/2.0;
|
|
|
|
dx = dy;
|
|
|
|
}
|
|
|
|
target[0]= (x + target[0])/dx;
|
|
|
|
target[1]= (y + target[1])/dy;
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
target[0] = 0.0;
|
|
|
|
target[1] = 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we know the values here and may need min_max later */
|
|
|
|
/* max requests independand from min; not fastest but safest */
|
|
|
|
if(min) {
|
|
|
|
min[0] = MIN2(target[0], min[0]);
|
|
|
|
min[1] = MIN2(target[1], min[1]);
|
|
|
|
}
|
|
|
|
if(max) {
|
|
|
|
max[0] = MAX2(target[0], max[0]);
|
|
|
|
max[1] = MAX2(target[1], max[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void correct_uv_aspect( EditMesh *em )
|
|
|
|
{
|
|
|
|
float aspx=1, aspy=1;
|
|
|
|
EditFace *efa = EM_get_actFace(em, 1);
|
|
|
|
MTFace *tface;
|
|
|
|
|
|
|
|
if (efa) {
|
|
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
// XXX image_final_aspect(tface->tpage, &aspx, &aspy);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aspx != aspy) {
|
|
|
|
|
|
|
|
float scale;
|
|
|
|
|
|
|
|
if (aspx > aspy) {
|
|
|
|
scale = aspy/aspx;
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
tface->uv[0][0] = ((tface->uv[0][0]-0.5)*scale)+0.5;
|
|
|
|
tface->uv[1][0] = ((tface->uv[1][0]-0.5)*scale)+0.5;
|
|
|
|
tface->uv[2][0] = ((tface->uv[2][0]-0.5)*scale)+0.5;
|
|
|
|
if(efa->v4) {
|
|
|
|
tface->uv[3][0] = ((tface->uv[3][0]-0.5)*scale)+0.5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
scale = aspx/aspy;
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
tface->uv[0][1] = ((tface->uv[0][1]-0.5)*scale)+0.5;
|
|
|
|
tface->uv[1][1] = ((tface->uv[1][1]-0.5)*scale)+0.5;
|
|
|
|
tface->uv[2][1] = ((tface->uv[2][1]-0.5)*scale)+0.5;
|
|
|
|
if(efa->v4) {
|
|
|
|
tface->uv[3][1] = ((tface->uv[3][1]-0.5)*scale)+0.5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void default_uv(float uv[][2], float size)
|
|
|
|
{
|
|
|
|
int dy;
|
|
|
|
|
|
|
|
if(size>1.0) size= 1.0;
|
|
|
|
|
|
|
|
dy= 1.0-size;
|
|
|
|
|
|
|
|
uv[0][0]= 0;
|
|
|
|
uv[0][1]= size+dy;
|
|
|
|
|
|
|
|
uv[1][0]= 0;
|
|
|
|
uv[1][1]= dy;
|
|
|
|
|
|
|
|
uv[2][0]= size;
|
|
|
|
uv[2][1]= dy;
|
|
|
|
|
|
|
|
uv[3][0]= size;
|
|
|
|
uv[3][1]= size+dy;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void calculate_uv_map(Scene *scene, ARegion *ar, View3D *v3d, EditMesh *em, unsigned short mapmode)
|
|
|
|
{
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
RegionView3D *rv3d= ar->regiondata;
|
2008-12-30 13:16:14 +00:00
|
|
|
MTFace *tface;
|
|
|
|
Object *ob;
|
|
|
|
EditFace *efa;
|
|
|
|
float dx, dy, rotatematrix[4][4], radius= 1.0, min[3], cent[3], max[3];
|
|
|
|
float fac= 1.0, upangledeg= 0.0, sideangledeg= 90.0;
|
|
|
|
int i, b, mi, n;
|
|
|
|
|
|
|
|
if(scene->toolsettings->uvcalc_mapdir==1) {
|
|
|
|
upangledeg= 90.0;
|
|
|
|
sideangledeg= 0.0;
|
|
|
|
} else {
|
|
|
|
upangledeg= 0.0;
|
|
|
|
if(scene->toolsettings->uvcalc_mapalign==1) sideangledeg= 0.0;
|
|
|
|
else sideangledeg= 90.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add uvs if there not here */
|
|
|
|
if (!EM_texFaceCheck(em)) {
|
|
|
|
if (em && em->faces.first)
|
|
|
|
EM_add_data_layer(em, &em->fdata, CD_MTFACE);
|
|
|
|
|
|
|
|
// XXX if (G.sima && G.sima->image) /* this is a bit of a kludge, but assume they want the image on their mesh when UVs are added */
|
|
|
|
// image_changed(G.sima, G.sima->image);
|
|
|
|
|
|
|
|
if (!EM_texFaceCheck(em))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* select new UV's */
|
|
|
|
// XX if ((G.sima && G.sima->flag & SI_SYNC_UVSEL)==0) {
|
|
|
|
// for(efa=em->faces.first; efa; efa=efa->next) {
|
|
|
|
// MTFace *tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
// simaFaceSel_Set(efa, tf);
|
|
|
|
// }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ob=OBACT;
|
|
|
|
|
|
|
|
switch(mapmode) {
|
|
|
|
case B_UVAUTO_BOUNDS:
|
|
|
|
min[0]= min[1]= 10000000.0;
|
|
|
|
max[0]= max[1]= -10000000.0;
|
|
|
|
|
|
|
|
cent[0] = cent[1] = cent[2] = 0.0;
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
uv_calc_map_matrix(rotatematrix, rv3d, ob, upangledeg, sideangledeg, 1.0f);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[0],cent,rotatematrix,3, efa->v1->co, min,max);
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[1],cent,rotatematrix,3, efa->v2->co, min,max);
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[2],cent,rotatematrix,3, efa->v3->co,min,max);
|
|
|
|
if(efa->v4)
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[3],cent,rotatematrix,3, efa->v4->co,min,max);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* rescale UV to be in 1/1 */
|
|
|
|
dx= (max[0]-min[0]);
|
|
|
|
dy= (max[1]-min[1]);
|
|
|
|
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
if(efa->v4) b= 3; else b= 2;
|
|
|
|
for(; b>=0; b--) {
|
|
|
|
tface->uv[b][0]= ((tface->uv[b][0]-min[0])*fac)/dx;
|
|
|
|
tface->uv[b][1]= 1.0-fac+((tface->uv[b][1]-min[1])/* *fac */)/dy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case B_UVAUTO_WINDOW:
|
|
|
|
cent[0] = cent[1] = cent[2] = 0.0;
|
|
|
|
Mat4CpyMat4(rotatematrix,ob->obmat);
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[0],cent,rotatematrix,4, efa->v1->co, NULL,NULL);
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[1],cent,rotatematrix,4, efa->v2->co, NULL,NULL);
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[2],cent,rotatematrix,4, efa->v3->co, NULL,NULL);
|
|
|
|
if(efa->v4)
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[3],cent,rotatematrix,4, efa->v4->co, NULL,NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case B_UVAUTO_RESET:
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
default_uv(tface->uv, 1.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case B_UVAUTO_CYLINDER:
|
|
|
|
case B_UVAUTO_SPHERE:
|
|
|
|
uv_calc_center_vector(scene, v3d, cent, ob, em);
|
|
|
|
|
|
|
|
if(mapmode==B_UVAUTO_CYLINDER) radius = scene->toolsettings->uvcalc_radius;
|
|
|
|
|
|
|
|
/* be compatible to the "old" sphere/cylinder mode */
|
|
|
|
if (scene->toolsettings->uvcalc_mapdir== 2)
|
|
|
|
Mat4One(rotatematrix);
|
|
|
|
else
|
2.5
View3D has been split now in a local part (RegionView3D) and a
per-area part (old View3D). Currently local is:
- view transform
- camera zoom/offset
- gpencil (todo)
- custom clipping planes
Rest is in Area still, like active camera, draw type, layers,
localview, custom centers, around-settings, transform widget,
gridlines, and so on (mostly stuff as available in header).
To see it work; also added new feature for region split,
press SHIFT+ALT+CTRL+S for four-split.
The idea is to make a preset 4-split, configured to stick
to top/right/front views for three views.
Another cool idea to explore is to then box-clip all drawing
based on these 3 views.
Note about the code:
- currently view3d still stores some depricated settings, to
convert from older files. Not all settings are copied over
though, like custom clip planes or the 'lock view to object'.
- since some view3d ops are now on area level, the operators
for it should keep track of that.
Bugfix in transform: quat initialize in operator-invoke missed
one zero.
Als brought back GE to compile for missing Ipos and channels.
2009-01-19 16:54:41 +00:00
|
|
|
uv_calc_map_matrix(rotatematrix, rv3d, ob, upangledeg,sideangledeg,radius);
|
2008-12-30 13:16:14 +00:00
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[0],cent,rotatematrix,mapmode, efa->v1->co, NULL,NULL);
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[1],cent,rotatematrix,mapmode, efa->v2->co, NULL,NULL);
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[2],cent,rotatematrix,mapmode, efa->v3->co, NULL,NULL);
|
|
|
|
n = 3;
|
|
|
|
if(efa->v4) {
|
|
|
|
uv_calc_shift_project(ar, v3d, tface->uv[3],cent,rotatematrix,mapmode, efa->v4->co, NULL,NULL);
|
|
|
|
n=4;
|
|
|
|
}
|
|
|
|
|
|
|
|
mi = 0;
|
|
|
|
for (i = 1; i < n; i++)
|
|
|
|
if (tface->uv[i][0] > tface->uv[mi][0]) mi = i;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
if (i != mi) {
|
|
|
|
dx = tface->uv[mi][0] - tface->uv[i][0];
|
|
|
|
if (dx > 0.5) tface->uv[i][0] += 1.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case B_UVAUTO_CUBE:
|
|
|
|
{
|
|
|
|
/* choose x,y,z axis for projetion depending on the largest normal */
|
|
|
|
/* component, but clusters all together around the center of map */
|
|
|
|
float no[3];
|
|
|
|
short cox, coy;
|
|
|
|
float *loc= ob->obmat[3];
|
|
|
|
/*MVert *mv= me->mvert;*/
|
|
|
|
float cubesize = scene->toolsettings->uvcalc_cubesize;
|
|
|
|
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
if (efa->f & SELECT) {
|
|
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, no);
|
|
|
|
|
|
|
|
no[0]= fabs(no[0]);
|
|
|
|
no[1]= fabs(no[1]);
|
|
|
|
no[2]= fabs(no[2]);
|
|
|
|
|
|
|
|
cox=0; coy= 1;
|
|
|
|
if(no[2]>=no[0] && no[2]>=no[1]);
|
|
|
|
else if(no[1]>=no[0] && no[1]>=no[2]) coy= 2;
|
|
|
|
else { cox= 1; coy= 2; }
|
|
|
|
|
|
|
|
tface->uv[0][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v1->co[cox]);
|
|
|
|
tface->uv[0][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v1->co[coy]);
|
|
|
|
dx = floor(tface->uv[0][0]);
|
|
|
|
dy = floor(tface->uv[0][1]);
|
|
|
|
tface->uv[0][0] -= dx;
|
|
|
|
tface->uv[0][1] -= dy;
|
|
|
|
tface->uv[1][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v2->co[cox]);
|
|
|
|
tface->uv[1][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v2->co[coy]);
|
|
|
|
tface->uv[1][0] -= dx;
|
|
|
|
tface->uv[1][1] -= dy;
|
|
|
|
tface->uv[2][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v3->co[cox]);
|
|
|
|
tface->uv[2][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v3->co[coy]);
|
|
|
|
tface->uv[2][0] -= dx;
|
|
|
|
tface->uv[2][1] -= dy;
|
|
|
|
if(efa->v4) {
|
|
|
|
tface->uv[3][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v4->co[cox]);
|
|
|
|
tface->uv[3][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v4->co[coy]);
|
|
|
|
tface->uv[3][0] -= dx;
|
|
|
|
tface->uv[3][1] -= dy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
if ((scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT)==0)
|
|
|
|
correct_uv_aspect(em);
|
|
|
|
return;
|
|
|
|
} /* end switch mapmode */
|
|
|
|
|
|
|
|
/* clipping and wrapping */
|
|
|
|
if(0) { // XXX (make it uv layer property!) G.sima && G.sima->flag & SI_CLIP_UV) {
|
|
|
|
for (efa= em->faces.first; efa; efa= efa->next) {
|
|
|
|
if (!(efa->f & SELECT)) continue;
|
|
|
|
tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
|
|
|
|
dx= dy= 0;
|
|
|
|
if(efa->v4) b= 3; else b= 2;
|
|
|
|
for(; b>=0; b--) {
|
|
|
|
while(tface->uv[b][0] + dx < 0.0) dx+= 0.5;
|
|
|
|
while(tface->uv[b][0] + dx > 1.0) dx-= 0.5;
|
|
|
|
while(tface->uv[b][1] + dy < 0.0) dy+= 0.5;
|
|
|
|
while(tface->uv[b][1] + dy > 1.0) dy-= 0.5;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(efa->v4) b= 3; else b= 2;
|
|
|
|
for(; b>=0; b--) {
|
|
|
|
tface->uv[b][0]+= dx;
|
|
|
|
CLAMP(tface->uv[b][0], 0.0, 1.0);
|
|
|
|
|
|
|
|
tface->uv[b][1]+= dy;
|
|
|
|
CLAMP(tface->uv[b][1], 0.0, 1.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (mapmode!=B_UVAUTO_BOUNDS) &&
|
|
|
|
(mapmode!=B_UVAUTO_RESET) &&
|
|
|
|
(scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT)==0
|
|
|
|
) {
|
|
|
|
correct_uv_aspect(em);
|
|
|
|
}
|
|
|
|
|
|
|
|
BIF_undo_push("UV calculation");
|
|
|
|
|
|
|
|
// XXX notifier object_uvs_changed(OBACT);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* last_sel, use em->act_face otherwise get the last selected face in the editselections
|
|
|
|
* at the moment, last_sel is mainly useful for gaking sure the space image dosnt flicker */
|
2.5: Space Image ported back
Organized as follows:
uvedit/
uv editing related code
uvedit_draw.c: drawing code
uvedit_ops.c: operators, just a few done
uvedit_unwrap_ops.c: will be operators for unwrapping
uvedit_paramatrizer.c: lscm/abf/stretch/pack
space_image/
space_image.c: registration and common getter/setters
image_draw.c: drawing code, mostly functional
image_panels.c: panels, all commented out
image_render.c: render callbacks, non functional
image_ops.c: operators, only view navigation done
image_header.c: header, menus mostly done but missing buttons
Notes:
* Header menus consist only of Operator and RNA buttons, if they
are not implemented they're displayed grayed out. Ideally the full
header could work like this, but std_libbuttons looks problematic.
* Started using view2d code more than the old code, but for now it
still does own view2d management due to some very specific
requirements that the image window has. The drawing code however
is more clear hopefully, it only uses view2d, and there is no
switching between 'p' and 'f' view2d's anymore, it is always 'f'.
* In order to make uvedit operators more independent I move some
image space settings to scene toolsettings, and the current image
and its buffer is in the context. Especially sync selection and
select mode belonged there anyway as this cannot work correct with
different spaces having different settings anyway.
* Image paint is not back yet, did not want to put that together with
uvedit because there's really no code sharing.. perhaps vertex paint,
image paint and sculpt would be good to have in one module to share
brush code, partial redraw, etc better.
2009-01-15 04:38:18 +00:00
|
|
|
MTFace *EM_get_active_mtface(EditMesh *em, EditFace **act_efa, MCol **mcol, int sloppy)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
EditFace *efa = NULL;
|
|
|
|
|
|
|
|
if(!EM_texFaceCheck(em))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
efa = EM_get_actFace(em, sloppy);
|
|
|
|
|
|
|
|
if (efa) {
|
|
|
|
if (mcol) {
|
|
|
|
if (CustomData_has_layer(&em->fdata, CD_MCOL))
|
|
|
|
*mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
|
|
|
|
else
|
|
|
|
*mcol = NULL;
|
|
|
|
}
|
|
|
|
if (act_efa) *act_efa = efa;
|
|
|
|
return CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
|
|
|
|
}
|
|
|
|
if (act_efa) *act_efa= NULL;
|
|
|
|
if(mcol) *mcol = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-01-04 14:14:06 +00:00
|
|
|
static void make_tfaces(Object *ob)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-04 14:14:06 +00:00
|
|
|
Mesh *me= ob->data;
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
if(!me->mtface) {
|
2009-01-06 18:59:03 +00:00
|
|
|
me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT,
|
|
|
|
NULL, me->totface);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void reveal_tface(Scene *scene)
|
|
|
|
{
|
|
|
|
Mesh *me;
|
|
|
|
MFace *mface;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
me= get_mesh(OBACT);
|
|
|
|
if(me==0 || me->totface==0) return;
|
|
|
|
|
|
|
|
mface= me->mface;
|
|
|
|
a= me->totface;
|
|
|
|
while(a--) {
|
|
|
|
if(mface->flag & ME_HIDE) {
|
|
|
|
mface->flag |= ME_FACE_SEL;
|
|
|
|
mface->flag -= ME_HIDE;
|
|
|
|
}
|
|
|
|
mface++;
|
|
|
|
}
|
|
|
|
|
|
|
|
BIF_undo_push("Reveal face");
|
|
|
|
|
|
|
|
// XXX notifier! object_tface_flags_changed(OBACT, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void hide_tface(Scene *scene)
|
|
|
|
{
|
|
|
|
Mesh *me;
|
|
|
|
MFace *mface;
|
|
|
|
int a;
|
|
|
|
int shift=0, alt= 0; // XXX
|
|
|
|
|
|
|
|
me= get_mesh(OBACT);
|
|
|
|
if(me==0 || me->totface==0) return;
|
|
|
|
|
|
|
|
if(alt) {
|
|
|
|
reveal_tface(scene);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mface= me->mface;
|
|
|
|
a= me->totface;
|
|
|
|
while(a--) {
|
|
|
|
if(mface->flag & ME_HIDE);
|
|
|
|
else {
|
|
|
|
if(shift) {
|
|
|
|
if( (mface->flag & ME_FACE_SEL)==0) mface->flag |= ME_HIDE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if( (mface->flag & ME_FACE_SEL)) mface->flag |= ME_HIDE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(mface->flag & ME_HIDE) mface->flag &= ~ME_FACE_SEL;
|
|
|
|
|
|
|
|
mface++;
|
|
|
|
}
|
|
|
|
|
|
|
|
BIF_undo_push("Hide face");
|
|
|
|
|
|
|
|
// XXX notifier! object_tface_flags_changed(OBACT, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void select_linked_tfaces(Scene *scene, View3D *v3d, int mode)
|
|
|
|
{
|
|
|
|
Object *ob;
|
|
|
|
Mesh *me;
|
|
|
|
short mval[2];
|
|
|
|
unsigned int index=0;
|
|
|
|
|
|
|
|
ob = OBACT;
|
|
|
|
me = get_mesh(ob);
|
|
|
|
if(me==0 || me->totface==0) return;
|
|
|
|
|
|
|
|
if (mode==0 || mode==1) {
|
|
|
|
if (!(ob->lay & v3d->lay))
|
|
|
|
error("The active object is not in this layer");
|
|
|
|
|
|
|
|
// XXX getmouseco_areawin(mval);
|
|
|
|
if (!facesel_face_pick(v3d, me, mval, &index, 1)) return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX unwrapper.c select_linked_tfaces_with_seams(mode, me, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void deselectall_tface(Scene *scene)
|
|
|
|
{
|
|
|
|
Mesh *me;
|
|
|
|
MFace *mface;
|
|
|
|
int a, sel;
|
|
|
|
|
|
|
|
me= get_mesh(OBACT);
|
|
|
|
if(me==0) return;
|
|
|
|
|
|
|
|
mface= me->mface;
|
|
|
|
a= me->totface;
|
|
|
|
sel= 0;
|
|
|
|
while(a--) {
|
|
|
|
if(mface->flag & ME_HIDE);
|
|
|
|
else if(mface->flag & ME_FACE_SEL) sel= 1;
|
|
|
|
mface++;
|
|
|
|
}
|
|
|
|
|
|
|
|
mface= me->mface;
|
|
|
|
a= me->totface;
|
|
|
|
while(a--) {
|
|
|
|
if(mface->flag & ME_HIDE);
|
|
|
|
else {
|
|
|
|
if(sel) mface->flag &= ~ME_FACE_SEL;
|
|
|
|
else mface->flag |= ME_FACE_SEL;
|
|
|
|
}
|
|
|
|
mface++;
|
|
|
|
}
|
|
|
|
|
|
|
|
BIF_undo_push("(De)select all faces");
|
|
|
|
|
|
|
|
// XXX notifier! object_tface_flags_changed(OBACT, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void selectswap_tface(Scene *scene)
|
|
|
|
{
|
|
|
|
Mesh *me;
|
|
|
|
MFace *mface;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
me= get_mesh(OBACT);
|
|
|
|
if(me==0) return;
|
|
|
|
|
|
|
|
mface= me->mface;
|
|
|
|
a= me->totface;
|
|
|
|
while(a--) {
|
|
|
|
if(mface->flag & ME_HIDE);
|
|
|
|
else {
|
|
|
|
if(mface->flag & ME_FACE_SEL) mface->flag &= ~ME_FACE_SEL;
|
|
|
|
else mface->flag |= ME_FACE_SEL;
|
|
|
|
}
|
|
|
|
mface++;
|
|
|
|
}
|
|
|
|
|
|
|
|
BIF_undo_push("Select inverse face");
|
|
|
|
|
|
|
|
// XXX notifier! object_tface_flags_changed(OBACT, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int minmax_tface(Scene *scene, float *min, float *max)
|
|
|
|
{
|
|
|
|
Object *ob;
|
|
|
|
Mesh *me;
|
|
|
|
MFace *mf;
|
|
|
|
MTFace *tf;
|
|
|
|
MVert *mv;
|
|
|
|
int a, ok=0;
|
|
|
|
float vec[3], bmat[3][3];
|
|
|
|
|
|
|
|
ob = OBACT;
|
|
|
|
if (ob==0) return ok;
|
|
|
|
me= get_mesh(ob);
|
|
|
|
if(me==0 || me->mtface==0) return ok;
|
|
|
|
|
|
|
|
Mat3CpyMat4(bmat, ob->obmat);
|
|
|
|
|
|
|
|
mv= me->mvert;
|
|
|
|
mf= me->mface;
|
|
|
|
tf= me->mtface;
|
|
|
|
for (a=me->totface; a>0; a--, mf++, tf++) {
|
|
|
|
if (mf->flag & ME_HIDE || !(mf->flag & ME_FACE_SEL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
VECCOPY(vec, (mv+mf->v1)->co);
|
|
|
|
Mat3MulVecfl(bmat, vec);
|
|
|
|
VecAddf(vec, vec, ob->obmat[3]);
|
|
|
|
DO_MINMAX(vec, min, max);
|
|
|
|
|
|
|
|
VECCOPY(vec, (mv+mf->v2)->co);
|
|
|
|
Mat3MulVecfl(bmat, vec);
|
|
|
|
VecAddf(vec, vec, ob->obmat[3]);
|
|
|
|
DO_MINMAX(vec, min, max);
|
|
|
|
|
|
|
|
VECCOPY(vec, (mv+mf->v3)->co);
|
|
|
|
Mat3MulVecfl(bmat, vec);
|
|
|
|
VecAddf(vec, vec, ob->obmat[3]);
|
|
|
|
DO_MINMAX(vec, min, max);
|
|
|
|
|
|
|
|
if (mf->v4) {
|
|
|
|
VECCOPY(vec, (mv+mf->v4)->co);
|
|
|
|
Mat3MulVecfl(bmat, vec);
|
|
|
|
VecAddf(vec, vec, ob->obmat[3]);
|
|
|
|
DO_MINMAX(vec, min, max);
|
|
|
|
}
|
|
|
|
ok= 1;
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ME_SEAM_DONE 2 /* reuse this flag */
|
|
|
|
|
|
|
|
static float edgetag_cut_cost(EditMesh *em, int e1, int e2, int vert)
|
|
|
|
{
|
|
|
|
EditVert *v = EM_get_vert_for_index(vert);
|
|
|
|
EditEdge *eed1 = EM_get_edge_for_index(e1), *eed2 = EM_get_edge_for_index(e2);
|
|
|
|
EditVert *v1 = EM_get_vert_for_index( (eed1->v1->tmp.l == vert)? eed1->v2->tmp.l: eed1->v1->tmp.l );
|
|
|
|
EditVert *v2 = EM_get_vert_for_index( (eed2->v1->tmp.l == vert)? eed2->v2->tmp.l: eed2->v1->tmp.l );
|
|
|
|
float cost, d1[3], d2[3];
|
|
|
|
|
|
|
|
cost = VecLenf(v1->co, v->co);
|
|
|
|
cost += VecLenf(v->co, v2->co);
|
|
|
|
|
|
|
|
VecSubf(d1, v->co, v1->co);
|
|
|
|
VecSubf(d2, v2->co, v->co);
|
|
|
|
|
|
|
|
cost = cost + 0.5f*cost*(2.0f - fabs(d1[0]*d2[0] + d1[1]*d2[1] + d1[2]*d2[2]));
|
|
|
|
|
|
|
|
return cost;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void edgetag_add_adjacent(EditMesh *em, Heap *heap, int mednum, int vertnum, int *nedges, int *edges, int *prevedge, float *cost)
|
|
|
|
{
|
|
|
|
int startadj, endadj = nedges[vertnum+1];
|
|
|
|
|
|
|
|
for (startadj = nedges[vertnum]; startadj < endadj; startadj++) {
|
|
|
|
int adjnum = edges[startadj];
|
|
|
|
EditEdge *eedadj = EM_get_edge_for_index(adjnum);
|
|
|
|
float newcost;
|
|
|
|
|
|
|
|
if (eedadj->f2 & ME_SEAM_DONE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
newcost = cost[mednum] + edgetag_cut_cost(em, mednum, adjnum, vertnum);
|
|
|
|
|
|
|
|
if (cost[adjnum] > newcost) {
|
|
|
|
cost[adjnum] = newcost;
|
|
|
|
prevedge[adjnum] = mednum;
|
|
|
|
BLI_heap_insert(heap, newcost, SET_INT_IN_POINTER(adjnum));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void edgetag_context_set(Scene *scene, EditEdge *eed, int val)
|
|
|
|
{
|
|
|
|
switch (scene->toolsettings->edge_mode) {
|
|
|
|
case EDGE_MODE_TAG_SEAM:
|
|
|
|
if (val) {eed->seam = 255;}
|
|
|
|
else {eed->seam = 0;}
|
|
|
|
break;
|
|
|
|
case EDGE_MODE_TAG_SHARP:
|
|
|
|
if (val) {eed->sharp = 1;}
|
|
|
|
else {eed->sharp = 0;}
|
|
|
|
break;
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
|
|
|
if (val) {eed->crease = 1.0f;}
|
|
|
|
else {eed->crease = 0.0f;}
|
|
|
|
break;
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
|
|
|
if (val) {eed->bweight = 1.0f;}
|
|
|
|
else {eed->bweight = 0.0f;}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int edgetag_context_check(Scene *scene, EditEdge *eed)
|
|
|
|
{
|
|
|
|
switch (scene->toolsettings->edge_mode) {
|
|
|
|
case EDGE_MODE_TAG_SEAM:
|
|
|
|
return eed->seam ? 1 : 0;
|
|
|
|
case EDGE_MODE_TAG_SHARP:
|
|
|
|
return eed->sharp ? 1 : 0;
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
|
|
|
return eed->crease ? 1 : 0;
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
|
|
|
return eed->bweight ? 1 : 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target)
|
|
|
|
{
|
|
|
|
EditEdge *eed;
|
|
|
|
EditVert *ev;
|
|
|
|
|
|
|
|
Heap *heap;
|
|
|
|
float *cost;
|
|
|
|
int a, totvert=0, totedge=0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/* we need the vert */
|
|
|
|
for (ev= em->verts.first, totvert=0; ev; ev= ev->next) {
|
|
|
|
ev->tmp.l = totvert;
|
|
|
|
totvert++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (eed= em->edges.first; eed; eed = eed->next) {
|
|
|
|
eed->f2 = 0;
|
|
|
|
if (eed->h) {
|
|
|
|
eed->f2 |= ME_SEAM_DONE;
|
|
|
|
}
|
|
|
|
eed->tmp.l = totedge;
|
|
|
|
totedge++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* alloc */
|
|
|
|
nedges = MEM_callocN(sizeof(*nedges)*totvert+1, "SeamPathNEdges");
|
|
|
|
edges = MEM_mallocN(sizeof(*edges)*totedge*2, "SeamPathEdges");
|
|
|
|
prevedge = MEM_mallocN(sizeof(*prevedge)*totedge, "SeamPathPrevious");
|
|
|
|
cost = MEM_mallocN(sizeof(*cost)*totedge, "SeamPathCost");
|
|
|
|
|
|
|
|
/* count edges, compute adjacent edges offsets and fill adjacent edges */
|
|
|
|
for (eed= em->edges.first; eed; eed = eed->next) {
|
|
|
|
nedges[eed->v1->tmp.l+1]++;
|
|
|
|
nedges[eed->v2->tmp.l+1]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (a=1; a<totvert; a++) {
|
|
|
|
int newswap = nedges[a+1];
|
|
|
|
nedges[a+1] = nedgeswap + nedges[a];
|
|
|
|
nedgeswap = newswap;
|
|
|
|
}
|
|
|
|
nedges[0] = nedges[1] = 0;
|
|
|
|
|
|
|
|
for (a=0, eed= em->edges.first; eed; a++, eed = eed->next) {
|
|
|
|
edges[nedges[eed->v1->tmp.l+1]++] = a;
|
|
|
|
edges[nedges[eed->v2->tmp.l+1]++] = a;
|
|
|
|
|
|
|
|
cost[a] = 1e20f;
|
|
|
|
prevedge[a] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* regular dijkstra shortest path, but over edges instead of vertices */
|
|
|
|
heap = BLI_heap_new();
|
|
|
|
BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(source->tmp.l));
|
|
|
|
cost[source->tmp.l] = 0.0f;
|
|
|
|
|
|
|
|
EM_init_index_arrays(em, 1, 1, 0);
|
|
|
|
|
|
|
|
|
|
|
|
while (!BLI_heap_empty(heap)) {
|
|
|
|
mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
|
|
|
|
eed = EM_get_edge_for_index( mednum );
|
|
|
|
|
|
|
|
if (mednum == target->tmp.l)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (eed->f2 & ME_SEAM_DONE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
eed->f2 |= ME_SEAM_DONE;
|
|
|
|
|
|
|
|
edgetag_add_adjacent(em, heap, mednum, eed->v1->tmp.l, nedges, edges, prevedge, cost);
|
|
|
|
edgetag_add_adjacent(em, heap, mednum, eed->v2->tmp.l, nedges, edges, prevedge, cost);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MEM_freeN(nedges);
|
|
|
|
MEM_freeN(edges);
|
|
|
|
MEM_freeN(cost);
|
|
|
|
BLI_heap_free(heap, NULL);
|
|
|
|
|
|
|
|
for (eed= em->edges.first; eed; eed = eed->next) {
|
|
|
|
eed->f2 &= ~ME_SEAM_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mednum != target->tmp.l) {
|
|
|
|
MEM_freeN(prevedge);
|
|
|
|
EM_free_index_arrays();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* follow path back to source and mark as seam */
|
|
|
|
if (mednum == target->tmp.l) {
|
|
|
|
short allseams = 1;
|
|
|
|
|
|
|
|
mednum = target->tmp.l;
|
|
|
|
do {
|
|
|
|
eed = EM_get_edge_for_index( mednum );
|
|
|
|
if (!edgetag_context_check(scene, eed)) {
|
|
|
|
allseams = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mednum = prevedge[mednum];
|
|
|
|
} while (mednum != source->tmp.l);
|
|
|
|
|
|
|
|
mednum = target->tmp.l;
|
|
|
|
do {
|
|
|
|
eed = EM_get_edge_for_index( mednum );
|
|
|
|
if (allseams)
|
|
|
|
edgetag_context_set(scene, eed, 0);
|
|
|
|
else
|
|
|
|
edgetag_context_set(scene, eed, 1);
|
|
|
|
mednum = prevedge[mednum];
|
|
|
|
} while (mednum != -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(prevedge);
|
|
|
|
EM_free_index_arrays();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seam_edgehash_insert_face(EdgeHash *ehash, MFace *mf)
|
|
|
|
{
|
|
|
|
BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
|
|
|
|
BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
|
|
|
|
if (mf->v4) {
|
|
|
|
BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
|
|
|
|
BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void seam_mark_clear_tface(Scene *scene, short mode)
|
|
|
|
{
|
|
|
|
Mesh *me;
|
|
|
|
MFace *mf;
|
|
|
|
MEdge *med;
|
|
|
|
int a;
|
|
|
|
|
|
|
|
me= get_mesh(OBACT);
|
|
|
|
if(me==0 || me->totface==0) return;
|
|
|
|
|
|
|
|
if (mode == 0)
|
|
|
|
mode = pupmenu("Seams%t|Mark Border Seam %x1|Clear Seam %x2");
|
|
|
|
|
|
|
|
if (mode != 1 && mode != 2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (mode == 2) {
|
|
|
|
EdgeHash *ehash = BLI_edgehash_new();
|
|
|
|
|
|
|
|
for (a=0, mf=me->mface; a<me->totface; a++, mf++)
|
|
|
|
if (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))
|
|
|
|
seam_edgehash_insert_face(ehash, mf);
|
|
|
|
|
|
|
|
for (a=0, med=me->medge; a<me->totedge; a++, med++)
|
|
|
|
if (BLI_edgehash_haskey(ehash, med->v1, med->v2))
|
|
|
|
med->flag &= ~ME_SEAM;
|
|
|
|
|
|
|
|
BLI_edgehash_free(ehash, NULL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* mark edges that are on both selected and deselected faces */
|
|
|
|
EdgeHash *ehash1 = BLI_edgehash_new();
|
|
|
|
EdgeHash *ehash2 = BLI_edgehash_new();
|
|
|
|
|
|
|
|
for (a=0, mf=me->mface; a<me->totface; a++, mf++) {
|
|
|
|
if ((mf->flag & ME_HIDE) || !(mf->flag & ME_FACE_SEL))
|
|
|
|
seam_edgehash_insert_face(ehash1, mf);
|
|
|
|
else
|
|
|
|
seam_edgehash_insert_face(ehash2, mf);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (a=0, med=me->medge; a<me->totedge; a++, med++)
|
|
|
|
if (BLI_edgehash_haskey(ehash1, med->v1, med->v2) &&
|
|
|
|
BLI_edgehash_haskey(ehash2, med->v1, med->v2))
|
|
|
|
med->flag |= ME_SEAM;
|
|
|
|
|
|
|
|
BLI_edgehash_free(ehash1, NULL);
|
|
|
|
BLI_edgehash_free(ehash2, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX if (G.rt == 8)
|
|
|
|
// unwrap_lscm(1);
|
|
|
|
|
|
|
|
G.f |= G_DRAWSEAMS;
|
|
|
|
BIF_undo_push("Mark Seam");
|
|
|
|
|
|
|
|
// XXX notifier! object_tface_flags_changed(OBACT, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void face_select(Scene *scene, View3D *v3d)
|
|
|
|
{
|
|
|
|
Object *ob;
|
|
|
|
Mesh *me;
|
|
|
|
MFace *mface, *msel;
|
|
|
|
short mval[2];
|
|
|
|
unsigned int a, index;
|
|
|
|
int shift= 0; // XXX
|
|
|
|
|
|
|
|
/* Get the face under the cursor */
|
|
|
|
ob = OBACT;
|
|
|
|
if (!(ob->lay & v3d->lay)) {
|
|
|
|
error("The active object is not in this layer");
|
|
|
|
}
|
|
|
|
me = get_mesh(ob);
|
|
|
|
// XXX getmouseco_areawin(mval);
|
|
|
|
|
|
|
|
if (!facesel_face_pick(v3d, me, mval, &index, 1)) return;
|
|
|
|
|
|
|
|
msel= (((MFace*)me->mface)+index);
|
|
|
|
if (msel->flag & ME_HIDE) return;
|
|
|
|
|
|
|
|
/* clear flags */
|
|
|
|
mface = me->mface;
|
|
|
|
a = me->totface;
|
|
|
|
if ((shift)==0) {
|
|
|
|
while (a--) {
|
|
|
|
mface->flag &= ~ME_FACE_SEL;
|
|
|
|
mface++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
me->act_face = (int)index;
|
|
|
|
|
|
|
|
if (shift) {
|
|
|
|
if (msel->flag & ME_FACE_SEL)
|
|
|
|
msel->flag &= ~ME_FACE_SEL;
|
|
|
|
else
|
|
|
|
msel->flag |= ME_FACE_SEL;
|
|
|
|
}
|
|
|
|
else msel->flag |= ME_FACE_SEL;
|
|
|
|
|
|
|
|
/* image window redraw */
|
|
|
|
|
|
|
|
BIF_undo_push("Select UV face");
|
|
|
|
|
|
|
|
// XXX notifier! object_tface_flags_changed(OBACT, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void face_borderselect(Scene *scene, ARegion *ar)
|
|
|
|
{
|
|
|
|
Mesh *me;
|
|
|
|
MFace *mface;
|
|
|
|
rcti rect;
|
|
|
|
struct ImBuf *ibuf;
|
|
|
|
unsigned int *rt;
|
|
|
|
int a, sx, sy, index, val;
|
|
|
|
char *selar;
|
|
|
|
|
|
|
|
me= get_mesh(OBACT);
|
|
|
|
if(me==0) return;
|
|
|
|
if(me->totface==0) return;
|
|
|
|
|
|
|
|
// XXX val= get_border(&rect, 3);
|
|
|
|
|
|
|
|
/* why readbuffer here? shouldn't be necessary (maybe a flush or so) */
|
|
|
|
glReadBuffer(GL_BACK);
|
|
|
|
#ifdef __APPLE__
|
|
|
|
glReadBuffer(GL_AUX0); /* apple only */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if(val) {
|
|
|
|
selar= MEM_callocN(me->totface+1, "selar");
|
|
|
|
|
|
|
|
sx= (rect.xmax-rect.xmin+1);
|
|
|
|
sy= (rect.ymax-rect.ymin+1);
|
|
|
|
if(sx*sy<=0) return;
|
|
|
|
|
|
|
|
ibuf = IMB_allocImBuf(sx,sy,32,IB_rect,0);
|
|
|
|
rt = ibuf->rect;
|
|
|
|
glReadPixels(rect.xmin+ar->winrct.xmin, rect.ymin+ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
|
|
|
|
if(ENDIAN_ORDER==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
|
|
|
|
|
|
|
|
a= sx*sy;
|
|
|
|
while(a--) {
|
|
|
|
if(*rt) {
|
|
|
|
index= WM_framebuffer_to_index(*rt);
|
|
|
|
if(index<=me->totface) selar[index]= 1;
|
|
|
|
}
|
|
|
|
rt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
mface= me->mface;
|
|
|
|
for(a=1; a<=me->totface; a++, mface++) {
|
|
|
|
if(selar[a]) {
|
|
|
|
if(mface->flag & ME_HIDE);
|
|
|
|
else {
|
|
|
|
if(val==LEFTMOUSE) mface->flag |= ME_FACE_SEL;
|
|
|
|
else mface->flag &= ~ME_FACE_SEL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IMB_freeImBuf(ibuf);
|
|
|
|
MEM_freeN(selar);
|
|
|
|
|
|
|
|
BIF_undo_push("Border Select UV face");
|
|
|
|
|
|
|
|
// XXX notifier! object_tface_flags_changed(OBACT, 0);
|
|
|
|
}
|
|
|
|
#ifdef __APPLE__
|
|
|
|
glReadBuffer(GL_BACK);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void uv_autocalc_tface(Scene *scene, ARegion *ar, View3D *v3d, EditMesh *em)
|
|
|
|
{
|
|
|
|
short mode;
|
|
|
|
#ifndef DISABLE_PYTHON
|
|
|
|
// short i=0, has_pymenu=0; /* pymenu must be bigger then UV_*_MAPPING */
|
|
|
|
// XXX BPyMenu *pym;
|
|
|
|
// char menu_number[3];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* uvmenu, will add python items */
|
|
|
|
char uvmenu[4096]=MENUTITLE("UV Calculation")
|
|
|
|
MENUSTRING("Unwrap", UV_UNWRAP_MAPPING) "|%l|"
|
|
|
|
|
|
|
|
MENUSTRING("Cube Projection", UV_CUBE_MAPPING) "|"
|
|
|
|
MENUSTRING("Cylinder from View", UV_CYL_MAPPING) "|"
|
|
|
|
MENUSTRING("Sphere from View", UV_SPHERE_MAPPING) "|%l|"
|
|
|
|
|
|
|
|
MENUSTRING("Project From View", UV_WINDOW_MAPPING) "|"
|
|
|
|
MENUSTRING("Project from View (Bounds)",UV_BOUNDS_MAPPING) "|%l|"
|
|
|
|
|
|
|
|
MENUSTRING("Reset", UV_RESET_MAPPING);
|
|
|
|
#ifndef DISABLE_PYTHON
|
|
|
|
#if 0
|
|
|
|
XXX
|
|
|
|
/* note that we account for the 10 previous entries with i+10: */
|
|
|
|
for (pym = BPyMenuTable[PYMENU_UVCALCULATION]; pym; pym = pym->next, i++) {
|
|
|
|
|
|
|
|
if (!has_pymenu) {
|
|
|
|
strcat(uvmenu, "|%l");
|
|
|
|
has_pymenu = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcat(uvmenu, "|");
|
|
|
|
strcat(uvmenu, pym->name);
|
|
|
|
strcat(uvmenu, " %x");
|
|
|
|
sprintf(menu_number, "%d", i+10);
|
|
|
|
strcat(uvmenu, menu_number);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
mode= pupmenu(uvmenu);
|
|
|
|
#ifndef DISABLE_PYTHON
|
|
|
|
// if (mode >= 10) {
|
|
|
|
// BPY_menu_do_python(PYMENU_UVCALCULATION, mode - 10);
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
#endif
|
|
|
|
switch(mode) {
|
|
|
|
case UV_CUBE_MAPPING:
|
|
|
|
calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_CUBE); break;
|
|
|
|
case UV_CYL_MAPPING:
|
|
|
|
calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_CYLINDER); break;
|
|
|
|
case UV_SPHERE_MAPPING:
|
|
|
|
calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_SPHERE); break;
|
|
|
|
case UV_BOUNDS_MAPPING:
|
|
|
|
calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_BOUNDS); break;
|
|
|
|
case UV_RESET_MAPPING:
|
|
|
|
calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_RESET); break;
|
|
|
|
case UV_WINDOW_MAPPING:
|
|
|
|
calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_WINDOW); break;
|
|
|
|
case UV_UNWRAP_MAPPING:
|
|
|
|
// XXX unwrap_lscm(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Texture Paint */
|
|
|
|
|
|
|
|
void set_texturepaint(Scene *scene) /* toggle */
|
|
|
|
{
|
|
|
|
Object *ob = OBACT;
|
|
|
|
Mesh *me = 0;
|
|
|
|
|
|
|
|
if(ob==NULL) return;
|
|
|
|
|
|
|
|
if (object_data_is_libdata(ob)) {
|
|
|
|
// XXX error_libdata();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
me= get_mesh(ob);
|
|
|
|
|
|
|
|
if(me)
|
|
|
|
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
|
|
|
|
|
|
|
if(G.f & G_TEXTUREPAINT) {
|
|
|
|
G.f &= ~G_TEXTUREPAINT;
|
|
|
|
GPU_paint_set_mipmap(1);
|
|
|
|
}
|
|
|
|
else if (me) {
|
|
|
|
G.f |= G_TEXTUREPAINT;
|
|
|
|
|
|
|
|
if(me->mtface==NULL)
|
2009-01-04 14:14:06 +00:00
|
|
|
make_tfaces(ob);
|
2008-12-30 13:16:14 +00:00
|
|
|
|
|
|
|
brush_check_exists(&scene->toolsettings->imapaint.brush);
|
|
|
|
GPU_paint_set_mipmap(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void texpaint_project(Object *ob, float *model, float *proj, float *co, float *pco)
|
|
|
|
{
|
|
|
|
VECCOPY(pco, co);
|
|
|
|
pco[3]= 1.0f;
|
|
|
|
|
|
|
|
Mat4MulVecfl(ob->obmat, pco);
|
|
|
|
Mat4MulVecfl((float(*)[4])model, pco);
|
|
|
|
Mat4MulVec4fl((float(*)[4])proj, pco);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void texpaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, float *co, float *w)
|
|
|
|
{
|
|
|
|
float pv1[4], pv2[4], pv3[4], h[3], divw;
|
|
|
|
float model[16], proj[16], wmat[3][3], invwmat[3][3];
|
|
|
|
GLint view[4];
|
|
|
|
|
|
|
|
/* compute barycentric coordinates */
|
|
|
|
|
|
|
|
/* get the needed opengl matrices */
|
|
|
|
glGetIntegerv(GL_VIEWPORT, view);
|
|
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, model);
|
|
|
|
glGetFloatv(GL_PROJECTION_MATRIX, proj);
|
|
|
|
view[0] = view[1] = 0;
|
|
|
|
|
|
|
|
/* project the verts */
|
|
|
|
texpaint_project(ob, model, proj, v1, pv1);
|
|
|
|
texpaint_project(ob, model, proj, v2, pv2);
|
|
|
|
texpaint_project(ob, model, proj, v3, pv3);
|
|
|
|
|
|
|
|
/* do inverse view mapping, see gluProject man page */
|
|
|
|
h[0]= (co[0] - view[0])*2.0f/view[2] - 1;
|
|
|
|
h[1]= (co[1] - view[1])*2.0f/view[3] - 1;
|
|
|
|
h[2]= 1.0f;
|
|
|
|
|
|
|
|
/* solve for (w1,w2,w3)/perspdiv in:
|
|
|
|
h*perspdiv = Project*Model*(w1*v1 + w2*v2 + w3*v3) */
|
|
|
|
|
|
|
|
wmat[0][0]= pv1[0]; wmat[1][0]= pv2[0]; wmat[2][0]= pv3[0];
|
|
|
|
wmat[0][1]= pv1[1]; wmat[1][1]= pv2[1]; wmat[2][1]= pv3[1];
|
|
|
|
wmat[0][2]= pv1[3]; wmat[1][2]= pv2[3]; wmat[2][2]= pv3[3];
|
|
|
|
|
|
|
|
Mat3Inv(invwmat, wmat);
|
|
|
|
Mat3MulVecfl(invwmat, h);
|
|
|
|
|
|
|
|
VECCOPY(w, h);
|
|
|
|
|
|
|
|
/* w is still divided by perspdiv, make it sum to one */
|
|
|
|
divw= w[0] + w[1] + w[2];
|
|
|
|
if(divw != 0.0f)
|
|
|
|
VecMulf(w, 1.0f/divw);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compute uv coordinates of mouse in face */
|
2009-01-04 14:14:06 +00:00
|
|
|
void texpaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceindex, short *xy, float *uv)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2009-01-04 14:14:06 +00:00
|
|
|
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
|
2008-12-30 13:16:14 +00:00
|
|
|
int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
|
|
|
|
MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
|
|
|
|
int numfaces = dm->getNumFaces(dm), a;
|
|
|
|
float p[2], w[3], absw, minabsw;
|
|
|
|
MFace mf;
|
|
|
|
MVert mv[4];
|
|
|
|
|
|
|
|
minabsw = 1e10;
|
|
|
|
uv[0] = uv[1] = 0.0;
|
|
|
|
|
|
|
|
// XXX persp(PERSP_VIEW);
|
|
|
|
|
|
|
|
/* test all faces in the derivedmesh with the original index of the picked face */
|
|
|
|
for (a = 0; a < numfaces; a++) {
|
|
|
|
if (index[a] == faceindex) {
|
|
|
|
dm->getFace(dm, a, &mf);
|
|
|
|
|
|
|
|
dm->getVert(dm, mf.v1, &mv[0]);
|
|
|
|
dm->getVert(dm, mf.v2, &mv[1]);
|
|
|
|
dm->getVert(dm, mf.v3, &mv[2]);
|
|
|
|
if (mf.v4)
|
|
|
|
dm->getVert(dm, mf.v4, &mv[3]);
|
|
|
|
|
|
|
|
tf= &tface[a];
|
|
|
|
|
|
|
|
p[0]= xy[0];
|
|
|
|
p[1]= xy[1];
|
|
|
|
|
|
|
|
if (mf.v4) {
|
|
|
|
/* the triangle with the largest absolute values is the one
|
|
|
|
with the most negative weights */
|
|
|
|
texpaint_tri_weights(ob, mv[0].co, mv[1].co, mv[3].co, p, w);
|
|
|
|
absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
|
|
|
|
if(absw < minabsw) {
|
|
|
|
uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2];
|
|
|
|
uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2];
|
|
|
|
minabsw = absw;
|
|
|
|
}
|
|
|
|
|
|
|
|
texpaint_tri_weights(ob, mv[1].co, mv[2].co, mv[3].co, p, w);
|
|
|
|
absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
|
|
|
|
if (absw < minabsw) {
|
|
|
|
uv[0]= tf->uv[1][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
|
|
|
|
uv[1]= tf->uv[1][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
|
|
|
|
minabsw = absw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
texpaint_tri_weights(ob, mv[0].co, mv[1].co, mv[2].co, p, w);
|
|
|
|
absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
|
|
|
|
if (absw < minabsw) {
|
|
|
|
uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
|
|
|
|
uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
|
|
|
|
minabsw = absw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dm->release(dm);
|
|
|
|
}
|