This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/src/editface.c
Kent Mein 5a9b727079 Ok last change for the night :)
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;
2002-12-20 02:52:58 +00:00

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 */