Orange: more work on float/exr buffers;
[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 #else
43 #include <unistd.h>
44 #endif   
45 #include "MEM_guardedalloc.h"
46
47 #include "BLI_arithb.h"
48 #include "BLI_blenlib.h"
49
50 #include "IMB_imbuf_types.h"
51
52 #include "DNA_color_types.h"
53 #include "DNA_image_types.h"
54 #include "DNA_mesh_types.h"
55 #include "DNA_meshdata_types.h"
56 #include "DNA_packedFile_types.h"
57 #include "DNA_scene_types.h"
58 #include "DNA_screen_types.h"
59 #include "DNA_space_types.h"
60 #include "DNA_userdef_types.h"
61
62 #include "BKE_colortools.h"
63 #include "BKE_utildefines.h"
64 #include "BKE_global.h"
65 #include "BKE_main.h"
66 #include "BKE_mesh.h"
67 #include "BKE_image.h"
68 #include "BKE_DerivedMesh.h"
69 #include "BKE_displist.h"
70 #include "BKE_object.h"
71
72 #include "BDR_editface.h"
73 #include "BDR_drawobject.h"
74 #include "BDR_drawmesh.h"
75 #include "BDR_imagepaint.h"
76
77 #include "BIF_gl.h"
78 #include "BIF_mywindow.h"
79 #include "BIF_drawimage.h"
80 #include "BIF_resources.h"
81 #include "BIF_interface.h"
82 #include "BIF_interface_icons.h"
83 #include "BIF_editsima.h"
84 #include "BIF_glutil.h"
85 #include "BIF_space.h"
86 #include "BIF_screen.h"
87 #include "BIF_transform.h"
88
89 #include "BSE_headerbuttons.h"
90 #include "BSE_trans_types.h"
91 #include "BSE_view.h"
92
93 /* Modules used */
94 #include "mydevice.h"
95 #include "blendef.h"
96 #include "butspace.h"  // event codes
97
98 static unsigned char *alloc_alpha_clone_image(int *width, int *height)
99 {
100         unsigned int size, alpha;
101         unsigned char *rect, *cp;
102
103         if(!Gip.clone.image)
104                 return NULL;
105
106         if(!Gip.clone.image->ibuf)
107                 load_image(Gip.clone.image, IB_rect, G.sce, G.scene->r.cfra);
108
109         if(!Gip.clone.image->ibuf || !Gip.clone.image->ibuf->rect)
110                 return NULL;
111
112         rect= MEM_dupallocN(Gip.clone.image->ibuf->rect);
113
114         if(!rect)
115                 return NULL;
116
117         *width= Gip.clone.image->ibuf->x;
118         *height= Gip.clone.image->ibuf->y;
119
120         size= (*width)*(*height);
121         alpha= (unsigned char)255*Gip.clone.alpha;
122         cp= rect;
123
124         while(size-- > 0) {
125                 cp[3]= alpha;
126                 cp += 4;
127         }
128
129         return rect;
130 }
131
132 static void setcloneimage()
133 {
134         if(G.sima->menunr > 0) {
135                 Image *ima= (Image*)BLI_findlink(&G.main->image, G.sima->menunr-1);
136
137                 if(ima) {
138                         Gip.clone.image= ima;
139                         Gip.clone.offset[0]= Gip.clone.offset[0]= 0.0;
140                 }
141         }
142 }
143
144 /**
145  * Sets up the fields of the View2D member of the SpaceImage struct
146  * This routine can be called in two modes:
147  * mode == 'f': float mode (0.0 - 1.0)
148  * mode == 'p': pixel mode (0 - size)
149  *
150  * @param     sima  the image space to update
151  * @param     mode  the mode to use for the update
152  * @return    void
153  *   
154  */
155 void calc_image_view(SpaceImage *sima, char mode)
156 {
157         float xim=256, yim=256;
158         float x1, y1;
159         float zoom;
160         
161         if(sima->image && sima->image->ibuf) {
162                 xim= sima->image->ibuf->x;
163                 yim= sima->image->ibuf->y;
164         }
165         
166         sima->v2d.tot.xmin= 0;
167         sima->v2d.tot.ymin= 0;
168         sima->v2d.tot.xmax= xim;
169         sima->v2d.tot.ymax= yim;
170         
171         sima->v2d.mask.xmin= sima->v2d.mask.ymin= 0;
172         sima->v2d.mask.xmax= curarea->winx;
173         sima->v2d.mask.ymax= curarea->winy;
174
175
176         /* Which part of the image space do we see? */
177         /* Same calculation as in lrectwrite: area left and down*/
178         x1= curarea->winrct.xmin+(curarea->winx-sima->zoom*xim)/2;
179         y1= curarea->winrct.ymin+(curarea->winy-sima->zoom*yim)/2;
180
181         x1-= sima->zoom*sima->xof;
182         y1-= sima->zoom*sima->yof;
183
184         /* float! */
185         zoom= sima->zoom;
186         
187         /* relative display right */
188         sima->v2d.cur.xmin= ((curarea->winrct.xmin - (float)x1)/zoom);
189         sima->v2d.cur.xmax= sima->v2d.cur.xmin + ((float)curarea->winx/zoom);
190         
191         /* relative display left */
192         sima->v2d.cur.ymin= ((curarea->winrct.ymin-(float)y1)/zoom);
193         sima->v2d.cur.ymax= sima->v2d.cur.ymin + ((float)curarea->winy/zoom);
194         
195         if(mode=='f') {         
196                 sima->v2d.cur.xmin/= xim;
197                 sima->v2d.cur.xmax/= xim;
198                 sima->v2d.cur.ymin/= yim;
199                 sima->v2d.cur.ymax/= yim;
200         }
201 }
202
203 void what_image(SpaceImage *sima)
204 {
205         extern TFace *lasttface;        /* editface.c */
206         Mesh *me;
207                 
208         if(sima->mode==SI_TEXTURE) {
209                 if(G.f & G_FACESELECT) {
210
211                         sima->image= 0;
212                         me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
213                         set_lasttface();
214                         
215                         if(me && me->tface && lasttface && lasttface->mode & TF_TEX) {
216                                 sima->image= lasttface->tpage;
217                                         
218                                 if(sima->flag & SI_EDITTILE);
219                                 else sima->curtile= lasttface->tile;
220                                 
221                                 if(sima->image) {
222                                         if(lasttface->mode & TF_TILES)
223                                                 sima->image->tpageflag |= IMA_TILES;
224                                         else sima->image->tpageflag &= ~IMA_TILES;
225                                 }
226                         }
227                 }
228         }
229 }
230
231 void image_changed(SpaceImage *sima, int dotile)
232 {
233         TFace *tface;
234         Mesh *me;
235         int a;
236         
237         if(sima->mode==SI_TEXTURE) {
238                 
239                 if(G.f & G_FACESELECT) {
240                         me= get_mesh(OBACT);
241                         if(me && me->tface) {
242                                 tface= me->tface;
243                                 a= me->totface;
244                                 while(a--) {
245                                         if(tface->flag & TF_SELECT) {
246                                                 
247                                                 if(dotile==2) {
248                                                         tface->mode &= ~TF_TILES;
249                                                 }
250                                                 else {
251                                                         tface->tpage= sima->image;
252                                                         tface->mode |= TF_TEX;
253                                                 
254                                                         if(dotile) tface->tile= sima->curtile;
255                                                 }
256                                                 
257                                                 if(sima->image) {
258                                                         if(sima->image->tpageflag & IMA_TILES) tface->mode |= TF_TILES;
259                                                         else tface->mode &= ~TF_TILES;
260                                                 
261                                                         if(sima->image->id.us==0) sima->image->id.us= 1;
262                                                 }
263                                         }
264                                         tface++;
265                                 }
266
267                                 object_uvs_changed(OBACT);
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]= IS_CLIPPED;
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, int *mval)
293 {
294         float x, y;
295
296         mval[0]= IS_CLIPPED;
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         float pointsize= BIF_GetThemeValuef(TH_VERTEX_SIZE);
316         
317         if(G.f & G_FACESELECT) {
318                 me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
319                 if(me && me->tface) {
320                         calc_image_view(G.sima, 'f');   /* float */
321                         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
322                         glLoadIdentity();
323                         
324                         /* draw shadow mesh */
325                         if((G.sima->flag & SI_DRAWSHADOW) && !(G.obedit==OBACT)){
326                                 int dmNeedsFree;
327                                 DerivedMesh *dm = mesh_get_derived_final(OBACT, &dmNeedsFree);
328
329                                 glColor3ub(112, 112, 112);
330                                 if (dm->drawUVEdges) dm->drawUVEdges(dm);
331
332                                 if (dmNeedsFree) dm->release(dm);
333                         }
334                         else if(G.sima->flag & SI_DRAWSHADOW){          
335                                 tface= me->tface;
336                                 mface= me->mface;
337                                 a= me->totface;                 
338                                 while(a--) {
339                                         if(!(tface->flag & TF_HIDE)) {
340                                                 glColor3ub(112, 112, 112);
341                                                 glBegin(GL_LINE_LOOP);
342                                                 glVertex2fv(tface->uv[0]);
343                                                 glVertex2fv(tface->uv[1]);
344                                                 glVertex2fv(tface->uv[2]);
345                                                 if(mface->v4) glVertex2fv(tface->uv[3]);
346                                                 glEnd();
347                                         } 
348                                         tface++;
349                                         mface++;                                        
350                                 }
351                         }
352                         
353                         /* draw transparent faces */
354                         if(G.f & G_DRAWFACES) {
355                                 BIF_GetThemeColor4ubv(TH_FACE, col1);
356                                 BIF_GetThemeColor4ubv(TH_FACE_SELECT, col2);
357                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
358                                 glEnable(GL_BLEND);
359                                 tface= me->tface;
360                                 mface= me->mface;
361                                 a= me->totface;                 
362                                 while(a--) {
363                                         if(tface->flag & TF_SELECT) {
364                                                 if(!(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&
365                                                    (!mface->v4 || tface->flag & TF_SEL4))
366                                                         glColor4ubv(col2);
367                                                 else
368                                                         glColor4ubv(col1);
369                                                         
370                                                 glBegin(mface->v4?GL_QUADS:GL_TRIANGLES);
371                                                         glVertex2fv(tface->uv[0]);
372                                                         glVertex2fv(tface->uv[1]);
373                                                         glVertex2fv(tface->uv[2]);
374                                                         if(mface->v4) glVertex2fv(tface->uv[3]);
375                                                 glEnd();
376                                         }
377                                         tface++;
378                                         mface++;                                        
379                                 }
380                                 glDisable(GL_BLEND);
381                         }
382
383
384                         tface= me->tface;
385                         mface= me->mface;
386                         a= me->totface;
387                         while(a--) {
388                                 if(tface->flag & TF_SELECT) {
389                                         if(tface->flag & TF_ACTIVE){
390                                                 activetface= tface; 
391                                                 activemface= mface; 
392                                         }
393
394                                         cpack(0x0);
395                                         glBegin(GL_LINE_LOOP);
396                                                 glVertex2fv(tface->uv[0]);
397                                                 glVertex2fv(tface->uv[1]);
398                                                 glVertex2fv(tface->uv[2]);
399                                                 if(mface->v4) glVertex2fv(tface->uv[3]);
400                                         glEnd();
401                                 
402                                         setlinestyle(2);
403                                         cpack(0xFFFFFF);
404                                         glBegin(GL_LINE_STRIP);
405                                                 glVertex2fv(tface->uv[0]);
406                                                 glVertex2fv(tface->uv[1]);
407                                         glEnd();
408
409                                         glBegin(GL_LINE_STRIP);
410                                                 glVertex2fv(tface->uv[0]);
411                                                 if(mface->v4) glVertex2fv(tface->uv[3]);
412                                                 else glVertex2fv(tface->uv[2]);
413                                         glEnd();
414         
415                                         glBegin(GL_LINE_STRIP);
416                                                 glVertex2fv(tface->uv[1]);
417                                                 glVertex2fv(tface->uv[2]);
418                                                 if(mface->v4) glVertex2fv(tface->uv[3]);
419                                         glEnd();
420                                         setlinestyle(0);
421                                 }
422                                         
423                                 tface++;
424                                 mface++;
425                         }
426
427                         /* draw active face edges */
428                         if (activetface){
429                                 /* colors: R=u G=v */
430
431                                 setlinestyle(2);
432                                 tface=activetface; 
433                                 mface=activemface; 
434
435                                 cpack(0x0);
436                                 glBegin(GL_LINE_LOOP);
437                                 glVertex2fv(tface->uv[0]);
438                                         glVertex2fv(tface->uv[1]);
439                                         glVertex2fv(tface->uv[2]);
440                                         if(mface->v4) glVertex2fv(tface->uv[3]);
441                                 glEnd();
442                                         
443                                 cpack(0xFF00);
444                                 glBegin(GL_LINE_STRIP);
445                                         glVertex2fv(tface->uv[0]);
446                                         glVertex2fv(tface->uv[1]);
447                                 glEnd();
448
449                                 cpack(0xFF);
450                                 glBegin(GL_LINE_STRIP);
451                                         glVertex2fv(tface->uv[0]);
452                                         if(mface->v4) glVertex2fv(tface->uv[3]);
453                                         else glVertex2fv(tface->uv[2]);
454                                 glEnd();
455
456                                 cpack(0xFFFFFF);
457                                 glBegin(GL_LINE_STRIP);
458                                         glVertex2fv(tface->uv[1]);
459                                         glVertex2fv(tface->uv[2]);
460                                         if(mface->v4) glVertex2fv(tface->uv[3]);
461                                 glEnd();
462                                 
463                                 setlinestyle(0);
464                         }
465
466             /* unselected uv's */
467                         BIF_ThemeColor(TH_VERTEX);
468                         glPointSize(pointsize);
469
470                         bglBegin(GL_POINTS);
471                         tface= me->tface;
472                         mface= me->mface;
473                         a= me->totface;
474                         while(a--) {
475                                 if(tface->flag & TF_SELECT) {
476                                         
477                                         if(tface->flag & TF_SEL1); else bglVertex2fv(tface->uv[0]);
478                                         if(tface->flag & TF_SEL2); else bglVertex2fv(tface->uv[1]);
479                                         if(tface->flag & TF_SEL3); else bglVertex2fv(tface->uv[2]);
480                                         if(mface->v4) {
481                                                 if(tface->flag & TF_SEL4); else bglVertex2fv(tface->uv[3]);
482                                         }
483                                 }
484                                 tface++;
485                                 mface++;
486                         }
487                         bglEnd();
488
489                         /* pinned uv's */
490                         /* give odd pointsizes odd pin pointsizes */
491                 glPointSize(pointsize*2 + (((int)pointsize % 2)? (-1): 0));
492                         cpack(0xFF);
493
494                         bglBegin(GL_POINTS);
495                         tface= me->tface;
496                         mface= me->mface;
497                         a= me->totface;
498                         while(a--) {
499                                 if(tface->flag & TF_SELECT) {
500                                         
501                                         if(tface->unwrap & TF_PIN1) bglVertex2fv(tface->uv[0]);
502                                         if(tface->unwrap & TF_PIN2) bglVertex2fv(tface->uv[1]);
503                                         if(tface->unwrap & TF_PIN3) bglVertex2fv(tface->uv[2]);
504                                         if(mface->v4) {
505                                                 if(tface->unwrap & TF_PIN4) bglVertex2fv(tface->uv[3]);
506                                         }
507                                 }
508                                 tface++;
509                                 mface++;
510                         }
511                         bglEnd();
512
513                         /* selected uv's */
514                         BIF_ThemeColor(TH_VERTEX_SELECT);
515                 glPointSize(pointsize);
516
517                         bglBegin(GL_POINTS);
518                         tface= me->tface;
519                         mface= me->mface;
520                         a= me->totface;
521                         while(a--) {
522                                 if(tface->flag & TF_SELECT) {
523                                         
524                                         if(tface->flag & TF_SEL1) bglVertex2fv(tface->uv[0]);
525                                         if(tface->flag & TF_SEL2) bglVertex2fv(tface->uv[1]);
526                                         if(tface->flag & TF_SEL3) bglVertex2fv(tface->uv[2]);
527                                         if(mface->v4) {
528                                                 if(tface->flag & TF_SEL4) bglVertex2fv(tface->uv[3]);
529                                         }
530                                 }
531                                 tface++;
532                                 mface++;
533                         }
534                         bglEnd();
535                 }
536         }
537         glPointSize(1.0);
538 }
539
540 static unsigned int *get_part_from_ibuf(ImBuf *ibuf, short startx, short starty, short endx, short endy)
541 {
542         unsigned int *rt, *rp, *rectmain;
543         short y, heigth, len;
544
545         /* the right offset in rectot */
546
547         rt= ibuf->rect+ (starty*ibuf->x+ startx);
548
549         len= (endx-startx);
550         heigth= (endy-starty);
551
552         rp=rectmain= MEM_mallocN(heigth*len*sizeof(int), "rect");
553         
554         for(y=0; y<heigth; y++) {
555                 memcpy(rp, rt, len*4);
556                 rt+= ibuf->x;
557                 rp+= len;
558         }
559         return rectmain;
560 }
561
562 static void draw_image_transform(ImBuf *ibuf)
563 {
564         if(G.moving) {
565                 float aspx, aspy, center[3];
566
567         BIF_drawConstraint();
568
569                 if(ibuf==0 || ibuf->rect==0 || ibuf->x==0 || ibuf->y==0) {
570                         aspx= aspy= 1.0;
571                 }
572                 else {
573                         aspx= 256.0/ibuf->x;
574                         aspy= 256.0/ibuf->y;
575                 }
576
577                 BIF_getPropCenter(center);
578
579                 /* scale and translate the circle into place and draw it */
580                 glPushMatrix();
581                 glScalef(aspx, aspy, 1.0);
582                 glTranslatef((1/aspx)*center[0] - center[0],
583                              (1/aspy)*center[1] - center[1], 0.0);
584
585                 BIF_drawPropCircle();
586
587                 glPopMatrix();
588         }
589 }
590
591 static void draw_image_view_icon(void)
592 {
593         float xPos = 5.0;
594
595         glEnable(GL_BLEND);
596         glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA); 
597         
598         if(G.sima->flag & SI_STICKYUVS) {
599                 BIF_icon_draw(xPos, 5.0, ICON_STICKY2_UVS);
600                 xPos = 25.0;
601         }
602         else if(G.sima->flag & SI_LOCALSTICKY) {
603                 BIF_icon_draw(xPos, 5.0, ICON_STICKY_UVS);
604                 xPos = 25.0;
605         }
606
607         if(G.sima->flag & SI_SELACTFACE) {
608                 BIF_icon_draw(xPos, 5.0, ICON_DRAW_UVFACES);
609         }
610         
611         glBlendFunc(GL_ONE,  GL_ZERO); 
612         glDisable(GL_BLEND);
613 }
614
615 static void draw_image_view_tool(void)
616 {
617         ImagePaintTool *tool = &Gip.tool[Gip.current];
618         short mval[2];
619         float radius;
620         int draw= 0;
621
622         if(Gip.flag & IMAGEPAINT_DRAWING) {
623                 if(Gip.flag & IMAGEPAINT_DRAW_TOOL_DRAWING)
624                         draw= 1;
625         }
626         else if(Gip.flag & IMAGEPAINT_DRAW_TOOL)
627                 draw= 1;
628         
629         if(draw) {
630                 getmouseco_areawin(mval);
631
632                 radius= tool->size*G.sima->zoom/2;
633                 fdrawXORcirc(mval[0], mval[1], radius);
634
635                 if (tool->innerradius != 1.0) {
636                         radius *= tool->innerradius;
637                         fdrawXORcirc(mval[0], mval[1], radius);
638                 }
639         }
640 }
641
642 /* ************ panel stuff ************* */
643
644 // button define is local, only events defined here possible
645 #define B_TRANS_IMAGE   1
646
647 /* is used for both read and write... */
648 static void image_editvertex_buts(uiBlock *block)
649 {
650         static float ocent[2];
651         float cent[2]= {0.0, 0.0};
652         int imx, imy;
653         int i, nactive= 0, step, digits;
654         Mesh *me;
655         
656         if( is_uv_tface_editing_allowed_silent()==0 ) return;
657         me= get_mesh(OBACT);
658         
659         if (G.sima->image && G.sima->image->ibuf) {
660                 imx= G.sima->image->ibuf->x;
661                 imy= G.sima->image->ibuf->y;
662         } else
663                 imx= imy= 256;
664         
665         for (i=0; i<me->totface; i++) {
666                 MFace *mf= &((MFace*) me->mface)[i];
667                 TFace *tf= &((TFace*) me->tface)[i];
668                 
669                 if (!(tf->flag & TF_SELECT))
670                         continue;
671                 
672                 if (tf->flag & TF_SEL1) {
673                         cent[0]+= tf->uv[0][0];
674                         cent[1]+= tf->uv[0][1];
675                         nactive++;
676                 }
677                 if (tf->flag & TF_SEL2) {
678                         cent[0]+= tf->uv[1][0];
679                         cent[1]+= tf->uv[1][1];
680                         nactive++;
681                 }
682                 if (tf->flag & TF_SEL3) {
683                         cent[0]+= tf->uv[2][0];
684                         cent[1]+= tf->uv[2][1];
685                         nactive++;
686                 }
687                 if (mf->v4 && (tf->flag & TF_SEL4)) {
688                         cent[0]+= tf->uv[3][0];
689                         cent[1]+= tf->uv[3][1];
690                         nactive++;
691                 }
692         }
693                 
694         if(block) {     // do the buttons
695                 if (nactive) {
696                         ocent[0]= cent[0]/nactive;
697                         ocent[1]= cent[1]/nactive;
698                         if (G.sima->flag & SI_COORDFLOATS) {
699                                 step= 1;
700                                 digits= 3;
701                         }
702                         else {
703                                 ocent[0] *= imx;
704                                 ocent[1] *= imy;
705                                 step= 100;
706                                 digits= 2;
707                         }
708                         
709                         uiDefBut(block, LABEL, 0, "UV Vertex:",10,55,302,19,0,0,0,0,0,"");
710                         uiBlockBeginAlign(block);
711                         if(nactive==1) {
712                                 uiDefButF(block, NUM, B_TRANS_IMAGE, "Vertex X:",       10, 35, 290, 19, &ocent[0], -10*imx, 10.0*imx, step, digits, "");
713                                 uiDefButF(block, NUM, B_TRANS_IMAGE, "Vertex Y:",       10, 15, 290, 19, &ocent[1], -10*imy, 10.0*imy, step, digits, "");
714                         }
715                         else {
716                                 uiDefButF(block, NUM, B_TRANS_IMAGE, "Median X:",       10, 35, 290, 19, &ocent[0], -10*imx, 10.0*imx, step, digits, "");
717                                 uiDefButF(block, NUM, B_TRANS_IMAGE, "Median Y:",       10, 15, 290, 19, &ocent[1], -10*imy, 10.0*imy, step, digits, "");
718                         }
719                         uiBlockEndAlign(block);
720                 }
721         }
722         else {  // apply event
723                 float delta[2];
724                 
725                 cent[0]= cent[0]/nactive;
726                 cent[1]= cent[1]/nactive;
727                         
728                 if (G.sima->flag & SI_COORDFLOATS) {
729                         delta[0]= ocent[0]-cent[0];
730                         delta[1]= ocent[1]-cent[1];
731                 }
732                 else {
733                         delta[0]= ocent[0]/imx - cent[0];
734                         delta[1]= ocent[1]/imy - cent[1];
735                 }
736
737                 for (i=0; i<me->totface; i++) {
738                         MFace *mf= &((MFace*) me->mface)[i];
739                         TFace *tf= &((TFace*) me->tface)[i];
740                 
741                         if (!(tf->flag & TF_SELECT))
742                                 continue;
743                 
744                         if (tf->flag & TF_SEL1) {
745                                 tf->uv[0][0]+= delta[0];
746                                 tf->uv[0][1]+= delta[1];
747                         }
748                         if (tf->flag & TF_SEL2) {
749                                 tf->uv[1][0]+= delta[0];
750                                 tf->uv[1][1]+= delta[1];
751                         }
752                         if (tf->flag & TF_SEL3) {
753                                 tf->uv[2][0]+= delta[0];
754                                 tf->uv[2][1]+= delta[1];
755                         }
756                         if (mf->v4 && (tf->flag & TF_SEL4)) {
757                                 tf->uv[3][0]+= delta[0];
758                                 tf->uv[3][1]+= delta[1];
759                         }
760                 }
761                         
762                 allqueue(REDRAWVIEW3D, 0);
763                 allqueue(REDRAWIMAGE, 0);
764         }
765 }
766
767
768 void do_imagebuts(unsigned short event)
769 {
770         switch(event) {
771         case B_TRANS_IMAGE:
772                 image_editvertex_buts(NULL);
773                 break;
774
775         case B_SIMAGEDRAW:
776                 if(G.f & G_FACESELECT) {
777                         make_repbind(G.sima->image);
778                         image_changed(G.sima, 1);
779                 }
780                 allqueue(REDRAWVIEW3D, 0);
781                 allqueue(REDRAWIMAGE, 0);
782                 break;
783
784         case B_SIMAGEDRAW1:
785                 image_changed(G.sima, 2);               /* 2: only tileflag */
786                 allqueue(REDRAWVIEW3D, 0);
787                 allqueue(REDRAWIMAGE, 0);
788                 break;
789                 
790         case B_TWINANIM:
791                 {
792                         Image *ima;
793                         int nr;
794
795                         ima = G.sima->image;
796                         if (ima) {
797                                 if(ima->flag & IMA_TWINANIM) {
798                                         nr= ima->xrep*ima->yrep;
799                                         if(ima->twsta>=nr) ima->twsta= 1;
800                                         if(ima->twend>=nr) ima->twend= nr-1;
801                                         if(ima->twsta>ima->twend) ima->twsta= 1;
802                                         allqueue(REDRAWIMAGE, 0);
803                                 }
804                         }
805                 }
806                 break;
807
808         case B_SIMACLONEBROWSE:
809                 setcloneimage();
810                 allqueue(REDRAWIMAGE, 0);
811                 break;
812                 
813         case B_SIMACLONEDELETE:
814                 Gip.clone.image= NULL;
815                 allqueue(REDRAWIMAGE, 0);
816                 break;
817
818         case B_SIMABRUSHCHANGE:
819                 allqueue(REDRAWIMAGE, 0);
820                 break;
821                 
822         case B_SIMACURVES:
823                 curvemapping_do_image(G.sima->cumap, G.sima->image);
824                 allqueue(REDRAWIMAGE, 0);
825                 break;
826                 
827         case B_SIMARANGE:
828                 curvemapping_set_black_white(G.sima->cumap, NULL, NULL);
829                 curvemapping_do_image(G.sima->cumap, G.sima->image);
830                 allqueue(REDRAWIMAGE, 0);
831                 break;
832         }
833 }
834
835 static void image_panel_properties(short cntrl) // IMAGE_HANDLER_PROPERTIES
836 {
837         uiBlock *block;
838
839         block= uiNewBlock(&curarea->uiblocks, "image_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
840         uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
841         uiSetPanelHandler(IMAGE_HANDLER_PROPERTIES);  // for close and esc
842         if(uiNewPanel(curarea, block, "Properties", "Image", 10, 10, 318, 204)==0)
843                 return;
844
845         if (G.sima->image && G.sima->image->ibuf) {
846                 char str[64];
847
848                 sprintf(str, "Image: size %d x %d", G.sima->image->ibuf->x, G.sima->image->ibuf->y);
849                 if(G.sima->image->ibuf->rect_float)
850                         strcat(str, " 4x32 bits");
851                 else 
852                         strcat(str, " 4x8 bits");
853                 
854                 uiDefBut(block, LABEL, B_NOP, str,              10,180,300,19, 0, 0, 0, 0, 0, "");
855
856                 uiBlockBeginAlign(block);
857                 uiDefButBitS(block, TOG, IMA_TWINANIM, B_TWINANIM, "Anim", 10,150,140,19, &G.sima->image->tpageflag, 0, 0, 0, 0, "Toggles use of animated texture");
858                 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");
859                 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");
860                 uiDefButS(block, NUM, B_NOP, "Speed",                           10,90,140,19, &G.sima->image->animspeed, 1.0, 100.0, 0, 0, "Displays Speed of the animation in frames per second");
861                 uiBlockEndAlign(block);
862
863                 uiBlockBeginAlign(block);
864                 uiDefButBitS(block, TOG, IMA_TILES, B_SIMAGEDRAW1, "Tiles",     160,150,140,19, &G.sima->image->tpageflag, 0, 0, 0, 0, "Toggles use of tilemode for faces");
865                 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");
866                 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");
867                 uiBlockBeginAlign(block);
868         }
869
870         image_editvertex_buts(block);
871 }
872
873 static void image_panel_paint(short cntrl)      // IMAGE_HANDLER_PROPERTIES
874 {
875         /* B_SIMABRUSHCHANGE only redraws and eats the mouse messages  */
876         /* so that LEFTMOUSE does not 'punch' through the floating panel */
877         /* B_SIMANOTHING */
878         ImagePaintTool *tool= &Gip.tool[Gip.current];
879         uiBlock *block;
880         ID *id;
881
882         block= uiNewBlock(&curarea->uiblocks, "image_panel_paint", UI_EMBOSS, UI_HELV, curarea->win);
883         uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
884         uiSetPanelHandler(IMAGE_HANDLER_PAINT);  // for close and esc
885         if(uiNewPanel(curarea, block, "Image Paint", "Image", 10, 230, 318, 204)==0)
886                 return;
887
888         uiBlockBeginAlign(block);
889         uiDefButF(block, COL, B_VPCOLSLI, "",           979,160,230,19, tool->rgba, 0, 0, 0, 0, "");
890         uiDefButF(block, NUMSLI, B_SIMANOTHING , "Opacity ",            979,140,230,19, tool->rgba+3, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
891         uiDefButI(block, NUMSLI, B_SIMANOTHING , "Size ",               979,120,230,19, &tool->size, 2, 64, 0, 0, "The size of the brush");
892         uiDefButF(block, NUMSLI, B_SIMANOTHING , "Fall ",               979,100,230,19, &tool->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush");
893
894         if(Gip.current == IMAGEPAINT_BRUSH || Gip.current == IMAGEPAINT_SMEAR)
895                 uiDefButF(block, NUMSLI, B_SIMANOTHING , "Stepsize ",979,80,230,19, &tool->timing, 1.0, 100.0, 0, 0, "Repeating Paint On %of Brush diameter");
896         else
897                 uiDefButF(block, NUMSLI, B_SIMANOTHING , "Flow ",       979,80,230,19, &tool->timing, 1.0, 100.0, 0, 0, "Paint Flow for Air Brush");
898         uiBlockEndAlign(block);
899
900         uiBlockBeginAlign(block);
901         uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Brush",               890,160,80,19, &Gip.current, 7.0, IMAGEPAINT_BRUSH, 0, 0, "Brush");
902         uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "AirBrush",            890,140,80,19, &Gip.current, 7.0, IMAGEPAINT_AIRBRUSH, 0, 0, "AirBrush");
903         uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Soften",              890,120,80,19, &Gip.current, 7.0, IMAGEPAINT_SOFTEN, 0, 0, "Soften");
904         uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Aux AB1",             890,100,80,19, &Gip.current, 7.0, IMAGEPAINT_AUX1, 0, 0, "Auxiliary Air Brush1");
905         uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Aux AB2",             890,80,80,19, &Gip.current, 7.0, IMAGEPAINT_AUX2, 0, 0, "Auxiliary Air Brush2");        
906         uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Smear",               890,60,80,19, &Gip.current, 7.0, IMAGEPAINT_SMEAR, 0, 0, "Smear");      
907         uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Clone",               890,40,80,19, &Gip.current, 7.0, IMAGEPAINT_CLONE, 0, 0, "Clone Brush / use RMB to drag source image"); 
908         uiBlockEndAlign(block);
909
910         uiBlockBeginAlign(block);       
911         id= (ID*)Gip.clone.image;
912         std_libbuttons(block, 979, 40, 0, NULL, B_SIMACLONEBROWSE, ID_IM, 0, id, 0, &G.sima->menunr, 0, 0, B_SIMACLONEDELETE, 0, 0);
913         uiDefButF(block, NUMSLI, B_SIMABRUSHCHANGE, "B ",979,20,230,19, &Gip.clone.alpha , 0.0, 1.0, 0, 0, "Blend clone image");
914         uiBlockEndAlign(block);
915
916 #if 0
917         uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL_DRAWING, B_SIMABRUSHCHANGE, "TD", 890,1,50,19, &Gip.flag, 0, 0, 0, 0, "Enables tool shape while drawing");
918         uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL, B_SIMABRUSHCHANGE, "TP", 940,1,50,19, &Gip.flag, 0, 0, 0, 0, "Enables tool shape while not drawing");
919 #endif
920         uiDefButBitS(block, TOG|BIT, IMAGEPAINT_TORUS, B_SIMABRUSHCHANGE, "Wrap", 890,1,50,19, &Gip.flag, 0, 0, 0, 0, "Enables torus wrapping");
921 }
922
923 static void image_panel_curves_reset(void *cumap_v, void *unused)
924 {
925         CurveMapping *cumap = cumap_v;
926         int a;
927         
928         for(a=0; a<CM_TOT; a++)
929                 curvemap_reset(cumap->cm+a, &cumap->clipr);
930         
931         cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f;
932         cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f;
933         curvemapping_set_black_white(cumap, NULL, NULL);
934         
935         curvemapping_changed(cumap, 0);
936         curvemapping_do_image(cumap, G.sima->image);
937         
938         allqueue(REDRAWIMAGE, 0);
939 }
940
941
942 static void image_panel_curves(short cntrl)     // IMAGE_HANDLER_PROPERTIES
943 {
944         uiBlock *block;
945         uiBut *bt;
946         
947         block= uiNewBlock(&curarea->uiblocks, "image_panel_curves", UI_EMBOSS, UI_HELV, curarea->win);
948         uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
949         uiSetPanelHandler(IMAGE_HANDLER_CURVES);  // for close and esc
950         if(uiNewPanel(curarea, block, "Curves", "Image", 10, 450, 318, 204)==0)
951                 return;
952         
953         if (G.sima->image && G.sima->image->ibuf) {
954                 rctf rect;
955                 
956                 if(G.sima->cumap==NULL)
957                         G.sima->cumap= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
958                 
959                 rect.xmin= 110; rect.xmax= 310;
960                 rect.ymin= 10; rect.ymax= 200;
961                 curvemap_buttons(block, G.sima->cumap, 'c', B_SIMACURVES, B_SIMAGEDRAW, &rect);
962                 
963                 bt=uiDefBut(block, BUT, B_SIMARANGE, "Reset",   10, 160, 90, 19, NULL, 0.0f, 0.0f, 0, 0, "Reset Black/White point and curves");
964                 uiButSetFunc(bt, image_panel_curves_reset, G.sima->cumap, NULL);
965                 
966                 uiBlockBeginAlign(block);
967                 uiDefButF(block, NUM, B_SIMARANGE, "Min R:",    10, 120, 90, 19, G.sima->cumap->black, -1000.0f, 1000.0f, 10, 2, "Black level");
968                 uiDefButF(block, NUM, B_SIMARANGE, "Min G:",    10, 100, 90, 19, G.sima->cumap->black+1, -1000.0f, 1000.0f, 10, 2, "Black level");
969                 uiDefButF(block, NUM, B_SIMARANGE, "Min B:",    10, 80, 90, 19, G.sima->cumap->black+2, -1000.0f, 1000.0f, 10, 2, "Black level");
970                 
971                 uiBlockBeginAlign(block);
972                 uiDefButF(block, NUM, B_SIMARANGE, "Max R:",    10, 50, 90, 19, G.sima->cumap->white, -1000.0f, 1000.0f, 10, 2, "White level");
973                 uiDefButF(block, NUM, B_SIMARANGE, "Max G:",    10, 30, 90, 19, G.sima->cumap->white+1, -1000.0f, 1000.0f, 10, 2, "White level");
974                 uiDefButF(block, NUM, B_SIMARANGE, "Max B:",    10, 10, 90, 19, G.sima->cumap->white+2, -1000.0f, 1000.0f, 10, 2, "White level");
975                 
976         }
977 }
978
979
980
981 static void image_blockhandlers(ScrArea *sa)
982 {
983         SpaceImage *sima= sa->spacedata.first;
984         short a;
985
986         /* warning; blocks need to be freed each time, handlers dont remove  */
987         uiFreeBlocksWin(&sa->uiblocks, sa->win);
988         
989         for(a=0; a<SPACE_MAXHANDLER; a+=2) {
990                 switch(sima->blockhandler[a]) {
991
992                 case IMAGE_HANDLER_PROPERTIES:
993                         image_panel_properties(sima->blockhandler[a+1]);
994                         break;
995                 case IMAGE_HANDLER_PAINT:
996                         image_panel_paint(sima->blockhandler[a+1]);
997                         break;          
998                 case IMAGE_HANDLER_CURVES:
999                         image_panel_curves(sima->blockhandler[a+1]);
1000                         break;          
1001                 }
1002                 /* clear action value for event */
1003                 sima->blockhandler[a+1]= 0;
1004         }
1005         uiDrawBlocksPanels(sa, 0);
1006 }
1007
1008 static void imagespace_grid(SpaceImage *sima)
1009 {
1010         float gridsize, gridstep= 1.0f/32.0f;
1011         float fac, blendfac;
1012         
1013         gridsize= sima->zoom;
1014         
1015         if(gridsize<=0.0f) return;
1016         
1017         if(gridsize<1.0f) {
1018                 while(gridsize<1.0f) {
1019                         gridsize*= 4.0;
1020                         gridstep*= 4.0;
1021                 }
1022         }
1023         else {
1024                 while(gridsize>=4.0f) {
1025                         gridsize/= 4.0;
1026                         gridstep/= 4.0;
1027                 }
1028         }
1029         
1030         /* the fine resolution level */
1031         blendfac= 0.25*gridsize - floor(0.25*gridsize);
1032         CLAMP(blendfac, 0.0, 1.0);
1033         BIF_ThemeColorShade(TH_BACK, (int)(20.0*(1.0-blendfac)));
1034         
1035         fac= 0.0f;
1036         glBegin(GL_LINES);
1037         while(fac<1.0) {
1038                 glVertex2f(0.0f, fac);
1039                 glVertex2f(1.0f, fac);
1040                 glVertex2f(fac, 0.0f);
1041                 glVertex2f(fac, 1.0f);
1042                 fac+= gridstep;
1043         }
1044         
1045         /* the large resolution level */
1046         BIF_ThemeColor(TH_BACK);
1047         
1048         fac= 0.0f;
1049         while(fac<1.0) {
1050                 glVertex2f(0.0f, fac);
1051                 glVertex2f(1.0f, fac);
1052                 glVertex2f(fac, 0.0f);
1053                 glVertex2f(fac, 1.0f);
1054                 fac+= 4.0*gridstep;
1055         }
1056         glEnd();
1057         
1058 }
1059
1060 void drawimagespace(ScrArea *sa, void *spacedata)
1061 {
1062         SpaceImage *sima= spacedata;
1063         ImBuf *ibuf= NULL;
1064         float col[3];
1065         unsigned int *rect;
1066         int x1, y1;
1067         short sx, sy, dx, dy;
1068         
1069                 /* If derived data is used then make sure that object
1070                  * is up-to-date... might not be the case because updates
1071                  * are normally done in drawview and could get here before
1072                  * drawing a View3D.
1073                  */
1074         if (!G.obedit && OBACT && (sima->flag & SI_DRAWSHADOW)) {
1075                 object_handle_update(OBACT);
1076         }
1077
1078         BIF_GetThemeColor3fv(TH_BACK, col);
1079         glClearColor(col[0], col[1], col[2], 0.0);
1080         glClear(GL_COLOR_BUFFER_BIT);
1081
1082         bwin_clear_viewmat(sa->win);    /* clear buttons view */
1083         glLoadIdentity();
1084         
1085         what_image(sima);
1086         
1087         if(sima->image) {
1088                 if(sima->image->ibuf==0) {
1089                         load_image(sima->image, IB_rect, G.sce, G.scene->r.cfra);
1090                 }       
1091                 tag_image_time(sima->image);
1092                 ibuf= sima->image->ibuf;
1093         }
1094         
1095         if(ibuf==NULL || ibuf->rect==NULL) {
1096                 calc_image_view(sima, 'f');
1097                 myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
1098                 BIF_ThemeColorShade(TH_BACK, 20);
1099                 glRectf(0.0, 0.0, 1.0, 1.0);
1100                 imagespace_grid(sima);
1101                 draw_tfaces();
1102         }
1103         else {
1104                 /* calc location */
1105                 x1= (curarea->winx-sima->zoom*ibuf->x)/2;
1106                 y1= (curarea->winy-sima->zoom*ibuf->y)/2;
1107         
1108                 x1-= sima->zoom*sima->xof;
1109                 y1-= sima->zoom*sima->yof;
1110                 
1111                 /* needed for gla draw */
1112                 glaDefine2DArea(&curarea->winrct);
1113                 glPixelZoom((float)sima->zoom, (float)sima->zoom);
1114                                 
1115                 if(sima->flag & SI_EDITTILE) {
1116                         glaDrawPixelsSafe(x1, y1, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect);
1117                         
1118                         glPixelZoom(1.0, 1.0);
1119                         
1120                         dx= ibuf->x/sima->image->xrep;
1121                         dy= ibuf->y/sima->image->yrep;
1122                         sy= (sima->curtile / sima->image->xrep);
1123                         sx= sima->curtile - sy*sima->image->xrep;
1124         
1125                         sx*= dx;
1126                         sy*= dy;
1127                         
1128                         calc_image_view(sima, 'p');     /* pixel */
1129                         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
1130                         
1131                         cpack(0x0);
1132                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glRects(sx,  sy,  sx+dx-1,  sy+dy-1); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1133                         cpack(0xFFFFFF);
1134                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glRects(sx+1,  sy+1,  sx+dx,  sy+dy); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1135                 }
1136                 else if(sima->mode==SI_TEXTURE) {
1137                         
1138                         if(sima->image->tpageflag & IMA_TILES) {
1139                                 
1140                                 /* just leave this a while */
1141                                 if(sima->image->xrep<1) return;
1142                                 if(sima->image->yrep<1) return;
1143                                 
1144                                 if(sima->curtile >= sima->image->xrep*sima->image->yrep) 
1145                                         sima->curtile = sima->image->xrep*sima->image->yrep - 1; 
1146                                 
1147                                 dx= ibuf->x/sima->image->xrep;
1148                                 dy= ibuf->y/sima->image->yrep;
1149                                 
1150                                 sy= (sima->curtile / sima->image->xrep);
1151                                 sx= sima->curtile - sy*sima->image->xrep;
1152                 
1153                                 sx*= dx;
1154                                 sy*= dy;
1155                                 
1156                                 rect= get_part_from_ibuf(ibuf, sx, sy, sx+dx, sy+dy);
1157                                 
1158                                 /* rect= ibuf->rect; */
1159                                 for(sy= 0; sy+dy<=ibuf->y; sy+= dy) {
1160                                         for(sx= 0; sx+dx<=ibuf->x; sx+= dx) {
1161                                                 glaDrawPixelsSafe(x1+sx*sima->zoom, y1+sy*sima->zoom, dx, dy, GL_UNSIGNED_BYTE, rect);
1162                                         }
1163                                 }
1164                                 
1165                                 MEM_freeN(rect);
1166                         }
1167                         else 
1168                                 glaDrawPixelsSafe(x1, y1, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect);
1169                         
1170                         if(Gip.current == IMAGEPAINT_CLONE) {
1171                                 int w, h;
1172                                 unsigned char *clonerect;
1173
1174                                 /* this is not very efficient, but glDrawPixels doesn't allow
1175                                    drawing with alpha */
1176                                 clonerect= alloc_alpha_clone_image(&w, &h);
1177
1178                                 if(clonerect) {
1179                                         int offx, offy;
1180                                         offx = sima->zoom*ibuf->x * + Gip.clone.offset[0];
1181                                         offy = sima->zoom*ibuf->y * + Gip.clone.offset[1];
1182
1183                                         glEnable(GL_BLEND);
1184                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1185                                         glaDrawPixelsSafe(x1 + offx, y1 + offy, w, h, GL_UNSIGNED_BYTE, clonerect);
1186                                         glDisable(GL_BLEND);
1187
1188                                         MEM_freeN(clonerect);
1189                                 }
1190                         }
1191                         
1192                         glPixelZoom(1.0, 1.0);
1193                         
1194                         draw_tfaces();
1195                 }
1196         
1197                 calc_image_view(sima, 'f');     /* float */
1198         }
1199
1200         draw_image_transform(ibuf);
1201
1202         mywinset(sa->win);      /* restore scissor after gla call... */
1203         myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
1204
1205         draw_image_view_tool();
1206         draw_image_view_icon();
1207         draw_area_emboss(sa);
1208
1209         /* it is important to end a view in a transform compatible with buttons */
1210         bwin_scalematrix(sa->win, sima->blockscale, sima->blockscale, sima->blockscale);
1211         image_blockhandlers(sa);
1212
1213         curarea->win_swap= WIN_BACK_OK;
1214 }
1215
1216 static void image_zoom_power_of_two(void)
1217 {
1218         /* Make zoom a power of 2 */
1219
1220         G.sima->zoom = 1 / G.sima->zoom;
1221         G.sima->zoom = log(G.sima->zoom) / log(2);
1222         G.sima->zoom = ceil(G.sima->zoom);
1223         G.sima->zoom = pow(2, G.sima->zoom);
1224         G.sima->zoom = 1 / G.sima->zoom;
1225 }
1226
1227 static void image_zoom_set_factor(float zoomfac)
1228 {
1229         SpaceImage *sima= curarea->spacedata.first;
1230         int width, height;
1231
1232         if (zoomfac <= 0.0f)
1233                 return;
1234
1235         sima->zoom *= zoomfac;
1236
1237         if (sima->zoom > 0.1f && sima->zoom < 4.0f)
1238                 return;
1239
1240         /* check zoom limits */
1241
1242         calc_image_view(G.sima, 'p');
1243         width= 256;
1244         height= 256;
1245         if (sima->image) {
1246                 if (sima->image->ibuf) {
1247                         width= sima->image->ibuf->x;
1248                         height= sima->image->ibuf->y;
1249                 }
1250         }
1251         width *= sima->zoom;
1252         height *= sima->zoom;
1253
1254         if ((width < 4) && (height < 4))
1255                 sima->zoom /= zoomfac;
1256         else if((curarea->winrct.xmax - curarea->winrct.xmin) <= sima->zoom)
1257                 sima->zoom /= zoomfac;
1258         else if((curarea->winrct.ymax - curarea->winrct.ymin) <= sima->zoom)
1259                 sima->zoom /= zoomfac;
1260 }
1261
1262 void image_viewmove(int mode)
1263 {
1264         short mval[2], mvalo[2], zoom0;
1265         
1266         getmouseco_sc(mvalo);
1267         zoom0= G.sima->zoom;
1268         
1269         while(get_mbut()&(L_MOUSE|M_MOUSE)) {
1270
1271                 getmouseco_sc(mval);
1272
1273                 if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
1274                 
1275                         if(mode==0) {
1276                                 G.sima->xof += (mvalo[0]-mval[0])/G.sima->zoom;
1277                                 G.sima->yof += (mvalo[1]-mval[1])/G.sima->zoom;
1278                         }
1279                         else if (mode==1) {
1280                                 float factor;
1281
1282                                 factor= 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/300.0;
1283                                 image_zoom_set_factor(factor);
1284                         }
1285
1286                         mvalo[0]= mval[0];
1287                         mvalo[1]= mval[1];
1288                         
1289                         scrarea_do_windraw(curarea);
1290                         screen_swapbuffers();
1291                 }
1292                 else BIF_wait_for_statechange();
1293         }
1294 }
1295
1296 void image_viewzoom(unsigned short event, int invert)
1297 {
1298         SpaceImage *sima= curarea->spacedata.first;
1299
1300         if(event==WHEELDOWNMOUSE || event==PADMINUS)
1301                 image_zoom_set_factor((U.uiflag & USER_WHEELZOOMDIR)? 1.25: 0.8);
1302         else if(event==WHEELUPMOUSE || event==PADPLUSKEY)
1303                 image_zoom_set_factor((U.uiflag & USER_WHEELZOOMDIR)? 0.8: 1.25);
1304         else if(event==PAD1)
1305                 sima->zoom= 1.0;
1306         else if(event==PAD2)
1307                 sima->zoom= (invert)? 2.0: 0.5;
1308         else if(event==PAD4)
1309                 sima->zoom= (invert)? 4.0: 0.25;
1310         else if(event==PAD8)
1311                 sima->zoom= (invert)? 8.0: 0.125;
1312         else
1313                 return;
1314 }
1315
1316 /**
1317  * Updates the fields of the View2D member of the SpaceImage struct.
1318  * Default behavior is to reset the position of the image and set the zoom to 1
1319  * If the image will not fit within the window rectangle, the zoom is adjusted
1320  *
1321  * @return    void
1322  *   
1323  */
1324 void image_home(void)
1325 {
1326         int width, height;
1327         float zoomX, zoomY;
1328
1329         if (curarea->spacetype != SPACE_IMAGE) return;
1330         if ((G.sima->image == 0) || (G.sima->image->ibuf == 0)) return;
1331
1332         /* Check if the image will fit in the image with zoom==1 */
1333         width = curarea->winx;
1334         height = curarea->winy;
1335         if (((G.sima->image->ibuf->x >= width) || (G.sima->image->ibuf->y >= height)) && 
1336                 ((width > 0) && (height > 0))) {
1337                 /* Find the zoom value that will fit the image in the image space */
1338                 zoomX = ((float)width) / ((float)G.sima->image->ibuf->x);
1339                 zoomY = ((float)height) / ((float)G.sima->image->ibuf->y);
1340                 G.sima->zoom= MIN2(zoomX, zoomY);
1341
1342                 image_zoom_power_of_two();
1343         }
1344         else {
1345                 G.sima->zoom= (float)1;
1346         }
1347
1348         G.sima->xof= G.sima->yof= 0;
1349         
1350         calc_image_view(G.sima, 'p');
1351         
1352         scrarea_queue_winredraw(curarea);
1353 }
1354
1355 void image_viewcentre(void)
1356 {
1357         float size, min[2], max[2], d[2], xim=256.0f, yim=256.0f;
1358
1359         if( is_uv_tface_editing_allowed()==0 ) return;
1360
1361         if (!minmax_tface_uv(min, max)) return;
1362
1363         if(G.sima->image && G.sima->image->ibuf) {
1364                 xim= G.sima->image->ibuf->x;
1365                 yim= G.sima->image->ibuf->y;
1366         }
1367
1368         G.sima->xof= ((min[0] + max[0])*0.5f - 0.5f)*xim;
1369         G.sima->yof= ((min[1] + max[1])*0.5f - 0.5f)*yim;
1370
1371         d[0] = max[0] - min[0];
1372         d[1] = max[1] - min[1];
1373         size= 0.5*MAX2(d[0], d[1])*MAX2(xim, yim)/256.0f;
1374         
1375         if(size<=0.01) size= 0.01;
1376
1377         G.sima->zoom= 0.7/size;
1378
1379         calc_image_view(G.sima, 'p');
1380
1381         scrarea_queue_winredraw(curarea);
1382 }
1383