The Anim and Tiles settings in the Image Window are now available again, in the
[blender.git] / source / blender / src / drawimage.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <math.h>
34 #include <string.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #ifdef WIN32
41 #include <io.h>
42 #include "BLI_winstuff.h"
43 #else
44 #include <unistd.h>
45 #endif   
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_blenlib.h"
49
50 #include "IMB_imbuf_types.h"
51
52 #include "DNA_image_types.h"
53 #include "DNA_mesh_types.h"
54 #include "DNA_meshdata_types.h"
55 #include "DNA_packedFile_types.h"
56 #include "DNA_screen_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_userdef_types.h"
59
60 #include "BKE_utildefines.h"
61 #include "BKE_global.h"
62 #include "BKE_mesh.h"
63 #include "BKE_image.h"
64
65 #include "BDR_editface.h"
66 #include "BDR_editobject.h"
67 #include "BDR_drawmesh.h"
68
69 #include "BIF_gl.h"
70 #include "BIF_space.h"
71 #include "BIF_screen.h"
72 #include "BIF_mywindow.h"
73 #include "BIF_drawimage.h"
74 #include "BIF_resources.h"
75 #include "BIF_interface.h"
76 #include "BIF_editsima.h"
77
78 /* Modules used */
79 #include "mydevice.h"
80 #include "blendef.h"
81 #include "render.h"
82 #include "butspace.h"  // event codes
83
84
85 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)
86 {
87         int cx, cy, oldxim, x2, y2;
88         
89         oldxim= xim;
90                 
91         /* coordinates how its drawn at the screen */
92         x2= x1+ zoomx*xim;
93         y2= y1+ zoomy*yim;
94
95         /* partial clip */
96         if(x1<winxmin) {
97                 /* with OpenGL, rects are not allowed to start outside of the left/bottom window edge */
98                 cx= winxmin-x1+(int)zoomx;
99                 /* make sure the rect will be drawn pixel-exact */
100                 cx/= zoomx;
101                 cx++;
102                 x1+= zoomx*cx;
103                 xim-= cx;
104                 rect+= cx;
105         }
106         if(y1<winymin) {
107                 cy= winymin-y1+(int)zoomy;
108                 cy/= zoomy;
109                 cy++;
110                 y1+= zoomy*cy;
111                 rect+= cy*oldxim;
112                 yim-= cy;
113         }
114         if(x2>=winxmax) {
115                 cx= x2-winxmax;
116                 cx/= zoomx;
117                 xim-= cx+3;
118         }
119         if(y2>=winymax) {
120                 cy= y2-winymax;
121                 cy/= zoomy;
122                 yim-= cy+3;
123         }
124         
125         if(xim<=0) return;
126         if(yim<=0) return;
127
128         mywinset(G.curscreen->mainwin);
129         glScissor(winxmin, winymin, winxmax-winxmin+1, winymax-winymin+1);
130         
131         glPixelStorei(GL_UNPACK_ROW_LENGTH,  oldxim);
132         
133         glPixelZoom(zoomx,  zoomy);
134
135         glRasterPos2i(x1, y1);
136         glDrawPixels(xim, yim, GL_RGBA, GL_UNSIGNED_BYTE,  rect);
137
138         glPixelZoom(1.0,  1.0);
139
140         glPixelStorei(GL_UNPACK_ROW_LENGTH,  0);
141         
142         mywinset(curarea->win);
143 }
144
145 /**
146  * Sets up the fields of the View2D member of the SpaceImage struct
147  * This routine can be called in two modes:
148  * mode == 'f': float mode ???
149  * mode == 'p': pixel mode ???
150  *
151  * @param     sima  the image space to update
152  * @param     mode  the mode to use for the update
153  * @return    void
154  *   
155  */
156 void calc_image_view(SpaceImage *sima, char mode)
157 {
158         float xim=256, yim=256;
159         float x1, y1;
160         float zoom;
161         
162         if(sima->image && sima->image->ibuf) {
163                 xim= sima->image->ibuf->x;
164                 yim= sima->image->ibuf->y;
165         }
166         
167         sima->v2d.tot.xmin= 0;
168         sima->v2d.tot.ymin= 0;
169         sima->v2d.tot.xmax= xim;
170         sima->v2d.tot.ymax= yim;
171         
172         sima->v2d.mask.xmin= sima->v2d.mask.ymin= 0;
173         sima->v2d.mask.xmax= curarea->winx;
174         sima->v2d.mask.ymax= curarea->winy;
175
176
177         /* Which part of the image space do we see? */
178         /* Same calculation as in lrectwrite: area left and down*/
179         x1= curarea->winrct.xmin+(curarea->winx-sima->zoom*xim)/2;
180         y1= curarea->winrct.ymin+(curarea->winy-sima->zoom*yim)/2;
181
182         x1-= sima->zoom*sima->xof;
183         y1-= sima->zoom*sima->yof;
184
185         /* float! */
186         zoom= sima->zoom;
187         
188         /* relative display right */
189         sima->v2d.cur.xmin= ((curarea->winrct.xmin - (float)x1)/zoom);
190         sima->v2d.cur.xmax= sima->v2d.cur.xmin + ((float)curarea->winx/zoom);
191         
192         /* relative display left */
193         sima->v2d.cur.ymin= ((curarea->winrct.ymin-(float)y1)/zoom);
194         sima->v2d.cur.ymax= sima->v2d.cur.ymin + ((float)curarea->winy/zoom);
195         
196         if(mode=='f') {         
197                 sima->v2d.cur.xmin/= xim;
198                 sima->v2d.cur.xmax/= xim;
199                 sima->v2d.cur.ymin/= yim;
200                 sima->v2d.cur.ymax/= yim;
201         }
202 }
203
204 void what_image(SpaceImage *sima)
205 {
206         extern TFace *lasttface;        /* editface.c */
207         Mesh *me;
208                 
209         if(sima->mode==SI_TEXTURE) {
210                 if(G.f & G_FACESELECT) {
211
212                         sima->image= 0;
213                         me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
214                         set_lasttface();
215                         
216                         if(me && me->tface && lasttface && lasttface->mode & TF_TEX) {
217                                 sima->image= lasttface->tpage;
218                                         
219                                 if(sima->flag & SI_EDITTILE);
220                                 else sima->curtile= lasttface->tile;
221                                 
222                                 if(sima->image) {
223                                         if(lasttface->mode & TF_TILES)
224                                                 sima->image->tpageflag |= IMA_TILES;
225                                         else sima->image->tpageflag &= ~IMA_TILES;
226                                 }
227                         }
228                 }
229         }
230 }
231
232 void image_changed(SpaceImage *sima, int dotile)
233 {
234         TFace *tface;
235         Mesh *me;
236         int a;
237         
238         if(sima->mode==SI_TEXTURE) {
239                 
240                 if(G.f & G_FACESELECT) {
241                         me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
242                         if(me && me->tface) {
243                                 tface= me->tface;
244                                 a= me->totface;
245                                 while(a--) {
246                                         if(tface->flag & TF_SELECT) {
247                                                 
248                                                 if(dotile==2) {
249                                                         tface->mode &= ~TF_TILES;
250                                                 }
251                                                 else {
252                                                         tface->tpage= sima->image;
253                                                         tface->mode |= TF_TEX;
254                                                 
255                                                         if(dotile) tface->tile= sima->curtile;
256                                                 }
257                                                 
258                                                 if(sima->image) {
259                                                         if(sima->image->tpageflag & IMA_TILES) tface->mode |= TF_TILES;
260                                                         else tface->mode &= ~TF_TILES;
261                                                 
262                                                         if(sima->image->id.us==0) sima->image->id.us= 1;
263                                                 }
264                                         }
265                                         tface++;
266                                 }
267                                 allqueue(REDRAWVIEW3D, 0);
268                                 allqueue(REDRAWBUTSEDIT, 0);
269                         }
270                 }
271         }
272 }
273
274
275 void uvco_to_areaco(float *vec, short *mval)
276 {
277         float x, y;
278
279         mval[0]= 3200;
280         
281         x= (vec[0] - G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
282         y= (vec[1] - G.v2d->cur.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
283
284         if(x>=0.0 && x<=1.0) {
285                 if(y>=0.0 && y<=1.0) {          
286                         mval[0]= G.v2d->mask.xmin + x*(G.v2d->mask.xmax-G.v2d->mask.xmin);
287                         mval[1]= G.v2d->mask.ymin + y*(G.v2d->mask.ymax-G.v2d->mask.ymin);
288                 }
289         }
290 }
291
292 void uvco_to_areaco_noclip(float *vec, short *mval)
293 {
294         float x, y;
295
296         mval[0]= 3200;
297         
298         x= (vec[0] - G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
299         y= (vec[1] - G.v2d->cur.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
300
301         x= G.v2d->mask.xmin + x*(G.v2d->mask.xmax-G.v2d->mask.xmin);
302         y= G.v2d->mask.ymin + y*(G.v2d->mask.ymax-G.v2d->mask.ymin);
303         
304         mval[0]= x;
305         mval[1]= y;
306 }
307
308 void draw_tfaces(void)
309 {
310         TFace *tface,*activetface = NULL;
311         MFace *mface,*activemface = NULL;
312         Mesh *me;
313         int a;
314         char col1[4], col2[4];
315         
316         glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
317
318         if(G.f & G_FACESELECT) {
319                 me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
320                 if(me && me->tface) {
321                         calc_image_view(G.sima, 'f');   /* float */
322                         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
323                         glLoadIdentity();
324                         
325                         /* draw shadow mesh */
326                         if(G.sima->flag & SI_DRAWSHADOW){               
327                                 tface= me->tface;
328                                 mface= me->mface;
329                                 a= me->totface;                 
330                                 while(a--) {
331                                         if(tface->flag & TF_HIDE);
332                                         else if(mface->v3) {
333                                                 cpack(0x707070);
334                                                 glBegin(GL_LINE_LOOP);
335                                                 glVertex2fv(tface->uv[0]);
336                                                 glVertex2fv(tface->uv[1]);
337                                                 glVertex2fv(tface->uv[2]);
338                                                 if(mface->v4) glVertex2fv(tface->uv[3]);
339                                                 glEnd();
340                                         } 
341                                         tface++;
342                                         mface++;                                        
343                                 }
344                         }
345                         
346                         /* draw transparent faces */
347                         if(G.f & G_DRAWFACES) {
348                                 BIF_GetThemeColor4ubv(TH_FACE, col1);
349                                 BIF_GetThemeColor4ubv(TH_FACE_SELECT, col2);
350                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
351                                 glEnable(GL_BLEND);
352                                 tface= me->tface;
353                                 mface= me->mface;
354                                 a= me->totface;                 
355                                 while(a--) {
356                                         if(mface->v3 && (tface->flag & TF_SELECT)) {
357                                                 if(!(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&
358                                                    (!mface->v4 || tface->flag & TF_SEL4))
359                                                         glColor4ubv(col2);
360                                                 else
361                                                         glColor4ubv(col1);
362                                                         
363                                                 glBegin(mface->v4?GL_QUADS:GL_TRIANGLES);
364                                                         glVertex2fv(tface->uv[0]);
365                                                         glVertex2fv(tface->uv[1]);
366                                                         glVertex2fv(tface->uv[2]);
367                                                         if(mface->v4) glVertex2fv(tface->uv[3]);
368                                                 glEnd();
369                                         }
370                                         tface++;
371                                         mface++;                                        
372                                 }
373                                 glDisable(GL_BLEND);
374                         }
375
376
377                         tface= me->tface;
378                         mface= me->mface;
379                         a= me->totface;
380                         while(a--) {
381                                 if(mface->v3 && (tface->flag & TF_SELECT) ) {
382                                         if(tface->flag & TF_ACTIVE){
383                                                 activetface= tface; 
384                                                 activemface= mface; 
385                                         }
386
387                                         cpack(0x0);
388                                         glBegin(GL_LINE_LOOP);
389                                                 glVertex2fv(tface->uv[0]);
390                                                 glVertex2fv(tface->uv[1]);
391                                                 glVertex2fv(tface->uv[2]);
392                                                 if(mface->v4) glVertex2fv(tface->uv[3]);
393                                         glEnd();
394                                 
395                                         setlinestyle(2);
396                                         cpack(0xFFFFFF);
397                                         glBegin(GL_LINE_STRIP);
398                                                 glVertex2fv(tface->uv[0]);
399                                                 glVertex2fv(tface->uv[1]);
400                                         glEnd();
401
402                                         glBegin(GL_LINE_STRIP);
403                                                 glVertex2fv(tface->uv[0]);
404                                                 if(mface->v4) glVertex2fv(tface->uv[3]);
405                                                 else glVertex2fv(tface->uv[2]);
406                                         glEnd();
407         
408                                         glBegin(GL_LINE_STRIP);
409                                                 glVertex2fv(tface->uv[1]);
410                                                 glVertex2fv(tface->uv[2]);
411                                                 if(mface->v4) glVertex2fv(tface->uv[3]);
412                                         glEnd();
413                                         setlinestyle(0);
414                                 }
415                                         
416                                 tface++;
417                                 mface++;
418                         }
419
420                         /* draw active face edges */
421                         if (activetface){
422                                 /* colors: R=u G=v */
423
424                                 setlinestyle(2);
425                                 tface=activetface; 
426                                 mface=activemface; 
427
428                                 cpack(0x0);
429                                 glBegin(GL_LINE_LOOP);
430                                 glVertex2fv(tface->uv[0]);
431                                         glVertex2fv(tface->uv[1]);
432                                         glVertex2fv(tface->uv[2]);
433                                         if(mface->v4) glVertex2fv(tface->uv[3]);
434                                 glEnd();
435                                         
436                                 cpack(0xFF00);
437                                 glBegin(GL_LINE_STRIP);
438                                         glVertex2fv(tface->uv[0]);
439                                         glVertex2fv(tface->uv[1]);
440                                 glEnd();
441
442                                 cpack(0xFF);
443                                 glBegin(GL_LINE_STRIP);
444                                         glVertex2fv(tface->uv[0]);
445                                         if(mface->v4) glVertex2fv(tface->uv[3]);
446                                         else glVertex2fv(tface->uv[2]);
447                                 glEnd();
448
449                                 cpack(0xFFFFFF);
450                                 glBegin(GL_LINE_STRIP);
451                                         glVertex2fv(tface->uv[1]);
452                                         glVertex2fv(tface->uv[2]);
453                                         if(mface->v4) glVertex2fv(tface->uv[3]);
454                                 glEnd();
455                                 
456                                 setlinestyle(0);
457                         }
458
459             /* to make sure vertices markers are visible, draw them last */
460                         /* we draw selected over unselected, so two loops */
461                         BIF_GetThemeColor3ubv(TH_VERTEX, col1);
462                         glColor4ubv(col1);
463                         tface= me->tface;
464                         mface= me->mface;
465                         a= me->totface;
466                         while(a--) {
467                                 if(mface->v3  && (tface->flag & TF_SELECT) ) {
468                                         glBegin(GL_POINTS);
469                                         
470                                         if(tface->flag & TF_SEL1); else glVertex2fv(tface->uv[0]);
471                                         if(tface->flag & TF_SEL2); else glVertex2fv(tface->uv[1]);
472                                         if(tface->flag & TF_SEL3); else glVertex2fv(tface->uv[2]);
473                                         if(mface->v4) {
474                                                 if(tface->flag & TF_SEL4); else glVertex2fv(tface->uv[3]);
475                                         }
476                                         glEnd();
477                                 }
478                                 tface++;
479                                 mface++;
480                         }
481                         /* selected */
482                         BIF_GetThemeColor3ubv(TH_VERTEX_SELECT, col2);
483                         glColor4ubv(col2);
484                         tface= me->tface;
485                         mface= me->mface;
486                         a= me->totface;
487                         while(a--) {
488                                 if(mface->v3  && (tface->flag & TF_SELECT) ) {
489                                         glBegin(GL_POINTS);
490                                         
491                                         if(tface->flag & TF_SEL1) glVertex2fv(tface->uv[0]);
492                                         if(tface->flag & TF_SEL2) glVertex2fv(tface->uv[1]);
493                                         if(tface->flag & TF_SEL3) glVertex2fv(tface->uv[2]);
494                                         if(mface->v4) {
495                                                 if(tface->flag & TF_SEL4) glVertex2fv(tface->uv[3]);
496                                         }
497                                         glEnd();
498                                 }
499                                 tface++;
500                                 mface++;
501                         }
502                 }
503         }
504         glPointSize(1.0);
505 }
506
507 static unsigned int *get_part_from_ibuf(ImBuf *ibuf, short startx, short starty, short endx, short endy)
508 {
509         unsigned int *rt, *rp, *rectmain;
510         short y, heigth, len;
511
512         /* the right offset in rectot */
513
514         rt= ibuf->rect+ (starty*ibuf->x+ startx);
515
516         len= (endx-startx);
517         heigth= (endy-starty);
518
519         rp=rectmain= MEM_mallocN(heigth*len*sizeof(int), "rect");
520         
521         for(y=0; y<heigth; y++) {
522                 memcpy(rp, rt, len*4);
523                 rt+= ibuf->x;
524                 rp+= len;
525         }
526         return rectmain;
527 }
528
529 static void draw_image_prop_circle(ImBuf *ibuf)
530 {
531         float aspx, aspy;
532         extern float prop_cent[3];
533
534         if(G.moving && G.f & G_PROPORTIONAL) {
535
536                 if(ibuf==0 || ibuf->rect==0 || ibuf->x==0 || ibuf->y==0) {
537                         aspx= aspy= 1.0;
538                 }
539                 else {
540                         aspx= 256.0/ibuf->x;
541                         aspy= 256.0/ibuf->y;
542                 }
543
544                 /* scale and translate the circle into place and draw it */
545                 glPushMatrix();
546                 glScalef(aspx, aspy, 1.0);
547                 glTranslatef((1/aspx)*prop_cent[0] - prop_cent[0],
548                              (1/aspy)*prop_cent[1] - prop_cent[1], 0.0);
549                 draw_prop_circle();
550                 glPopMatrix();
551         }
552 }
553
554 static void draw_image_view_icon(void)
555 {
556         glEnable(GL_BLEND);
557         glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA); 
558         
559         glRasterPos2f(5.0, 5.0);
560
561         if(G.sima->flag & SI_STICKYUVS) {
562                 BIF_draw_icon(ICON_STICKY2_UVS);
563                 glRasterPos2f(25.0, 5.0);
564         }
565         else if(G.sima->flag & SI_LOCALSTICKY) {
566                 BIF_draw_icon(ICON_STICKY_UVS);
567                 glRasterPos2f(25.0, 5.0);
568         }
569
570         if(G.sima->flag & SI_SELACTFACE) {
571                         BIF_draw_icon(ICON_DRAW_UVFACES);
572         }
573         
574         glBlendFunc(GL_ONE,  GL_ZERO); 
575         glDisable(GL_BLEND);
576 }
577
578 /* ************ panel stuff ************* */
579
580 // button define is local, only events defined here possible
581 #define B_TRANS_IMAGE   1
582
583 /* is used for both read and write... */
584 static void image_editvertex_buts(uiBlock *block)
585 {
586         static float ocent[2];
587         float cent[2]= {0.0, 0.0};
588         int imx, imy;
589         int i, nactive= 0;
590         Mesh *me;
591         
592         if( is_uv_tface_editing_allowed_silent()==0 ) return;
593         me= get_mesh(OBACT);
594         
595         if (G.sima->image && G.sima->image->ibuf) {
596                 imx= G.sima->image->ibuf->x;
597                 imy= G.sima->image->ibuf->y;
598         } else
599                 imx= imy= 256;
600         
601         for (i=0; i<me->totface; i++) {
602                 MFace *mf= &((MFace*) me->mface)[i];
603                 TFace *tf= &((TFace*) me->tface)[i];
604                 
605                 if (!mf->v3 || !(tf->flag & TF_SELECT))
606                         continue;
607                 
608                 if (tf->flag & TF_SEL1) {
609                         cent[0]+= tf->uv[0][0];
610                         cent[1]+= tf->uv[0][1];
611                         nactive++;
612                 }
613                 if (tf->flag & TF_SEL2) {
614                         cent[0]+= tf->uv[1][0];
615                         cent[1]+= tf->uv[1][1];
616                         nactive++;
617                 }
618                 if (tf->flag & TF_SEL3) {
619                         cent[0]+= tf->uv[2][0];
620                         cent[1]+= tf->uv[2][1];
621                         nactive++;
622                 }
623                 if (mf->v4 && (tf->flag & TF_SEL4)) {
624                         cent[0]+= tf->uv[3][0];
625                         cent[1]+= tf->uv[3][1];
626                         nactive++;
627                 }
628         }
629                 
630         if(block) {     // do the buttons
631                 if (nactive) {
632                         ocent[0]= (cent[0]*imx)/nactive;
633                         ocent[1]= (cent[1]*imy)/nactive;
634                         
635                         uiDefBut(block, LABEL, 0, "UV Vertex:",10,55,302,19,0,0,0,0,0,"");
636                         if(nactive==1) {
637                                 uiBlockBeginAlign(block);
638                                 uiDefButF(block, NUM, B_TRANS_IMAGE, "Vertex X:",       10, 35, 290, 19, &ocent[0], -10*imx, 10.0*imx, 100, 0, "");
639                                 uiDefButF(block, NUM, B_TRANS_IMAGE, "Vertex Y:",       10, 15, 290, 19, &ocent[1], -10*imy, 10.0*imy, 100, 0, "");
640                                 uiBlockEndAlign(block);
641                         }
642                         else {
643                                 uiBlockBeginAlign(block);
644                                 uiDefButF(block, NUM, B_TRANS_IMAGE, "Median X:",       10, 35, 290, 19, &ocent[0], -10*imx, 10.0*imx, 100, 0, "");
645                                 uiDefButF(block, NUM, B_TRANS_IMAGE, "Median Y:",       10, 15, 290, 19, &ocent[1], -10*imy, 10.0*imy, 100, 0, "");
646                                 uiBlockEndAlign(block);
647                         }
648                 }
649         }
650         else {  // apply event
651                 float delta[2];
652                 
653                 cent[0]= (cent[0]*imx)/nactive;
654                 cent[1]= (cent[1]*imy)/nactive;
655                         
656                 delta[0]= (ocent[0]-cent[0])/imx;
657                 delta[1]= (ocent[1]-cent[1])/imy;
658
659                 for (i=0; i<me->totface; i++) {
660                         MFace *mf= &((MFace*) me->mface)[i];
661                         TFace *tf= &((TFace*) me->tface)[i];
662                 
663                         if (!mf->v3 || !(tf->flag & TF_SELECT))
664                                 continue;
665                 
666                         if (tf->flag & TF_SEL1) {
667                                 tf->uv[0][0]+= delta[0];
668                                 tf->uv[0][1]+= delta[1];
669                         }
670                         if (tf->flag & TF_SEL2) {
671                                 tf->uv[1][0]+= delta[0];
672                                 tf->uv[1][1]+= delta[1];
673                         }
674                         if (tf->flag & TF_SEL3) {
675                                 tf->uv[2][0]+= delta[0];
676                                 tf->uv[2][1]+= delta[1];
677                         }
678                         if (mf->v4 && (tf->flag & TF_SEL4)) {
679                                 tf->uv[3][0]+= delta[0];
680                                 tf->uv[3][1]+= delta[1];
681                         }
682                 }
683                         
684                 allqueue(REDRAWVIEW3D, 0);
685                 allqueue(REDRAWIMAGE, 0);
686         }
687 }
688
689
690 void do_imagebuts(unsigned short event)
691 {
692         switch(event) {
693         case B_TRANS_IMAGE:
694                 image_editvertex_buts(NULL);
695                 break;
696
697         case B_SIMAGEDRAW:
698                 if(G.f & G_FACESELECT) {
699                         make_repbind(G.sima->image);
700                         image_changed(G.sima, 1);
701                 }
702                 allqueue(REDRAWVIEW3D, 0);
703                 allqueue(REDRAWIMAGE, 0);
704                 break;
705
706         case B_SIMAGEDRAW1:
707                 image_changed(G.sima, 2);               /* 2: only tileflag */
708                 allqueue(REDRAWVIEW3D, 0);
709                 allqueue(REDRAWIMAGE, 0);
710                 break;
711                 
712         case B_TWINANIM:
713                 {
714                         Image *ima;
715                         int nr;
716
717                         ima = G.sima->image;
718                         if (ima) {
719                                 if(ima->flag & IMA_TWINANIM) {
720                                         nr= ima->xrep*ima->yrep;
721                                         if(ima->twsta>=nr) ima->twsta= 1;
722                                         if(ima->twend>=nr) ima->twend= nr-1;
723                                         if(ima->twsta>ima->twend) ima->twsta= 1;
724                                         allqueue(REDRAWIMAGE, 0);
725                                 }
726                         }
727                 }
728                 break;
729         }
730 }
731
732 static void image_panel_properties(short cntrl) // IMAGE_HANDLER_PROPERTIES
733 {
734         uiBlock *block;
735
736         block= uiNewBlock(&curarea->uiblocks, "image_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
737         uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
738         uiSetPanelHandler(IMAGE_HANDLER_PROPERTIES);  // for close and esc
739         if(uiNewPanel(curarea, block, "Properties", "Image", 10, 230, 318, 204)==0)
740                 return;
741
742         if (G.sima->image && G.sima->image->ibuf) {
743                 char str[32];
744
745                 sprintf(str, "Image: size %d x %d", G.sima->image->ibuf->x, G.sima->image->ibuf->y);
746                 uiDefBut(block, LABEL, 0, str,          10,180,300,19, 0, 0, 0, 0, 0, "");
747
748                 uiBlockBeginAlign(block);
749                 uiDefButS(block, TOG|BIT|1, B_TWINANIM, "Anim", 10,150,140,19, &G.sima->image->tpageflag, 0, 0, 0, 0, "Toggles use of animated texture");
750                 uiDefButS(block, NUM, B_TWINANIM, "Start:",             10,130,140,19, &G.sima->image->twsta, 0.0, 128.0, 0, 0, "Displays the start frame of an animated texture");
751                 uiDefButS(block, NUM, B_TWINANIM, "End:",               10,110,140,19, &G.sima->image->twend, 0.0, 128.0, 0, 0, "Displays the end frame of an animated texture");
752                 uiDefButS(block, NUM, 0, "Speed",                               10,90,140,19, &G.sima->image->animspeed, 1.0, 100.0, 0, 0, "Displays Speed of the animation in frames per second");
753                 uiBlockEndAlign(block);
754
755                 uiBlockBeginAlign(block);
756                 uiDefButS(block, TOG|BIT|0, B_SIMAGEDRAW1, "Tiles",     160,150,140,19, &G.sima->image->tpageflag, 0, 0, 0, 0, "Toggles use of tilemode for faces");
757                 uiDefButS(block, NUM, B_SIMAGEDRAW, "X:",               160,130,70,19, &G.sima->image->xrep, 1.0, 16.0, 0, 0, "Sets the degree of repetition in the X direction");
758                 uiDefButS(block, NUM, B_SIMAGEDRAW, "Y:",               230,130,70,19, &G.sima->image->yrep, 1.0, 16.0, 0, 0, "Sets the degree of repetition in the Y direction");
759                 uiBlockBeginAlign(block);
760         }
761
762         image_editvertex_buts(block);
763 }
764
765 static void image_blockhandlers(ScrArea *sa)
766 {
767         SpaceImage *sima= sa->spacedata.first;
768         short a;
769
770         /* warning; blocks need to be freed each time, handlers dont remove  */
771         uiFreeBlocksWin(&sa->uiblocks, sa->win);
772         
773         for(a=0; a<SPACE_MAXHANDLER; a+=2) {
774                 switch(sima->blockhandler[a]) {
775
776                 case IMAGE_HANDLER_PROPERTIES:
777                         image_panel_properties(sima->blockhandler[a+1]);
778                         break;
779                 
780                 }
781                 /* clear action value for event */
782                 sima->blockhandler[a+1]= 0;
783         }
784         uiDrawBlocksPanels(sa, 0);
785 }
786
787
788
789 void drawimagespace(ScrArea *sa, void *spacedata)
790 {
791         ImBuf *ibuf= NULL;
792         float col[3];
793         unsigned int *rect;
794         int x1, y1, xmin, xmax, ymin, ymax;
795         short sx, sy, dx, dy;
796         
797         BIF_GetThemeColor3fv(TH_BACK, col);
798         glClearColor(col[0], col[1], col[2], 0.0);
799         glClear(GL_COLOR_BUFFER_BIT);
800
801         bwin_clear_viewmat(sa->win);    /* clear buttons view */
802         glLoadIdentity();
803         
804         xmin= curarea->winrct.xmin; xmax= curarea->winrct.xmax;
805         ymin= curarea->winrct.ymin; ymax= curarea->winrct.ymax;
806         
807         what_image(G.sima);
808         
809         if(G.sima->image) {
810         
811                 if(G.sima->image->ibuf==0) {
812                         load_image(G.sima->image, IB_rect, G.sce, G.scene->r.cfra);
813                 }       
814                 ibuf= G.sima->image->ibuf;
815         }
816         
817         if(ibuf==0 || ibuf->rect==0) {
818                 calc_image_view(G.sima, 'f');
819                 myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
820                 cpack(0x404040);
821                 glRectf(0.0, 0.0, 1.0, 1.0);
822                 draw_tfaces();
823         }
824         else {
825                 /* calc location */
826                 x1= xmin+(curarea->winx-G.sima->zoom*ibuf->x)/2;
827                 y1= ymin+(curarea->winy-G.sima->zoom*ibuf->y)/2;
828         
829                 x1-= G.sima->zoom*G.sima->xof;
830                 y1-= G.sima->zoom*G.sima->yof;
831         
832                 
833                 if(G.sima->flag & SI_EDITTILE) {
834                         rectwrite_part(xmin, ymin, xmax, ymax, x1, y1, ibuf->x, ibuf->y, (float)G.sima->zoom, (float)G.sima->zoom, ibuf->rect);
835                         
836                         dx= ibuf->x/G.sima->image->xrep;
837                         dy= ibuf->y/G.sima->image->yrep;
838                         sy= (G.sima->curtile / G.sima->image->xrep);
839                         sx= G.sima->curtile - sy*G.sima->image->xrep;
840         
841                         sx*= dx;
842                         sy*= dy;
843                         
844                         calc_image_view(G.sima, 'p');   /* pixel */
845                         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
846                         
847                         cpack(0x0);
848                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glRects(sx,  sy,  sx+dx-1,  sy+dy-1); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
849                         cpack(0xFFFFFF);
850                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glRects(sx+1,  sy+1,  sx+dx,  sy+dy); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
851                 }
852                 else if(G.sima->mode==SI_TEXTURE) {
853                         if(G.sima->image->tpageflag & IMA_TILES) {
854                                 
855                                 
856                                 /* just leave this a while */
857                                 if(G.sima->image->xrep<1) return;
858                                 if(G.sima->image->yrep<1) return;
859                                 
860                                 if(G.sima->curtile >= G.sima->image->xrep*G.sima->image->yrep) 
861                                         G.sima->curtile = G.sima->image->xrep*G.sima->image->yrep - 1; 
862                                 
863                                 dx= ibuf->x/G.sima->image->xrep;
864                                 dy= ibuf->y/G.sima->image->yrep;
865                                 
866                                 sy= (G.sima->curtile / G.sima->image->xrep);
867                                 sx= G.sima->curtile - sy*G.sima->image->xrep;
868                 
869                                 sx*= dx;
870                                 sy*= dy;
871                                 
872                                 rect= get_part_from_ibuf(ibuf, sx, sy, sx+dx, sy+dy);
873                                 
874                                 /* rect= ibuf->rect; */
875                                 for(sy= 0; sy+dy<=ibuf->y; sy+= dy) {
876                                         for(sx= 0; sx+dx<=ibuf->x; sx+= dx) {
877                                                 
878                                                 rectwrite_part(xmin, ymin, xmax, ymax, 
879                                                         x1+sx*G.sima->zoom, y1+sy*G.sima->zoom, dx, dy, (float)G.sima->zoom, (float)G.sima->zoom, rect);
880                                         }
881                                 }
882                                 
883                                 MEM_freeN(rect);
884                         }
885                         else 
886                                 rectwrite_part(xmin, ymin, xmax, ymax, x1, y1, ibuf->x, ibuf->y, (float)G.sima->zoom,(float)G.sima->zoom, ibuf->rect);
887                 
888                         draw_tfaces();
889                 }
890         
891                 calc_image_view(G.sima, 'f');   /* float */
892         }
893
894         draw_image_prop_circle(ibuf);
895
896         myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
897         draw_image_view_icon();
898         draw_area_emboss(sa);
899
900         /* it is important to end a view in a transform compatible with buttons */
901         bwin_scalematrix(sa->win, G.sima->blockscale, G.sima->blockscale, G.sima->blockscale);
902         image_blockhandlers(sa);
903
904         curarea->win_swap= WIN_BACK_OK;
905 }
906
907 void image_viewmove(void)
908 {
909         short mval[2], mvalo[2], xof, yof;
910         
911         getmouseco_sc(mvalo);
912         
913         while(get_mbut()&(L_MOUSE|M_MOUSE)) {
914
915                 getmouseco_sc(mval);
916                 
917                 xof= (mvalo[0]-mval[0])/G.sima->zoom;
918                 yof= (mvalo[1]-mval[1])/G.sima->zoom;
919                 
920                 if(xof || yof) {
921                         
922                         G.sima->xof+= xof;
923                         G.sima->yof+= yof;
924                         
925                         mvalo[0]= mval[0];
926                         mvalo[1]= mval[1];
927                         
928                         scrarea_do_windraw(curarea);
929                         screen_swapbuffers();
930                 }               
931                 else BIF_wait_for_statechange();
932         }
933 }
934
935 void image_viewzoom(unsigned short event)
936 {
937         SpaceImage *sima= curarea->spacedata.first;
938         int width, height;
939
940         if(U.uiflag & USER_WHEELZOOMDIR) {
941                 if (event==WHEELDOWNMOUSE || event == PADPLUSKEY) {
942                         sima->zoom *= 2;
943                 } else {
944                         sima->zoom /= 2;
945                         /* Check if the image will still be visible after zooming out */
946                         if (sima->zoom < 1) {
947                                 calc_image_view(G.sima, 'p');
948                                 if (sima->image) {
949                                         if (sima->image->ibuf) {
950                                                 width = sima->image->ibuf->x * sima->zoom;
951                                                 height = sima->image->ibuf->y * sima->zoom;
952                                                 if ((width < 4) && (height < 4)) {
953                                                         /* Image will become too small, reset value */
954                                                         sima->zoom *= 2;
955                                                 }
956                                         }
957                                 }
958                         }
959                 }
960         } else {
961                 if (event==WHEELUPMOUSE || event == PADPLUSKEY) {
962                         sima->zoom *= 2;
963                 } else {
964                         sima->zoom /= 2;
965                         /* Check if the image will still be visible after zooming out */
966                         if (sima->zoom < 1) {
967                                 calc_image_view(G.sima, 'p');
968                                 if (sima->image) {
969                                         if (sima->image->ibuf) {
970                                                 width = sima->image->ibuf->x * sima->zoom;
971                                                 height = sima->image->ibuf->y * sima->zoom;
972                                                 if ((width < 4) && (height < 4)) {
973                                                         /* Image will become too small, reset value */
974                                                         sima->zoom *= 2;
975                                                 }
976                                         }
977                                 }
978                         }
979                 }
980         }
981 }
982
983 /**
984  * Updates the fields of the View2D member of the SpaceImage struct.
985  * Default behavior is to reset the position of the image and set the zoom to 1
986  * If the image will not fit within the window rectangle, the zoom is adjusted
987  *
988  * @return    void
989  *   
990  */
991 void image_home(void)
992 {
993         int width, height;
994         float zoomX, zoomY;
995
996         if (curarea->spacetype != SPACE_IMAGE) return;
997         if ((G.sima->image == 0) || (G.sima->image->ibuf == 0)) return;
998
999         /* Check if the image will fit in the image with zoom==1 */
1000         width = curarea->winx;
1001         height = curarea->winy;
1002         if (((G.sima->image->ibuf->x >= width) || (G.sima->image->ibuf->y >= height)) && 
1003                 ((width > 0) && (height > 0))) {
1004                 /* Find the zoom value that will fit the image in the image space */
1005                 zoomX = ((float)width) / ((float)G.sima->image->ibuf->x);
1006                 zoomY = ((float)height) / ((float)G.sima->image->ibuf->y);
1007                 G.sima->zoom= MIN2(zoomX, zoomY);
1008
1009                 /* Now make it a power of 2 */
1010                 G.sima->zoom = 1 / G.sima->zoom;
1011                 G.sima->zoom = log(G.sima->zoom) / log(2);
1012                 G.sima->zoom = ceil(G.sima->zoom);
1013                 G.sima->zoom = pow(2, G.sima->zoom);
1014                 G.sima->zoom = 1 / G.sima->zoom;
1015         }
1016         else {
1017                 G.sima->zoom= (float)1;
1018         }
1019
1020         G.sima->xof= G.sima->yof= 0;
1021         
1022         calc_image_view(G.sima, 'p');
1023         
1024         scrarea_queue_winredraw(curarea);
1025 }
1026