Orange branch: Revived hidden treasure, the Groups!
[blender.git] / source / blender / src / previewrender.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 /* global includes */
34
35 #include <stdlib.h>
36 #include <math.h>
37 #include <string.h>
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #ifndef WIN32
44 #include <unistd.h>
45 #else
46 #include <io.h>
47 #endif   
48 #include "MEM_guardedalloc.h"
49 #include "BLI_arithb.h"
50 #include "BKE_utildefines.h"
51
52 #include "MTC_matrixops.h"
53
54 #include "render.h"
55 #include "mydevice.h"
56
57 #include "DNA_group_types.h"
58 #include "DNA_texture_types.h"
59 #include "DNA_world_types.h"
60 #include "DNA_camera_types.h"
61 #include "DNA_image_types.h"
62 #include "DNA_material_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_mywindow.h"
83 #include "BIF_interface.h"
84 #include "BIF_glutil.h"
85
86 #include "BIF_previewrender.h"  /* include ourself for prototypes */
87
88 #include "PIL_time.h"
89
90 #include "RE_renderconverter.h"
91
92 #include "blendef.h"    /* CLAMP */
93 #include "interface.h"  /* ui_graphics_to_window() SOLVE! (ton) */
94
95 #define PR_RECTX        141
96 #define PR_RECTY        141
97 #define PR_XMIN         10
98 #define PR_YMIN         5
99 #define PR_XMAX         200
100 #define PR_YMAX         195
101
102 #define PR_FACY         (PR_YMAX-PR_YMIN-4)/(PR_RECTY)
103
104 static rctf prerect;
105 static float pr_facx, pr_facy;
106
107
108 /* implementation */
109
110 static short snijpunt(float *v1,   float *v2,  float *v3,  float *rtlabda, float *ray1, float *ray2)
111 {
112         float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22;
113         float m0,m1,m2,deeldet,det1,det2,det3;
114         float rtu, rtv;
115         
116         t00= v3[0]-v1[0];
117         t01= v3[1]-v1[1];
118         t02= v3[2]-v1[2];
119         t10= v3[0]-v2[0];
120         t11= v3[1]-v2[1];
121         t12= v3[2]-v2[2];
122         t20= ray1[0]-ray2[0];
123         t21= ray1[1]-ray2[1];
124         t22= ray1[2]-ray2[2];
125         
126         x0= t11*t22-t12*t21;
127         x1= t12*t20-t10*t22;
128         x2= t10*t21-t11*t20;
129
130         deeldet= t00*x0+t01*x1+t02*x2;
131         if(deeldet!=0.0f) {
132                 m0= ray1[0]-v3[0];
133                 m1= ray1[1]-v3[1];
134                 m2= ray1[2]-v3[2];
135                 det1= m0*x0+m1*x1+m2*x2;
136                 rtu= det1/deeldet;
137                 if(rtu<=0.0f) {
138                         det2= t00*(m1*t22-m2*t21);
139                         det2+= t01*(m2*t20-m0*t22);
140                         det2+= t02*(m0*t21-m1*t20);
141                         rtv= det2/deeldet;
142                         if(rtv<=0.0f) {
143                                 if(rtu+rtv>= -1.0f) {
144                                         
145                                         det3=  m0*(t12*t01-t11*t02);
146                                         det3+= m1*(t10*t02-t12*t00);
147                                         det3+= m2*(t11*t00-t10*t01);
148                                         *rtlabda= det3/deeldet;
149                                         
150                                         if(*rtlabda>=0.0f && *rtlabda<=1.0f) {
151                                                 return 1;
152                                         }
153                                 }
154                         }
155                 }
156         }
157         return 0;
158 }
159
160 static float rcubev[7][3]= {
161         {-0.002055,  6.627364, -3.369742}, 
162         {-6.031684, -3.750204, -1.992980}, 
163         {-6.049086,  3.817431,  1.969788}, 
164         { 6.031685,  3.833064,  1.992979}, 
165         { 6.049086, -3.734571, -1.969787}, 
166         { 0.002054, -6.544502,  3.369744}, 
167         {-0.015348,  1.023131,  7.332510} };
168
169 static int rcubi[3][4]= {
170         {3,  6,  5,  4},
171         {1,  5,  6,  2},  
172         {3,  0,  2,  6} };
173
174
175 static int ray_previewrender(int x,  int y,  float *vec, float *vn)
176 {
177         float scalef= 10.0f/100.0f;
178         float ray1[3], ray2[3];
179         float minlabda, labda;
180         int totface= 3, hitface= -1;
181         int a;
182
183         ray1[0]= ray2[0]= x*scalef;
184         ray1[1]= ray2[1]= y*scalef;
185         ray1[2]= -10.0f;
186         ray2[2]= 10.0f;
187         
188         minlabda= 1.0f;
189         for(a=0; a<totface; a++) {
190                 if(snijpunt( rcubev[rcubi[a][0]], rcubev[rcubi[a][1]], rcubev[rcubi[a][2]], &labda, ray1, ray2)) {
191                         if( labda < minlabda) {
192                                 minlabda= labda;
193                                 hitface= a;
194                         }
195                 }
196                 if(snijpunt( rcubev[rcubi[a][0]], rcubev[rcubi[a][2]], rcubev[rcubi[a][3]], &labda, ray1, ray2)) {
197                         if( labda < minlabda) {
198                                 minlabda= labda;
199                                 hitface= a;
200                         }
201                 }
202         }
203         
204         if(hitface > -1) {
205                 
206                 CalcNormFloat(rcubev[rcubi[hitface][0]], rcubev[rcubi[hitface][1]], rcubev[rcubi[hitface][2]], vn);
207                 
208                 vec[0]= (minlabda*(ray1[0]-ray2[0])+ray2[0])/4.1;
209                 vec[1]= (minlabda*(ray1[1]-ray2[1])+ray2[1])/4.1;
210                 vec[2]= (minlabda*(ray1[2]-ray2[2])+ray2[2])/4.1;
211                 
212                 return 1;
213         }
214         return 0;
215 }
216
217
218 static unsigned int previewback(int type, int x, int y)
219 {
220         
221         /* checkerboard, for later
222         x+= PR_RECTX/2;
223         y+= PR_RECTX/2;
224         if( ((x/24) + (y/24)) & 1) return 0x40404040;
225         else return 0xa0a0a0a0;
226         */
227         
228         if(type & MA_DARK) {
229                 if(abs(x)>abs(y)) return 0;
230                 else return 0x40404040;
231         }
232         else {
233                 if(abs(x)>abs(y)) return 0x40404040;
234                 else return 0xa0a0a0a0;
235         }
236 }
237
238 static void set_previewrect(int win, int xmin, int ymin, int xmax, int ymax)
239 {
240         float pr_sizex, pr_sizey;
241         
242         prerect.xmin= xmin;
243         prerect.ymin= ymin;
244         prerect.xmax= xmax;
245         prerect.ymax= ymax;
246
247         ui_graphics_to_window(win, &prerect.xmin, &prerect.ymin);
248         ui_graphics_to_window(win, &prerect.xmax, &prerect.ymax);
249         
250         pr_sizex= (prerect.xmax-prerect.xmin);
251         pr_sizey= (prerect.ymax-prerect.ymin);
252
253         pr_facx= ( pr_sizex-1.0f)/PR_RECTX;
254         pr_facy= ( pr_sizey-1.0f)/PR_RECTY;
255
256         /* correction for gla draw */
257         prerect.xmin-= curarea->winrct.xmin;
258         prerect.ymin-= curarea->winrct.ymin;
259         
260         glMatrixMode(GL_PROJECTION);
261         glPushMatrix();
262         glMatrixMode(GL_MODELVIEW);
263         glPushMatrix();
264         
265         glaDefine2DArea(&curarea->winrct);
266
267         glPixelZoom(pr_facx, pr_facy);
268         
269 }
270
271 static void end_previewrect(void)
272 {
273         glMatrixMode(GL_PROJECTION);
274         glPopMatrix();
275         glMatrixMode(GL_MODELVIEW);
276         glPopMatrix();
277         
278         glPixelZoom(1.0f, 1.0f);
279         
280         // restore viewport / scissor which was set by glaDefine2DArea
281         glViewport(curarea->winrct.xmin, curarea->winrct.ymin, curarea->winx, curarea->winy);
282         glScissor(curarea->winrct.xmin, curarea->winrct.ymin, curarea->winx, curarea->winy);
283
284 }
285
286 static void display_pr_scanline(unsigned int *rect, int recty)
287 {
288         
289         /* we do steps of 4 scanlines. but draw 5, because of errors in some gfx cards (nvidia geforce, ati...) */
290         if( (recty & 3)==3) {
291                 
292                 if(recty == 3) {
293                         glaDrawPixelsSafe(prerect.xmin, prerect.ymin, PR_RECTX, 4, rect);
294                 }
295                 else {
296                         rect+= (recty-4)*PR_RECTX;
297                         glaDrawPixelsSafe(prerect.xmin, prerect.ymin + (((float)recty-4.0)*pr_facy), PR_RECTX, 5, rect);
298                 }
299         }
300 }
301
302 static void draw_tex_crop(Tex *tex)
303 {
304         rcti rct;
305         int ret= 0;
306         
307         if(tex==0) return;
308         
309         if(tex->type==TEX_IMAGE) {
310                 if(tex->cropxmin==0.0f) ret++;
311                 if(tex->cropymin==0.0f) ret++;
312                 if(tex->cropxmax==1.0f) ret++;
313                 if(tex->cropymax==1.0f) ret++;
314                 if(ret==4) return;
315                 
316                 rct.xmin= PR_XMIN+2+tex->cropxmin*(PR_XMAX-PR_XMIN-4);
317                 rct.xmax= PR_XMIN+2+tex->cropxmax*(PR_XMAX-PR_XMIN-4);
318                 rct.ymin= PR_YMIN+2+tex->cropymin*(PR_YMAX-PR_YMIN-4);
319                 rct.ymax= PR_YMIN+2+tex->cropymax*(PR_YMAX-PR_YMIN-4);
320
321                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
322
323                 glColor3ub(0, 0, 0);
324                 glRecti(rct.xmin+1,  rct.ymin-1,  rct.xmax+1,  rct.ymax-1); 
325
326                 glColor3ub(255, 255, 255);
327                 glRecti(rct.xmin,  rct.ymin,  rct.xmax,  rct.ymax);
328
329                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);                      
330         }
331         
332 }
333
334 void BIF_all_preview_changed(void)
335 {
336         ScrArea *sa;
337         SpaceButs *sbuts;
338         
339         sa= G.curscreen->areabase.first;
340         while(sa) {
341                 if(sa->spacetype==SPACE_BUTS) {
342                         sbuts= sa->spacedata.first;
343                         sbuts->cury= 0;
344                         addafterqueue(sa->win, RENDERPREVIEW, 1);
345                 }
346                 sa= sa->next;
347         }
348 }
349
350 /* signal all previews in current screen of current type */
351 void BIF_preview_changed(SpaceButs *sbuts)
352 {
353
354         /* can be called when no buttonswindow visible */
355         if(sbuts) {
356                 ScrArea *sa;
357                 short mainb= sbuts->mainb;
358                 short tab= sbuts->tab[mainb];
359                 
360                 sa= G.curscreen->areabase.first;
361                 while(sa) {
362                         if(sa->spacetype==SPACE_BUTS) {
363                                 sbuts= sa->spacedata.first;
364                                 if(sbuts->mainb==mainb && sbuts->tab[mainb]==tab) {
365                                         sbuts->cury= 0;
366                                         addafterqueue(sbuts->area->win, RENDERPREVIEW, 1);
367                                 }
368                         }
369                         sa= sa->next;
370                 }
371         }
372 }
373
374 /* is panel callback, supposed to be called with correct panel offset matrix */
375 void BIF_previewdraw(void)
376 {
377         SpaceButs *sbuts= curarea->spacedata.first;
378         
379         if (sbuts->rect==0) BIF_preview_changed(sbuts);
380         else {
381                 int y;
382
383                 set_previewrect(sbuts->area->win, PR_XMIN, PR_YMIN, PR_XMAX, PR_YMAX);
384                 
385                 for (y=0; y<PR_RECTY; y++) {
386                         display_pr_scanline(sbuts->rect, y);
387                 }
388
389                 end_previewrect();
390                 
391                 if (sbuts->mainb==CONTEXT_SHADING && sbuts->tab[CONTEXT_SHADING]==TAB_SHADING_TEX) {
392                         draw_tex_crop(sbuts->lockpoin);
393                 }
394         }
395         if(sbuts->cury==0) BIF_preview_changed(sbuts);
396         
397 }
398
399 static void sky_preview_pixel(float lens, int x, int y, char *rect)
400 {
401         float view[3];
402         
403         if(R.wrld.skytype & WO_SKYPAPER) {
404                 view[0]= (2*x)/(float)PR_RECTX;
405                 view[1]= (2*y)/(float)PR_RECTY;
406                 view[2]= 0.0f;
407         }
408         else {
409                 view[0]= x;
410                 view[1]= y;
411                 view[2]= -lens*PR_RECTX/32.0;
412                 Normalise(view);
413         }
414         RE_sky_char(view, rect);
415 }
416
417 static void lamp_preview_pixel(ShadeInput *shi, LampRen *la, int x, int y, char *rect)
418 {
419         float inpr, i, t, dist, distkw, vec[3], lacol[3];
420         int col;
421         
422         shi->co[0]= (float)x/(PR_RECTX/4);
423         shi->co[1]= (float)y/(PR_RECTX/4);
424         shi->co[2]= 0;
425         
426         vec[0]= 0.02f*x;
427         vec[1]= 0.02f*y;
428         vec[2]= 0.005f*PR_RECTX;
429         VECCOPY(shi->view, vec);
430         dist= Normalise(shi->view);
431
432         lacol[0]= la->r;
433         lacol[1]= la->g;
434         lacol[2]= la->b;
435         
436         if(la->mode & LA_TEXTURE) do_lamp_tex(la, vec, shi, lacol);
437
438         if(la->type==LA_SUN || la->type==LA_HEMI) {
439                 dist= 1.0f;
440         }
441         else {
442                 
443                 if(la->mode & LA_QUAD) {
444                         
445                         t= 1.0f;
446                         if(la->ld1>0.0f)
447                                 t= la->dist/(la->dist+la->ld1*dist);
448                         if(la->ld2>0.0f) {
449                                 distkw= la->dist*la->dist;
450                                 t= t*distkw/(t*distkw+la->ld2*dist*dist);
451                         }
452                         dist= t;
453                 }
454                 else {
455                         dist= (la->dist/(la->dist+dist));
456                 }
457         }
458
459         /* yafray: preview shade as spot, sufficient */
460         if ((la->type==LA_SPOT) || (la->type==LA_YF_PHOTON)) {
461
462                 
463                 if(la->mode & LA_SQUARE) {
464                         /* slightly smaller... */
465                         inpr= 1.7*cos(MAX2(fabs(shi->view[0]/shi->view[2]) , fabs(shi->view[1]/shi->view[2]) ));
466                 }
467                 else {
468                         inpr= shi->view[2];
469                 }
470                 
471                 t= la->spotsi;
472                 if(inpr<t) dist= 0.0f;
473                 else {
474                         t= inpr-t;
475                         if(t<la->spotbl && la->spotbl!=0.0f) {
476                                 /* soft area */
477                                 i= t/la->spotbl;
478                                 t= i*i;
479                                 i= t*i;
480                                 inpr*=(3.0*t-2.0*i);
481                         }
482                 }
483                 dist*=inpr;
484         }
485         else if ELEM(la->type, LA_LOCAL, LA_AREA) dist*= shi->view[2];
486         
487         col= 255.0*dist*lacol[0];
488         if(col<=0) rect[0]= 0; else if(col>=255) rect[0]= 255; else rect[0]= col;
489
490         col= 255.0*dist*lacol[1];
491         if(col<=0) rect[1]= 0; else if(col>=255) rect[1]= 255; else rect[1]= col;
492
493         col= 255.0*dist*lacol[2];
494         if(col<=0) rect[2]= 0; else if(col>=255) rect[2]= 255; else rect[2]= col;
495 }
496
497 static void init_previewhalo(HaloRen *har, Material *mat)
498 {
499         
500         har->type= 0;
501         if(mat->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
502         har->mat= mat;
503         har->hard= mat->har;
504         har->rad= PR_RECTX/2.0;
505         har->radsq= PR_RECTX*PR_RECTX/4.0;
506         har->alfa= mat->alpha;
507         har->add= 255.0*mat->add;
508         har->r= mat->r;
509         har->g= mat->g; 
510         har->b= mat->b;
511         har->xs= PR_RECTX/2.0;
512         har->ys= PR_RECTX/2.0;
513         har->zs= har->zd= 0;
514         har->seed= (mat->seed1 % 256);
515         
516         if( (mat->mode & MA_HALOTEX) && mat->mtex[0] ) har->tex= 1; else har->tex=0;
517
518         if(mat->mode & MA_STAR) har->starpoints= mat->starc; else har->starpoints= 0;
519         if(mat->mode & MA_HALO_LINES) har->linec= mat->linec; else har->linec= 0;
520         if(mat->mode & MA_HALO_RINGS) har->ringc= mat->ringc; else har->ringc= 0;
521         if(mat->mode & MA_HALO_FLARE) har->flarec= mat->flarec; else har->flarec= 0;
522         
523         if(har->flarec) {
524                 har->xs-= PR_RECTX/3;
525                 har->ys+= PR_RECTX/3;
526                 
527                 har->rad*= 0.3;
528                 har->radsq= har->rad*har->rad;
529                 
530                 har->pixels= har->rad*har->rad*har->rad;
531         }
532 }       
533
534 static void halo_preview_pixel(HaloRen *har, int startx, int endx, int y, char *rect)
535 {
536         float dist, xn, yn, xsq, ysq, colf[4];
537         int x;
538         char front[4];
539         
540         if(har->flarec) yn= y-PR_RECTX/3;
541         else yn= y;
542         ysq= yn*yn;
543         
544         for(x=startx; x<endx; x++) {
545                 
546                 if(har->flarec) xn= x+PR_RECTX/3;
547                 else xn= x;
548                 
549                 xsq= xn*xn;
550                 dist= xsq+ysq;
551
552                 if(dist<har->radsq) {
553                         RE_shadehalo(har, front, colf, 0, dist, xn, yn, har->flarec);
554                         RE_addalphaAddfac(rect, front, har->add);
555                 }
556                 rect+= 4;
557         }
558 }
559
560 static void previewflare(SpaceButs *sbuts, HaloRen *har, unsigned int *rect)
561 {
562         uiBlock *block;
563         float ycor;
564         unsigned int *rectot;
565         int afmx, afmy, rectx, recty, y;
566         
567         block= uiFindOpenPanelBlockName(&curarea->uiblocks, "Preview");
568         if(block==NULL) return;
569
570         /* temps */
571         ycor= R.ycor;
572         rectx= R.rectx;
573         recty= R.recty;
574         afmx= R.afmx;
575         afmy= R.afmy;
576         rectot= R.rectot;
577
578         R.r.postmul= R.r.postgamma= R.r.postsat= 1.0f;
579         R.r.posthue= R.r.postadd= 0.0f;
580         R.ycor= 1.0f;
581         R.rectx= PR_RECTX;      
582         R.recty= PR_RECTY;
583         R.afmx= PR_RECTX/2;
584         R.afmy= PR_RECTY/2;
585         R.rectot= rect;
586
587         waitcursor(1);
588         RE_renderflare(har);
589         waitcursor(0);
590         // not sure why, either waitcursor or renderflare screws up (disabled then)
591         //areawinset(curarea->win);
592         
593         /* draw can just be this way, all settings are OK */
594         for (y=0; y<PR_RECTY; y++) {
595                 display_pr_scanline(sbuts->rect, y);
596         }
597         
598         /* temps */
599         R.ycor= ycor;
600         R.rectx= rectx;
601         R.recty= recty;
602         R.afmx= afmx;
603         R.afmy= afmy;
604         R.rectot= rectot;
605 }
606
607 static void texture_preview_pixel(Tex *tex, int x, int y, char *rect)
608 {
609         float i, v1, xsq, ysq, texvec[3];
610         float tin=1.0f, tr, tg, tb, ta;
611         int rgbnor, tracol, skip=0;
612         
613         if(tex->type==TEX_IMAGE) {
614                 v1= 1.0f/PR_RECTX;
615                 
616                 texvec[0]= 0.5+v1*x;
617                 texvec[1]= 0.5+v1*y;
618                 
619                 /* no coordinate mapping, exception: repeat */
620                 if(tex->extend==TEX_REPEAT) {
621                         if(tex->xrepeat>1) {
622                                 texvec[0] *= tex->xrepeat;
623                                 if(texvec[0]>1.0f) texvec[0] -= (int)(texvec[0]);
624                         }
625                         if(tex->yrepeat>1) {
626                                 texvec[1] *= tex->yrepeat;
627                                 if(texvec[1]>1.0f) texvec[1] -= (int)(texvec[1]);
628                         }
629                 }
630                 else if(tex->extend==TEX_CHECKER) {
631                         texvec[0]= 0.5+1.6*v1*x;
632                         texvec[1]= 0.5+1.6*v1*y;
633                 }
634         }
635         else if(tex->type==TEX_ENVMAP) {
636                 if(tex->env) {
637                         ysq= y*y;
638                         xsq= x*x;
639                         if(xsq+ysq < (PR_RECTX/2)*(PR_RECTY/2)) {
640                                 texvec[2]= sqrt( (float)((PR_RECTX/2)*(PR_RECTY/2)-xsq-ysq) );
641                                 texvec[0]= -x;
642                                 texvec[1]= -y;
643                                 Normalise(texvec);
644
645                                 i= 2.0*(texvec[2]);
646                                 texvec[0]= (i*texvec[0]);
647                                 texvec[1]= (i*texvec[1]);
648                                 texvec[2]= (-1.0f+i*texvec[2]);
649
650                         }
651                         else {
652                                 skip= 1;
653                                 tr= tg= tb= ta= 0.0f;
654                         }
655                 }
656                 else {
657                         skip= 1;
658                         tr= tg= tb= ta= 0.0f;
659                 }
660         }
661         else {
662                 v1= 2.0/PR_RECTX;
663         
664                 texvec[0]= v1*x;
665                 texvec[1]= v1*y;
666                 texvec[2]= 0.0f;
667         }
668         
669         if(skip==0) rgbnor= multitex_ext(tex, texvec, &tin, &tr, &tg, &tb, &ta);
670         else rgbnor= 1;
671         
672         if(rgbnor & 1) {
673                 
674                 v1= 255.0*tr;
675                 rect[0]= CLAMPIS(v1, 0, 255);
676                 v1= 255.0*tg;
677                 rect[1]= CLAMPIS(v1, 0, 255);
678                 v1= 255.0*tb;
679                 rect[2]= CLAMPIS(v1, 0, 255);
680                 
681                 if(ta!=1.0f) {
682                         tracol=  64+100*(abs(x)>abs(y));
683                         tracol= (1.0f-ta)*tracol;
684                         
685                         rect[0]= tracol+ (rect[0]*ta) ;
686                         rect[1]= tracol+ (rect[1]*ta) ;
687                         rect[2]= tracol+ (rect[2]*ta) ;
688                                         
689                 }
690         }
691         else {
692                 rect[0]= 255.0*tin;
693                 rect[1]= 255.0*tin;
694                 rect[2]= 255.0*tin;
695         }
696 }
697
698 static float pr1_lamp[3]= {2.3, -2.4, -4.6};
699 static float pr2_lamp[3]= {-8.8, -5.6, -1.5};
700 static float pr1_col[3]= {0.8, 0.8, 0.8};
701 static float pr2_col[3]= {0.5, 0.6, 0.7};
702
703 static void refraction_prv(int *x, int *y, float *n, float index)
704 {
705         float dot, fac, view[3], len;
706
707         index= 1.0f/index;
708         
709         view[0]= index*(float)*x;
710         view[1]= ((float)*y)/index;
711         view[2]= 20.0f;
712         len= Normalise(view);
713         
714         dot= view[0]*n[0] + view[1]*n[1] + view[2]*n[2];
715
716         if(dot>0.0f) {
717                 fac= 1.0f - (1.0f - dot*dot)*index*index;
718                 if(fac<= 0.0f) return;
719                 fac= -dot*index + sqrt(fac);
720         }
721         else {
722                 index = 1.0f/index;
723                 fac= 1.0f - (1.0f - dot*dot)*index*index;
724                 if(fac<= 0.0f) return;
725                 fac= -dot*index - sqrt(fac);
726         }
727
728         *x= (int)(len*(index*view[0] + fac*n[0]));
729         *y= (int)(len*(index*view[1] + fac*n[1]));
730 }
731
732 static void shade_lamp_loop_preview(ShadeInput *shi, ShadeResult *shr, int pr_lamp)
733 {
734         extern float fresnel_fac(float *view, float *vn, float ior, float fac);
735         Material *mat= shi->mat;
736         float inp, is, inprspec=0;
737         float lv[3], *la;
738         int a;
739         
740         // copy all relevant material vars, note, keep this synced with render_types.h
741         memcpy(&shi->r, &mat->r, 23*sizeof(float));
742         // set special cases:
743         shi->har= mat->har;
744         
745         if((mat->mode & MA_RAYMIRROR)==0) shi->ray_mirror= 0.0f;
746         memset(shr, 0, sizeof(ShadeResult));
747         
748         /* normals flipped in render for smooth... */
749         if( (mat->mapto & MAP_NORM)) VecMulf(shi->vn, -1.0f);
750         
751         do_material_tex(shi);
752         
753         /* normals flipped in render... */
754         if( (mat->mapto & MAP_NORM)) VecMulf(shi->vn, -1.0f);   
755         
756         shr->alpha= shi->alpha;
757         
758         if(mat->mode & (MA_ZTRA|MA_RAYTRANSP)) 
759                 if(mat->fresnel_tra!=0.0f) 
760                         shr->alpha*= fresnel_fac(shi->view, shi->vn, mat->fresnel_tra_i, mat->fresnel_tra);
761         
762         if(mat->mode & MA_SHLESS) {
763                 shr->diff[0]= shi->r;
764                 shr->diff[1]= shi->g;
765                 shr->diff[2]= shi->b;
766                 
767         }
768         else {
769                 
770                 for(a=0; a<2; a++) {
771                         
772                         if((pr_lamp & (1<<a))==0) continue;
773                         
774                         if(a==0) la= pr1_lamp;
775                         else la= pr2_lamp;
776                         
777                         lv[0]= shi->co[0]-la[0];
778                         lv[1]= shi->co[1]-la[1];
779                         lv[2]= shi->co[2]-la[2];
780                         Normalise(lv);
781                         
782                         is= shi->vn[0]*lv[0]+shi->vn[1]*lv[1]+shi->vn[2]*lv[2];
783                         if(is<0.0f) is= 0.0f;
784                         
785                         if(shi->spec>0.0f)  {
786                                 
787                                 if(is>0.0f) {
788                                         /* specular shaders */
789                                         float specfac;
790                                         
791                                         if(mat->spec_shader==MA_SPEC_PHONG) 
792                                                 specfac= Phong_Spec(shi->vn, lv, shi->view, shi->har, 0);
793                                         else if(mat->spec_shader==MA_SPEC_COOKTORR) 
794                                                 specfac= CookTorr_Spec(shi->vn, lv, shi->view, shi->har, 0);
795                                         else if(mat->spec_shader==MA_SPEC_BLINN) 
796                                                 specfac= Blinn_Spec(shi->vn, lv, shi->view, mat->refrac, (float)shi->har, 0);
797                                         else if(mat->spec_shader==MA_SPEC_WARDISO)
798                                                 specfac= WardIso_Spec(shi->vn, lv, shi->view, mat->rms, 0);
799                                         else 
800                                                 specfac= Toon_Spec(shi->vn, lv, shi->view, mat->param[2], mat->param[3], 0);
801                                         
802                                         inprspec= specfac*shi->spec;
803                                         
804                                         if(mat->mode & MA_RAMP_SPEC) {
805                                                 float spec[3];
806                                                 do_specular_ramp(shi, specfac, inprspec, spec);
807                                                 shr->spec[0]+= inprspec*spec[0];
808                                                 shr->spec[1]+= inprspec*spec[1];
809                                                 shr->spec[2]+= inprspec*spec[2];
810                                         }
811                                         else {  
812                                                 shr->spec[0]+= inprspec*shi->specr;
813                                                 shr->spec[1]+= inprspec*shi->specg;
814                                                 shr->spec[2]+= inprspec*shi->specb;
815                                         }
816                                 }
817                         }
818                         /* diffuse shaders */
819                         if(mat->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(shi->vn, lv, shi->view, mat->roughness);
820                         else if(mat->diff_shader==MA_DIFF_TOON) is= Toon_Diff(shi->vn, lv, shi->view, mat->param[0], mat->param[1]);
821                         else if(mat->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(is, shi->vn, shi->view, mat->darkness);
822                         else if(mat->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(shi->vn, lv, shi->view, mat->param[0], mat->param[1]);
823                         // else Lambert
824                         
825                         inp= (shi->refl*is + shi->emit);
826                         
827                         if(a==0) la= pr1_col;
828                         else la= pr2_col;
829                         
830                         add_to_diffuse(shr->diff, shi, is, inp*la[0], inp*la[1], inp*la[2]);
831                 }
832                 /* end lamp loop */
833                 
834                 /* drawing checkerboard and sky */
835                 if(mat->mode & MA_RAYMIRROR) {
836                         float col, div, y, z;
837                         int fac;
838                         
839                         /* rotate a bit in x */
840                         y= shi->ref[1]; z= shi->ref[2];
841                         shi->ref[1]= 0.98*y - 0.17*z;
842                         shi->ref[2]= 0.17*y + 0.98*z;
843                         
844                         /* scale */
845                         div= (0.85f*shi->ref[1]);
846                         
847                         shi->refcol[0]= shi->ray_mirror*fresnel_fac(shi->view, shi->vn, mat->fresnel_mir_i, mat->fresnel_mir);
848                         /* not real 'alpha', but mirror overriding transparency */
849                         if(mat->mode & MA_RAYTRANSP) {
850                                 float fac= sqrt(shi->refcol[0]);
851                                 shr->alpha= shr->alpha*(1.0f-fac) + fac;
852                         }
853                         else shr->alpha= shr->alpha*(1.0f-shi->refcol[0]) + shi->refcol[0];
854                         
855                         if(div<0.0f) {
856                                 /* minus 0.5 prevents too many small tiles in distance */
857                                 fac= (int)(shi->ref[0]/(div-0.1f) ) + (int)(shi->ref[2]/(div-0.1f) );
858                                 if(fac & 1) col= 0.8f;
859                                 else col= 0.3f;
860                                 
861                                 shi->refcol[1]= shi->refcol[0]*col;
862                                 shi->refcol[2]= shi->refcol[1];
863                                 shi->refcol[3]= shi->refcol[2];
864                         }
865                         else {
866                                 shi->refcol[1]= 0.0f;
867                                 shi->refcol[2]= shi->refcol[0]*0.3f*div;
868                                 shi->refcol[3]= shi->refcol[0]*0.8f*div;
869                         }
870                 }
871                 
872                 shr->diff[0]+= shi->ambr;
873                 shr->diff[1]+= shi->ambg;
874                 shr->diff[2]+= shi->ambb;
875                 
876                 if(mat->mode & MA_RAMP_COL) ramp_diffuse_result(shr->diff, shi);
877                 if(mat->mode & MA_RAMP_SPEC) ramp_spec_result(shr->spec, shr->spec+1, shr->spec+2, shi);
878                 
879                 /* refcol */
880                 if(shi->refcol[0]!=0.0f) {
881                         shr->diff[0]= shi->mirr*shi->refcol[1] + (1.0f - shi->mirr*shi->refcol[0])*shr->diff[0];
882                         shr->diff[1]= shi->mirg*shi->refcol[2] + (1.0f - shi->mirg*shi->refcol[0])*shr->diff[1];
883                         shr->diff[2]= shi->mirb*shi->refcol[3] + (1.0f - shi->mirb*shi->refcol[0])*shr->diff[2];
884                 }
885         
886                 /* ztra shade */
887                 if(shi->spectra!=0.0f) {
888                         inp = MAX3(shr->spec[0], shr->spec[1], shr->spec[2]);
889                         inp *= shi->spectra;
890                         if(inp>1.0f) inp= 1.0f;
891                         shr->alpha= (1.0f-inp)*shr->alpha+inp;
892                 }
893         }       
894 }
895
896 static void shade_preview_pixel(ShadeInput *shi, float *vec, int x, int y, char *rect, int smooth)
897 {
898         Material *mat;
899         MaterialLayer *ml;
900         ShadeResult shr;
901         float v1, inp;
902         float eul[3], tmat[3][3], imat[3][3], col[3];
903         char tracol;
904                 
905         mat= shi->mat;
906
907         v1= 1.0/PR_RECTX;
908         shi->view[0]= v1*x;
909         shi->view[1]= v1*y;
910         shi->view[2]= 1.0f;
911         Normalise(shi->view);
912         
913         shi->xs= (float)x;
914         shi->ys= (float)y;
915         
916         shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f;
917         VECCOPY(shi->co, vec);
918         
919         /* texture handling */
920         if(mat->texco) {
921                 
922                 VECCOPY(shi->lo, vec);
923                 
924                 if(mat->pr_type==MA_CUBE) {
925                         
926                         eul[0]= (297)*M_PI/180.0;
927                         eul[1]= 0.0;
928                         eul[2]= (45)*M_PI/180.0;
929                         EulToMat3(eul, tmat);
930
931                         MTC_Mat3MulVecfl(tmat, shi->lo);
932                         MTC_Mat3MulVecfl(tmat, shi->vn);
933                         /* hack for cubemap, why!!! */
934                         SWAP(float, shi->vn[0], shi->vn[1]);
935                 }
936                 /* textures otherwise upside down */
937                 if(mat->pr_type==MA_CUBE || mat->pr_type==MA_SPHERE) 
938                         shi->lo[2]= -shi->lo[2];
939
940                 if(mat->texco & TEXCO_GLOB) {
941                         VECCOPY(shi->gl, shi->lo);
942                 }
943                 if(mat->texco & TEXCO_WINDOW) {
944                         VECCOPY(shi->winco, shi->lo);
945                 }
946                 if(mat->texco & TEXCO_STICKY) {
947                         VECCOPY(shi->sticky, shi->lo);
948                 }
949                 if(mat->texco & TEXCO_UV) {
950                         VECCOPY(shi->uv, shi->lo);
951                 }
952                 if(mat->texco & TEXCO_STRAND) {
953                         shi->strand= shi->lo[0];
954                 }
955                 if(mat->texco & TEXCO_OBJECT) {
956                         /* nothing */
957                 }
958                 if(mat->texco & (TEXCO_NORM)) {
959                         shi->orn[0]= shi->vn[0];
960                         shi->orn[1]= shi->vn[1];
961                         shi->orn[2]= shi->vn[2];
962                 }
963                 if(mat->texco & TEXCO_REFL) {
964                         
965                         inp= -2.0*(shi->vn[0]*shi->view[0]+shi->vn[1]*shi->view[1]+shi->vn[2]*shi->view[2]);
966                         shi->ref[0]= (shi->view[0]+inp*shi->vn[0]);
967                         shi->ref[1]= (shi->view[1]+inp*shi->vn[1]);
968                         shi->ref[2]= (shi->view[2]+inp*shi->vn[2]);
969                 }
970
971                 /* Clear displase vec for preview */
972                 shi->displace[0]= shi->displace[1]= shi->displace[2]= 0.0;
973                         
974                 if(mat->texco & TEXCO_REFL) {
975                         /* normals in render are pointing different... rhm */
976                         if(smooth) shi->ref[1]= -shi->ref[1];
977                 }
978
979                 if(mat->pr_type==MA_CUBE) {
980                         /* rotate normal back for normals texture */
981                         SWAP(float, shi->vn[0], shi->vn[1]);
982                         MTC_Mat3Inv(imat, tmat);
983                         MTC_Mat3MulVecfl(imat, shi->vn);
984                 }
985                 
986         }
987
988         if(mat->mapto & MAP_DISPLACE) { /* Quick hack of fake displacement preview */
989 //              shi->vn[0]-=2.0*shi->displace[2];
990 //              shi->vn[1]-=2.0*shi->displace[0];
991 //              shi->vn[2]+=2.0*shi->displace[1];
992 //              Normalise(shi->vn);
993         }
994
995         /* ------  main shading loop with material layers */
996         VECCOPY(shi->vno, shi->vn);
997         if(mat->ml_flag & ML_RENDER) 
998                 shade_lamp_loop_preview(shi, &shr, mat->pr_lamp);
999         else {
1000                 memset(&shr, 0, sizeof(ShadeResult));
1001                 shr.alpha= 1.0f;
1002         }
1003
1004         for(ml= mat->layers.first; ml; ml= ml->next) {
1005                 if(ml->mat && (ml->flag & ML_RENDER)) {
1006                         ShadeResult shrlay;
1007                         
1008                         shi->mat= ml->mat;
1009                         shi->layerfac= ml->blendfac;
1010                         VECCOPY(shi->vn, shi->vno);
1011                         if(ml->flag & ML_NEG_NORMAL)
1012                                 VecMulf(shi->vn, -1.0);
1013
1014                         shade_lamp_loop_preview(shi, &shrlay, mat->pr_lamp);
1015                         matlayer_blend(ml, shi->layerfac, &shr, &shrlay);
1016                 }
1017         }
1018
1019         shi->mat= mat;  /* restore, shade input is re-used! */
1020
1021         /* after shading and composit layers */
1022         if(shr.spec[0]<0.0f) shr.spec[0]= 0.0f;
1023         if(shr.spec[1]<0.0f) shr.spec[1]= 0.0f;
1024         if(shr.spec[2]<0.0f) shr.spec[2]= 0.0f;
1025
1026         if(shr.diff[0]<0.0f) shr.diff[0]= 0.0f;
1027         if(shr.diff[1]<0.0f) shr.diff[1]= 0.0f;
1028         if(shr.diff[2]<0.0f) shr.diff[2]= 0.0f;
1029
1030         VECADD(col, shr.diff, shr.spec);
1031         if(col[0]<=0.0f) rect[0]= 0; else if(col[0]>=1.0f) rect[0]= 255; else rect[0]= (char)(255.0*col[0]);
1032         if(col[1]<=0.0f) rect[1]= 0; else if(col[1]>=1.0f) rect[1]= 255; else rect[1]= (char)(255.0*col[1]);
1033         if(col[2]<=0.0f) rect[2]= 0; else if(col[2]>=1.0f) rect[2]= 255; else rect[2]= (char)(255.0*col[2]);
1034
1035         if(shr.alpha!=1.0f) {
1036                 if(mat->mode & MA_RAYTRANSP) {
1037                         refraction_prv(&x, &y, shi->vn, shi->ang);
1038                 }
1039                 
1040                 tracol=  previewback(mat->pr_back, x, y) & 255;
1041                 
1042                 tracol= (1.0f-shr.alpha)*tracol;
1043                 
1044                 if((mat->mode & MA_RAYTRANSP) && mat->filter!=0.0) {
1045                         float fr= 1.0f+ mat->filter*(shr.diff[0]-1.0f);
1046                         rect[0]= fr*tracol+ (rect[0]*shr.alpha) ;
1047                         fr= 1.0f+ mat->filter*(shr.diff[0]-1.0f);
1048                         rect[1]= fr*tracol+ (rect[1]*shr.alpha) ;
1049                         fr= 1.0f+ mat->filter*(shr.diff[0]-1.0f);
1050                         rect[2]= fr*tracol+ (rect[2]*shr.alpha) ;
1051                 }
1052                 else {
1053                         rect[0]= tracol+ (rect[0]*shr.alpha) ;
1054                         rect[1]= tracol+ (rect[1]*shr.alpha) ;
1055                         rect[2]= tracol+ (rect[2]*shr.alpha) ;
1056                 }
1057         }
1058 }
1059
1060 static void preview_init_render_textures(MTex **mtex)
1061 {
1062         int x;
1063         
1064         for(x=0; x<MAX_MTEX; x++) {
1065                 if(mtex[x]) {
1066                         if(mtex[x]->tex) {
1067                                 init_render_texture(mtex[x]->tex);
1068                                 
1069                                 if(mtex[x]->tex->env && mtex[x]->tex->env->object) 
1070                                         MTC_Mat4One(mtex[x]->tex->env->object->imat);
1071                                 
1072                         }
1073                         if(mtex[x]->object) MTC_Mat4One(mtex[x]->object->imat);
1074                         if(mtex[x]->object) MTC_Mat4One(mtex[x]->object->imat);
1075                 }
1076         }
1077         
1078 }
1079
1080 void BIF_previewrender(SpaceButs *sbuts)
1081 {
1082         static double lasttime= 0;
1083         ID *id, *idfrom;
1084         Material *mat= NULL;
1085         Tex *tex= NULL;
1086         Lamp *la= NULL;
1087         World *wrld= NULL;
1088         LampRen *lar= NULL;
1089         Image *ima;
1090         HaloRen har;
1091         Object *ob;
1092         uiBlock *block;
1093         ShadeInput shi;
1094         float lens = 0.0, vec[3];
1095         int x, y, starty, startx, endy, endx, radsq, xsq, ysq, last = 0;
1096         unsigned int *rect;
1097
1098         if(sbuts->cury>=PR_RECTY) return;
1099         
1100         /* we safely assume curarea has panel "preview" */
1101         /* quick hack for now, later on preview should become uiBlock itself */
1102         
1103         block= uiFindOpenPanelBlockName(&curarea->uiblocks, "Preview");
1104         if(block==NULL) return;
1105
1106         ob= ((G.scene->basact)? (G.scene->basact)->object: 0);
1107         
1108         /* we cant trust this global lockpoin.. for example with headerless window */
1109         buttons_active_id(&id, &idfrom);
1110         G.buts->lockpoin= id;
1111
1112         if(sbuts->mainb==CONTEXT_SHADING) {
1113                 int tab= sbuts->tab[CONTEXT_SHADING];
1114                 
1115                 if(tab==TAB_SHADING_MAT) 
1116                         mat= sbuts->lockpoin;
1117                 else if(tab==TAB_SHADING_TEX) 
1118                         tex= sbuts->lockpoin;
1119                 else if(tab==TAB_SHADING_LAMP) {
1120                         if(ob && ob->type==OB_LAMP) la= ob->data;
1121                 }
1122                 else if(tab==TAB_SHADING_WORLD)
1123                         wrld= sbuts->lockpoin;
1124         }
1125         else if(sbuts->mainb==CONTEXT_OBJECT) {
1126                 if(ob && ob->type==OB_LAMP) la= ob->data;
1127         }
1128         
1129         /* return: when no active block to render. but we do draw black if possible */
1130         if(mat==NULL && tex==NULL && la==NULL && wrld==NULL) {
1131                 if(sbuts->rect) {
1132                         memset(sbuts->rect, 0, sizeof(int)*PR_RECTX*PR_RECTY);
1133                         sbuts->cury= PR_RECTY;
1134                         addqueue(curarea->win, REDRAW, 1);
1135                 }
1136                 return;
1137         }
1138         
1139         har.flarec= 0;  /* below is a test for postrender flare */
1140         
1141         if(qtest()) {
1142                 addafterqueue(curarea->win, RENDERPREVIEW, 1);
1143                 return;
1144         }
1145
1146         MTC_Mat4One(R.viewmat);
1147         MTC_Mat4One(R.viewinv);
1148         
1149         shi.osatex= 0;
1150         
1151         if(mat) {
1152                 MaterialLayer *ml;
1153                 
1154                 /* rendervars */
1155                 init_render_world();
1156                 init_render_material(mat);
1157                 /* also clears imats */
1158                 preview_init_render_textures(mat->mtex);
1159                 
1160                 for(ml= mat->layers.first; ml; ml= ml->next) {
1161                         if(ml->mat && (ml->flag & ML_RENDER)) {
1162                                 init_render_material(ml->mat);
1163                                 preview_init_render_textures(ml->mat->mtex);
1164                                 mat->texco |= ml->mat->texco;
1165                         }
1166                 }
1167                 
1168                 shi.vlr= NULL;          
1169                 shi.mat= mat;
1170                 
1171                 if(mat->mode & MA_HALO) init_previewhalo(&har, mat);
1172         }
1173         else if(tex) {
1174
1175                 ima= tex->ima;
1176                 if(ima) last= ima->lastframe;
1177                 init_render_texture(tex);
1178                 free_unused_animimages();
1179                 if(tex->ima) {
1180                         if(tex->ima!=ima) allqueue(REDRAWBUTSSHADING, 0);
1181                         else if(last!=ima->lastframe) allqueue(REDRAWBUTSSHADING, 0);
1182                 }
1183                 if(tex->env && tex->env->object) 
1184                         MTC_Mat4Invert(tex->env->object->imat, tex->env->object->obmat);
1185         }
1186         else if(la) {
1187
1188                 init_render_world();
1189                 preview_init_render_textures(la->mtex);
1190                 
1191                 RE_add_render_lamp(ob, 0);      /* 0=no shadbuf or tables */
1192                 lar= ((GroupObject *)R.lights.first)->lampren;
1193                 
1194                 /* exceptions: */
1195                 lar->spottexfac= 1.0f;
1196                 lar->spotsi= cos( M_PI/3.0f );
1197                 lar->spotbl= (1.0f-lar->spotsi)*la->spotblend;
1198                 
1199                 MTC_Mat3One(lar->imat);
1200         }
1201         else if(wrld) {
1202                 
1203                 lens= 35.0;
1204                 if(G.scene->camera) {
1205                         lens= ( (Camera *)G.scene->camera->data)->lens;
1206
1207                         /* needed for init_render_world */
1208                         MTC_Mat4CpyMat4(R.viewinv, G.scene->camera->obmat);
1209                         MTC_Mat4Ortho(R.viewinv);
1210                         MTC_Mat4Invert(R.viewmat, R.viewinv);
1211                 }
1212                 init_render_world();
1213                 preview_init_render_textures(wrld->mtex);       
1214         }
1215
1216         uiPanelPush(block);     // sets UImat
1217         
1218         set_previewrect(sbuts->area->win, PR_XMIN, PR_YMIN, PR_XMAX, PR_YMAX); // uses UImat
1219
1220         if(sbuts->rect==NULL) {
1221                 sbuts->rect= MEM_callocN(sizeof(int)*PR_RECTX*PR_RECTY, "butsrect");
1222                 
1223                 /* built in emboss */
1224                 rect= sbuts->rect;
1225                 for(y=0; y<PR_RECTY; y++, rect++) *rect= 0xFFFFFFFF;
1226                 
1227                 rect= sbuts->rect + PR_RECTX-1;
1228                 for(y=0; y<PR_RECTY; y++, rect+=PR_RECTX) *rect= 0xFFFFFFFF;
1229         }
1230         
1231         starty= -PR_RECTY/2;
1232         endy= starty+PR_RECTY;
1233         starty+= sbuts->cury;
1234         
1235         /* offset +1 for emboss */
1236         startx= -PR_RECTX/2 +1;
1237         endx= startx+PR_RECTX -2;
1238
1239         radsq= (PR_RECTX/2)*(PR_RECTY/2);
1240         
1241         if(mat) {
1242                 if(mat->pr_type==MA_SPHERE) {
1243                         pr1_lamp[0]= 2.3; pr1_lamp[1]= -2.4; pr1_lamp[2]= -4.6;
1244                         pr2_lamp[0]= -8.8; pr2_lamp[1]= -5.6; pr2_lamp[2]= -1.5;
1245                 }
1246                 else {
1247                         pr1_lamp[0]= 1.9; pr1_lamp[1]= 3.1; pr1_lamp[2]= -8.5;
1248                         pr2_lamp[0]= 1.2; pr2_lamp[1]= -18; pr2_lamp[2]= 3.2;
1249                 }
1250         }
1251
1252         /* here it starts! */
1253         glDrawBuffer(GL_FRONT);
1254
1255         for(y=starty; y<endy; y++) {
1256                 
1257                 rect= sbuts->rect + 1 + PR_RECTX*sbuts->cury;
1258                 
1259                 if(y== -PR_RECTY/2 || y==endy-1);               /* emboss */
1260                 else if(mat) {
1261                         
1262                         if(mat->mode & MA_HALO) {
1263                                 for(x=startx; x<endx; x++, rect++) {
1264                                         rect[0]= previewback(mat->pr_back, x, y);
1265                                 }
1266
1267                                 if(har.flarec) {
1268                                         if(y==endy-2) previewflare(sbuts, &har, sbuts->rect);
1269                                 }
1270                                 else {
1271                                         halo_preview_pixel(&har, startx, endx, y, (char *) (rect-PR_RECTX));
1272                                 }
1273                         }
1274                         else {
1275                                 ysq= y*y;
1276                                 for(x=startx; x<endx; x++, rect++) {
1277                                         xsq= x*x;
1278                                         if(mat->pr_type==MA_SPHERE) {
1279                                         
1280                                                 if(xsq+ysq <= radsq) {
1281                                                         shi.vn[0]= x;
1282                                                         shi.vn[1]= y;
1283                                                         shi.vn[2]= sqrt( (float)(radsq-xsq-ysq) );
1284                                                         Normalise(shi.vn);
1285                                                         
1286                                                         vec[0]= shi.vn[0];
1287                                                         vec[1]= shi.vn[2];
1288                                                         vec[2]= -shi.vn[1];
1289                                                         
1290                                                         shade_preview_pixel(&shi, vec, x, y, (char *)rect, 1);
1291                                                 }
1292                                                 else {
1293                                                         rect[0]= previewback(mat->pr_back, x, y);
1294                                                 }
1295                                         }
1296                                         else if(mat->pr_type==MA_CUBE) {
1297                                                 if( ray_previewrender(x, y, vec, shi.vn) ) {
1298                                                         
1299                                                         shade_preview_pixel(&shi, vec, x, y, (char *)rect, 0);
1300                                                 }
1301                                                 else {
1302                                                         rect[0]= previewback(mat->pr_back, x, y);
1303                                                 }
1304                                         }
1305                                         else {
1306                                                 vec[0]= x*(2.0f/PR_RECTX);
1307                                                 vec[1]= y*(2.0f/PR_RECTX);
1308                                                 vec[2]= 0.0;
1309                                                 
1310                                                 shi.vn[0]= shi.vn[1]= 0.0f;
1311                                                 shi.vn[2]= 1.0f;
1312                                                 
1313                                                 shade_preview_pixel(&shi, vec, x, y, (char *)rect, 0);
1314                                         }
1315                                 }
1316                         }
1317                 }
1318                 else if(tex) {
1319                         for(x=startx; x<endx; x++, rect++) {
1320                                 texture_preview_pixel(tex, x, y, (char *)rect);
1321                         }
1322                 }
1323                 else if(la) {
1324                         for(x=startx; x<endx; x++, rect++) {
1325                                 lamp_preview_pixel(&shi, lar, x, y, (char *)rect);
1326                         }
1327                 }
1328                 else  {
1329                         for(x=startx; x<endx; x++, rect++) {                            
1330                                 sky_preview_pixel(lens, x, y, (char *)rect);
1331                         }
1332                 }
1333                 
1334                 if(y<endy-2) {
1335
1336                         if(qtest()) {
1337                                 addafterqueue(curarea->win, RENDERPREVIEW, 1);
1338                                 break;
1339                         }
1340                 }
1341
1342                 display_pr_scanline(sbuts->rect, sbuts->cury);
1343                 
1344                 /* flush opengl for cards with frontbuffer slowness */
1345                 if(sbuts->cury==PR_RECTY-1 || (PIL_check_seconds_timer() - lasttime > 0.05)) {
1346                         lasttime= PIL_check_seconds_timer();
1347                         glFlush();
1348                 }
1349                 
1350                 sbuts->cury++;
1351         }
1352
1353         end_previewrect();
1354         
1355         if(sbuts->cury>=PR_RECTY && tex) 
1356                 if (sbuts->tab[CONTEXT_SHADING]==TAB_SHADING_TEX) 
1357                         draw_tex_crop(sbuts->lockpoin);
1358         
1359         glDrawBuffer(GL_BACK);
1360         /* draw again for clean swapbufers */
1361         BIF_previewdraw();
1362
1363         uiPanelPop(block);
1364         
1365         if(lar) {
1366                 MEM_freeN(lar);
1367                 MEM_freeN(R.lights.first);
1368                 R.lights.first= R.lights.last= NULL;
1369         }
1370 }
1371