Subsurface scattering:
[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
50 #include "BLI_arithb.h"
51 #include "BLI_blenlib.h"
52
53 #include "MTC_matrixops.h"
54
55 #include "DNA_texture_types.h"
56 #include "DNA_world_types.h"
57 #include "DNA_camera_types.h"
58 #include "DNA_image_types.h"
59 #include "DNA_material_types.h"
60 #include "DNA_node_types.h"
61 #include "DNA_object_types.h"
62 #include "DNA_lamp_types.h"
63 #include "DNA_space_types.h"
64 #include "DNA_view3d_types.h"
65 #include "DNA_scene_types.h"
66 #include "DNA_screen_types.h"
67
68 #include "BKE_depsgraph.h"
69 #include "BKE_global.h"
70 #include "BKE_image.h"
71 #include "BKE_icons.h"
72 #include "BKE_library.h"
73 #include "BKE_main.h"
74 #include "BKE_texture.h"
75 #include "BKE_material.h"
76 #include "BKE_node.h"
77 #include "BKE_world.h"
78 #include "BKE_texture.h"
79 #include "BKE_utildefines.h"
80
81 #include "IMB_imbuf.h"
82 #include "IMB_imbuf_types.h"
83
84 #include "BSE_headerbuttons.h"
85 #include "BSE_node.h"
86 #include "BSE_view.h"
87
88 #include "BIF_gl.h"
89 #include "BIF_screen.h"
90 #include "BIF_space.h"          /* allqueue */
91 #include "BIF_butspace.h"       
92 #include "BIF_mywindow.h"
93 #include "BIF_interface.h"
94 #include "BIF_glutil.h"
95
96 #include "BIF_previewrender.h"  /* include ourself for prototypes */
97
98 #include "PIL_time.h"
99
100 #include "RE_pipeline.h"
101 #include "BLO_readfile.h" 
102
103 #include "blendef.h"    /* CLAMP */
104 #include "interface.h"  /* ui_graphics_to_window(),  SOLVE! (ton) */
105 #include "mydevice.h"
106
107
108 #define PR_XMIN         10
109 #define PR_YMIN         5
110 #define PR_XMAX         200
111 #define PR_YMAX         195
112
113
114 static void set_previewrect(RenderInfo *ri, int win)
115 {
116         rctf viewplane;
117         
118         BLI_init_rctf(&viewplane, PR_XMIN, PR_XMAX, PR_YMIN, PR_YMAX);
119
120         ui_graphics_to_window_rct(win, &viewplane, &ri->disprect);
121         
122         /* correction for gla draw */
123         BLI_translate_rcti(&ri->disprect, -curarea->winrct.xmin, -curarea->winrct.ymin);
124         
125         glMatrixMode(GL_PROJECTION);
126         glPushMatrix();
127         glMatrixMode(GL_MODELVIEW);
128         glPushMatrix();
129         
130         glaDefine2DArea(&curarea->winrct);
131
132         ri->pr_rectx= (ri->disprect.xmax-ri->disprect.xmin);
133         ri->pr_recty= (ri->disprect.ymax-ri->disprect.ymin);
134 }
135
136 static void end_previewrect(void)
137 {
138         glMatrixMode(GL_PROJECTION);
139         glPopMatrix();
140         glMatrixMode(GL_MODELVIEW);
141         glPopMatrix();
142         
143         // restore viewport / scissor which was set by glaDefine2DArea
144         glViewport(curarea->winrct.xmin, curarea->winrct.ymin, curarea->winx, curarea->winy);
145         glScissor(curarea->winrct.xmin, curarea->winrct.ymin, curarea->winx, curarea->winy);
146
147 }
148
149 /* unused now */
150 void draw_tex_crop(Tex *tex)
151 {
152         rcti rct;
153         int ret= 0;
154         
155         if(tex==0) return;
156         
157         if(tex->type==TEX_IMAGE) {
158                 if(tex->cropxmin==0.0f) ret++;
159                 if(tex->cropymin==0.0f) ret++;
160                 if(tex->cropxmax==1.0f) ret++;
161                 if(tex->cropymax==1.0f) ret++;
162                 if(ret==4) return;
163                 
164                 rct.xmin= PR_XMIN+2+tex->cropxmin*(PR_XMAX-PR_XMIN-4);
165                 rct.xmax= PR_XMIN+2+tex->cropxmax*(PR_XMAX-PR_XMIN-4);
166                 rct.ymin= PR_YMIN+2+tex->cropymin*(PR_YMAX-PR_YMIN-4);
167                 rct.ymax= PR_YMIN+2+tex->cropymax*(PR_YMAX-PR_YMIN-4);
168
169                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
170
171                 glColor3ub(0, 0, 0);
172                 glRecti(rct.xmin+1,  rct.ymin-1,  rct.xmax+1,  rct.ymax-1); 
173
174                 glColor3ub(255, 255, 255);
175                 glRecti(rct.xmin,  rct.ymin,  rct.xmax,  rct.ymax);
176
177                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);                      
178         }
179         
180 }
181
182 /* temporal abuse; if id_code is -1 it only does texture.... solve! */
183 void BIF_preview_changed(short id_code)
184 {
185         ScrArea *sa;
186         
187         for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
188                 if(sa->spacetype==SPACE_BUTS) {
189                         SpaceButs *sbuts= sa->spacedata.first;
190                         if(sbuts->mainb==CONTEXT_SHADING) {
191                                 int tab= sbuts->tab[CONTEXT_SHADING];
192                                 if(tab==TAB_SHADING_MAT && (id_code==ID_MA || id_code==ID_TE)) {
193                                         if (sbuts->ri) sbuts->ri->curtile= 0;
194                                         addafterqueue(sa->win, RENDERPREVIEW, 1);
195                                 }
196                                 else if(tab==TAB_SHADING_TEX && (id_code==ID_TE || id_code==-1)) {
197                                         if (sbuts->ri) sbuts->ri->curtile= 0;
198                                         addafterqueue(sa->win, RENDERPREVIEW, 1);
199                                 }
200                                 else if(tab==TAB_SHADING_LAMP && (id_code==ID_LA || id_code==ID_TE)) {
201                                         if (sbuts->ri) sbuts->ri->curtile= 0;
202                                         addafterqueue(sa->win, RENDERPREVIEW, 1);
203                                 }
204                                 else if(tab==TAB_SHADING_WORLD && (id_code==ID_WO || id_code==ID_TE)) {
205                                         if (sbuts->ri) sbuts->ri->curtile= 0;
206                                         addafterqueue(sa->win, RENDERPREVIEW, 1);
207                                 }
208                         }
209                         else if (sbuts->ri) 
210                                 sbuts->ri->curtile= 0;  /* ensure changes always result in re-render when context is restored */
211                 }
212                 else if(sa->spacetype==SPACE_NODE) {
213                         SpaceNode *snode= sa->spacedata.first;
214                         if(snode->treetype==NTREE_SHADER && (id_code==ID_MA || id_code==ID_TE)) {
215                                 snode_tag_dirty(snode);
216                         }
217                 }
218                 else if(sa->spacetype==SPACE_VIEW3D) {
219                         View3D *vd= sa->spacedata.first;
220                         /* if is has a renderinfo, we consider that reason for signalling */
221                         if (vd->ri) {
222                                 vd->ri->curtile= 0;
223                                 addafterqueue(sa->win, RENDERPREVIEW, 1);
224                         }
225                 }
226         }
227 }
228
229 /* *************************** Preview for buttons *********************** */
230
231 static Main *pr_main= NULL;
232
233 void BIF_preview_init_dbase(void)
234 {
235         BlendReadError bre;
236         BlendFileData *bfd;
237         extern int datatoc_preview_blend_size;
238         extern char datatoc_preview_blend[];
239         
240         G.fileflags |= G_FILE_NO_UI;
241         bfd= BLO_read_from_memory(datatoc_preview_blend, datatoc_preview_blend_size, &bre);
242         if (bfd) {
243                 pr_main= bfd->main;
244                 
245                 MEM_freeN(bfd);
246         }
247         G.fileflags &= ~G_FILE_NO_UI;
248 }
249
250 void BIF_preview_free_dbase(void)
251 {
252         if(pr_main)
253                 free_main(pr_main);
254 }
255
256 /* call this with an ID pointer to initialize preview scene */
257 /* call this with ID NULL to restore assigned ID pointers in preview scene */
258 static Scene *preview_prepare_scene(RenderInfo *ri, int id_type, ID *id, int pr_method)
259 {
260         Scene *sce;
261         Base *base;
262         
263         if(pr_main==NULL) return NULL;
264         
265         sce= pr_main->scene.first;
266         if(sce) {
267                 
268                 // sce->r.mode |= G.scene->r.mode & R_THREADS;
269                 /* this flag tells render to not execute depsgraph or ipos etc */
270                 sce->r.scemode |= R_PREVIEWBUTS;
271                 /* set world always back, is used now */
272                 sce->world= pr_main->world.first;
273                 
274                 sce->r.cfra= G.scene->r.cfra;
275                 
276                 if(id_type==ID_MA) {
277                         Material *mat= (Material *)id;
278                         
279                         if(id) {
280                                 init_render_material(mat, 0, NULL);             /* call that retrieves mode_l */
281                                 end_render_material(mat);
282                                 
283                                 /* turn on raytracing if needed */
284                                 if(mat->mode_l & (MA_RAYTRANSP|MA_RAYMIRROR))
285                                         sce->r.mode |= R_RAYTRACE;
286                                 
287                                 /* turn off fake shadows if needed */
288                                 /* this only works in a specific case where the preview.blend contains
289                                  * an object starting with 'c' which has a material linked to it (not the obdata)
290                                  * and that material has a fake shadow texture in the active texture slot */
291                                 for(base= sce->base.first; base; base= base->next) {
292                                         if(base->object->id.name[2]=='c') {
293                                                 Material *shadmat= give_current_material(base->object, base->object->actcol);
294                                                 if(shadmat) {
295                                                         if (mat->mode & MA_SHADBUF) shadmat->septex = 0;
296                                                         else shadmat->septex |= 1;
297                                                 }
298                                         }
299                                 }
300
301                                 
302                                 if(pr_method==PR_ICON_RENDER) {
303                                         if (mat->mode & MA_HALO) {
304                                                 sce->lay= 1<<MA_FLAT;
305                                         } 
306                                         else {
307                                                 sce->lay= 1<<MA_SPHERE_A;
308                                         }
309                                 }
310                                 else {
311                                         sce->lay= 1<<mat->pr_type;
312                                         if(mat->nodetree)
313                                                 ntreeInitPreview(mat->nodetree, ri->pr_rectx, ri->pr_recty);
314                                 }
315                         }
316                         else {
317                                 sce->r.mode &= ~(R_OSA|R_RAYTRACE);
318                         }
319                         
320                         for(base= sce->base.first; base; base= base->next) {
321                                 if(base->object->id.name[2]=='p') {
322                                         if(ELEM4(base->object->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL))
323                                                 assign_material(base->object, mat, base->object->actcol);
324                                 }
325                         }
326                 }
327                 else if(id_type==ID_TE) {
328                         Tex *tex= (Tex *)id;
329                         
330                         sce->lay= 1<<MA_TEXTURE;
331                         
332                         for(base= sce->base.first; base; base= base->next) {
333                                 if(base->object->id.name[2]=='t') {
334                                         Material *mat= give_current_material(base->object, base->object->actcol);
335                                         if(mat && mat->mtex[0]) {
336                                                 mat->mtex[0]->tex= tex;
337                                                 /* show alpha in this case */
338                                                 if(tex==NULL || (tex->flag & TEX_PRV_ALPHA)) {
339                                                         mat->mtex[0]->mapto |= MAP_ALPHA;
340                                                         mat->alpha= 0.0f;
341                                                 }
342                                                 else {
343                                                         mat->mtex[0]->mapto &= ~MAP_ALPHA;
344                                                         mat->alpha= 1.0f;
345                                                 }
346                                         }
347                                 }
348                         }
349                 }
350                 else if(id_type==ID_LA) {
351                         Lamp *la= (Lamp *)id;
352                         
353                         sce->lay= 1<<MA_LAMP;
354                         sce->r.mode &= ~R_SHADOW;
355                         
356                         for(base= sce->base.first; base; base= base->next) {
357                                 if(base->object->id.name[2]=='p') {
358                                         if(base->object->type==OB_LAMP)
359                                                 base->object->data= la;
360                                 }
361                         }
362                 }
363                 else if(id_type==ID_WO) {
364                         sce->lay= 1<<MA_SKY;
365                         sce->world= (World *)id;
366                 }
367                 
368                 return sce;
369         }
370         
371         return NULL;
372 }
373
374 static void previewrender_progress(RenderResult *rr, volatile rcti *renrect)
375 {
376         RenderLayer *rl;
377         RenderInfo *ri= G.buts->ri;
378         float ofsx, ofsy;
379         
380         if(renrect) return;
381         
382         rl= rr->layers.first;
383         
384         ofsx= ri->disprect.xmin + rr->tilerect.xmin;
385         ofsy= ri->disprect.ymin + rr->tilerect.ymin;
386         
387         glDrawBuffer(GL_FRONT);
388         glaDrawPixelsSafe_to32(ofsx, ofsy, rr->rectx, rr->recty, rr->rectx, rl->rectf);
389         bglFlush();
390         glDrawBuffer(GL_BACK);
391 }
392
393
394 /* called by interface_icons.c, or by BIF_previewrender_buts or by nodes... */
395 void BIF_previewrender(struct ID *id, struct RenderInfo *ri, struct ScrArea *area, int pr_method)
396 {
397         Render *re;
398         RenderStats *rstats;
399         Scene *sce;
400         SpaceButs *sbuts= NULL;
401         int oldx= ri->pr_rectx, oldy= ri->pr_recty;
402         char name [32];
403         
404         if(ri->tottile && ri->curtile>=ri->tottile) return;
405         
406         /* check for return with a new event */
407         if(pr_method!=PR_ICON_RENDER && qtest()) {
408                 if(area)
409                         addafterqueue(area->win, RENDERPREVIEW, 1);
410                 return;
411         }
412         
413         /* get the stuff from the builtin preview dbase */
414         sce= preview_prepare_scene(ri, GS(id->name), id, pr_method);
415         if(sce==NULL) return;
416         
417         /* set drawing conditions OK */
418         if(area) {
419                 sbuts= area->spacedata.first;   /* needed for flag */
420                 
421                 set_previewrect(ri, area->win); // uses UImat
422                 
423                 /* because preview render size can differs */
424                 if(ri->rect && (oldx!=ri->pr_rectx || oldy!=ri->pr_recty)) {
425                         MEM_freeN(ri->rect);
426                         ri->rect= NULL;
427                         ri->curtile= 0;
428                 }
429         }
430         
431         sprintf(name, "ButsPreview %d", area?area->win:0);
432         re= RE_GetRender(name);
433         
434         /* full refreshed render from first tile */
435         if(re==NULL || ri->curtile==0) {
436                 
437                 re= RE_NewRender(name);
438                 
439                 /* handle cases */
440                 if(pr_method==PR_DRAW_RENDER) {
441                         RE_display_draw_cb(re, previewrender_progress);
442                         RE_test_break_cb(re, qtest);
443                         sce->r.scemode |= R_NODE_PREVIEW;
444                         if(sbuts->flag & SB_PRV_OSA)
445                                 sce->r.mode |= R_OSA;
446                         sce->r.scemode &= ~R_NO_IMAGE_LOAD;
447                 }
448                 else if(pr_method==PR_DO_RENDER) {
449                         RE_test_break_cb(re, qtest);
450                         sce->r.scemode |= R_NODE_PREVIEW;
451                         sce->r.scemode &= ~R_NO_IMAGE_LOAD;
452                 }
453                 else {  /* PR_ICON_RENDER */
454                         sce->r.scemode &= ~R_NODE_PREVIEW;
455                         sce->r.scemode |= R_NO_IMAGE_LOAD;
456                 }
457                 
458                 /* allocates render result */
459                 RE_InitState(re, &sce->r, ri->pr_rectx, ri->pr_recty, NULL);
460                 
461                 /* enforce preview image clear */
462                 if(GS(id->name)==ID_MA) {
463                         Material *ma= (Material *)id;
464                         ntreeClearPreview(ma->nodetree);
465                 }
466         }
467         /* entire cycle for render engine */
468         RE_SetCamera(re, sce->camera);
469         RE_Database_FromScene(re, sce, 1);
470         RE_TileProcessor(re, ri->curtile, 0);   // actual render engine
471         RE_Database_Free(re);
472         
473         /* handle results */
474         if(pr_method==PR_ICON_RENDER) {
475                 if(ri->rect==NULL)
476                         ri->rect= MEM_mallocN(sizeof(int)*ri->pr_rectx*ri->pr_recty, "BIF_previewrender");
477                 RE_ResultGet32(re, ri->rect);
478         }
479         else {
480                 rstats= RE_GetStats(re);
481                 
482                 if(rstats->partsdone!=ri->curtile) {
483                         if(ri->rect==NULL)
484                                 ri->rect= MEM_mallocN(sizeof(int)*ri->pr_rectx*ri->pr_recty, "BIF_previewrender");
485                         RE_ResultGet32(re, ri->rect);
486                 }
487                 
488                 if(rstats->totpart==rstats->partsdone && rstats->partsdone) {
489                         if(GS(id->name)==ID_MA && ((Material *)id)->use_nodes)
490                                 allqueue(REDRAWNODE, 0);
491                         allqueue(REDRAWBUTSSHADING, 0);
492                 }
493                 else {
494                         if(pr_method==PR_DRAW_RENDER && qtest())
495                                 addafterqueue(area->win, RENDERPREVIEW, 1);
496                 }
497                 
498                 ri->curtile= rstats->partsdone;
499                 ri->tottile= rstats->totpart;
500         }
501
502         /* unassign the pointers, reset vars */
503         preview_prepare_scene(ri, GS(id->name), NULL, 0);
504         
505 }
506
507
508 /* afterqueue call */
509 void BIF_previewrender_buts(SpaceButs *sbuts)
510 {
511         uiBlock *block;
512         struct ID* id = 0;
513         struct ID* idfrom = 0;
514         struct ID* idshow = 0;
515         Object *ob;
516         
517         if (!sbuts->ri) return;
518         
519         /* we safely assume curarea has panel "preview" */
520         /* quick hack for now, later on preview should become uiBlock itself */
521         
522         block= uiFindOpenPanelBlockName(&curarea->uiblocks, "Preview");
523         if(block==NULL) return;
524         
525         ob= ((G.scene->basact)? (G.scene->basact)->object: 0);
526         
527         /* we cant trust this global lockpoin.. for example with headerless window */
528         buttons_active_id(&id, &idfrom);
529         G.buts->lockpoin= id;
530         
531         if(sbuts->mainb==CONTEXT_SHADING) {
532                 int tab= sbuts->tab[CONTEXT_SHADING];
533                 
534                 if(tab==TAB_SHADING_MAT) 
535                         idshow = sbuts->lockpoin;
536                 else if(tab==TAB_SHADING_TEX) 
537                         idshow = sbuts->lockpoin;
538                 else if(tab==TAB_SHADING_LAMP) {
539                         if(ob && ob->type==OB_LAMP) idshow= ob->data;
540                 }
541                 else if(tab==TAB_SHADING_WORLD)
542                         idshow = sbuts->lockpoin;
543         }
544         else if(sbuts->mainb==CONTEXT_OBJECT) {
545                 if(ob && ob->type==OB_LAMP) idshow = ob->data;
546         }
547         
548         if (idshow) {
549                 BKE_icon_changed(BKE_icon_getid(idshow));
550                 uiPanelPush(block);
551                 BIF_previewrender(idshow, sbuts->ri, sbuts->area, PR_DRAW_RENDER);
552                 uiPanelPop(block);
553                 end_previewrect();
554         }
555         else {
556                 /* no active block to draw. But we do draw black if possible */
557                 if(sbuts->ri->rect) {
558                         memset(sbuts->ri->rect, 0, sizeof(int)*sbuts->ri->pr_rectx*sbuts->ri->pr_recty);
559                         sbuts->ri->tottile= 10000;
560                         addqueue(curarea->win, REDRAW, 1);
561                 }
562                 return;
563         }
564 }
565
566
567 /* is panel callback, supposed to be called with correct panel offset matrix */
568 void BIF_previewdraw(ScrArea *sa, uiBlock *block)
569 {
570         SpaceButs *sbuts= sa->spacedata.first;
571         short id_code= 0;
572         
573         if(sbuts->lockpoin) {
574                 ID *id= sbuts->lockpoin;
575                 id_code= GS(id->name);
576         }
577         
578         if (!sbuts->ri) {
579                 sbuts->ri= MEM_callocN(sizeof(RenderInfo), "butsrenderinfo");
580                 sbuts->ri->tottile = 10000;
581         }
582         
583         if (sbuts->ri->rect==NULL) BIF_preview_changed(id_code);
584         else {
585                 RenderInfo *ri= sbuts->ri;
586                 int oldx= ri->pr_rectx, oldy= ri->pr_recty;
587                 
588                 /* we now do scalable previews! */
589                 set_previewrect(ri, sa->win);
590                 if( ABS(oldx-ri->pr_rectx)<2 && ABS(oldy-ri->pr_recty)<2 ) {
591                         /* restore old values for drawing! */
592                         ri->pr_rectx= oldx;
593                         ri->pr_recty= oldy;
594                         glaDrawPixelsSafe(ri->disprect.xmin, ri->disprect.ymin, ri->pr_rectx, ri->pr_recty, ri->pr_rectx, GL_RGBA, GL_UNSIGNED_BYTE, ri->rect);
595                 }
596                 else {
597                         MEM_freeN(ri->rect);
598                         ri->rect= NULL;
599                         sbuts->ri->curtile= 0;
600                 }
601                 end_previewrect();
602         }
603         if(sbuts->ri->curtile==0) BIF_preview_changed(id_code);
604         
605 }
606
607 /* *************************** Preview for 3d window *********************** */
608 static void view3d_previewrender_stats(RenderStats *rs)
609 {
610 //      if(rs->convertdone) 
611 //              printf("rendered %d %.3f\n", rs->partsdone, rs->lastframetime);
612 }
613
614 static void view3d_previewrender_progress(RenderResult *rr, volatile rcti *renrect)
615 {
616         RenderLayer *rl;
617         int ofsx, ofsy;
618         
619         if(renrect) return;
620         
621         rl= rr->layers.first;
622         
623         /* this case is when we render envmaps... */
624         if(rr->rectx>G.vd->ri->pr_rectx || rr->recty>G.vd->ri->pr_recty)
625                 return;
626         
627         ofsx= G.vd->ri->disprect.xmin + rr->tilerect.xmin;
628         ofsy= G.vd->ri->disprect.ymin + rr->tilerect.ymin;
629         
630         glDrawBuffer(GL_FRONT);
631         glaDefine2DArea(&curarea->winrct);
632         glaDrawPixelsSafe_to32(ofsx, ofsy, rr->rectx, rr->recty, rr->rectx, rl->rectf);
633         bglFlush();
634         glDrawBuffer(GL_BACK);
635
636 }
637
638 void BIF_view3d_previewrender_signal(ScrArea *sa, short signal)
639 {
640         View3D *v3d= sa->spacedata.first;
641         
642         /* this can be called from other window... solve! */
643         if(sa->spacetype!=SPACE_VIEW3D)
644                 v3d= G.vd;
645            
646         if(v3d && v3d->ri) {
647                 RenderInfo *ri= v3d->ri;
648                 ri->status &= ~signal;
649                 ri->curtile= 0;
650                 //printf("preview signal %d\n", signal);
651                 if(ri->re && (signal & PR_DBASE))
652                         RE_Database_Free(ri->re);
653
654                 addafterqueue(sa->win, RENDERPREVIEW, 1);
655         }
656 }
657
658 void BIF_view3d_previewrender_free(View3D *v3d)
659 {
660
661         if(v3d->ri) {
662                 RenderInfo *ri= v3d->ri;
663                 if(ri->re) {
664 //                      printf("free render\n");
665                         RE_Database_Free(ri->re);
666                         RE_FreeRender(ri->re);
667                         ri->re= NULL;
668                 }
669                 if (v3d->ri->rect) MEM_freeN(v3d->ri->rect);
670                 MEM_freeN(v3d->ri);
671                 v3d->ri= NULL;
672         }
673 }
674
675 /* returns 1 if OK, do not call while in panel space!  */
676 static int view3d_previewrender_get_rects(ScrArea *sa, rctf *viewplane, RenderInfo *ri, float *clipsta, float *clipend, int *ortho)
677 {
678         int rectx, recty;
679         uiBlock *block;
680         
681         block= uiFindOpenPanelBlockName(&curarea->uiblocks, "Preview");
682         if(block==NULL) return 0;
683         
684         /* calculate preview rect size */
685         BLI_init_rctf(viewplane, 15.0f, (block->maxx - block->minx)-15.0f, 15.0f, (block->maxy - block->miny)-15.0f);
686         uiPanelPush(block);
687         ui_graphics_to_window_rct(sa->win, viewplane, &ri->disprect);
688         uiPanelPop(block);
689         
690         /* correction for gla draw */
691         BLI_translate_rcti(&ri->disprect, -sa->winrct.xmin, -sa->winrct.ymin);
692         
693         *ortho= get_view3d_viewplane(sa->winx, sa->winy, viewplane, clipsta, clipend);
694
695         rectx= ri->disprect.xmax - ri->disprect.xmin;
696         recty= ri->disprect.ymax - ri->disprect.ymin;
697         
698         if(rectx<4 || recty<4) return 0;
699         
700         if(ri->rect && (rectx!=ri->pr_rectx || recty!=ri->pr_recty)) {
701                 MEM_freeN(ri->rect);
702                 ri->rect= NULL;
703                 ri->curtile= 0;
704                 printf("changed size\n");
705         }
706         ri->pr_rectx= rectx;
707         ri->pr_recty= recty;
708         
709         return 1;
710 }
711
712 /* called before a panel gets moved/scaled, makes sure we can see through */
713 void BIF_view3d_previewrender_clear(ScrArea *sa)
714 {
715         View3D *v3d= sa->spacedata.first;
716
717         if(v3d->ri) {
718                 RenderInfo *ri= v3d->ri;
719                 ri->curtile= 0;
720                 if(ri->rect)
721                         MEM_freeN(ri->rect);
722                 ri->rect= NULL;
723         }
724 }
725
726 /* afterqueue call */
727 void BIF_view3d_previewrender(ScrArea *sa)
728 {
729         View3D *v3d= sa->spacedata.first;
730         Render *re;
731         RenderInfo *ri; /* preview struct! */
732         RenderStats *rstats;
733         RenderData rdata;
734         rctf viewplane;
735         float clipsta, clipend;
736         int orth;
737         
738         /* first get the render info right */
739         if (!v3d->ri) {
740                 ri= v3d->ri= MEM_callocN(sizeof(RenderInfo), "butsrenderinfo");
741                 ri->tottile= 10000;
742         }
743         ri= v3d->ri;
744         
745         if(0==view3d_previewrender_get_rects(sa, &viewplane, ri, &clipsta, &clipend, &orth))
746                 return;
747         
748         /* render is finished, so return */
749         if(ri->tottile && ri->curtile>=ri->tottile) return;
750
751         /* or return with a new event */
752         if(qtest()) {
753                 addafterqueue(curarea->win, RENDERPREVIEW, 1);
754                 return;
755         }
756         //printf("Enter previewrender\n");
757         /* ok, are we rendering all over? */
758         if(ri->re==NULL) {
759                 char name[32];
760                 
761                 ri->status= 0;
762                 
763                 sprintf(name, "View3dPreview %d", sa->win);
764                 re= ri->re= RE_NewRender(name);
765                 RE_display_draw_cb(re, view3d_previewrender_progress);
766                 RE_stats_draw_cb(re, view3d_previewrender_stats);
767                 RE_test_break_cb(re, qtest);
768                 
769                 /* no osa, blur, seq, layers, etc for preview render */
770                 rdata= G.scene->r;
771                 rdata.mode &= ~(R_OSA|R_MBLUR);
772                 rdata.scemode &= ~(R_DOSEQ|R_DOCOMP|R_FREE_IMAGE);
773                 rdata.layers.first= rdata.layers.last= NULL;
774                 rdata.renderer= R_INTERN;
775                  
776                 RE_InitState(re, &rdata, sa->winx, sa->winy, &ri->disprect);
777         
778                 if(orth)
779                         RE_SetOrtho(re, &viewplane, clipsta, clipend);
780                 else
781                         RE_SetWindow(re, &viewplane, clipsta, clipend);
782                 
783                 /* until here are no escapes */
784                 ri->status |= PR_DISPRECT;
785                 ri->curtile= 0;
786                 //printf("new render\n");
787         }
788
789         re= ri->re;
790         
791         PIL_sleep_ms(100);      /* wait 0.1 second if theres really no event... */
792         if(qtest()==0)  {
793                 
794                 /* check status */
795                 if((ri->status & PR_DISPRECT)==0) {
796                         RE_SetDispRect(ri->re, &ri->disprect);
797                         if(orth)
798                                 RE_SetOrtho(ri->re, &viewplane, clipsta, clipend);
799                         else
800                                 RE_SetWindow(ri->re, &viewplane, clipsta, clipend);
801                         ri->status |= PR_DISPRECT;
802                         ri->curtile= 0;
803                         //printf("disprect update\n");
804                 }
805                 if((ri->status & PR_DBASE)==0) {
806                         unsigned int lay= G.scene->lay;
807                         
808                         RE_SetView(re, G.vd->viewmat);
809                         
810                         /* allow localview render for objects with lights in normal layers */
811                         if(v3d->lay & 0xFF000000)
812                                 G.scene->lay |= v3d->lay;
813                         else G.scene->lay= v3d->lay;
814                         
815                         RE_Database_FromScene(re, G.scene, 0);          // 0= dont use camera view
816                         G.scene->lay= lay;
817                         
818                         rstats= RE_GetStats(re);
819                         if(rstats->convertdone) 
820                                 ri->status |= PR_DBASE|PR_PROJECTED|PR_ROTATED;
821                         ri->curtile= 0;
822                         
823                         /* database can have created render-resol data... */
824                         if(rstats->convertdone) 
825                                 DAG_scene_update_flags(G.scene, screen_view3d_layers());
826                         
827                         //printf("dbase update\n");
828                 }
829                 if((ri->status & PR_PROJECTED)==0) {
830                         if(ri->status & PR_DBASE) {
831                                 if(orth)
832                                         RE_SetOrtho(ri->re, &viewplane, clipsta, clipend);
833                                 else
834                                         RE_SetWindow(ri->re, &viewplane, clipsta, clipend);
835                                 RE_DataBase_ApplyWindow(re);
836                                 ri->status |= PR_PROJECTED;
837                         }
838                         ri->curtile= 0;
839                         //printf("project update\n");
840                 }
841         
842                 /* OK, can we enter render code? */
843                 if(ri->status==(PR_DISPRECT|PR_DBASE|PR_PROJECTED|PR_ROTATED)) {
844                         //printf("curtile %d tottile %d\n", ri->curtile, ri->tottile);
845                         RE_TileProcessor(ri->re, ri->curtile, 0);
846         
847                         if(ri->rect==NULL)
848                                 ri->rect= MEM_mallocN(sizeof(int)*ri->pr_rectx*ri->pr_recty, "preview view3d rect");
849                         
850                         RE_ResultGet32(ri->re, ri->rect);
851                 }
852                 
853                 rstats= RE_GetStats(ri->re);
854                 if(rstats->totpart==rstats->partsdone && rstats->partsdone)
855                         addqueue(sa->win, REDRAW, 1);
856                 else
857                         addafterqueue(curarea->win, RENDERPREVIEW, 1);
858                 
859                 ri->curtile= rstats->partsdone;
860                 ri->tottile= rstats->totpart;
861         }
862         else {
863                 addafterqueue(curarea->win, RENDERPREVIEW, 1);
864         }
865         
866         //printf("\n");
867 }
868
869 /* in panel space! */
870 static void view3d_previewdraw_rect(ScrArea *sa, uiBlock *block, RenderInfo *ri)
871 {
872         rctf dispf;
873         
874         if(ri->rect==NULL)
875                 return;
876         
877         BLI_init_rctf(&dispf, 15.0f, (block->maxx - block->minx)-15.0f, 15.0f, (block->maxy - block->miny)-15.0f);
878         ui_graphics_to_window_rct(sa->win, &dispf, &ri->disprect);
879
880         /* correction for gla draw */
881         BLI_translate_rcti(&ri->disprect, -curarea->winrct.xmin, -curarea->winrct.ymin);
882         
883         /* when panel scale changed, free rect */
884         if(ri->disprect.xmax-ri->disprect.xmin != ri->pr_rectx ||
885            ri->disprect.ymax-ri->disprect.ymin != ri->pr_recty) {
886                 MEM_freeN(ri->rect);
887                 ri->rect= NULL;
888         }
889         else {
890                 glaDefine2DArea(&sa->winrct);
891                 glaDrawPixelsSafe(ri->disprect.xmin, ri->disprect.ymin, ri->pr_rectx, ri->pr_recty, ri->pr_rectx, GL_RGBA, GL_UNSIGNED_BYTE, ri->rect);
892         }       
893 }
894
895 /* is panel callback, supposed to be called with correct panel offset matrix */
896 void BIF_view3d_previewdraw(struct ScrArea *sa, struct uiBlock *block)
897 {
898         View3D *v3d= sa->spacedata.first;
899
900         if (v3d->ri==NULL || v3d->ri->rect==NULL) 
901                 addafterqueue(sa->win, RENDERPREVIEW, 1);
902         else {
903                 view3d_previewdraw_rect(sa, block, v3d->ri);
904                 if(v3d->ri->curtile==0) 
905                         addafterqueue(sa->win, RENDERPREVIEW, 1);
906         }
907 }
908