Time to go watch er. Note this was already done with face_old, img_old was probably just overlooked. (If you guys didn't notice I was sick for a couple of days but I'm back now as you can tell) Kent -- mein@cs.umn.edu Index: editface.c =================================================================== RCS file: /cvs01/blender/source/blender/src/editface.c,v retrieving revision 1.3 diff -u -r1.3 editface.c --- editface.c 2002/11/25 12:02:05 1.3 +++ editface.c 2002/12/20 02:50:55 @@ -1202,7 +1202,7 @@ TFace *face, *face_old = 0; short xy[2], xy_old[2]; //int a, index; - Image *img, *img_old; + Image *img, *img_old = 0;
1344 lines
32 KiB
C
1344 lines
32 KiB
C
/**
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL/BL DUAL 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. The Blender
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
* about this.
|
|
*
|
|
* 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/BL DUAL LICENSE BLOCK *****
|
|
*/
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#include "BLI_winstuff.h"
|
|
#endif
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_arithb.h"
|
|
|
|
#include "MTC_matrixops.h"
|
|
|
|
#include "IMB_imbuf_types.h"
|
|
#include "IMB_imbuf.h"
|
|
|
|
#include "DNA_image_types.h"
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_space_types.h"
|
|
#include "DNA_screen_types.h"
|
|
#include "DNA_view3d_types.h"
|
|
|
|
#include "BKE_utildefines.h"
|
|
#include "BKE_displist.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_mesh.h"
|
|
#include "BKE_texture.h"
|
|
|
|
#include "BSE_view.h"
|
|
#include "BSE_edit.h"
|
|
#include "BSE_drawview.h" /* for backdrawview3d */
|
|
|
|
#include "BIF_interface.h"
|
|
#include "BIF_mywindow.h"
|
|
#include "BIF_toolbox.h"
|
|
#include "BIF_screen.h"
|
|
#include "BIF_gl.h"
|
|
#include "BIF_graphics.h"
|
|
#include "BIF_space.h" /* for allqueue */
|
|
|
|
#include "BDR_drawmesh.h"
|
|
#include "BDR_editface.h"
|
|
#include "BDR_vpaint.h"
|
|
|
|
#include "BDR_editface.h"
|
|
#include "BDR_vpaint.h"
|
|
|
|
#include "mydevice.h"
|
|
#include "blendef.h"
|
|
#include "render.h"
|
|
|
|
/* #include "graphics.h" */
|
|
// #include "blendef.h"
|
|
#include "interface.h"
|
|
#include "TPT_DependKludge.h"
|
|
|
|
#ifdef NAN_TPT
|
|
#include "../img/IMG_Api.h"
|
|
#include "BSE_trans_types.h"
|
|
#endif /* NAN_TPT */
|
|
|
|
TFace *lasttface=0;
|
|
|
|
void set_lasttface()
|
|
{
|
|
Mesh *me;
|
|
TFace *tface;
|
|
int a;
|
|
|
|
lasttface= 0;
|
|
|
|
me= get_mesh(OBACT);
|
|
if(me==0 || me->tface==0) return;
|
|
|
|
tface= me->tface;
|
|
a= me->totface;
|
|
while(a--) {
|
|
if(tface->flag & TF_ACTIVE) {
|
|
lasttface= tface;
|
|
return;
|
|
}
|
|
tface++;
|
|
}
|
|
|
|
tface= me->tface;
|
|
a= me->totface;
|
|
while(a--) {
|
|
if(tface->flag & TF_SELECT) {
|
|
lasttface= tface;
|
|
return;
|
|
}
|
|
tface++;
|
|
}
|
|
|
|
tface= me->tface;
|
|
a= me->totface;
|
|
while(a--) {
|
|
if((tface->flag & TF_HIDE)==0) {
|
|
lasttface= tface;
|
|
return;
|
|
}
|
|
tface++;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
void default_tface(TFace *tface)
|
|
{
|
|
default_uv(tface->uv, 1.0);
|
|
|
|
tface->col[0]= tface->col[1]= tface->col[2]= tface->col[3]= vpaint_get_current_col();
|
|
|
|
tface->mode= TF_TEX;
|
|
tface->mode= 0;
|
|
tface->flag= TF_SELECT;
|
|
tface->tpage= 0;
|
|
tface->mode |= TF_DYNAMIC;
|
|
}
|
|
|
|
void make_tfaces(Mesh *me)
|
|
{
|
|
TFace *tface;
|
|
int a;
|
|
|
|
a= me->totface;
|
|
if(a==0) return;
|
|
tface= me->tface= MEM_callocN(a*sizeof(TFace), "tface");
|
|
while(a--) {
|
|
default_tface(tface);
|
|
tface++;
|
|
}
|
|
if(me->mcol) {
|
|
mcol_to_tface(me, 1);
|
|
}
|
|
}
|
|
|
|
void reveal_tface()
|
|
{
|
|
Mesh *me;
|
|
TFace *tface;
|
|
int a;
|
|
|
|
me= get_mesh(OBACT);
|
|
if(me==0 || me->tface==0 || me->totface==0) return;
|
|
|
|
tface= me->tface;
|
|
a= me->totface;
|
|
while(a--) {
|
|
if(tface->flag & TF_HIDE) {
|
|
tface->flag |= TF_SELECT;
|
|
tface->flag -= TF_HIDE;
|
|
}
|
|
tface++;
|
|
}
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
|
|
|
|
|
|
void hide_tface()
|
|
{
|
|
Mesh *me;
|
|
TFace *tface;
|
|
int a;
|
|
|
|
me= get_mesh(OBACT);
|
|
if(me==0 || me->tface==0 || me->totface==0) return;
|
|
|
|
if(G.qual & LR_ALTKEY) {
|
|
reveal_tface();
|
|
return;
|
|
}
|
|
|
|
tface= me->tface;
|
|
a= me->totface;
|
|
while(a--) {
|
|
if(tface->flag & TF_HIDE);
|
|
else {
|
|
if(G.qual & LR_SHIFTKEY) {
|
|
if( (tface->flag & TF_SELECT)==0) tface->flag |= TF_HIDE;
|
|
}
|
|
else {
|
|
if( (tface->flag & TF_SELECT)) tface->flag |= TF_HIDE;
|
|
}
|
|
}
|
|
if(tface->flag & TF_HIDE) tface->flag &= ~TF_SELECT;
|
|
|
|
tface++;
|
|
}
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
|
|
}
|
|
|
|
void select_linked_tfaces()
|
|
{
|
|
Mesh *me;
|
|
TFace *tface;
|
|
MFace *mface;
|
|
int a, doit=1;
|
|
char *cpmain;
|
|
|
|
me= get_mesh(OBACT);
|
|
if(me==0 || me->tface==0 || me->totface==0) return;
|
|
|
|
cpmain= MEM_callocN(me->totvert, "cpmain");
|
|
|
|
while(doit) {
|
|
doit= 0;
|
|
|
|
/* select connected: array vullen */
|
|
tface= me->tface;
|
|
mface= me->mface;
|
|
a= me->totface;
|
|
while(a--) {
|
|
if(tface->flag & TF_HIDE);
|
|
else if(tface->flag & TF_SELECT) {
|
|
if( mface->v3) {
|
|
cpmain[mface->v1]= 1;
|
|
cpmain[mface->v2]= 1;
|
|
cpmain[mface->v3]= 1;
|
|
if(mface->v4) cpmain[mface->v4]= 1;
|
|
}
|
|
}
|
|
tface++; mface++;
|
|
}
|
|
|
|
/* omgekeerd: vanuit array vlakken selecteren */
|
|
|
|
tface= me->tface;
|
|
mface= me->mface;
|
|
a= me->totface;
|
|
while(a--) {
|
|
if(tface->flag & TF_HIDE);
|
|
else if((tface->flag & TF_SELECT)==0) {
|
|
if( mface->v3) {
|
|
if(mface->v4) {
|
|
if(cpmain[mface->v4]) {
|
|
tface->flag |= TF_SELECT;
|
|
doit= 1;
|
|
}
|
|
}
|
|
if( cpmain[mface->v1] || cpmain[mface->v2] || cpmain[mface->v3] ) {
|
|
tface->flag |= TF_SELECT;
|
|
doit= 1;
|
|
}
|
|
}
|
|
}
|
|
tface++; mface++;
|
|
}
|
|
|
|
}
|
|
MEM_freeN(cpmain);
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
|
|
}
|
|
|
|
void deselectall_tface()
|
|
{
|
|
Mesh *me;
|
|
TFace *tface;
|
|
int a, sel;
|
|
|
|
me= get_mesh(OBACT);
|
|
if(me==0 || me->tface==0) return;
|
|
|
|
tface= me->tface;
|
|
a= me->totface;
|
|
sel= 0;
|
|
while(a--) {
|
|
if(tface->flag & TF_HIDE);
|
|
else if(tface->flag & TF_SELECT) sel= 1;
|
|
tface++;
|
|
}
|
|
|
|
tface= me->tface;
|
|
a= me->totface;
|
|
while(a--) {
|
|
if(tface->flag & TF_HIDE);
|
|
else {
|
|
if(sel) tface->flag &= ~TF_SELECT;
|
|
else tface->flag |= TF_SELECT;
|
|
}
|
|
tface++;
|
|
}
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
|
|
}
|
|
|
|
void rotate_uv_tface()
|
|
{
|
|
Mesh *me;
|
|
TFace *tface;
|
|
MFace *mface;
|
|
short mode;
|
|
int a;
|
|
|
|
me= get_mesh(OBACT);
|
|
if(me==0 || me->tface==0) return;
|
|
|
|
mode= pupmenu("OK? %t|Rot UV %x1|Rot VertexCol %x2");
|
|
|
|
if(mode<1) return;
|
|
|
|
tface= me->tface;
|
|
mface= me->mface;
|
|
a= me->totface;
|
|
while(a--) {
|
|
if(tface->flag & TF_SELECT) {
|
|
if(mode==1) {
|
|
float u1= tface->uv[0][0];
|
|
float v1= tface->uv[0][1];
|
|
|
|
tface->uv[0][0]= tface->uv[1][0];
|
|
tface->uv[0][1]= tface->uv[1][1];
|
|
|
|
tface->uv[1][0]= tface->uv[2][0];
|
|
tface->uv[1][1]= tface->uv[2][1];
|
|
|
|
if(mface->v4) {
|
|
tface->uv[2][0]= tface->uv[3][0];
|
|
tface->uv[2][1]= tface->uv[3][1];
|
|
|
|
tface->uv[3][0]= u1;
|
|
tface->uv[3][1]= v1;
|
|
}
|
|
else {
|
|
tface->uv[2][0]= u1;
|
|
tface->uv[2][1]= v1;
|
|
}
|
|
}
|
|
else if(mode==2) {
|
|
unsigned int tcol= tface->col[0];
|
|
|
|
tface->col[0]= tface->col[1];
|
|
tface->col[1]= tface->col[2];
|
|
|
|
if(mface->v4) {
|
|
tface->col[2]= tface->col[3];
|
|
tface->col[3]= tcol;
|
|
}
|
|
else {
|
|
tface->col[2]= tcol;
|
|
}
|
|
}
|
|
}
|
|
tface++;
|
|
mface++;
|
|
}
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
|
|
/**
|
|
* Returns the face under the give position in screen coordinates.
|
|
* Code extracted from face_select routine.
|
|
* Question: why is all of the backbuffer drawn?
|
|
* We're only interested in one pixel!
|
|
* @author Maarten Gribnau
|
|
* @param me the mesh with the faces to be picked
|
|
* @param x the x-coordinate to pick at
|
|
* @param y the y-coordinate to pick at
|
|
* @return the face under the cursor (0 if there was no face found)
|
|
*/
|
|
TFace* face_pick(Mesh *me, short x, short y)
|
|
{
|
|
unsigned int col;
|
|
int index;
|
|
TFace *ret = 0;
|
|
|
|
if (me==0 || me->tface==0) {
|
|
return ret;
|
|
}
|
|
|
|
/* Have OpenGL draw in the back buffer with color coded face indices */
|
|
if (curarea->win_swap==WIN_EQUAL) {
|
|
G.vd->flag |= V3D_NEEDBACKBUFDRAW;
|
|
}
|
|
if (G.vd->flag & V3D_NEEDBACKBUFDRAW) {
|
|
backdrawview3d(0);
|
|
}
|
|
/* Read the pixel under the cursor */
|
|
glReadPixels(x+curarea->winrct.xmin, y+curarea->winrct.ymin, 1, 1,
|
|
GL_RGBA, GL_UNSIGNED_BYTE, &col);
|
|
/* Unbelievable! */
|
|
if (G.order==B_ENDIAN) {
|
|
SWITCH_INT(col);
|
|
}
|
|
/* Convert the color back to a face index */
|
|
index = framebuffer_to_index(col);
|
|
if (col==0 || index<=0 || index>me->totface) {
|
|
return ret;
|
|
}
|
|
/* Return the face */
|
|
ret = ((TFace*)me->tface) + (index-1);
|
|
return ret;
|
|
}
|
|
|
|
void face_select()
|
|
{
|
|
Object *ob;
|
|
Mesh *me;
|
|
TFace *tface, *tsel;
|
|
short mval[2];
|
|
int a;
|
|
|
|
/* Get the face under the cursor */
|
|
ob = OBACT;
|
|
if (!(ob->lay & G.vd->lay)) {
|
|
error("Active object not in this layer!");
|
|
}
|
|
me = get_mesh(ob);
|
|
getmouseco_areawin(mval);
|
|
tsel = face_pick(me, mval[0], mval[1]);
|
|
if (!tsel) return;
|
|
|
|
if (tsel->flag & TF_HIDE) return;
|
|
|
|
/* clear flags */
|
|
tface = me->tface;
|
|
a = me->totface;
|
|
while (a--) {
|
|
if (G.qual & LR_SHIFTKEY) {
|
|
tface->flag &= ~TF_ACTIVE;
|
|
}
|
|
else {
|
|
tface->flag &= ~(TF_ACTIVE+TF_SELECT);
|
|
}
|
|
tface++;
|
|
}
|
|
|
|
tsel->flag |= TF_ACTIVE;
|
|
|
|
if (G.qual & LR_SHIFTKEY) {
|
|
if (tsel->flag & TF_SELECT) {
|
|
tsel->flag &= ~TF_SELECT;
|
|
}
|
|
else {
|
|
tsel->flag |= TF_SELECT;
|
|
}
|
|
}
|
|
else {
|
|
tsel->flag |= TF_SELECT;
|
|
}
|
|
|
|
lasttface = tsel;
|
|
|
|
/* image window redraw */
|
|
allqueue(REDRAWIMAGE, 0);
|
|
allqueue(REDRAWBUTSGAME, 0);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
|
|
|
|
void face_borderselect()
|
|
{
|
|
Mesh *me;
|
|
TFace *tface;
|
|
rcti rect;
|
|
unsigned int *rectm, *rt;
|
|
int a, sx, sy, index, val;
|
|
char *selar;
|
|
|
|
me= get_mesh(OBACT);
|
|
if(me==0 || me->tface==0) return;
|
|
if(me->totface==0) return;
|
|
|
|
val= get_border(&rect, 3);
|
|
|
|
/* why readbuffer here? shouldn't be necessary */
|
|
glReadBuffer(GL_BACK);
|
|
|
|
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;
|
|
|
|
rt=rectm= MEM_mallocN(sizeof(int)*sx*sy, "selrect");
|
|
glReadPixels(rect.xmin+curarea->winrct.xmin, rect.ymin+curarea->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, rectm);
|
|
if(G.order==B_ENDIAN) IMB_convert_rgba_to_abgr(sx*sy, rectm);
|
|
|
|
a= sx*sy;
|
|
while(a--) {
|
|
if(*rt) {
|
|
index= framebuffer_to_index(*rt);
|
|
if(index<=me->totface) selar[index]= 1;
|
|
}
|
|
rt++;
|
|
}
|
|
|
|
tface= me->tface;
|
|
for(a=1; a<=me->totface; a++, tface++) {
|
|
if(selar[a]) {
|
|
if(tface->flag & TF_HIDE);
|
|
else {
|
|
if(val==LEFTMOUSE) tface->flag |= TF_SELECT;
|
|
else tface->flag &= ~TF_SELECT;
|
|
}
|
|
}
|
|
}
|
|
|
|
MEM_freeN(rectm);
|
|
MEM_freeN(selar);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
}
|
|
}
|
|
|
|
#define TEST_STRUBI 1
|
|
#ifdef TEST_STRUBI
|
|
float CalcNormUV(float *a, float *b, float *c)
|
|
{
|
|
float d1[3], d2[3];
|
|
|
|
d1[0] = a[0] - b[0];
|
|
d1[1] = a[1] - b[1];
|
|
d2[0] = b[0] - c[0];
|
|
d2[1] = b[1] - c[1];
|
|
return (d1[0] * d2[1] - d1[1] * d2[0]);
|
|
}
|
|
#endif
|
|
|
|
|
|
/* Pupmenu codes: */
|
|
#define UV_CUBE_MAPPING 2
|
|
#define UV_CYL_MAPPING 3
|
|
#define UV_SPHERE_MAPPING 4
|
|
#define UV_BOUNDS4_MAPPING 65
|
|
#define UV_BOUNDS2_MAPPING 66
|
|
#define UV_BOUNDS1_MAPPING 67
|
|
#define UV_STD4_MAPPING 130
|
|
#define UV_STD2_MAPPING 129
|
|
#define UV_STD1_MAPPING 128
|
|
#define UV_WINDOW_MAPPING 5
|
|
|
|
/* 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|"
|
|
|
|
void uv_autocalc_tface()
|
|
{
|
|
Mesh *me;
|
|
TFace *tface;
|
|
MFace *mface;
|
|
MVert *mv;
|
|
Object *ob;
|
|
extern float cumapsize; /* buttons.c */
|
|
float dx, dy, min[3], cent[3], max[3], no[3], *loc, mat[4][4];
|
|
float fac = 1.0;
|
|
|
|
int i, n, mi; /* strubi */
|
|
int a, b;
|
|
short cox, coy, mode, adr[2];
|
|
|
|
me= get_mesh(ob=OBACT);
|
|
if(me==0 || me->tface==0) return;
|
|
if(me->totface==0) return;
|
|
|
|
mode= pupmenu(MENUTITLE("UV Calculation")
|
|
MENUSTRING("Cube", UV_CUBE_MAPPING) "|"
|
|
MENUSTRING("Cylinder", UV_CYL_MAPPING) "|"
|
|
MENUSTRING("Bounds to 1/4", UV_BOUNDS4_MAPPING) "|"
|
|
MENUSTRING("Bounds to 1/2", UV_BOUNDS2_MAPPING) "|"
|
|
MENUSTRING("Bounds to 1/1", UV_BOUNDS1_MAPPING) "|"
|
|
MENUSTRING("Standard 1/4", UV_STD4_MAPPING) "|"
|
|
MENUSTRING("Standard 1/2", UV_STD2_MAPPING) "|"
|
|
MENUSTRING("Standard 1/1", UV_STD1_MAPPING) "|"
|
|
MENUSTRING("From Window", UV_WINDOW_MAPPING) );
|
|
|
|
switch(mode) {
|
|
case UV_CUBE_MAPPING:
|
|
tface= me->tface;
|
|
mface= me->mface;
|
|
mv= me->mvert;
|
|
loc= ob->obmat[3];
|
|
|
|
fbutton(&cumapsize, 0.0001, 100.0, "Cubemap size");
|
|
|
|
for(a=0; a<me->totface; a++, mface++, tface++) {
|
|
if(tface->flag & TF_SELECT) {
|
|
if(mface->v3==0) continue;
|
|
|
|
CalcNormFloat((mv+mface->v1)->co, (mv+mface->v2)->co, (mv+mface->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*cumapsize*(loc[cox] + (mv+mface->v1)->co[cox]);
|
|
tface->uv[0][1]= 0.5+0.5*cumapsize*(loc[coy] + (mv+mface->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*cumapsize*(loc[cox] + (mv+mface->v2)->co[cox]);
|
|
tface->uv[1][1]= 0.5+0.5*cumapsize*(loc[coy] + (mv+mface->v2)->co[coy]);
|
|
tface->uv[1][0] -= dx;
|
|
tface->uv[1][1] -= dy;
|
|
tface->uv[2][0]= 0.5+0.5*cumapsize*(loc[cox] + (mv+mface->v3)->co[cox]);
|
|
tface->uv[2][1]= 0.5+0.5*cumapsize*(loc[coy] + (mv+mface->v3)->co[coy]);
|
|
tface->uv[2][0] -= dx;
|
|
tface->uv[2][1] -= dy;
|
|
if(mface->v4) {
|
|
tface->uv[3][0]= 0.5+0.5*cumapsize*(loc[cox] + (mv+mface->v4)->co[cox]);
|
|
tface->uv[3][1]= 0.5+0.5*cumapsize*(loc[coy] + (mv+mface->v4)->co[coy]);
|
|
tface->uv[3][0] -= dx;
|
|
tface->uv[3][1] -= dy;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
case UV_BOUNDS4_MAPPING:
|
|
fac = 0.25;
|
|
goto bounds_mapping;
|
|
case UV_BOUNDS2_MAPPING:
|
|
fac = 0.5;
|
|
goto bounds_mapping;
|
|
case UV_BOUNDS1_MAPPING:
|
|
// fac = 1.0; was already initialized as 1.0
|
|
case UV_WINDOW_MAPPING:
|
|
bounds_mapping:
|
|
mymultmatrix(ob->obmat);
|
|
MTC_Mat4SwapMat4(G.vd->persmat, mat);
|
|
mygetsingmatrix(G.vd->persmat);
|
|
|
|
tface= me->tface;
|
|
mface= me->mface;
|
|
|
|
dx = curarea->winx;
|
|
dy = curarea->winy;
|
|
|
|
if (dx > dy) dy = dx;
|
|
else dx = dy;
|
|
|
|
for(a=0; a<me->totface; a++, mface++, tface++) {
|
|
if(tface->flag & TF_SELECT) {
|
|
|
|
if(mface->v3==0) continue;
|
|
|
|
project_short( (me->mvert+mface->v1)->co, adr);
|
|
if(adr[0]!=3200) {
|
|
tface->uv[0][0]= ((float)adr[0])/dx;
|
|
tface->uv[0][1]= ((float)adr[1])/dy;
|
|
}
|
|
project_short( (me->mvert+mface->v2)->co, adr);
|
|
if(adr[0]!=3200) {
|
|
tface->uv[1][0]= ((float)adr[0])/dx;
|
|
tface->uv[1][1]= ((float)adr[1])/dy;
|
|
}
|
|
project_short( (me->mvert+mface->v3)->co, adr);
|
|
if(adr[0]!=3200) {
|
|
tface->uv[2][0]= ((float)adr[0])/dx;
|
|
tface->uv[2][1]= ((float)adr[1])/dy;
|
|
}
|
|
if(mface->v4) {
|
|
project_short( (me->mvert+mface->v4)->co, adr);
|
|
if(adr[0]!=3200) {
|
|
tface->uv[3][0]= ((float)adr[0])/dx;
|
|
tface->uv[3][1]= ((float)adr[1])/dy;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//stop here if WINDOW_MAPPING:
|
|
if (mode == UV_WINDOW_MAPPING) break;
|
|
|
|
/* minmax */
|
|
min[0]= min[1]= 1.0;
|
|
max[0]= max[1]= 0.0;
|
|
tface= me->tface;
|
|
mface= me->mface;
|
|
for(a=0; a<me->totface; a++, mface++, tface++) {
|
|
if(tface->flag & TF_SELECT) {
|
|
if(mface->v3==0) continue;
|
|
|
|
if(mface->v4) b= 3; else b= 2;
|
|
for(; b>=0; b--) {
|
|
min[0]= MIN2(tface->uv[b][0], min[0]);
|
|
min[1]= MIN2(tface->uv[b][1], min[1]);
|
|
max[0]= MAX2(tface->uv[b][0], max[0]);
|
|
max[1]= MAX2(tface->uv[b][1], max[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
dx= max[0]-min[0];
|
|
dy= max[1]-min[1];
|
|
|
|
tface= me->tface;
|
|
mface= me->mface;
|
|
for(a=0; a<me->totface; a++, mface++, tface++) {
|
|
if(tface->flag & TF_SELECT) {
|
|
if(mface->v3==0) continue;
|
|
|
|
if(mface->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 UV_STD4_MAPPING:
|
|
fac = 0.25;
|
|
goto standard_mapping;
|
|
case UV_STD2_MAPPING:
|
|
fac = 0.5;
|
|
goto standard_mapping;
|
|
case UV_STD1_MAPPING:
|
|
fac = 1.0;
|
|
|
|
standard_mapping:
|
|
tface= me->tface;
|
|
for(a=0; a<me->totface; a++, tface++) {
|
|
if(tface->flag & TF_SELECT) {
|
|
default_uv(tface->uv, fac);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case UV_SPHERE_MAPPING:
|
|
case UV_CYL_MAPPING:
|
|
|
|
/* calc centre */
|
|
|
|
INIT_MINMAX(min, max);
|
|
|
|
tface= me->tface;
|
|
mface= me->mface;
|
|
for(a=0; a<me->totface; a++, mface++, tface++) {
|
|
if(tface->flag & TF_SELECT) {
|
|
if(mface->v3==0) continue;
|
|
|
|
DO_MINMAX( (me->mvert+mface->v1)->co, min, max);
|
|
DO_MINMAX( (me->mvert+mface->v2)->co, min, max);
|
|
DO_MINMAX( (me->mvert+mface->v3)->co, min, max);
|
|
if(mface->v4) DO_MINMAX( (me->mvert+mface->v3)->co, min, max);
|
|
}
|
|
}
|
|
|
|
VecMidf(cent, min, max);
|
|
|
|
tface= me->tface;
|
|
mface= me->mface;
|
|
for(a=0; a<me->totface; a++, mface++, tface++) {
|
|
if(tface->flag & TF_SELECT) {
|
|
if(mface->v3==0) continue;
|
|
|
|
VecSubf(no, (me->mvert+mface->v1)->co, cent);
|
|
if(mode==UV_CYL_MAPPING) tubemap(no[0], no[1], no[2], tface->uv[0], &tface->uv[0][1]);
|
|
else spheremap(no[0], no[1], no[2], tface->uv[0], &tface->uv[0][1]);
|
|
|
|
VecSubf(no, (me->mvert+mface->v2)->co, cent);
|
|
if(mode==UV_CYL_MAPPING) tubemap(no[0], no[1], no[2], tface->uv[1], &tface->uv[1][1]);
|
|
else spheremap(no[0], no[1], no[2], tface->uv[1], &tface->uv[1][1]);
|
|
|
|
VecSubf(no, (me->mvert+mface->v3)->co, cent);
|
|
if(mode==UV_CYL_MAPPING) tubemap(no[0], no[1], no[2], tface->uv[2], &tface->uv[2][1]);
|
|
else spheremap(no[0], no[1], no[2], tface->uv[2], &tface->uv[2][1]);
|
|
n = 3;
|
|
|
|
if(mface->v4) {
|
|
VecSubf(no, (me->mvert+mface->v4)->co, cent);
|
|
if(mode==3) tubemap(no[0], no[1], no[2], tface->uv[3], &tface->uv[3][1]);
|
|
else spheremap(no[0], no[1], no[2], tface->uv[3], &tface->uv[3][1]);
|
|
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;
|
|
default:
|
|
return;
|
|
} // end switch
|
|
|
|
/* clipping and wrapping */
|
|
if(G.sima && G.sima->flag & SI_CLIP_UV) {
|
|
tface= me->tface;
|
|
mface= me->mface;
|
|
for(a=0; a<me->totface; a++, mface++, tface++) {
|
|
if(tface->flag & TF_SELECT) {
|
|
if(mface->v3==0) continue;
|
|
|
|
dx= dy= 0;
|
|
if(mface->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(mface->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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
myloadmatrix(G.vd->viewmat);
|
|
MTC_Mat4SwapMat4(G.vd->persmat, mat);
|
|
|
|
}
|
|
|
|
void set_faceselect() /* toggle */
|
|
{
|
|
Object *ob = OBACT;
|
|
Mesh *me = 0;
|
|
|
|
scrarea_queue_headredraw(curarea);
|
|
|
|
if(G.f & G_FACESELECT) G.f &= ~G_FACESELECT;
|
|
else {
|
|
if (ob && ob->type == OB_MESH) G.f |= G_FACESELECT;
|
|
}
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWBUTSGAME, 0);
|
|
allqueue(REDRAWBUTSEDIT, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
|
|
ob= OBACT;
|
|
me= get_mesh(ob);
|
|
if(me && me->tface==NULL) make_tfaces(me);
|
|
|
|
if(G.f & G_FACESELECT) {
|
|
setcursor_space(SPACE_VIEW3D, CURSOR_FACESEL);
|
|
if(me) set_lasttface();
|
|
}
|
|
else if((G.f & (G_WEIGHTPAINT|G_VERTEXPAINT|G_TEXTUREPAINT))==0) {
|
|
if(me) reveal_tface();
|
|
setcursor_space(SPACE_VIEW3D, CURSOR_STD);
|
|
makeDispList(ob);
|
|
}
|
|
countall();
|
|
}
|
|
|
|
|
|
#ifdef NAN_TPT
|
|
/**
|
|
* Get the view ray through the screen point.
|
|
* Uses the OpenGL settings of the active view port.
|
|
* The coordinates should be given in viewport coordinates.
|
|
* @author Maarten Gribnau
|
|
* @param x the x-coordinate of the screen point.
|
|
* @param y the y-coordinate of the screen point.
|
|
* @param org origin of the view ray.
|
|
* @param dir direction of the view ray.
|
|
*/
|
|
void get_pick_ray(short x, short y, float org[3], float dir[3])
|
|
{
|
|
double mvmatrix[16];
|
|
double projmatrix[16];
|
|
GLint viewport[4];
|
|
double px, py, pz;
|
|
float l;
|
|
|
|
/* Get the matrices needed for gluUnProject */
|
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
|
|
glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
|
|
|
|
/* Set up viewport so that gluUnProject will give correct values */
|
|
viewport[0] = 0;
|
|
viewport[1] = 0;
|
|
/* printf("viewport = (%4d, %4d, %4d, %4d)\n", viewport[0], viewport[1], viewport[2], viewport[3]); */
|
|
/* printf("cursor = (%4d, %4d)\n", x, y); */
|
|
|
|
gluUnProject((GLdouble) x, (GLdouble) y, 0.0, mvmatrix, projmatrix, viewport, &px, &py, &pz);
|
|
org[0] = (float)px; org[1] = (float)py; org[2] = (float)pz;
|
|
/* printf("world point at z=0.0 is (%f, %f, %f)\n", org[0], org[1], org[2]); */
|
|
gluUnProject((GLdouble) x, (GLdouble) y, 1.0, mvmatrix, projmatrix, viewport, &px, &py, &pz);
|
|
/* printf("world point at z=1.0 is (%f, %f, %f)\n", px, py, pz); */
|
|
dir[0] = ((float)px) - org[0];
|
|
dir[1] = ((float)py) - org[1];
|
|
dir[2] = ((float)pz) - org[2];
|
|
l = (float)sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]);
|
|
if (!l) return;
|
|
l = 1. / l;
|
|
dir[0] *= l; dir[1] *= l; dir[2] *= l;
|
|
/* printf("ray org. is (%f, %f, %f)\n", org[0], org[1], org[2]); */
|
|
/* printf("ray dir. is (%f, %f, %f)\n", dir[0], dir[1], dir[2]); */
|
|
}
|
|
|
|
|
|
int triangle_ray_intersect(float tv0[3], float tv1[3], float tv2[3], float org[3], float dir[3], float uv[2])
|
|
{
|
|
float v1v0[3];
|
|
float v2v0[3];
|
|
float n[3], an[3];
|
|
float t, d, l;
|
|
float p[3];
|
|
double u0, v0, u1, v1, u2, v2, uvtemp;
|
|
unsigned int iu, iv;
|
|
|
|
/* Calculate normal of the plane (cross, normalize)
|
|
* Could really use moto here...
|
|
*/
|
|
v1v0[0] = tv1[0] - tv0[0];
|
|
v1v0[1] = tv1[1] - tv0[1];
|
|
v1v0[2] = tv1[2] - tv0[2];
|
|
v2v0[0] = tv2[0] - tv0[0];
|
|
v2v0[1] = tv2[1] - tv0[1];
|
|
v2v0[2] = tv2[2] - tv0[2];
|
|
n[0] = (v1v0[1] * v2v0[2]) - (v1v0[2] * v2v0[1]);
|
|
n[1] = (v1v0[2] * v2v0[0]) - (v1v0[0] * v2v0[2]);
|
|
n[2] = (v1v0[0] * v2v0[1]) - (v1v0[1] * v2v0[0]);
|
|
l = sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
|
|
if (!l) return 0;
|
|
l = 1. / l;
|
|
n[0] *= l; n[1] *= l; n[2] *= l;
|
|
|
|
/* Calculate intersection point */
|
|
t = n[0]*dir[0] + n[1]*dir[1] + n[2]*dir[2];
|
|
if (fabs(t) < 1.0e-6) return 0;
|
|
d = -(n[0]*tv0[0] + n[1]*tv0[1] + n[2]*tv0[2]);
|
|
t = -(((n[0]*org[0] + n[1]*org[1] + n[2]*org[2]) + d) / t);
|
|
if (t < 0) return 0;
|
|
p[0] = org[0] + dir[0]*t;
|
|
p[1] = org[1] + dir[1]*t;
|
|
p[2] = org[2] + dir[2]*t;
|
|
/*printf("intersection at (%f, %f, %f)\n", p[0], p[1], p[2]);*/
|
|
|
|
/* Calculate the largest component of the normal */
|
|
an[0] = fabs(n[0]); an[1] = fabs(n[1]); an[2] = fabs(n[2]);
|
|
if ((an[0] > an[1]) && (an[0] > an[2])) {
|
|
iu = 1; iv = 2;
|
|
}
|
|
else if ((an[1] > an[0]) && (an[1] > an[2])) {
|
|
iu = 2; iv = 0;
|
|
}
|
|
else {
|
|
iu = 0; iv = 1;
|
|
}
|
|
/* printf("iu, iv = (%d, %d)\n", iu, iv); */
|
|
|
|
/* Calculate (u,v) */
|
|
u0 = p[iu] - tv0[iu];
|
|
v0 = p[iv] - tv0[iv];
|
|
u1 = tv1[iu] - tv0[iu];
|
|
v1 = tv1[iv] - tv0[iv];
|
|
u2 = tv2[iu] - tv0[iu];
|
|
v2 = tv2[iv] - tv0[iv];
|
|
/* printf("u0, v0, u1, v1, u2, v2 = (%f, %f, %f, %f, %f, %f)\n", u0, v0, u1, v1, u2, v2); */
|
|
|
|
/* These calculations should be in double precision.
|
|
* On windows we get inpredictable results in single precision
|
|
*/
|
|
if (u1 == 0) {
|
|
uvtemp = u0/u2;
|
|
uv[1] = (float)uvtemp;
|
|
/* if ((uv[1] >= 0.) && (uv[1] <= 1.)) { */
|
|
uv[0] = (float)((v0 - uvtemp*v2) / v1);
|
|
/* } */
|
|
}
|
|
else {
|
|
uvtemp = (v0*u1 - u0*v1)/(v2*u1-u2*v1);
|
|
uv[1] = (float)uvtemp;
|
|
/* if ((uv[1] >= 0) && (uv[1] <= 1)) { */
|
|
uv[0] = (float)((u0 - uvtemp*u2) / u1);
|
|
/* } */
|
|
}
|
|
/* printf("uv[0], uv[1] = (%f, %f)\n", uv[0], uv[1]); */
|
|
return ((uv[0] >= 0) && (uv[1] >= 0) && ((uv[0]+uv[1]) <= 1)) ? 2 : 1;
|
|
}
|
|
|
|
/**
|
|
* Returns the vertex (local) coordinates of a face.
|
|
* No bounds checking!
|
|
* @author Maarten Gribnau
|
|
* @param mesh the mesh with the face.
|
|
* @param face the face.
|
|
* @param v1 vertex 1 coordinates.
|
|
* @param v2 vertex 2 coordinates.
|
|
* @param v3 vertex 3 coordinates.
|
|
* @param v4 vertex 4 coordinates.
|
|
* @return number of vertices of this face
|
|
*/
|
|
int face_get_vertex_coordinates(Mesh* mesh, TFace* face, float v1[3], float v2[3], float v3[3], float v4[3])
|
|
{
|
|
int num_vertices;
|
|
MVert *mv;
|
|
MFace *mf = (MFace *) (((MFace *)mesh->mface) + (face - (TFace *) mesh->tface));
|
|
|
|
num_vertices = mf->v4 == 0 ? 3 : 4;
|
|
mv = mesh->mvert + mf->v1;
|
|
v1[0] = mv->co[0]; v1[1] = mv->co[1]; v1[2] = mv->co[2];
|
|
mv = mesh->mvert + mf->v2;
|
|
v2[0] = mv->co[0]; v2[1] = mv->co[1]; v2[2] = mv->co[2];
|
|
mv = mesh->mvert + mf->v3;
|
|
v3[0] = mv->co[0]; v3[1] = mv->co[1]; v3[2] = mv->co[2];
|
|
if (num_vertices == 4) {
|
|
mv = mesh->mvert + mf->v4;
|
|
v4[0] = mv->co[0]; v4[1] = mv->co[1]; v4[2] = mv->co[2];
|
|
}
|
|
|
|
return num_vertices;
|
|
}
|
|
|
|
/**
|
|
* Finds texture coordinates from face edge interpolation values.
|
|
* @author Maarten Gribnau
|
|
* @param face the face.
|
|
* @param v1 vertex 1 index.
|
|
* @param v2 vertex 2 index.
|
|
* @param v3 vertex 3 index.
|
|
* @param a interpolation value of edge v2-v1.
|
|
* @param b interpolation value of edge v3-v1.
|
|
* @param u (u,v) coordinate.
|
|
* @param v (u,v) coordinate.
|
|
*/
|
|
void face_get_uv(TFace* face, int v1, int v2, int v3, float a, float b, float* u, float* v)
|
|
{
|
|
float uv01[2], uv21[2];
|
|
|
|
/* Pin a,b inside [0,1] range */
|
|
#if 0
|
|
a = (float)fmod(a, 1.);
|
|
b = (float)fmod(b, 1.);
|
|
#else
|
|
if (a < 0.f) a = 0.f;
|
|
else if (a > 1.f) a = 1.f;
|
|
if (b < 0.f) b = 0.f;
|
|
else if (b > 1.f) b = 1.f;
|
|
#endif
|
|
|
|
/* Convert to texture coordinates */
|
|
uv01[0] = face->uv[v2][0] - face->uv[v1][0];
|
|
uv01[1] = face->uv[v2][1] - face->uv[v1][1];
|
|
uv21[0] = face->uv[v3][0] - face->uv[v1][0];
|
|
uv21[1] = face->uv[v3][1] - face->uv[v1][1];
|
|
uv01[0] *= a;
|
|
uv01[1] *= a;
|
|
uv21[0] *= b;
|
|
uv21[1] *= b;
|
|
*u = face->uv[v1][0] + (uv01[0] + uv21[0]);
|
|
*v = face->uv[v1][1] + (uv01[1] + uv21[1]);
|
|
}
|
|
|
|
/**
|
|
* Get the (u,v) coordinates on a face from a point in screen coordinates.
|
|
* The coordinates should be given in viewport coordinates.
|
|
* @author Maarten Gribnau
|
|
* @param object the object with the mesh
|
|
* @param mesh the mesh with the face to be picked.
|
|
* @param face the face to be picked.
|
|
* @param x the x-coordinate to pick at.
|
|
* @param y the y-coordinate to pick at.
|
|
* @param u the u-coordinate calculated.
|
|
* @param v the v-coordinate calculated.
|
|
* @return intersection result:
|
|
* 0 == no intersection, (u,v) invalid
|
|
* 1 == intersection, (u,v) valid
|
|
*/
|
|
int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short x, short y, float* u, float* v)
|
|
{
|
|
float org[3], dir[3];
|
|
float ab[2];
|
|
float v1[3], v2[3], v3[3], v4[3];
|
|
int result;
|
|
int num_verts;
|
|
|
|
/* Get a view ray to intersect with the face */
|
|
get_pick_ray(x, y, org, dir);
|
|
|
|
/* Convert local vertex coordinates to world */
|
|
num_verts = face_get_vertex_coordinates(mesh, face, v1, v2, v3, v4);
|
|
/* Convert local vertex coordinates to world */
|
|
Mat4MulVecfl(object->obmat, v1);
|
|
Mat4MulVecfl(object->obmat, v2);
|
|
Mat4MulVecfl(object->obmat, v3);
|
|
if (num_verts > 3) {
|
|
Mat4MulVecfl(object->obmat, v4);
|
|
}
|
|
|
|
/* Get (u,v) values (local face coordinates) of intersection point
|
|
* If face is a quad, there are two triangles to check.
|
|
*/
|
|
result = triangle_ray_intersect(v2, v1, v3, org, dir, ab);
|
|
if ((num_verts == 3) || (num_verts == 4) && (result > 1)) {
|
|
/* Face is a triangle or a quad with a hit on the first triangle */
|
|
face_get_uv(face, 1, 0, 2, ab[0], ab[1], u, v);
|
|
/* printf("triangle 1, texture (u,v)=(%f, %f)\n", *u, *v); */
|
|
}
|
|
else {
|
|
/* Face is a quad and no intersection with first triangle */
|
|
result = triangle_ray_intersect(v4, v3, v1, org, dir, ab);
|
|
face_get_uv(face, 3, 2, 0, ab[0], ab[1], u, v);
|
|
/* printf("triangle 2, texture (u,v)=(%f, %f)\n", *u, *v); */
|
|
}
|
|
return result > 0;
|
|
}
|
|
|
|
/**
|
|
* First attempt at drawing in the texture of a face.
|
|
* @author Maarten Gribnau
|
|
*/
|
|
void face_draw()
|
|
{
|
|
Object *ob;
|
|
Mesh *me;
|
|
TFace *face, *face_old = 0;
|
|
short xy[2], xy_old[2];
|
|
//int a, index;
|
|
Image *img, *img_old = 0;
|
|
IMG_BrushPtr brush;
|
|
IMG_CanvasPtr canvas = 0;
|
|
int rowBytes;
|
|
char *warn_packed_file = 0;
|
|
float uv[2], uv_old[2];
|
|
extern VPaint Gvp;
|
|
|
|
ob = OBACT;
|
|
if (!ob) {
|
|
error("No active object"); return;
|
|
}
|
|
if (!(ob->lay & G.vd->lay)) {
|
|
error("Active object not in this layer"); return;
|
|
}
|
|
me = get_mesh(ob);
|
|
if (!me) {
|
|
error("Active object does not have a mesh"); return;
|
|
}
|
|
|
|
brush = IMG_BrushCreate(Gvp.size, Gvp.size, Gvp.r, Gvp.g, Gvp.b, Gvp.a);
|
|
if (!brush) {
|
|
error("Can not create brush"); return;
|
|
}
|
|
|
|
getmouseco_areawin(xy_old);
|
|
while (get_mbut() & L_MOUSE) {
|
|
getmouseco_areawin(xy);
|
|
/* Check if cursor has moved */
|
|
if ((xy[0] != xy_old[0]) || (xy[1] != xy_old[1])) {
|
|
|
|
/* Get face to draw on */
|
|
face = face_pick(me, xy[0], xy[1]);
|
|
|
|
/* Check if this is another face. */
|
|
if (face != face_old) {
|
|
/* The active face changed, check the texture */
|
|
if (face) {
|
|
img = face->tpage;
|
|
}
|
|
else {
|
|
img = 0;
|
|
}
|
|
|
|
if (img != img_old) {
|
|
/* Faces have different textures. Finish drawing in the old face. */
|
|
if (face_old && canvas) {
|
|
face_pick_uv(ob, me, face_old, xy[0], xy[1], &uv[0], &uv[1]);
|
|
IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]);
|
|
img_old->ibuf->userflags |= IB_BITMAPDIRTY;
|
|
/* Delete old canvas */
|
|
IMG_CanvasDispose(canvas);
|
|
canvas = 0;
|
|
}
|
|
|
|
/* Create new canvas and start drawing in the new face. */
|
|
if (img) {
|
|
if (img->ibuf && img->packedfile == 0) {
|
|
/* MAART: skipx is not set most of the times. Make a guess. */
|
|
rowBytes = img->ibuf->skipx ? img->ibuf->skipx : img->ibuf->x * 4;
|
|
canvas = IMG_CanvasCreateFromPtr(img->ibuf->rect, img->ibuf->x, img->ibuf->y, rowBytes);
|
|
if (canvas) {
|
|
face_pick_uv(ob, me, face, xy_old[0], xy_old[1], &uv_old[0], &uv_old[1]);
|
|
face_pick_uv(ob, me, face, xy[0], xy[1], &uv[0], &uv[1]);
|
|
IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]);
|
|
img->ibuf->userflags |= IB_BITMAPDIRTY;
|
|
}
|
|
}
|
|
else {
|
|
/* TODO: should issue warning that no texture is assigned */
|
|
if (img->packedfile) {
|
|
warn_packed_file = img->id.name + 2;
|
|
img = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* Face changed and faces have the same texture. */
|
|
if (canvas) {
|
|
/* Finish drawing in the old face. */
|
|
if (face_old) {
|
|
face_pick_uv(ob, me, face_old, xy[0], xy[1], &uv[0], &uv[1]);
|
|
IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]);
|
|
img_old->ibuf->userflags |= IB_BITMAPDIRTY;
|
|
}
|
|
|
|
/* Start drawing in the new face. */
|
|
if (face) {
|
|
face_pick_uv(ob, me, face, xy_old[0], xy_old[1], &uv_old[0], &uv_old[1]);
|
|
face_pick_uv(ob, me, face, xy[0], xy[1], &uv[0], &uv[1]);
|
|
IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]);
|
|
img->ibuf->userflags |= IB_BITMAPDIRTY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* Same face, continue drawing */
|
|
if (face && canvas) {
|
|
/* Get the new (u,v) coordinates */
|
|
face_pick_uv(ob, me, face, xy[0], xy[1], &uv[0], &uv[1]);
|
|
IMG_CanvasDrawLineUV(canvas, brush, uv_old[0], uv_old[1], uv[0], uv[1]);
|
|
img->ibuf->userflags |= IB_BITMAPDIRTY;
|
|
}
|
|
}
|
|
|
|
if (face && img) {
|
|
/* Make OpenGL aware of a change in the texture */
|
|
free_realtime_image(img);
|
|
/* Redraw the view */
|
|
scrarea_do_windraw(curarea);
|
|
screen_swapbuffers();
|
|
}
|
|
|
|
xy_old[0] = xy[0];
|
|
xy_old[1] = xy[1];
|
|
uv_old[0] = uv[0];
|
|
uv_old[1] = uv[1];
|
|
face_old = face;
|
|
img_old = img;
|
|
}
|
|
}
|
|
|
|
IMG_BrushDispose(brush);
|
|
if (canvas) {
|
|
IMG_CanvasDispose(canvas);
|
|
canvas = 0;
|
|
}
|
|
|
|
if (warn_packed_file) {
|
|
error("Painting in packed images not supported: %s", warn_packed_file);
|
|
}
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWIMAGE, 0);
|
|
allqueue(REDRAWHEADERS, 0);
|
|
}
|
|
#endif /* NAN_TPT */
|