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