- removed temporal patch from myortho2() in mywindow.c, and changed
[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 #include "BLI_editVert.h"
50
51 #include "IMB_imbuf_types.h"
52
53 #include "DNA_image_types.h"
54 #include "DNA_mesh_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
67 #include "BIF_gl.h"
68 #include "BIF_space.h"
69 #include "BIF_screen.h"
70 #include "BIF_mywindow.h"
71 #include "BIF_drawimage.h"
72 #include "BIF_resources.h"
73
74 /* Modules used */
75 #include "mydevice.h"
76 #include "render.h"
77
78
79 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)
80 {
81         int cx, cy, oldxim, x2, y2;
82         
83         oldxim= xim;
84                 
85         /* coordinates how its drawn at the screen */
86         x2= x1+ zoomx*xim;
87         y2= y1+ zoomy*yim;
88
89         /* partial clip */
90         if(x1<winxmin) {
91                 /* with OpenGL, rects are not allowed to start outside of the left/bottom window edge */
92                 cx= winxmin-x1+(int)zoomx;
93                 /* make sure the rect will be drawn pixel-exact */
94                 cx/= zoomx;
95                 cx++;
96                 x1+= zoomx*cx;
97                 xim-= cx;
98                 rect+= cx;
99         }
100         if(y1<winymin) {
101                 cy= winymin-y1+(int)zoomy;
102                 cy/= zoomy;
103                 cy++;
104                 y1+= zoomy*cy;
105                 rect+= cy*oldxim;
106                 yim-= cy;
107         }
108         if(x2>=winxmax) {
109                 cx= x2-winxmax;
110                 cx/= zoomx;
111                 xim-= cx+3;
112         }
113         if(y2>=winymax) {
114                 cy= y2-winymax;
115                 cy/= zoomy;
116                 yim-= cy+3;
117         }
118         
119         if(xim<=0) return;
120         if(yim<=0) return;
121
122         mywinset(G.curscreen->mainwin);
123         glScissor(winxmin, winymin, winxmax-winxmin+1, winymax-winymin+1);
124         
125         glPixelStorei(GL_UNPACK_ROW_LENGTH,  oldxim);
126         
127         glPixelZoom(zoomx,  zoomy);
128
129         glRasterPos2i(x1, y1);
130         glDrawPixels(xim, yim, GL_RGBA, GL_UNSIGNED_BYTE,  rect);
131
132         glPixelZoom(1.0,  1.0);
133
134         glPixelStorei(GL_UNPACK_ROW_LENGTH,  0);
135         
136         mywinset(curarea->win);
137 }
138
139 /**
140  * Sets up the fields of the View2D member of the SpaceImage struct
141  * This routine can be called in two modes:
142  * mode == 'f': float mode ???
143  * mode == 'p': pixel mode ???
144  *
145  * @param     sima  the image space to update
146  * @param     mode  the mode to use for the update
147  * @return    void
148  *   
149  */
150 void calc_image_view(SpaceImage *sima, char mode)
151 {
152         float xim=256, yim=256;
153         float x1, y1;
154         float zoom;
155         
156         if(sima->image && sima->image->ibuf) {
157                 xim= sima->image->ibuf->x;
158                 yim= sima->image->ibuf->y;
159         }
160         
161         sima->v2d.tot.xmin= 0;
162         sima->v2d.tot.ymin= 0;
163         sima->v2d.tot.xmax= xim;
164         sima->v2d.tot.ymax= yim;
165         
166         sima->v2d.mask.xmin= sima->v2d.mask.ymin= 0;
167         sima->v2d.mask.xmax= curarea->winx;
168         sima->v2d.mask.ymax= curarea->winy;
169
170
171         /* Which part of the image space do we see? */
172         /* Same calculation as in lrectwrite: area left and down*/
173         x1= curarea->winrct.xmin+(curarea->winx-sima->zoom*xim)/2;
174         y1= curarea->winrct.ymin+(curarea->winy-sima->zoom*yim)/2;
175
176         x1-= sima->zoom*sima->xof;
177         y1-= sima->zoom*sima->yof;
178
179         /* float! */
180         zoom= sima->zoom;
181         
182         /* relative display right */
183         sima->v2d.cur.xmin= ((curarea->winrct.xmin - (float)x1)/zoom);
184         sima->v2d.cur.xmax= sima->v2d.cur.xmin + ((float)curarea->winx/zoom);
185         
186         /* relative display left */
187         sima->v2d.cur.ymin= ((curarea->winrct.ymin-(float)y1)/zoom);
188         sima->v2d.cur.ymax= sima->v2d.cur.ymin + ((float)curarea->winy/zoom);
189         
190         if(mode=='f') {         
191                 sima->v2d.cur.xmin/= xim;
192                 sima->v2d.cur.xmax/= xim;
193                 sima->v2d.cur.ymin/= yim;
194                 sima->v2d.cur.ymax/= yim;
195         }
196 }
197
198 void what_image(SpaceImage *sima)
199 {
200         extern TFace *lasttface;        /* editface.c */
201         Mesh *me;
202                 
203         if(sima->mode==SI_TEXTURE) {
204                 if(G.f & G_FACESELECT) {
205
206                         sima->image= 0;
207                         me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
208                         set_lasttface();
209                         
210                         if(me && me->tface && lasttface) {
211                                 if(lasttface->mode & TF_TEX) {
212                                         sima->image= lasttface->tpage;
213                                         
214                                         if(sima->flag & SI_EDITTILE);
215                                         else sima->curtile= lasttface->tile;
216                                         
217                                         if(sima->image) {
218                                                 if(lasttface->mode & TF_TILES) sima->image->tpageflag |= IMA_TILES;
219                                                 else sima->image->tpageflag &= ~IMA_TILES;
220                                         }
221                                 }
222                         }
223                 }
224         }
225 }
226
227 void image_changed(SpaceImage *sima, int dotile)
228 {
229         TFace *tface;
230         Mesh *me;
231         int a;
232         
233         if(sima->mode==SI_TEXTURE) {
234                 
235                 if(G.f & G_FACESELECT) {
236                         me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
237                         if(me && me->tface) {
238                                 tface= me->tface;
239                                 a= me->totface;
240                                 while(a--) {
241                                         if(tface->flag & TF_SELECT) {
242                                                 
243                                                 if(dotile==2) {
244                                                         tface->mode &= ~TF_TILES;
245                                                 }
246                                                 else {
247                                                         tface->tpage= sima->image;
248                                                         tface->mode |= TF_TEX;
249                                                 
250                                                         if(dotile) tface->tile= sima->curtile;
251                                                 }
252                                                 
253                                                 if(sima->image) {
254                                                         if(sima->image->tpageflag & IMA_TILES) tface->mode |= TF_TILES;
255                                                         else tface->mode &= ~TF_TILES;
256                                                 
257                                                         if(sima->image->id.us==0) sima->image->id.us= 1;
258                                                 }
259                                         }
260                                         tface++;
261                                 }
262                                 allqueue(REDRAWVIEW3D, 0);
263                                 allqueue(REDRAWBUTSEDIT, 0);
264                         }
265                 }
266         }
267 }
268
269
270 void uvco_to_areaco(float *vec, short *mval)
271 {
272         float x, y;
273
274         mval[0]= 3200;
275         
276         x= (vec[0] - G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
277         y= (vec[1] - G.v2d->cur.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
278
279         if(x>=0.0 && x<=1.0) {
280                 if(y>=0.0 && y<=1.0) {          
281                         mval[0]= G.v2d->mask.xmin + x*(G.v2d->mask.xmax-G.v2d->mask.xmin);
282                         mval[1]= G.v2d->mask.ymin + y*(G.v2d->mask.ymax-G.v2d->mask.ymin);
283                 }
284         }
285 }
286
287 void uvco_to_areaco_noclip(float *vec, short *mval)
288 {
289         float x, y;
290
291         mval[0]= 3200;
292         
293         x= (vec[0] - G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
294         y= (vec[1] - G.v2d->cur.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
295
296         x= G.v2d->mask.xmin + x*(G.v2d->mask.xmax-G.v2d->mask.xmin);
297         y= G.v2d->mask.ymin + y*(G.v2d->mask.ymax-G.v2d->mask.ymin);
298         
299         mval[0]= x;
300         mval[1]= y;
301 }
302
303
304 void draw_tfaces(void)
305 {
306         TFace *tface;
307         MFace *mface;
308         Mesh *me;
309         int a;
310         
311         glPointSize(2.0);
312         
313         if(G.f & G_FACESELECT) {
314                 me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
315                 if(me && me->tface) {
316                         
317                         calc_image_view(G.sima, 'f');   /* float */
318                         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
319
320                         tface= me->tface;
321                         mface= me->mface;
322                         a= me->totface;
323                         
324                         while(a--) {
325                                 if(mface->v3 && (tface->flag & TF_SELECT) ) {
326                                 
327                                         cpack(0x0);
328                                         glBegin(GL_LINE_LOOP);
329                                                 glVertex2fv( tface->uv[0] );
330                                                 glVertex2fv( tface->uv[1] );
331                                                 glVertex2fv( tface->uv[2] );
332                                                 if(mface->v4) glVertex2fv( tface->uv[3] );
333                                         glEnd();
334                                 
335                                         setlinestyle(2);
336                                         /* colors: R=x G=y */
337                                         
338                                         if(tface->flag & TF_ACTIVE) cpack(0xFF00); 
339                                         else cpack(0xFFFFFF);
340         
341                                         glBegin(GL_LINE_STRIP);
342                                                 glVertex2fv( tface->uv[0] );
343                                                 glVertex2fv( tface->uv[1] );
344                                         glEnd();
345                                         
346                                         if(tface->flag & TF_ACTIVE) cpack(0xFF); else cpack(0xFFFFFF);
347         
348                                         glBegin(GL_LINE_STRIP);
349                                                 glVertex2fv( tface->uv[0] );
350                                                 if(mface->v4) glVertex2fv( tface->uv[3] ); else glVertex2fv( tface->uv[2] );
351                                         glEnd();
352                                         
353                                         cpack(0xFFFFFF);
354         
355                                         glBegin(GL_LINE_STRIP);
356                                                 glVertex2fv( tface->uv[1] );
357                                                 glVertex2fv( tface->uv[2] );
358                                                 if(mface->v4) glVertex2fv( tface->uv[3] );
359                                         glEnd();
360                                         
361                                         setlinestyle(0);
362                                         
363                                         glBegin(GL_POINTS);
364                                         
365                                         if(tface->flag & TF_SEL1) BIF_ThemeColor(TH_VERTEX_SELECT); 
366                                         else BIF_ThemeColor(TH_VERTEX); 
367                                         glVertex2fv(tface->uv[0]);
368                                         
369                                         if(tface->flag & TF_SEL2) BIF_ThemeColor(TH_VERTEX_SELECT); 
370                                         else BIF_ThemeColor(TH_VERTEX); 
371                                         glVertex2fv(tface->uv[1]);
372                                         
373                                         if(tface->flag & TF_SEL3) BIF_ThemeColor(TH_VERTEX_SELECT); 
374                                         else BIF_ThemeColor(TH_VERTEX); 
375                                         glVertex2fv(tface->uv[2]);
376                                         
377                                         if(mface->v4) {
378                                                 if(tface->flag & TF_SEL4) BIF_ThemeColor(TH_VERTEX_SELECT); 
379                                                 else BIF_ThemeColor(TH_VERTEX); 
380                                                 glVertex2fv(tface->uv[3]);
381                                         }
382                                         glEnd();
383                                 }
384                                         
385                                 tface++;
386                                 mface++;
387                         }
388                 }
389         }
390         glPointSize(1.0);
391 }
392
393 static unsigned int *get_part_from_ibuf(ImBuf *ibuf, short startx, short starty, short endx, short endy)
394 {
395         unsigned int *rt, *rp, *rectmain;
396         short y, heigth, len;
397
398         /* the right offset in rectot */
399
400         rt= ibuf->rect+ (starty*ibuf->x+ startx);
401
402         len= (endx-startx);
403         heigth= (endy-starty);
404
405         rp=rectmain= MEM_mallocN(heigth*len*sizeof(int), "rect");
406         
407         for(y=0; y<heigth; y++) {
408                 memcpy(rp, rt, len*4);
409                 rt+= ibuf->x;
410                 rp+= len;
411         }
412         return rectmain;
413 }
414
415 void drawimagespace(ScrArea *sa, void *spacedata)
416 {
417         ImBuf *ibuf= NULL;
418         float col[3];
419         unsigned int *rect;
420         int x1, y1, xmin, xmax, ymin, ymax;
421         short sx, sy, dx, dy;
422         
423         BIF_GetThemeColor3fv(TH_BACK, col);
424         glClearColor(col[0], col[1], col[2], 0.0);
425         glClear(GL_COLOR_BUFFER_BIT);
426
427
428         curarea->win_swap= WIN_BACK_OK;
429         
430         xmin= curarea->winrct.xmin; xmax= curarea->winrct.xmax;
431         ymin= curarea->winrct.ymin; ymax= curarea->winrct.ymax;
432         
433         what_image(G.sima);
434         
435         if(G.sima->image) {
436         
437                 if(G.sima->image->ibuf==0) {
438                         load_image(G.sima->image, IB_rect, G.sce, G.scene->r.cfra);
439                 }       
440                 ibuf= G.sima->image->ibuf;
441         }
442         
443         if(ibuf==0 || ibuf->rect==0) {
444                 calc_image_view(G.sima, 'f');
445                 myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
446                 cpack(0x404040);
447                 glRectf(0.0, 0.0, 1.0, 1.0);
448                 draw_tfaces();
449         }
450         else {
451                 /* calc location */
452                 x1= xmin+(curarea->winx-G.sima->zoom*ibuf->x)/2;
453                 y1= ymin+(curarea->winy-G.sima->zoom*ibuf->y)/2;
454         
455                 x1-= G.sima->zoom*G.sima->xof;
456                 y1-= G.sima->zoom*G.sima->yof;
457         
458                 
459                 if(G.sima->flag & SI_EDITTILE) {
460                         rectwrite_part(xmin, ymin, xmax, ymax, x1, y1, ibuf->x, ibuf->y, (float)G.sima->zoom, (float)G.sima->zoom, ibuf->rect);
461                         
462                         dx= ibuf->x/G.sima->image->xrep;
463                         dy= ibuf->y/G.sima->image->yrep;
464                         sy= (G.sima->curtile / G.sima->image->xrep);
465                         sx= G.sima->curtile - sy*G.sima->image->xrep;
466         
467                         sx*= dx;
468                         sy*= dy;
469                         
470                         calc_image_view(G.sima, 'p');   /* pixel */
471                         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
472                         
473                         cpack(0x0);
474                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glRects(sx,  sy,  sx+dx-1,  sy+dy-1); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
475                         cpack(0xFFFFFF);
476                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glRects(sx+1,  sy+1,  sx+dx,  sy+dy); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
477                 }
478                 else if(G.sima->mode==SI_TEXTURE) {
479                         if(G.sima->image->tpageflag & IMA_TILES) {
480                                 
481                                 
482                                 /* just leave this a while */
483                                 if(G.sima->image->xrep<1) return;
484                                 if(G.sima->image->yrep<1) return;
485                                 
486                                 if(G.sima->curtile >= G.sima->image->xrep*G.sima->image->yrep) 
487                                         G.sima->curtile = G.sima->image->xrep*G.sima->image->yrep - 1; 
488                                 
489                                 dx= ibuf->x/G.sima->image->xrep;
490                                 dy= ibuf->y/G.sima->image->yrep;
491                                 
492                                 sy= (G.sima->curtile / G.sima->image->xrep);
493                                 sx= G.sima->curtile - sy*G.sima->image->xrep;
494                 
495                                 sx*= dx;
496                                 sy*= dy;
497                                 
498                                 rect= get_part_from_ibuf(ibuf, sx, sy, sx+dx, sy+dy);
499                                 
500                                 /* rect= ibuf->rect; */
501                                 for(sy= 0; sy+dy<=ibuf->y; sy+= dy) {
502                                         for(sx= 0; sx+dx<=ibuf->x; sx+= dx) {
503                                                 
504                                                 rectwrite_part(xmin, ymin, xmax, ymax, 
505                                                         x1+sx*G.sima->zoom, y1+sy*G.sima->zoom, dx, dy, (float)G.sima->zoom, (float)G.sima->zoom, rect);
506                                         }
507                                 }
508                                 
509                                 MEM_freeN(rect);
510                         }
511                         else 
512                                 rectwrite_part(xmin, ymin, xmax, ymax, x1, y1, ibuf->x, ibuf->y, (float)G.sima->zoom,(float)G.sima->zoom, ibuf->rect);
513                 
514                         draw_tfaces();
515                 }
516         
517                 calc_image_view(G.sima, 'f');   /* float */
518         }
519         myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
520         draw_area_emboss(sa);
521         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
522 }
523
524 void image_viewmove(void)
525 {
526         short mval[2], mvalo[2], xof, yof;
527         
528         getmouseco_sc(mvalo);
529         
530         while(get_mbut()&(L_MOUSE|M_MOUSE)) {
531
532                 getmouseco_sc(mval);
533                 
534                 xof= (mvalo[0]-mval[0])/G.sima->zoom;
535                 yof= (mvalo[1]-mval[1])/G.sima->zoom;
536                 
537                 if(xof || yof) {
538                         
539                         G.sima->xof+= xof;
540                         G.sima->yof+= yof;
541                         
542                         mvalo[0]= mval[0];
543                         mvalo[1]= mval[1];
544                         
545                         scrarea_do_windraw(curarea);
546                         screen_swapbuffers();
547                 }               
548                 else BIF_wait_for_statechange();
549         }
550 }
551
552 void image_viewzoom(unsigned short event)
553 {
554         SpaceImage *sima= curarea->spacedata.first;
555         int width, height;
556
557         if(U.uiflag & WHEELZOOMDIR) {
558                 if (event==WHEELDOWNMOUSE || event == PADPLUSKEY) {
559                         sima->zoom *= 2;
560                 } else {
561                         sima->zoom /= 2;
562                         /* Check if the image will still be visible after zooming out */
563                         if (sima->zoom < 1) {
564                                 calc_image_view(G.sima, 'p');
565                                 if (sima->image) {
566                                         if (sima->image->ibuf) {
567                                                 width = sima->image->ibuf->x * sima->zoom;
568                                                 height = sima->image->ibuf->y * sima->zoom;
569                                                 if ((width < 4) && (height < 4)) {
570                                                         /* Image will become too small, reset value */
571                                                         sima->zoom *= 2;
572                                                 }
573                                         }
574                                 }
575                         }
576                 }
577         } else {
578                 if (event==WHEELUPMOUSE || event == PADPLUSKEY) {
579                         sima->zoom *= 2;
580                 } else {
581                         sima->zoom /= 2;
582                         /* Check if the image will still be visible after zooming out */
583                         if (sima->zoom < 1) {
584                                 calc_image_view(G.sima, 'p');
585                                 if (sima->image) {
586                                         if (sima->image->ibuf) {
587                                                 width = sima->image->ibuf->x * sima->zoom;
588                                                 height = sima->image->ibuf->y * sima->zoom;
589                                                 if ((width < 4) && (height < 4)) {
590                                                         /* Image will become too small, reset value */
591                                                         sima->zoom *= 2;
592                                                 }
593                                         }
594                                 }
595                         }
596                 }
597         }
598 }
599
600 /**
601  * Updates the fields of the View2D member of the SpaceImage struct.
602  * Default behavior is to reset the position of the image and set the zoom to 1
603  * If the image will not fit within the window rectangle, the zoom is adjusted
604  *
605  * @return    void
606  *   
607  */
608 void image_home(void)
609 {
610         int width, height;
611         float zoomX, zoomY;
612
613         if (curarea->spacetype != SPACE_IMAGE) return;
614         if ((G.sima->image == 0) || (G.sima->image->ibuf == 0)) return;
615
616         /* Check if the image will fit in the image with zoom==1 */
617         width = curarea->winx;
618         height = curarea->winy;
619         if (((G.sima->image->ibuf->x >= width) || (G.sima->image->ibuf->y >= height)) && 
620                 ((width > 0) && (height > 0))) {
621                 /* Find the zoom value that will fit the image in the image space */
622                 zoomX = ((float)width) / ((float)G.sima->image->ibuf->x);
623                 zoomY = ((float)height) / ((float)G.sima->image->ibuf->y);
624                 G.sima->zoom= MIN2(zoomX, zoomY);
625
626                 /* Now make it a power of 2 */
627                 G.sima->zoom = 1 / G.sima->zoom;
628                 G.sima->zoom = log(G.sima->zoom) / log(2);
629                 G.sima->zoom = ceil(G.sima->zoom);
630                 G.sima->zoom = pow(2, G.sima->zoom);
631                 G.sima->zoom = 1 / G.sima->zoom;
632         }
633         else {
634                 G.sima->zoom= (float)1;
635         }
636
637         G.sima->xof= G.sima->yof= 0;
638         
639         calc_image_view(G.sima, 'p');
640         
641         scrarea_queue_winredraw(curarea);
642 }
643