Solved crash caused by referencing NULL ->camera pointer in preview for
[blender.git] / source / blender / src / previewrender.c
1 /* previewrender.c              GRAPHICS
2  * 
3  * maart 95
4  * 
5  * $Id$
6  *
7  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version. The Blender
13  * Foundation also sells licenses for use in proprietary software under
14  * the Blender License.  See http://www.blender.org/BL/ for information
15  * about this.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
27  * All rights reserved.
28  *
29  * The Original Code is: all of this file.
30  *
31  * Contributor(s): none yet.
32  *
33  * ***** END GPL/BL DUAL LICENSE BLOCK *****
34  */
35
36 /* global includes */
37
38 #include <stdlib.h>
39 #include <math.h>
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44
45 #ifndef WIN32
46 #include <unistd.h>
47 #else
48 #include <io.h>
49 #endif   
50 #include "MEM_guardedalloc.h"
51 #include "BLI_arithb.h"
52 #include "BKE_utildefines.h"
53
54 #include "MTC_matrixops.h"
55
56 #include "render.h"
57 #include "mydevice.h"
58
59 #include "DNA_texture_types.h"
60 #include "DNA_world_types.h"
61 #include "DNA_camera_types.h"
62 #include "DNA_image_types.h"
63 #include "DNA_object_types.h"
64 #include "DNA_lamp_types.h"
65 #include "DNA_space_types.h"
66 #include "DNA_scene_types.h"
67 #include "DNA_screen_types.h"
68
69 #include "BKE_global.h"
70 #include "BKE_image.h"
71 #include "BKE_texture.h"
72 #include "BKE_material.h"
73 #include "BKE_world.h"
74 #include "BKE_texture.h"
75
76 #include "BSE_headerbuttons.h"
77
78 #include "BIF_gl.h"
79 #include "BIF_screen.h"
80 #include "BIF_space.h"          /* allqueue */
81 #include "BIF_butspace.h"       
82 #include "BIF_drawimage.h"      /* rectwrite_part */
83 #include "BIF_mywindow.h"
84 #include "BIF_interface.h"
85 #include "BIF_glutil.h"
86
87 #include "PIL_time.h"
88
89 #include "RE_renderconverter.h"
90
91 #define PR_RECTX        141
92 #define PR_RECTY        141
93 #define PR_XMIN         10
94 #define PR_YMIN         5
95 #define PR_XMAX         200
96 #define PR_YMAX         195
97
98 #define PR_FACY         (PR_YMAX-PR_YMIN-4)/(PR_RECTY)
99
100 static rcti prerect;
101 static int pr_sizex, pr_sizey;
102 static float pr_facx, pr_facy;
103
104
105 /* implementation */
106
107 static short snijpunt(float *v1,   float *v2,  float *v3,  float *rtlabda, float *ray1, float *ray2)
108 {
109         float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22;
110         float m0,m1,m2,deeldet,det1,det2,det3;
111         float rtu, rtv;
112         
113         t00= v3[0]-v1[0];
114         t01= v3[1]-v1[1];
115         t02= v3[2]-v1[2];
116         t10= v3[0]-v2[0];
117         t11= v3[1]-v2[1];
118         t12= v3[2]-v2[2];
119         t20= ray1[0]-ray2[0];
120         t21= ray1[1]-ray2[1];
121         t22= ray1[2]-ray2[2];
122         
123         x0= t11*t22-t12*t21;
124         x1= t12*t20-t10*t22;
125         x2= t10*t21-t11*t20;
126
127         deeldet= t00*x0+t01*x1+t02*x2;
128         if(deeldet!=0.0) {
129                 m0= ray1[0]-v3[0];
130                 m1= ray1[1]-v3[1];
131                 m2= ray1[2]-v3[2];
132                 det1= m0*x0+m1*x1+m2*x2;
133                 rtu= det1/deeldet;
134                 if(rtu<=0.0) {
135                         det2= t00*(m1*t22-m2*t21);
136                         det2+= t01*(m2*t20-m0*t22);
137                         det2+= t02*(m0*t21-m1*t20);
138                         rtv= det2/deeldet;
139                         if(rtv<=0.0) {
140                                 if(rtu+rtv>= -1.0) {
141                                         
142                                         det3=  m0*(t12*t01-t11*t02);
143                                         det3+= m1*(t10*t02-t12*t00);
144                                         det3+= m2*(t11*t00-t10*t01);
145                                         *rtlabda= det3/deeldet;
146                                         
147                                         if(*rtlabda>=0.0 && *rtlabda<=1.0) {
148                                                 return 1;
149                                         }
150                                 }
151                         }
152                 }
153         }
154         return 0;
155 }
156
157 static float rcubev[7][3]= {
158         {-0.002055,  6.627364, -3.369742}, 
159         {-6.031684, -3.750204, -1.992980}, 
160         {-6.049086,  3.817431,  1.969788}, 
161         { 6.031685,  3.833064,  1.992979}, 
162         { 6.049086, -3.734571, -1.969787}, 
163         { 0.002054, -6.544502,  3.369744}, 
164         {-0.015348,  1.023131,  7.332510} };
165
166 static int rcubi[3][4]= {
167         {3,  6,  5,  4},
168         {1,  5,  6,  2},  
169         {3,  0,  2,  6} };
170
171
172 static int ray_previewrender(int x,  int y,  float *vec, float *vn)
173 {
174         float scalef= 10.0/100.0;
175         float ray1[3], ray2[3];
176         float minlabda, labda;
177         int totface= 3, hitface= -1;
178         int a;
179
180         ray1[0]= ray2[0]= x*scalef;
181         ray1[1]= ray2[1]= y*scalef;
182         ray1[2]= -10.0;
183         ray2[2]= 10.0;
184         
185         minlabda= 1.0;
186         for(a=0; a<totface; a++) {
187                 if(snijpunt( rcubev[rcubi[a][0]], rcubev[rcubi[a][1]], rcubev[rcubi[a][2]], &labda, ray1, ray2)) {
188                         if( labda < minlabda) {
189                                 minlabda= labda;
190                                 hitface= a;
191                         }
192                 }
193                 if(snijpunt( rcubev[rcubi[a][0]], rcubev[rcubi[a][2]], rcubev[rcubi[a][3]], &labda, ray1, ray2)) {
194                         if( labda < minlabda) {
195                                 minlabda= labda;
196                                 hitface= a;
197                         }
198                 }
199         }
200         
201         if(hitface > -1) {
202                 
203                 CalcNormFloat(rcubev[rcubi[hitface][0]], rcubev[rcubi[hitface][1]], rcubev[rcubi[hitface][2]], vn);
204                 
205                 vec[0]= (minlabda*(ray1[0]-ray2[0])+ray2[0])/3.7;
206                 vec[1]= (minlabda*(ray1[1]-ray2[1])+ray2[1])/3.7;
207                 vec[2]= (minlabda*(ray1[2]-ray2[2])+ray2[2])/3.7;
208                 
209                 return 1;
210         }
211         return 0;
212 }
213
214
215 static unsigned int previewback(int type, int x, int y)
216 {
217         
218         /* checkerboard, for later
219         x+= PR_RECTX/2;
220         y+= PR_RECTX/2;
221         if( ((x/24) + (y/24)) & 1) return 0x40404040;
222         else return 0xa0a0a0a0;
223         */
224         
225         if(type & MA_DARK) {
226                 if(abs(x)>abs(y)) return 0;
227                 else return 0x40404040;
228         }
229         else {
230                 if(abs(x)>abs(y)) return 0x40404040;
231                 else return 0xa0a0a0a0;
232         }
233 }
234
235 static void view2d_to_window(int win, int *x_r, int *y_r)
236 {
237         int x= *x_r, y= *y_r;
238         int size[2], origin[2];
239         float winmat[4][4];
240
241         bwin_getsinglematrix(win, winmat);
242         bwin_getsize(win, &size[0], &size[1]);
243         bwin_getsuborigin(win, &origin[0], &origin[1]);
244         
245         *x_r= origin[0] + (size[0]*(0.5 + 0.5*(x*winmat[0][0] + y*winmat[1][0] + winmat[3][0])));
246         *y_r= origin[1] + (size[1]*(0.5 + 0.5*(x*winmat[0][1] + y*winmat[1][1] + winmat[3][1])));
247 }
248
249 static void set_previewrect(int win, int xmin, int ymin, int xmax, int ymax)
250 {
251         prerect.xmin= xmin;
252         prerect.ymin= ymin;
253         prerect.xmax= xmax;
254         prerect.ymax= ymax;
255
256         view2d_to_window(win, &prerect.xmin, &prerect.ymin);
257         view2d_to_window(win, &prerect.xmax, &prerect.ymax);
258         
259         pr_sizex= (prerect.xmax-prerect.xmin);
260         pr_sizey= (prerect.ymax-prerect.ymin);
261
262         pr_facx= ( (float)pr_sizex-1)/PR_RECTX;
263         pr_facy= ( (float)pr_sizey-1)/PR_RECTY;
264 }
265
266 static void display_pr_scanline(unsigned int *rect, int recty)
267 {
268         static double lasttime= 0;
269         /* we display 3 new scanlines, one old, the overlap is for wacky 3d cards that cant handle zoom proper */
270
271         if(recty % 2) return;
272         if(recty<2) return;
273         
274         rect+= (recty-2)*PR_RECTX;
275
276         /* enlarge a bit in the y direction, to avoid GL/mesa bug */
277         glPixelZoom(pr_facx, pr_facy);
278
279         glRasterPos2f( (float)PR_XMIN+0.5, 1.0+(float)PR_YMIN + (recty*PR_FACY) );
280         glDrawPixels(PR_RECTX, 3, GL_RGBA, GL_UNSIGNED_BYTE,  rect);
281
282         //glaDrawPixelsTex((float)PR_XMIN, (float)PR_YMIN + (recty*PR_FACY), PR_RECTX, 3, rect);
283
284         glPixelZoom(1.0, 1.0);
285         
286         /* flush opengl for cards with frontbuffer slowness */
287         if(recty==PR_RECTY-1 || (PIL_check_seconds_timer() - lasttime > 0.05)) {
288                 lasttime= PIL_check_seconds_timer();
289                 glFinish();
290         }
291 }
292
293 static void draw_tex_crop(Tex *tex)
294 {
295         rcti rct;
296         int ret= 0;
297         
298         if(tex==0) return;
299         
300         if(tex->type==TEX_IMAGE) {
301                 if(tex->cropxmin==0.0) ret++;
302                 if(tex->cropymin==0.0) ret++;
303                 if(tex->cropxmax==1.0) ret++;
304                 if(tex->cropymax==1.0) ret++;
305                 if(ret==4) return;
306                 
307                 rct.xmin= PR_XMIN+2+tex->cropxmin*(PR_XMAX-PR_XMIN-4);
308                 rct.xmax= PR_XMIN+2+tex->cropxmax*(PR_XMAX-PR_XMIN-4);
309                 rct.ymin= PR_YMIN+2+tex->cropymin*(PR_YMAX-PR_YMIN-4);
310                 rct.ymax= PR_YMIN+2+tex->cropymax*(PR_YMAX-PR_YMIN-4);
311
312                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
313
314                 glColor3ub(0, 0, 0);
315                 glRecti(rct.xmin+1,  rct.ymin-1,  rct.xmax+1,  rct.ymax-1); 
316
317                 glColor3ub(255, 255, 255);
318                 glRecti(rct.xmin,  rct.ymin,  rct.xmax,  rct.ymax);
319
320                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);                      
321         }
322         
323 }
324
325 void BIF_all_preview_changed(void)
326 {
327         ScrArea *sa;
328         SpaceButs *sbuts;
329         
330         sa= G.curscreen->areabase.first;
331         while(sa) {
332                 if(sa->spacetype==SPACE_BUTS) {
333                         sbuts= sa->spacedata.first;
334                         sbuts->cury= 0;
335                         addafterqueue(sa->win, RENDERPREVIEW, 1);
336                 }
337                 sa= sa->next;
338         }
339 }
340
341
342 void BIF_preview_changed(SpaceButs *sbuts)
343 {
344         /* can be called when no buttonswindow visible */
345         if(sbuts) {
346                 sbuts->cury= 0;
347                 addafterqueue(sbuts->area->win, RENDERPREVIEW, 1);
348         }
349 }
350
351 /* is supposed to be called with correct panel offset matrix */
352 void BIF_previewdraw(void)
353 {
354         SpaceButs *sbuts= curarea->spacedata.first;
355         
356         set_previewrect(sbuts->area->win, PR_XMIN, PR_YMIN, PR_XMAX, PR_YMAX);
357
358         if (sbuts->rect==0) BIF_preview_changed(sbuts);
359         else {
360                 int y;
361
362                 for (y=0; y<PR_RECTY; y++) {
363                         display_pr_scanline(sbuts->rect, y);
364                 }
365
366                 if (sbuts->mainb==CONTEXT_SHADING && sbuts->tab[CONTEXT_SHADING]==TAB_SHADING_TEX) {
367                         draw_tex_crop(sbuts->lockpoin);
368                 }
369         }
370         if(sbuts->cury==0) BIF_preview_changed(sbuts);
371 }
372
373 static void sky_preview_pixel(float lens, int x, int y, char *rect)
374 {
375         float view[3];
376         
377         if(R.wrld.skytype & WO_SKYPAPER) {
378                 view[0]= (2*x)/(float)PR_RECTX;
379                 view[1]= (2*y)/(float)PR_RECTY;
380                 view[2]= 0.0;
381         }
382         else {
383                 view[0]= x;
384                 view[1]= y;
385                 view[2]= -lens*PR_RECTX/32.0;
386                 Normalise(view);
387         }
388         RE_sky(view, rect);
389 }
390
391 static void lamp_preview_pixel(ShadeInput *shi, LampRen *la, int x, int y, char *rect)
392 {
393         float inpr, i, t, dist, distkw, vec[3];
394         int col;
395         
396         shi->co[0]= (float)x/(PR_RECTX/4);
397         shi->co[1]= (float)y/(PR_RECTX/4);
398         shi->co[2]= 0;
399         
400         vec[0]= 0.02*x;
401         vec[1]= 0.02*y;
402         vec[2]= 0.005*PR_RECTX;
403         VECCOPY(shi->view, vec);
404         dist= Normalise(shi->view);
405
406         if(la->mode & LA_TEXTURE) do_lamp_tex(la, vec, shi);
407
408         if(la->type==LA_SUN || la->type==LA_HEMI) {
409                 dist= 1.0;
410         }
411         else {
412                 
413                 if(la->mode & LA_QUAD) {
414                         
415                         t= 1.0;
416                         if(la->ld1>0.0)
417                                 t= la->dist/(la->dist+la->ld1*dist);
418                         if(la->ld2>0.0) {
419                                 distkw= la->dist*la->dist;
420                                 t= t*distkw/(t*distkw+la->ld2*dist*dist);
421                         }
422                         dist= t;
423                 }
424                 else {
425                         dist= (la->dist/(la->dist+dist));
426                 }
427         }
428
429         if(la->type==LA_SPOT) {
430
431                 
432                 if(la->mode & LA_SQUARE) {
433                         /* slightly smaller... */
434                         inpr= 1.7*cos(MAX2(fabs(shi->view[0]/shi->view[2]) , fabs(shi->view[1]/shi->view[2]) ));
435                 }
436                 else {
437                         inpr= shi->view[2];
438                 }
439                 
440                 t= la->spotsi;
441                 if(inpr<t) dist= 0.0;
442                 else {
443                         t= inpr-t;
444                         if(t<la->spotbl && la->spotbl!=0.0) {
445                                 /* soft area */
446                                 i= t/la->spotbl;
447                                 t= i*i;
448                                 i= t*i;
449                                 inpr*=(3.0*t-2.0*i);
450                         }
451                 }
452                 dist*=inpr;
453         }
454         else if ELEM(la->type, LA_LOCAL, LA_AREA) dist*= shi->view[2];
455         
456         col= 255.0*dist*la->r;
457         if(col<=0) rect[0]= 0; else if(col>=255) rect[0]= 255; else rect[0]= col;
458
459         col= 255.0*dist*la->g;
460         if(col<=0) rect[1]= 0; else if(col>=255) rect[1]= 255; else rect[1]= col;
461
462         col= 255.0*dist*la->b;
463         if(col<=0) rect[2]= 0; else if(col>=255) rect[2]= 255; else rect[2]= col;
464 }
465
466 static void init_previewhalo(HaloRen *har, Material *mat)
467 {
468         
469         har->type= 0;
470         if(mat->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
471         har->mat= mat;
472         har->hard= mat->har;
473         har->rad= PR_RECTX/2.0;
474         har->radsq= PR_RECTX*PR_RECTX/4.0;
475         har->alfa= mat->alpha;
476         har->add= 255.0*mat->add;
477         har->r= 255.0*mat->r;
478         har->g= 255.0*mat->g; 
479         har->b= 255.0*mat->b;
480         har->xs= PR_RECTX/2.0;
481         har->ys= PR_RECTX/2.0;
482         har->zs= har->zd= 0;
483         har->seed= (mat->seed1 % 256);
484         
485         if( (mat->mode & MA_HALOTEX) && mat->mtex[0] ) har->tex= 1; else har->tex=0;
486
487         if(mat->mode & MA_STAR) har->starpoints= mat->starc; else har->starpoints= 0;
488         if(mat->mode & MA_HALO_LINES) har->linec= mat->linec; else har->linec= 0;
489         if(mat->mode & MA_HALO_RINGS) har->ringc= mat->ringc; else har->ringc= 0;
490         if(mat->mode & MA_HALO_FLARE) har->flarec= mat->flarec; else har->flarec= 0;
491         
492         if(har->flarec) {
493                 har->xs-= PR_RECTX/3;
494                 har->ys+= PR_RECTX/3;
495                 
496                 har->rad*= 0.3;
497                 har->radsq= har->rad*har->rad;
498                 
499                 har->pixels= har->rad*har->rad*har->rad;
500         }
501 }       
502
503 static void halo_preview_pixel(HaloRen *har, int startx, int endx, int y, char *rect)
504 {
505         float dist, xn, yn, xsq, ysq;
506         int x;
507         char front[4];
508         
509         if(har->flarec) yn= y-PR_RECTX/3;
510         else yn= y;
511         ysq= yn*yn;
512         
513         for(x=startx; x<endx; x++) {
514                 
515                 if(har->flarec) xn= x+PR_RECTX/3;
516                 else xn= x;
517                 
518                 xsq= xn*xn;
519                 dist= xsq+ysq;
520
521                 
522                 
523                 if(dist<har->radsq) {
524                         RE_shadehalo(har, front, 0, dist, xn, yn, har->flarec);
525                         RE_addalphaAddfac(rect, front, har->add);
526                 }
527                 rect+= 4;
528         }
529 }
530
531 static void previewflare(SpaceButs *sbuts, HaloRen *har, unsigned int *rect)
532 {
533         uiBlock *block;
534         float ycor;
535         unsigned int *rectot;
536         int afmx, afmy, rectx, recty;
537         
538         block= uiFindOpenPanelBlockName(&curarea->uiblocks, "Preview");
539         if(block==NULL) return;
540
541         /* temps */
542         ycor= R.ycor;
543         rectx= R.rectx;
544         recty= R.recty;
545         afmx= R.afmx;
546         afmy= R.afmy;
547         rectot= R.rectot;
548
549         R.ycor= 1.0;
550         R.rectx= PR_RECTX;      
551         R.recty= PR_RECTY;
552         R.afmx= PR_RECTX/2;
553         R.afmy= PR_RECTY/2;
554         R.rectot= rect;
555
556         waitcursor(1);
557         RE_renderflare(har);
558         waitcursor(0);
559         // not sure why, either waitcursor or renderflare screws up
560         areawinset(curarea->win);
561         
562         uiPanelPush(block);
563         BIF_previewdraw();
564         uiPanelPop(block);
565         
566         
567         /* temps */
568         R.ycor= ycor;
569         R.rectx= rectx;
570         R.recty= recty;
571         R.afmx= afmx;
572         R.afmy= afmy;
573         R.rectot= rectot;
574 }
575
576 extern float Tin, Tr, Tg, Tb, Ta; /* texture.c */
577 static void texture_preview_pixel(Tex *tex, int x, int y, char *rect)
578 {
579         float i, v1, xsq, ysq, texvec[3], dummy[3];
580         int rgbnor, tracol, skip=0;
581                 
582         if(tex->type==TEX_IMAGE) {
583                 v1= 1.0/PR_RECTX;
584                 
585                 texvec[0]= 0.5+v1*x;
586                 texvec[1]= 0.5+v1*y;
587                 
588                 /* no coordinate mapping, exception: repeat */
589                 if(tex->xrepeat>1) {
590                         texvec[0] *= tex->xrepeat;
591                         if(texvec[0]>1.0) texvec[0] -= (int)(texvec[0]);
592                 }
593                 if(tex->yrepeat>1) {
594                         texvec[1] *= tex->yrepeat;
595                         if(texvec[1]>1.0) texvec[1] -= (int)(texvec[1]);
596                 }
597
598         }
599         else if(tex->type==TEX_ENVMAP) {
600                 if(tex->env) {
601                         ysq= y*y;
602                         xsq= x*x;
603                         if(xsq+ysq < (PR_RECTX/2)*(PR_RECTY/2)) {
604                                 texvec[2]= sqrt( (float)((PR_RECTX/2)*(PR_RECTY/2)-xsq-ysq) );
605                                 texvec[0]= -x;
606                                 texvec[1]= -y;
607                                 Normalise(texvec);
608
609                                 i= 2.0*(texvec[2]);
610                                 texvec[0]= (i*texvec[0]);
611                                 texvec[1]= (i*texvec[1]);
612                                 texvec[2]= (-1.0+i*texvec[2]);
613
614                         }
615                         else {
616                                 skip= 1;
617                                 Ta= 0.0;
618                         }
619                 }
620                 else {
621                         skip= 1;
622                         Ta= 0.0;
623                 }
624         }
625         else {
626                 v1= 2.0/PR_RECTX;
627         
628                 texvec[0]= v1*x;
629                 texvec[1]= v1*y;
630                 texvec[2]= 0.0;
631         }
632         
633         /* does not return Tin */
634         if(tex->type==TEX_STUCCI) {
635                 tex->nor= dummy;
636                 dummy[0]= 1.0;
637                 dummy[1]= dummy[2]= 0.0;
638         }
639         
640         if(skip==0) rgbnor= multitex(tex, texvec, NULL, NULL, 0);
641         else rgbnor= 1;
642         
643         if(rgbnor & 1) {
644                 
645                 rect[0]= 255.0*Tr;
646                 rect[1]= 255.0*Tg;
647                 rect[2]= 255.0*Tb;
648                 
649                 if(Ta!=1.0) {
650                         tracol=  64+100*(abs(x)>abs(y));
651                         tracol= (1.0-Ta)*tracol;
652                         
653                         rect[0]= tracol+ (rect[0]*Ta) ;
654                         rect[1]= tracol+ (rect[1]*Ta) ;
655                         rect[2]= tracol+ (rect[2]*Ta) ;
656                                         
657                 }
658         }
659         else {
660         
661                 if(tex->type==TEX_STUCCI) {
662                         Tin= 0.5 + 0.7*tex->nor[0];
663                         CLAMP(Tin, 0.0, 1.0);
664                 }
665                 rect[0]= 255.0*Tin;
666                 rect[1]= 255.0*Tin;
667                 rect[2]= 255.0*Tin;
668         }
669 }
670
671 static float pr1_lamp[3]= {2.3, -2.4, -4.6};
672 static float pr2_lamp[3]= {-8.8, -5.6, -1.5};
673 static float pr1_col[3]= {0.8, 0.8, 0.8};
674 static float pr2_col[3]= {0.5, 0.6, 0.7};
675
676 static void refraction_prv(int *x, int *y, float *n, float index)
677 {
678         float dot, fac, view[3], len;
679
680         index= 1.0/index;
681         
682         view[0]= index*(float)*x;
683         view[1]= ((float)*y)/index;
684         view[2]= 20.0;
685         len= Normalise(view);
686         
687         dot= view[0]*n[0] + view[1]*n[1] + view[2]*n[2];
688
689         if(dot>0.0) {
690                 fac= 1.0 - (1.0 - dot*dot)*index*index;
691                 if(fac<= 0.0) return;
692                 fac= -dot*index + sqrt(fac);
693         }
694         else {
695                 index = 1.0/index;
696                 fac= 1.0 - (1.0 - dot*dot)*index*index;
697                 if(fac<= 0.0) return;
698                 fac= -dot*index - sqrt(fac);
699         }
700
701         *x= (int)(len*(index*view[0] + fac*n[0]));
702         *y= (int)(len*(index*view[1] + fac*n[1]));
703 }
704
705
706 static void shade_preview_pixel(ShadeInput *shi, float *vec, int x, int y,char *rect, int smooth)
707 {
708         extern float fresnel_fac(float *view, float *vn, float ior, float fac);
709         Material *mat;
710         float v1,inp, inprspec=0, isr=0.0, isb=0.0, isg=0.0;
711         float ir=0.0, ib=0.0, ig=0.0;
712         float view[3], lv[3], *la, alpha;
713         float eul[3], tmat[3][3], imat[3][3];
714         int temp, a;
715         char tracol;
716                 
717         mat= shi->matren;
718
719         v1= 1.0/PR_RECTX;
720         view[0]= v1*x;
721         view[1]= v1*y;
722         view[2]= 1.0;
723         Normalise(view);
724         
725         shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0;
726
727         /* texture handling */
728         if(mat->texco) {
729                 
730                 VECCOPY(shi->lo, vec);
731                 
732                 if(mat->pr_type==MA_CUBE) {
733                         
734                         eul[0]= (297)*M_PI/180.0;
735                         eul[1]= 0.0;
736                         eul[2]= (45)*M_PI/180.0;
737                         EulToMat3(eul, tmat);
738
739                         MTC_Mat3MulVecfl(tmat, shi->lo);
740                         MTC_Mat3MulVecfl(tmat, shi->vn);
741                         /* hack for cubemap, why!!! */
742                         SWAP(float, shi->vn[0], shi->vn[1]);
743                 }
744                 /* textures otherwise upside down */
745                 if(mat->pr_type==MA_CUBE || mat->pr_type==MA_SPHERE) 
746                         shi->lo[2]= -shi->lo[2];
747
748                 if(mat->texco & TEXCO_GLOB) {
749                         VECCOPY(shi->gl, shi->lo);
750                 }
751                 if(mat->texco & TEXCO_WINDOW) {
752                         VECCOPY(shi->winco, shi->lo);
753                 }
754                 if(mat->texco & TEXCO_STICKY) {
755                         VECCOPY(shi->sticky, shi->lo);
756                 }
757                 if(mat->texco & TEXCO_UV) {
758                         VECCOPY(shi->uv, shi->lo);
759                 }
760                 if(mat->texco & TEXCO_OBJECT) {
761                         VECCOPY(shi->co, shi->lo);
762                 }
763                 if(mat->texco & TEXCO_NORM) {
764                         shi->orn[0]= shi->vn[0];
765                         shi->orn[1]= shi->vn[1];
766                         shi->orn[2]= shi->vn[2];
767                 }
768                 if(mat->texco & TEXCO_REFL) {
769                         /* for bump texture */
770                         VECCOPY(shi->view, view);
771                         
772                         inp= -2.0*(shi->vn[0]*view[0]+shi->vn[1]*view[1]+shi->vn[2]*view[2]);
773                         shi->ref[0]= (view[0]+inp*shi->vn[0]);
774                         shi->ref[1]= (view[1]+inp*shi->vn[1]);
775                         shi->ref[2]= (view[2]+inp*shi->vn[2]);
776                 }
777
778                 /* Clear displase vec for preview */
779                 shi->displace[0]= shi->displace[1]= shi->displace[2]= 0.0;
780                 
781                 /* normals flipped in render... */
782                 if(mat->mapto & MAP_NORM) VecMulf(shi->vn, -1.0);
783                 
784                 do_material_tex(shi);
785
786                 /* normals flipped in render... */
787                 if(mat->mapto & MAP_NORM) VecMulf(shi->vn, -1.0);
788         
789                 if(mat->texco & TEXCO_REFL) {
790                         /* normals in render are pointing different... rhm */
791                         if(smooth) shi->ref[1]= -shi->ref[1];
792                 }
793
794                 if(mat->pr_type==MA_CUBE) {
795                         /* rotate normal back for normals texture */
796                         SWAP(float, shi->vn[0], shi->vn[1]);
797                         MTC_Mat3Inv(imat, tmat);
798                         MTC_Mat3MulVecfl(imat, shi->vn);
799                 }
800                 
801         }
802         /* set it here, because ray_mirror will affect it */
803         alpha= mat->alpha;
804
805         if(mat->mapto & MAP_DISPLACE) { /* Quick hack of fake displacement preview */
806                 shi->vn[0]-=2.0*shi->displace[2];
807                 shi->vn[1]-=2.0*shi->displace[0];
808                 shi->vn[2]+=2.0*shi->displace[1];
809                 Normalise(shi->vn);
810         }
811                 
812         if(mat->mode & (MA_ZTRA|MA_RAYTRANSP)) 
813                 if(mat->fresnel_tra!=0.0) 
814                         alpha*= fresnel_fac(view, shi->vn, mat->fresnel_tra_i, mat->fresnel_tra);
815
816         if(mat->mode & MA_SHLESS) {
817                 temp= 255.0*(mat->r);
818                 if(temp>255) rect[0]= 255; else if(temp<0) rect[0]= 0; else rect[0]= temp;
819
820                 temp= 255.0*(mat->g);
821                 if(temp>255) rect[1]= 255; else if(temp<0) rect[1]= 0; else rect[1]= temp;
822
823                 temp= 255.0*(mat->b);
824                 if(temp>255) rect[2]= 255; else if(temp<0) rect[2]= 0; else rect[2]= temp;
825         }
826         else {
827                 
828                 for(a=0; a<2; a++) {
829                         
830                         if(a==0) la= pr1_lamp;
831                         else la= pr2_lamp;
832                         
833                         lv[0]= vec[0]-la[0];
834                         lv[1]= vec[1]-la[1];
835                         lv[2]= vec[2]-la[2];
836                         Normalise(lv);
837                         
838                         inp= shi->vn[0]*lv[0]+shi->vn[1]*lv[1]+shi->vn[2]*lv[2];
839                         if(inp<0.0) inp= 0.0;
840                         
841                         if(mat->spec)  {
842                                 
843                                 if(inp>0.0) {
844                                         /* specular shaders */
845                                         float specfac;
846                                         
847                                         if(mat->spec_shader==MA_SPEC_PHONG) 
848                                                 specfac= Phong_Spec(shi->vn, lv, view, mat->har);
849                                         else if(mat->spec_shader==MA_SPEC_COOKTORR) 
850                                                 specfac= CookTorr_Spec(shi->vn, lv, view, mat->har);
851                                         else if(mat->spec_shader==MA_SPEC_BLINN) 
852                                                 specfac= Blinn_Spec(shi->vn, lv, view, mat->refrac, (float)mat->har);
853                                         else 
854                                                 specfac= Toon_Spec(shi->vn, lv, view, mat->param[2], mat->param[3]);
855                                 
856                                         inprspec= specfac*mat->spec;
857                                         
858                                         isr+= inprspec*mat->specr;
859                                         isg+= inprspec*mat->specg;
860                                         isb+= inprspec*mat->specb;
861
862                                 }
863                         }
864                         /* diffuse shaders */
865                         if(mat->diff_shader==MA_DIFF_ORENNAYAR) inp= OrenNayar_Diff(shi->vn, lv, view, mat->roughness);
866                         else if(mat->diff_shader==MA_DIFF_TOON) inp= Toon_Diff(shi->vn, lv, view, mat->param[0], mat->param[1]);
867                         // else Lambert
868
869                         inp= (mat->ref*inp + mat->emit);
870                         
871                         if(a==0) la= pr1_col;
872                         else la= pr2_col;
873
874                         ir+= inp*la[0];
875                         ig+= inp*la[1];
876                         ib+= inp*la[2];
877                 }
878                 
879                 /* drawing checkerboard and sky */
880                 if(mat->mode & MA_RAYMIRROR) {
881                         float col, div, y, z;
882                         int fac;
883                         
884                         /* rotate a bit in x */
885                         y= shi->ref[1]; z= shi->ref[2];
886                         shi->ref[1]= 0.98*y - 0.17*z;
887                         shi->ref[2]= 0.17*y + 0.98*z;
888                         
889                         /* scale */
890                         div= (0.85*shi->ref[1]);
891                         
892                         shi->refcol[0]= mat->ray_mirror*fresnel_fac(view, shi->vn, mat->fresnel_mir_i, mat->fresnel_mir);
893                         /* not real 'alpha', but mirror overriding transparency */
894                         if(mat->mode & MA_RAYTRANSP) {
895                                 float fac= sqrt(shi->refcol[0]);
896                                 alpha= alpha*(1.0-fac) + fac;
897                         }
898                         else alpha= alpha*(1.0-shi->refcol[0]) + shi->refcol[0];
899                         
900                         if(div<0.0) {
901                                 /* minus 0.5 prevents too many small tiles in distance */
902                                 fac= (int)(shi->ref[0]/(div-0.1) ) + (int)(shi->ref[2]/(div-0.1) );
903                                 if(fac & 1) col= 0.8;
904                                 else col= 0.3;
905
906                                 shi->refcol[1]= shi->refcol[0]*col;
907                                 shi->refcol[2]= shi->refcol[1];
908                                 shi->refcol[3]= shi->refcol[2];
909                         }
910                         else {
911                                 shi->refcol[1]= 0.0;
912                                 shi->refcol[2]= shi->refcol[0]*0.3*div;
913                                 shi->refcol[3]= shi->refcol[0]*0.8*div;
914                         }
915                 }
916
917                 if(shi->refcol[0]==0.0) {
918                         a= 255.0*( mat->r*ir +mat->ambr +isr);
919                         if(a>255) a=255; else if(a<0) a= 0;
920                         rect[0]= a;
921                         a= 255.0*(mat->g*ig +mat->ambg +isg);
922                         if(a>255) a=255; else if(a<0) a= 0;
923                         rect[1]= a;
924                         a= 255*(mat->b*ib +mat->ambb +isb);
925                         if(a>255) a=255; else if(a<0) a= 0;
926                         rect[2]= a;
927                 }
928                 else {
929                         a= 255.0*( mat->mirr*shi->refcol[1] + (1.0 - mat->mirr*shi->refcol[0])*(mat->r*ir +mat->ambr) +isr);
930                         if(a>255) a=255; else if(a<0) a= 0;
931                         rect[0]= a;
932                         a= 255.0*( mat->mirg*shi->refcol[2] + (1.0 - mat->mirg*shi->refcol[0])*(mat->g*ig +mat->ambg) +isg);
933                         if(a>255) a=255; else if(a<0) a= 0;
934                         rect[1]= a;
935                         a= 255.0*( mat->mirb*shi->refcol[3] + (1.0 - mat->mirb*shi->refcol[0])*(mat->b*ib +mat->ambb) +isb);
936                         if(a>255) a=255; else if(a<0) a= 0;
937                         rect[2]= a;
938                 }
939         }
940
941                 /* ztra shade */
942         if(mat->spectra!=0.0) {
943                 inp = MAX3(isr, isg, isb);
944                 inp *= mat->spectra;
945                 if(inp>1.0) inp= 1.0;
946                 alpha= (1.0-inp)*alpha+inp;
947         }
948
949         if(alpha!=1.0) {
950                 if(mat->mode & MA_RAYTRANSP) {
951                         refraction_prv(&x, &y, shi->vn, mat->ang);
952                 }
953                 
954                 tracol=  previewback(mat->pr_back, x, y) & 255;
955                 
956                 tracol= (1.0-alpha)*tracol;
957                 
958                 rect[0]= tracol+ (rect[0]*alpha) ;
959                 rect[1]= tracol+ (rect[1]*alpha) ;
960                 rect[2]= tracol+ (rect[2]*alpha) ;
961         }
962 }
963
964
965 void BIF_previewrender(SpaceButs *sbuts)
966 {
967         ID *id, *idfrom;
968         Material *mat= NULL;
969         Tex *tex= NULL;
970         Lamp *la= NULL;
971         World *wrld= NULL;
972         LampRen *lar= NULL;
973         Image *ima;
974         HaloRen har;
975         Object *ob;
976         uiBlock *block;
977         ShadeInput shi;
978         float lens = 0.0, vec[3];
979         int x, y, starty, startx, endy, endx, radsq, xsq, ysq, last = 0;
980         unsigned int *rect;
981
982         if(sbuts->cury>=PR_RECTY) return;
983         
984         /* we safely assume curarea has panel "preview" */
985         /* quick hack for now, later on preview should become uiBlock itself */
986         
987         block= uiFindOpenPanelBlockName(&curarea->uiblocks, "Preview");
988         if(block==NULL) return;
989
990         ob= ((G.scene->basact)? (G.scene->basact)->object: 0);
991         
992         /* we cant trust this global lockpoin.. for example with headerless window */
993         buttons_active_id(&id, &idfrom);
994         G.buts->lockpoin= id;
995
996         if(sbuts->mainb==CONTEXT_SHADING) {
997                 int tab= sbuts->tab[CONTEXT_SHADING];
998                 
999                 if(tab==TAB_SHADING_MAT) 
1000                         mat= sbuts->lockpoin;
1001                 else if(tab==TAB_SHADING_TEX) 
1002                         tex= sbuts->lockpoin;
1003                 else if(tab==TAB_SHADING_LAMP) {
1004                         if(ob && ob->type==OB_LAMP) la= ob->data;
1005                 }
1006                 else if(tab==TAB_SHADING_WORLD)
1007                         wrld= sbuts->lockpoin;
1008         }
1009         else if(sbuts->mainb==CONTEXT_OBJECT) {
1010                 if(ob && ob->type==OB_LAMP) la= ob->data;
1011         }
1012         
1013         if(mat==NULL && tex==NULL && la==NULL && wrld==NULL) return;
1014         
1015         har.flarec= 0;  /* below is a test for postrender flare */
1016         
1017         if(qtest()) {
1018                 addafterqueue(curarea->win, RENDERPREVIEW, 1);
1019                 return;
1020         }
1021
1022         MTC_Mat4One(R.viewmat);
1023         MTC_Mat4One(R.viewinv);
1024         
1025         shi.osatex= 0;
1026         
1027         if(mat) {
1028                 /* rendervars */
1029                 init_render_world();
1030                 init_render_material(mat);
1031                 
1032                 /* clear imats */
1033                 for(x=0; x<8; x++) {
1034                         if(mat->mtex[x]) {
1035                                 if(mat->mtex[x]->tex) {
1036                                         init_render_texture(mat->mtex[x]->tex);
1037                                         
1038                                         if(mat->mtex[x]->tex->env && mat->mtex[x]->tex->env->object) 
1039                                                 MTC_Mat4One(mat->mtex[x]->tex->env->object->imat);
1040                                 }
1041                                 if(mat->mtex[x]->object) MTC_Mat4One(mat->mtex[x]->object->imat);
1042                                 if(mat->mtex[x]->object) MTC_Mat4One(mat->mtex[x]->object->imat);
1043                         }
1044                 }
1045                 shi.vlr= 0;
1046                 shi.mat= mat;
1047                 shi.matren= mat->ren;
1048                 
1049                 if(mat->mode & MA_HALO) init_previewhalo(&har, mat);
1050         }
1051         else if(tex) {
1052
1053                 ima= tex->ima;
1054                 if(ima) last= ima->lastframe;
1055                 init_render_texture(tex);
1056                 free_unused_animimages();
1057                 if(tex->ima) {
1058                         if(tex->ima!=ima) allqueue(REDRAWBUTSSHADING, 0);
1059                         else if(last!=ima->lastframe) allqueue(REDRAWBUTSSHADING, 0);
1060                 }
1061                 if(tex->env && tex->env->object) 
1062                         MTC_Mat4Invert(tex->env->object->imat, tex->env->object->obmat);
1063         }
1064         else if(la) {
1065
1066                 init_render_world();
1067                 init_render_textures(); /* do not do it twice!! (brightness) */
1068                 R.totlamp= 0;
1069                 RE_add_render_lamp(ob, 0);      /* 0=no shadbuf */
1070                 lar= R.la[0];
1071                 
1072                 /* exceptions: */
1073                 lar->spottexfac= 1.0;
1074                 lar->spotsi= cos( M_PI/3.0 );
1075                 lar->spotbl= (1.0-lar->spotsi)*la->spotblend;
1076                 
1077                 MTC_Mat3One(lar->imat);
1078         }
1079         else if(wrld) {
1080                 
1081                 lens= 35.0;
1082                 if(G.scene->camera) {
1083                         lens= ( (Camera *)G.scene->camera->data)->lens;
1084
1085                         /* needed for init_render_world */
1086                         MTC_Mat4CpyMat4(R.viewinv, G.scene->camera->obmat);
1087                         MTC_Mat4Ortho(R.viewinv);
1088                         MTC_Mat4Invert(R.viewmat, R.viewinv);
1089                 }
1090                 init_render_world();
1091                 init_render_textures(); /* dont do it twice!! (brightness) */
1092         }
1093
1094         set_previewrect(sbuts->area->win, PR_XMIN, PR_YMIN, PR_XMAX, PR_YMAX);
1095
1096         if(sbuts->rect==0) {
1097                 sbuts->rect= MEM_callocN(sizeof(int)*PR_RECTX*PR_RECTY, "butsrect");
1098                 
1099                 /* built in emboss */
1100                 rect= sbuts->rect;
1101                 for(y=0; y<PR_RECTY; y++, rect++) *rect= 0xFFFFFFFF;
1102                 
1103                 rect= sbuts->rect + PR_RECTX-1;
1104                 for(y=0; y<PR_RECTY; y++, rect+=PR_RECTX) *rect= 0xFFFFFFFF;
1105         }
1106         
1107         starty= -PR_RECTY/2;
1108         endy= starty+PR_RECTY;
1109         starty+= sbuts->cury;
1110         
1111         /* offset +1 for emboss */
1112         startx= -PR_RECTX/2 +1;
1113         endx= startx+PR_RECTX -2;
1114
1115         radsq= (PR_RECTX/2)*(PR_RECTY/2);
1116         
1117         if(mat) {
1118                 if(mat->pr_type==MA_SPHERE) {
1119                         pr1_lamp[0]= 2.3; pr1_lamp[1]= -2.4; pr1_lamp[2]= -4.6;
1120                         pr2_lamp[0]= -8.8; pr2_lamp[1]= -5.6; pr2_lamp[2]= -1.5;
1121                 }
1122                 else {
1123                         pr1_lamp[0]= 1.9; pr1_lamp[1]= 3.1; pr1_lamp[2]= -8.5;
1124                         pr2_lamp[0]= 1.2; pr2_lamp[1]= -18; pr2_lamp[2]= 3.2;
1125                 }
1126         }
1127
1128         /* here it starts! */
1129         glDrawBuffer(GL_FRONT);
1130         uiPanelPush(block);
1131
1132         for(y=starty; y<endy; y++) {
1133                 
1134                 rect= sbuts->rect + 1 + PR_RECTX*sbuts->cury;
1135                 
1136                 if(y== -PR_RECTY/2 || y==endy-1);               /* emboss */
1137                 else if(mat) {
1138                         
1139                         if(mat->mode & MA_HALO) {
1140                                 for(x=startx; x<endx; x++, rect++) {
1141                                         rect[0]= previewback(mat->pr_back, x, y);
1142                                 }
1143
1144                                 if(har.flarec) {
1145                                         if(y==endy-2) previewflare(sbuts, &har, sbuts->rect);
1146                                 }
1147                                 else {
1148                                         halo_preview_pixel(&har, startx, endx, y, (char *) (rect-PR_RECTX));
1149                                 }
1150                         }
1151                         else {
1152                                 ysq= y*y;
1153                                 for(x=startx; x<endx; x++, rect++) {
1154                                         xsq= x*x;
1155                                         if(mat->pr_type==MA_SPHERE) {
1156                                         
1157                                                 if(xsq+ysq <= radsq) {
1158                                                         shi.vn[0]= x;
1159                                                         shi.vn[1]= y;
1160                                                         shi.vn[2]= sqrt( (float)(radsq-xsq-ysq) );
1161                                                         Normalise(shi.vn);
1162                                                         
1163                                                         vec[0]= shi.vn[0];
1164                                                         vec[1]= shi.vn[2];
1165                                                         vec[2]= -shi.vn[1];
1166                                                         
1167                                                         shade_preview_pixel(&shi, vec, x, y, (char *)rect, 1);
1168                                                 }
1169                                                 else {
1170                                                         rect[0]= previewback(mat->pr_back, x, y);
1171                                                 }
1172                                         }
1173                                         else if(mat->pr_type==MA_CUBE) {
1174                                                 if( ray_previewrender(x, y, vec, shi.vn) ) {
1175                                                         
1176                                                         shade_preview_pixel(&shi, vec, x, y, (char *)rect, 0);
1177                                                 }
1178                                                 else {
1179                                                         rect[0]= previewback(mat->pr_back, x, y);
1180                                                 }
1181                                         }
1182                                         else {
1183                                                 vec[0]= x*(2.0/PR_RECTX);
1184                                                 vec[1]= y*(2.0/PR_RECTX);
1185                                                 vec[2]= 0.0;
1186                                                 
1187                                                 shi.vn[0]= shi.vn[1]= 0.0;
1188                                                 shi.vn[2]= 1.0;
1189                                                 
1190                                                 shade_preview_pixel(&shi, vec, x, y, (char *)rect, 0);
1191                                         }
1192                                 }
1193                         }
1194                 }
1195                 else if(tex) {
1196                         for(x=startx; x<endx; x++, rect++) {
1197                                 texture_preview_pixel(tex, x, y, (char *)rect);
1198                         }
1199                 }
1200                 else if(la) {
1201                         for(x=startx; x<endx; x++, rect++) {
1202                                 lamp_preview_pixel(&shi, lar, x, y, (char *)rect);
1203                         }
1204                 }
1205                 else  {
1206                         for(x=startx; x<endx; x++, rect++) {                            
1207                                 sky_preview_pixel(lens, x, y, (char *)rect);
1208                         }
1209                 }
1210                 
1211                 if(y<endy-2) {
1212
1213                         if(qtest()) {
1214                                 addafterqueue(curarea->win, RENDERPREVIEW, 1);
1215                                 break;
1216                         }
1217                 }
1218
1219                 display_pr_scanline(sbuts->rect, sbuts->cury);
1220                 
1221                 sbuts->cury++;
1222         }
1223
1224         if(sbuts->cury>=PR_RECTY && tex) 
1225                 if (sbuts->tab[CONTEXT_SHADING]==TAB_SHADING_TEX) 
1226                         draw_tex_crop(sbuts->lockpoin);
1227         
1228         glDrawBuffer(GL_BACK);
1229         /* draw again for clean swapbufers */
1230         BIF_previewdraw();
1231
1232         uiPanelPop(block);
1233         
1234         if(mat) {
1235                 end_render_material(mat);
1236                 for(x=0; x<8; x++) {
1237                         if(mat->mtex[x] && mat->mtex[x]->tex) end_render_texture(mat->mtex[x]->tex);
1238                 }       
1239         }
1240         else if(tex) {
1241                 end_render_texture(tex);
1242         }
1243         else if(la) {
1244                 if(R.totlamp) {
1245                         if(R.la[0]->org) MEM_freeN(R.la[0]->org);
1246                         MEM_freeN(R.la[0]);
1247                 }
1248                 R.totlamp= 0;
1249                 end_render_textures();
1250         }
1251         else if(wrld) {
1252                 end_render_textures();
1253         }
1254 }
1255