/** * $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 #ifdef HAVE_CONFIG_H #include #endif #ifdef WIN32 #include #include "BLI_winstuff.h" #else #include #endif #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_editVert.h" #include "IMB_imbuf_types.h" #include "DNA_image_types.h" #include "DNA_mesh_types.h" #include "DNA_packedFile_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "BKE_utildefines.h" #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_image.h" #include "BDR_editface.h" #include "BIF_gl.h" #include "BIF_space.h" #include "BIF_screen.h" #include "BIF_mywindow.h" #include "BIF_drawimage.h" /* Modules used */ #include "mydevice.h" #include "render.h" void rectwrite_part(int winxmin, int winymin, int winxmax, int winymax, int x1, int y1, int xim, int yim, float zoomx, float zoomy, unsigned int *rect) { int cx, cy, oldxim, x2, y2; oldxim= xim; /* coordinaten hoe 't op scherm komt */ x2= x1+ zoomx*xim; y2= y1+ zoomy*yim; /* partiele clip */ if(x1=winxmax) { cx= x2-winxmax; cx/= zoomx; xim-= cx+3; } if(y2>=winymax) { cy= y2-winymax; cy/= zoomy; yim-= cy+3; } if(xim<=0) return; if(yim<=0) return; mywinset(G.curscreen->mainwin); glScissor(winxmin, winymin, winxmax-winxmin+1, winymax-winymin+1); glPixelStorei(GL_UNPACK_ROW_LENGTH, oldxim); glPixelZoom(zoomx, zoomy); glRasterPos2i(x1, y1); glDrawPixels(xim, yim, GL_RGBA, GL_UNSIGNED_BYTE, rect); glPixelZoom(1.0, 1.0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); mywinset(curarea->win); } /** * Sets up the fields of the View2D member of the SpaceImage struct * This routine can be called in two modes: * mode == 'f': float mode ??? * mode == 'p': pixel mode ??? * * @param sima the image space to update * @param mode the mode to use for the update * @return void * */ void calc_image_view(SpaceImage *sima, char mode) { float xim=256, yim=256; float x1, y1; float zoom; if(sima->image && sima->image->ibuf) { xim= sima->image->ibuf->x; yim= sima->image->ibuf->y; } sima->v2d.tot.xmin= 0; sima->v2d.tot.ymin= 0; sima->v2d.tot.xmax= xim; sima->v2d.tot.ymax= yim; sima->v2d.mask.xmin= sima->v2d.mask.ymin= 0; sima->v2d.mask.xmax= curarea->winx; sima->v2d.mask.ymax= curarea->winy; /* Which part of the image space do we see? */ /* Same calculation as in lrectwrite: area left and down*/ x1= curarea->winrct.xmin+(curarea->winx-sima->zoom*xim)/2; y1= curarea->winrct.ymin+(curarea->winy-sima->zoom*yim)/2; x1-= sima->zoom*sima->xof; y1-= sima->zoom*sima->yof; /* float! */ zoom= sima->zoom; /* relatieve afbeeld links */ sima->v2d.cur.xmin= ((curarea->winrct.xmin - (float)x1)/zoom); sima->v2d.cur.xmax= sima->v2d.cur.xmin + ((float)curarea->winx/zoom); /* relatieve afbeeld links */ sima->v2d.cur.ymin= ((curarea->winrct.ymin-(float)y1)/zoom); sima->v2d.cur.ymax= sima->v2d.cur.ymin + ((float)curarea->winy/zoom); if(mode=='f') { sima->v2d.cur.xmin/= xim; sima->v2d.cur.xmax/= xim; sima->v2d.cur.ymin/= yim; sima->v2d.cur.ymax/= yim; } } void what_image(SpaceImage *sima) { extern TFace *lasttface; /* editface.c */ Mesh *me; if(sima->mode==SI_TEXTURE) { if(G.f & G_FACESELECT) { sima->image= 0; me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0); set_lasttface(); if(me && me->tface && lasttface) { if(lasttface->mode & TF_TEX) { sima->image= lasttface->tpage; if(sima->flag & SI_EDITTILE); else sima->curtile= lasttface->tile; if(sima->image) { if(lasttface->mode & TF_TILES) sima->image->tpageflag |= IMA_TILES; else sima->image->tpageflag &= ~IMA_TILES; } } } } } } void image_changed(SpaceImage *sima, int dotile) { TFace *tface; Mesh *me; int a; if(sima->mode==SI_TEXTURE) { if(G.f & G_FACESELECT) { me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0); if(me && me->tface) { tface= me->tface; a= me->totface; while(a--) { if(tface->flag & TF_SELECT) { if(dotile==2) { tface->mode &= ~TF_TILES; } else { tface->tpage= sima->image; tface->mode |= TF_TEX; if(dotile) tface->tile= sima->curtile; } if(sima->image) { if(sima->image->tpageflag & IMA_TILES) tface->mode |= TF_TILES; else tface->mode &= ~TF_TILES; if(sima->image->id.us==0) sima->image->id.us= 1; } } tface++; } allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWBUTSGAME, 0); } } } } void uvco_to_areaco(float *vec, short *mval) { float x, y; mval[0]= 3200; x= (vec[0] - G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin); y= (vec[1] - G.v2d->cur.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin); if(x>=0.0 && x<=1.0) { if(y>=0.0 && y<=1.0) { mval[0]= G.v2d->mask.xmin + x*(G.v2d->mask.xmax-G.v2d->mask.xmin); mval[1]= G.v2d->mask.ymin + y*(G.v2d->mask.ymax-G.v2d->mask.ymin); } } } void uvco_to_areaco_noclip(float *vec, short *mval) { float x, y; mval[0]= 3200; x= (vec[0] - G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin); y= (vec[1] - G.v2d->cur.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin); x= G.v2d->mask.xmin + x*(G.v2d->mask.xmax-G.v2d->mask.xmin); y= G.v2d->mask.ymin + y*(G.v2d->mask.ymax-G.v2d->mask.ymin); mval[0]= x; mval[1]= y; } void draw_tfaces(void) { TFace *tface; MFace *mface; Mesh *me; unsigned int col; int a; glPointSize(2.0); if(G.f & G_FACESELECT) { me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0); if(me && me->tface) { calc_image_view(G.sima, 'f'); /* float */ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax); tface= me->tface; mface= me->mface; a= me->totface; while(a--) { if(mface->v3 && (tface->flag & TF_SELECT) ) { cpack(0x0); glBegin(GL_LINE_LOOP); glVertex2fv( tface->uv[0] ); glVertex2fv( tface->uv[1] ); glVertex2fv( tface->uv[2] ); if(mface->v4) glVertex2fv( tface->uv[3] ); glEnd(); setlinestyle(2); /* kleuren: R=x G=y */ if(tface->flag & TF_ACTIVE) cpack(0xFF00); else cpack(0xFFFFFF); glBegin(GL_LINE_STRIP); glVertex2fv( tface->uv[0] ); glVertex2fv( tface->uv[1] ); glEnd(); if(tface->flag & TF_ACTIVE) cpack(0xFF); else cpack(0xFFFFFF); glBegin(GL_LINE_STRIP); glVertex2fv( tface->uv[0] ); if(mface->v4) glVertex2fv( tface->uv[3] ); else glVertex2fv( tface->uv[2] ); glEnd(); cpack(0xFFFFFF); glBegin(GL_LINE_STRIP); glVertex2fv( tface->uv[1] ); glVertex2fv( tface->uv[2] ); if(mface->v4) glVertex2fv( tface->uv[3] ); glEnd(); setlinestyle(0); glBegin(GL_POINTS); if(tface->flag & TF_SEL1) col= 0x77FFFF; else col= 0xFF70FF; cpack(col); glVertex2fv(tface->uv[0]); if(tface->flag & TF_SEL2) col= 0x77FFFF; else col= 0xFF70FF; cpack(col); glVertex2fv(tface->uv[1]); if(tface->flag & TF_SEL3) col= 0x77FFFF; else col= 0xFF70FF; cpack(col); glVertex2fv(tface->uv[2]); if(mface->v4) { if(tface->flag & TF_SEL4) col= 0x77FFFF; else col= 0xFF70FF; cpack(col); glVertex2fv(tface->uv[3]); } glEnd(); } tface++; mface++; } } } glPointSize(1.0); } static unsigned int *get_part_from_ibuf(ImBuf *ibuf, short startx, short starty, short endx, short endy) { unsigned int *rt, *rp, *rectmain; short y, heigth, len; /* de juiste offset in rectot */ rt= ibuf->rect+ (starty*ibuf->x+ startx); len= (endx-startx); heigth= (endy-starty); rp=rectmain= MEM_mallocN(heigth*len*sizeof(int), "rect"); for(y=0; yx; rp+= len; } return rectmain; } void drawimagespace(void) { ImBuf *ibuf= NULL; unsigned int *rect; int x1, y1, xmin, xmax, ymin, ymax; short sx, sy, dx, dy; glClearColor(.1875, .1875, .1875, 0.0); glClear(GL_COLOR_BUFFER_BIT); curarea->win_swap= WIN_BACK_OK; xmin= curarea->winrct.xmin; xmax= curarea->winrct.xmax; ymin= curarea->winrct.ymin; ymax= curarea->winrct.ymax; what_image(G.sima); if(G.sima->image) { if(G.sima->image->ibuf==0) { load_image(G.sima->image, IB_rect, G.sce, G.scene->r.cfra); } ibuf= G.sima->image->ibuf; } if(ibuf==0 || ibuf->rect==0) { calc_image_view(G.sima, 'f'); myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax); cpack(0x404040); glRectf(0.0, 0.0, 1.0, 1.0); draw_tfaces(); return; } /* plek berekenen */ x1= xmin+(curarea->winx-G.sima->zoom*ibuf->x)/2; y1= ymin+(curarea->winy-G.sima->zoom*ibuf->y)/2; x1-= G.sima->zoom*G.sima->xof; y1-= G.sima->zoom*G.sima->yof; if(G.sima->flag & SI_EDITTILE) { rectwrite_part(xmin, ymin, xmax, ymax, x1, y1, ibuf->x, ibuf->y, (float)G.sima->zoom, (float)G.sima->zoom, ibuf->rect); dx= ibuf->x/G.sima->image->xrep; dy= ibuf->y/G.sima->image->yrep; sy= (G.sima->curtile / G.sima->image->xrep); sx= G.sima->curtile - sy*G.sima->image->xrep; sx*= dx; sy*= dy; calc_image_view(G.sima, 'p'); /* pixel */ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax); cpack(0x0); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glRects(sx, sy, sx+dx-1, sy+dy-1); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); cpack(0xFFFFFF); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glRects(sx+1, sy+1, sx+dx, sy+dy); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } else if(G.sima->mode==SI_TEXTURE) { if(G.sima->image->tpageflag & IMA_TILES) { /* eventjes laten staan */ if(G.sima->image->xrep<1) return; if(G.sima->image->yrep<1) return; if(G.sima->curtile >= G.sima->image->xrep*G.sima->image->yrep) G.sima->curtile = G.sima->image->xrep*G.sima->image->yrep - 1; dx= ibuf->x/G.sima->image->xrep; dy= ibuf->y/G.sima->image->yrep; sy= (G.sima->curtile / G.sima->image->xrep); sx= G.sima->curtile - sy*G.sima->image->xrep; sx*= dx; sy*= dy; rect= get_part_from_ibuf(ibuf, sx, sy, sx+dx, sy+dy); /* rect= ibuf->rect; */ for(sy= 0; sy+dy<=ibuf->y; sy+= dy) { for(sx= 0; sx+dx<=ibuf->x; sx+= dx) { rectwrite_part(xmin, ymin, xmax, ymax, x1+sx*G.sima->zoom, y1+sy*G.sima->zoom, dx, dy, (float)G.sima->zoom, (float)G.sima->zoom, rect); } } MEM_freeN(rect); } else rectwrite_part(xmin, ymin, xmax, ymax, x1, y1, ibuf->x, ibuf->y, (float)G.sima->zoom,(float)G.sima->zoom, ibuf->rect); draw_tfaces(); } calc_image_view(G.sima, 'f'); /* float */ } void image_viewmove(void) { short mval[2], mvalo[2], xof, yof; getmouseco_sc(mvalo); while(get_mbut()&(L_MOUSE|M_MOUSE)) { getmouseco_sc(mval); xof= (mvalo[0]-mval[0])/G.sima->zoom; yof= (mvalo[1]-mval[1])/G.sima->zoom; if(xof || yof) { G.sima->xof+= xof; G.sima->yof+= yof; mvalo[0]= mval[0]; mvalo[1]= mval[1]; scrarea_do_windraw(curarea); screen_swapbuffers(); } else BIF_wait_for_statechange(); } } /** * Updates the fields of the View2D member of the SpaceImage struct. * Default behavior is to reset the position of the image and set the zoom to 1 * If the image will not fit within the window rectangle, the zoom is adjusted * * @return void * */ void image_home(void) { int width, height; float zoomX, zoomY; if (curarea->spacetype != SPACE_IMAGE) return; if ((G.sima->image == 0) || (G.sima->image->ibuf == 0)) return; /* Check if the image will fit in the image with zoom==1 */ width = curarea->winx; height = curarea->winy; if (((G.sima->image->ibuf->x >= width) || (G.sima->image->ibuf->y >= height)) && ((width > 0) && (height > 0))) { /* Find the zoom value that will fit the image in the image space */ zoomX = ((float)width) / ((float)G.sima->image->ibuf->x); zoomY = ((float)height) / ((float)G.sima->image->ibuf->y); G.sima->zoom= MIN2(zoomX, zoomY); /* Now make it a power of 2 */ G.sima->zoom = 1 / G.sima->zoom; G.sima->zoom = log(G.sima->zoom) / log(2); G.sima->zoom = ceil(G.sima->zoom); G.sima->zoom = pow(2, G.sima->zoom); G.sima->zoom = 1 / G.sima->zoom; } else { G.sima->zoom= (float)1; } G.sima->xof= G.sima->yof= 0; calc_image_view(G.sima, 'p'); scrarea_queue_winredraw(curarea); }