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