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