Stamp refactoring:
[blender.git] / source / blender / editors / render / render_opengl.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/editors/render/render_opengl.c
26  *  \ingroup edrend
27  */
28
29
30 #include <math.h>
31 #include <string.h>
32 #include <stddef.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_camera_types.h"
37 #include "BLI_math.h"
38 #include "BLI_math_color_blend.h"
39 #include "BLI_blenlib.h"
40 #include "BLI_utildefines.h"
41 #include "BLI_jitter.h"
42 #include "BLI_threads.h"
43
44 #include "DNA_scene_types.h"
45 #include "DNA_object_types.h"
46
47 #include "BKE_camera.h"
48 #include "BKE_context.h"
49 #include "BKE_global.h"
50 #include "BKE_image.h"
51 #include "BKE_main.h"
52 #include "BKE_report.h"
53 #include "BKE_scene.h"
54 #include "BKE_sequencer.h"
55 #include "BKE_writeavi.h"
56
57 #include "WM_api.h"
58 #include "WM_types.h"
59
60 #include "ED_screen.h"
61 #include "ED_view3d.h"
62 #include "ED_gpencil.h"
63
64 #include "RE_pipeline.h"
65 #include "IMB_imbuf_types.h"
66 #include "IMB_imbuf.h"
67 #include "IMB_colormanagement.h"
68
69 #include "RNA_access.h"
70 #include "RNA_define.h"
71
72 #include "GPU_extensions.h"
73 #include "GPU_glew.h"
74 #include "GPU_compositing.h"
75
76
77 #include "render_intern.h"
78
79 typedef struct OGLRender {
80         Main *bmain;
81         Render *re;
82         Scene *scene;
83
84         View3D *v3d;
85         RegionView3D *rv3d;
86         ARegion *ar;
87
88         ScrArea *prevsa;
89         ARegion *prevar;
90
91         bool is_sequencer;
92         SpaceSeq *sseq;
93
94
95         Image *ima;
96         ImageUser iuser;
97
98         GPUOffScreen *ofs;
99         GPUFX *fx;
100         int sizex, sizey;
101         int write_still;
102
103         ReportList *reports;
104         bMovieHandle *mh;
105         int cfrao, nfra;
106
107         size_t totvideos;
108
109         /* quick lookup */
110         int view_id;
111
112         /* wm vars for timer and progress cursor */
113         wmWindowManager *wm;
114         wmWindow *win;
115
116         wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
117         void **movie_ctx_arr;
118 } OGLRender;
119
120 /* added because v3d is not always valid */
121 static unsigned int screen_opengl_layers(OGLRender *oglrender)
122 {
123         if (oglrender->v3d) {
124                 return oglrender->scene->lay | oglrender->v3d->lay;
125         }
126         else {
127                 return oglrender->scene->lay;
128         }
129 }
130
131 static bool screen_opengl_is_multiview(OGLRender *oglrender)
132 {
133         View3D *v3d = oglrender->v3d;
134         RegionView3D *rv3d = oglrender->rv3d;
135         RenderData *rd = &oglrender->scene->r;
136
137         if ((rd == NULL) || ((!oglrender->is_sequencer) && ((rv3d == NULL) || (v3d == NULL))))
138                 return false;
139
140         return (rd->scemode & R_MULTIVIEW) && ((oglrender->is_sequencer) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
141 }
142
143 static void screen_opengl_views_setup(OGLRender *oglrender)
144 {
145         RenderResult *rr;
146         RenderView *rv;
147         SceneRenderView *srv;
148         bool is_multiview;
149         View3D *v3d = oglrender->v3d;
150
151         RenderData *rd = &oglrender->scene->r;
152
153         rr = RE_AcquireResultWrite(oglrender->re);
154
155         is_multiview = screen_opengl_is_multiview(oglrender);
156
157         if (!is_multiview) {
158                 /* we only have one view when multiview is off */
159                 rv = rr->views.first;
160
161                 if (rv == NULL) {
162                         rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
163                         BLI_addtail(&rr->views, rv);
164                 }
165
166                 while (rv->next) {
167                         RenderView *rv_del = rv->next;
168                         BLI_remlink(&rr->views, rv_del);
169
170                         if (rv_del->rectf)
171                                 MEM_freeN(rv_del->rectf);
172
173                         if (rv_del->rectz)
174                                 MEM_freeN(rv_del->rectz);
175
176                         MEM_freeN(rv_del);
177                 }
178         }
179         else {
180                 if (!oglrender->is_sequencer)
181                         RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d));
182
183                 /* remove all the views that are not needed */
184                 rv = rr->views.last;
185                 while (rv) {
186                         srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
187                         if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
188                                 if (rv->rectf == NULL)
189                                         rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
190                                 rv = rv->prev;
191                         }
192                         else {
193                                 RenderView *rv_del = rv;
194                                 rv  = rv_del->prev;
195
196                                 BLI_remlink(&rr->views, rv_del);
197
198                                 if (rv_del->rectf)
199                                         MEM_freeN(rv_del->rectf);
200
201                                 if (rv_del->rectz)
202                                         MEM_freeN(rv_del->rectz);
203
204                                 MEM_freeN(rv_del);
205                         }
206                 }
207
208                 /* create all the views that are needed */
209                 for (srv = rd->views.first; srv; srv = srv->next) {
210                         if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
211                                 continue;
212
213                         rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name));
214
215                         if (rv == NULL) {
216                                 rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
217                                 BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
218                                 BLI_addtail(&rr->views, rv);
219                         }
220                 }
221         }
222
223         for (rv = rr->views.first; rv; rv = rv->next) {
224                 if (rv->rectf == NULL) {
225                         rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
226                 }
227         }
228
229         BLI_lock_thread(LOCK_DRAW_IMAGE);
230         if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) {
231                 oglrender->ima->flag |= IMA_IS_STEREO;
232         }
233         else {
234                 oglrender->ima->flag &= ~IMA_IS_STEREO;
235                 oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
236         }
237         BLI_unlock_thread(LOCK_DRAW_IMAGE);
238
239         RE_ReleaseResult(oglrender->re);
240 }
241
242 static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
243 {
244         Scene *scene = oglrender->scene;
245         ARegion *ar = oglrender->ar;
246         View3D *v3d = oglrender->v3d;
247         RegionView3D *rv3d = oglrender->rv3d;
248         Object *camera = NULL;
249         ImBuf *ibuf;
250         float winmat[4][4];
251         float *rectf = RE_RenderViewGetRectf(rr, oglrender->view_id);
252         int sizex = oglrender->sizex;
253         int sizey = oglrender->sizey;
254         const short view_context = (v3d != NULL);
255         bool draw_bgpic = true;
256         bool draw_sky = (scene->r.alphamode == R_ADDSKY);
257         unsigned char *rect = NULL;
258         const char *viewname = RE_GetActiveRenderView(oglrender->re);
259
260         if (oglrender->is_sequencer) {
261                 SeqRenderData context;
262                 SpaceSeq *sseq = oglrender->sseq;
263                 int chanshown = sseq ? sseq->chanshown : 0;
264                 struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL;
265
266                 BKE_sequencer_new_render_data(
267                         oglrender->bmain->eval_ctx, oglrender->bmain, scene,
268                         oglrender->sizex, oglrender->sizey, 100.0f,
269                         &context);
270
271                 context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
272                 ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);
273
274                 if (ibuf) {
275                         ImBuf *linear_ibuf;
276
277                         BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y));
278
279                         linear_ibuf = IMB_dupImBuf(ibuf);
280                         IMB_freeImBuf(ibuf);
281
282                         if (linear_ibuf->rect_float == NULL) {
283                                 /* internally sequencer working in display space and stores both bytes and float buffers in that space.
284                                  * It is possible that byte->float onversion didn't happen in sequencer (e.g. when adding image sequence/movie
285                                  * into sequencer) there'll be only byte buffer. Create float buffer from existing byte buffer, making it linear
286                                  */
287
288                                 IMB_float_from_rect(linear_ibuf);
289                         }
290                         else {
291                                 /* ensure float buffer is in linear space, not in display space */
292                                 BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf);
293                         }
294
295                         memcpy(rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
296
297                         IMB_freeImBuf(linear_ibuf);
298                 }
299
300                 if (gpd) {
301                         int i;
302                         unsigned char *gp_rect;
303
304                         GPU_offscreen_bind(oglrender->ofs, true);
305
306                         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
307                         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
308
309                         wmOrtho2(0, sizex, 0, sizey);
310                         glTranslatef(sizex / 2, sizey / 2, 0.0f);
311
312                         G.f |= G_RENDER_OGL;
313                         ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
314                         G.f &= ~G_RENDER_OGL;
315
316                         gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
317                         GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);
318
319                         BLI_assert(rectf != NULL);
320
321                         for (i = 0; i < sizex * sizey * 4; i += 4) {
322                                 float  col_src[4];
323                                 rgba_uchar_to_float(col_src, &gp_rect[i]);
324                                 blend_color_mix_float(&rectf[i], &rectf[i], col_src);
325                         }
326                         GPU_offscreen_unbind(oglrender->ofs, true);
327
328                         MEM_freeN(gp_rect);
329                 }
330         }
331         else if (view_context) {
332                 bool is_persp;
333                 /* full copy */
334                 GPUFXSettings fx_settings = v3d->fx_settings;
335
336                 ED_view3d_draw_offscreen_init(scene, v3d);
337
338                 GPU_offscreen_bind(oglrender->ofs, true); /* bind */
339
340                 /* render 3d view */
341                 if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
342 #if 0
343                         const bool is_ortho = (scene->r.mode & R_ORTHO) != 0;
344 #endif
345                         camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
346                         RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat);
347                         if (camera->type == OB_CAMERA) {
348                                 Camera *cam = camera->data;
349                                 is_persp = cam->type == CAM_PERSP;
350                         }
351                         else
352                                 is_persp = true;
353                         BKE_camera_to_gpu_dof(camera, &fx_settings);
354                 }
355                 else {
356                         rctf viewplane;
357                         float clipsta, clipend;
358
359                         bool is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
360                         if (is_ortho) orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
361                         else perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
362
363                         is_persp = !is_ortho;
364                 }
365
366                 rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
367
368                 if ((scene->r.mode & R_OSA) == 0) {
369                         ED_view3d_draw_offscreen(
370                                 scene, v3d, ar, sizex, sizey, NULL, winmat,
371                                 draw_bgpic, draw_sky, is_persp,
372                                 oglrender->ofs, oglrender->fx, &fx_settings, viewname);
373                         GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
374                 }
375                 else {
376                         /* simple accumulation, less hassle then FSAA FBO's */
377                         static float jit_ofs[32][2];
378                         float winmat_jitter[4][4];
379                         int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int) * 4, "accum1");
380                         int i, j;
381
382                         BLI_jitter_init(jit_ofs, scene->r.osa);
383
384                         /* first sample buffer, also initializes 'rv3d->persmat' */
385                         ED_view3d_draw_offscreen(
386                                 scene, v3d, ar, sizex, sizey, NULL, winmat,
387                                 draw_bgpic, draw_sky, is_persp,
388                                 oglrender->ofs, oglrender->fx, &fx_settings, viewname);
389                         GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
390
391                         for (i = 0; i < sizex * sizey * 4; i++)
392                                 accum_buffer[i] = rect[i];
393
394                         /* skip the first sample */
395                         for (j = 1; j < scene->r.osa; j++) {
396                                 copy_m4_m4(winmat_jitter, winmat);
397                                 window_translate_m4(winmat_jitter, rv3d->persmat,
398                                                     (jit_ofs[j][0] * 2.0f) / sizex,
399                                                     (jit_ofs[j][1] * 2.0f) / sizey);
400
401                                 ED_view3d_draw_offscreen(
402                                         scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
403                                         draw_bgpic, draw_sky, is_persp,
404                                         oglrender->ofs, oglrender->fx, &fx_settings, viewname);
405                                 GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
406
407                                 for (i = 0; i < sizex * sizey * 4; i++)
408                                         accum_buffer[i] += rect[i];
409                         }
410
411                         for (i = 0; i < sizex * sizey * 4; i++)
412                                 rect[i] = accum_buffer[i] / scene->r.osa;
413
414                         MEM_freeN(accum_buffer);
415                 }
416
417                 GPU_offscreen_unbind(oglrender->ofs, true); /* unbind */
418         }
419         else {
420                 /* shouldnt suddenly give errors mid-render but possible */
421                 char err_out[256] = "unknown";
422                 ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey,
423                                                                          IB_rect, OB_SOLID, false, true, true,
424                                                                          (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, viewname, err_out);
425                 camera = scene->camera;
426
427                 if (ibuf_view) {
428                         /* steal rect reference from ibuf */
429                         rect = (unsigned char *)ibuf_view->rect;
430                         ibuf_view->mall &= ~IB_rect;
431
432                         IMB_freeImBuf(ibuf_view);
433                 }
434                 else {
435                         fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
436                 }
437         }
438
439         /* note on color management:
440          *
441          * OpenGL renders into sRGB colors, but render buffers are expected to be
442          * linear So we convert to linear here, so the conversion back to bytes can make it
443          * sRGB (or other display space) again, and so that e.g. openexr saving also saves the
444          * correct linear float buffer.
445          */
446
447         if (rect) {
448                 int profile_to;
449                 float *rectf = RE_RenderViewGetRectf(rr, oglrender->view_id);
450                 
451                 if (BKE_scene_check_color_management_enabled(scene))
452                         profile_to = IB_PROFILE_LINEAR_RGB;
453                 else
454                         profile_to = IB_PROFILE_SRGB;
455
456                 /* sequencer has got trickier conversion happened above
457                  * also assume opengl's space matches byte buffer color space */
458                 IMB_buffer_float_from_byte(rectf, rect,
459                                            profile_to, IB_PROFILE_SRGB, true,
460                                            oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex);
461
462                 /* rr->rectf is now filled with image data */
463
464                 if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
465                         BKE_image_stamp_buf(scene, camera, rect, rectf, rr->rectx, rr->recty, 4);
466
467                 MEM_freeN(rect);
468         }
469 }
470
471 static void screen_opengl_render_write(OGLRender *oglrender)
472 {
473         Scene *scene = oglrender->scene;
474         RenderResult *rr;
475         bool ok;
476         char name[FILE_MAX];
477         Object *camera = RE_GetCamera(oglrender->re);
478
479         rr = RE_AcquireResultRead(oglrender->re);
480
481         BKE_render_result_stamp_info(scene, camera, rr);
482
483         BKE_image_path_from_imformat(
484                 name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
485                 &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL);
486
487         /* write images as individual images or stereo */
488         ok = RE_WriteRenderViewsImage(oglrender->reports, rr, scene, false, name);
489
490         RE_ReleaseResultImage(oglrender->re);
491
492         if (ok) printf("OpenGL Render written to '%s'\n", name);
493         else printf("OpenGL Render failed to write '%s'\n", name);
494 }
495
496 static void screen_opengl_render_apply(OGLRender *oglrender)
497 {
498         RenderResult *rr;
499         RenderView *rv;
500         int view_id;
501         ImBuf *ibuf;
502         void *lock;
503
504         rr = RE_AcquireResultRead(oglrender->re);
505         for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
506                 RE_SetActiveRenderView(oglrender->re, rv->name);
507                 oglrender->view_id = view_id;
508                 screen_opengl_render_doit(oglrender, rr);
509         }
510
511         RE_ReleaseResult(oglrender->re);
512
513         ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
514         if (ibuf) {
515                 ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
516         }
517         BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
518
519         if (oglrender->write_still) {
520                 screen_opengl_render_write(oglrender);
521         }
522 }
523
524 static bool screen_opengl_render_init(bContext *C, wmOperator *op)
525 {
526         /* new render clears all callbacks */
527         wmWindowManager *wm = CTX_wm_manager(C);
528         wmWindow *win = CTX_wm_window(C);
529
530         Scene *scene = CTX_data_scene(C);
531         ScrArea *prevsa = CTX_wm_area(C);
532         ARegion *prevar = CTX_wm_region(C);
533         GPUOffScreen *ofs;
534         OGLRender *oglrender;
535         int sizex, sizey;
536         bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
537         const bool is_animation = RNA_boolean_get(op->ptr, "animation");
538         const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
539         const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
540         char err_out[256] = "unknown";
541
542         if (G.background) {
543                 BKE_report(op->reports, RPT_ERROR, "Cannot use OpenGL render in background mode (no opengl context)");
544                 return false;
545         }
546
547         /* only one render job at a time */
548         if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER))
549                 return false;
550
551         if (is_sequencer) {
552                 is_view_context = false;
553         }
554         else {
555                 /* ensure we have a 3d view */
556                 if (!ED_view3d_context_activate(C)) {
557                         RNA_boolean_set(op->ptr, "view_context", false);
558                         is_view_context = false;
559                 }
560
561                 if (!is_view_context && scene->camera == NULL) {
562                         BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
563                         return false;
564                 }
565         }
566
567         if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) {
568                 BKE_report(op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected");
569                 return false;
570         }
571
572         /* stop all running jobs, except screen one. currently previews frustrate Render */
573         WM_jobs_kill_all_except(wm, CTX_wm_screen(C));
574
575         /* create offscreen buffer */
576         sizex = (scene->r.size * scene->r.xsch) / 100;
577         sizey = (scene->r.size * scene->r.ysch) / 100;
578
579         /* corrects render size with actual size, not every card supports non-power-of-two dimensions */
580         ofs = GPU_offscreen_create(sizex, sizey, err_out);
581
582         if (!ofs) {
583                 BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out);
584                 return false;
585         }
586
587         /* allocate opengl render */
588         oglrender = MEM_callocN(sizeof(OGLRender), "OGLRender");
589         op->customdata = oglrender;
590
591         oglrender->ofs = ofs;
592         oglrender->sizex = sizex;
593         oglrender->sizey = sizey;
594         oglrender->bmain = CTX_data_main(C);
595         oglrender->scene = scene;
596         oglrender->cfrao = scene->r.cfra;
597
598         oglrender->write_still = is_write_still && !is_animation;
599
600         oglrender->is_sequencer = is_sequencer;
601         if (is_sequencer) {
602                 oglrender->sseq = CTX_wm_space_seq(C);
603         }
604
605         oglrender->prevsa = prevsa;
606         oglrender->prevar = prevar;
607
608         if (is_view_context) {
609                 ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->ar); /* so quad view renders camera */
610                 oglrender->rv3d = oglrender->ar->regiondata;
611
612                 /* MUST be cleared on exit */
613                 oglrender->scene->customdata_mask_modal = ED_view3d_datamask(oglrender->scene, oglrender->v3d);
614
615                 /* apply immediately in case we're rendering from a script,
616                  * running notifiers again will overwrite */
617                 oglrender->scene->customdata_mask |= oglrender->scene->customdata_mask_modal;
618
619                 if (oglrender->v3d->fx_settings.fx_flag & (GPU_FX_FLAG_DOF | GPU_FX_FLAG_SSAO)) {
620                         oglrender->fx = GPU_fx_compositor_create();
621                 }
622         }
623
624         /* create render */
625         oglrender->re = RE_NewRender(scene->id.name);
626
627         /* create image and image user */
628         oglrender->ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
629         BKE_image_signal(oglrender->ima, NULL, IMA_SIGNAL_FREE);
630         BKE_image_backup_render(oglrender->scene, oglrender->ima);
631
632         oglrender->iuser.scene = scene;
633         oglrender->iuser.ok = 1;
634
635         /* create render result */
636         RE_InitState(oglrender->re, NULL, &scene->r, NULL, sizex, sizey, NULL);
637
638         /* create render views */
639         screen_opengl_views_setup(oglrender);
640
641         /* wm vars */
642         oglrender->wm = wm;
643         oglrender->win = win;
644
645         oglrender->totvideos = 0;
646         oglrender->mh = NULL;
647         oglrender->movie_ctx_arr = NULL;
648
649         return true;
650 }
651
652 static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
653 {
654         Main *bmain = CTX_data_main(C);
655         Scene *scene = oglrender->scene;
656         size_t i;
657
658         if (oglrender->mh) {
659                 if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
660                         for (i = 0; i < oglrender->totvideos; i++) {
661                                 oglrender->mh->end_movie(oglrender->movie_ctx_arr[i]);
662                                 oglrender->mh->context_free(oglrender->movie_ctx_arr[i]);
663                         }
664                 }
665
666                 if (oglrender->movie_ctx_arr) {
667                         MEM_freeN(oglrender->movie_ctx_arr);
668                 }
669         }
670
671         if (oglrender->timer) { /* exec will not have a timer */
672                 scene->r.cfra = oglrender->cfrao;
673                 BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, screen_opengl_layers(oglrender));
674
675                 WM_event_remove_timer(oglrender->wm, oglrender->win, oglrender->timer);
676         }
677
678         WM_cursor_modal_restore(oglrender->win);
679
680         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
681
682         if (oglrender->fx)
683                 GPU_fx_compositor_destroy(oglrender->fx);
684
685         GPU_offscreen_free(oglrender->ofs);
686
687         oglrender->scene->customdata_mask_modal = 0;
688
689         CTX_wm_area_set(C, oglrender->prevsa);
690         CTX_wm_region_set(C, oglrender->prevar);
691
692         MEM_freeN(oglrender);
693 }
694
695 static void screen_opengl_render_cancel(bContext *C, wmOperator *op)
696 {
697         screen_opengl_render_end(C, op->customdata);
698 }
699
700 /* share between invoke and exec */
701 static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
702 {
703         /* initialize animation */
704         OGLRender *oglrender;
705         Scene *scene;
706
707         oglrender = op->customdata;
708         scene = oglrender->scene;
709         oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
710
711         oglrender->reports = op->reports;
712
713         if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
714                 size_t i, width, height;
715
716                 BKE_scene_multiview_videos_dimensions_get(&scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
717                 oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
718                 oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
719
720                 for (i = 0; i < oglrender->totvideos; i++) {
721                         const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
722
723                         oglrender->movie_ctx_arr[i] = oglrender->mh->context_create();
724                         if (!oglrender->mh->start_movie(oglrender->movie_ctx_arr[i], scene, &scene->r, oglrender->sizex,
725                                                         oglrender->sizey, oglrender->reports, PRVRANGEON != 0, suffix))
726                         {
727                                 screen_opengl_render_end(C, oglrender);
728                                 return 0;
729                         }
730                 }
731         }
732
733         oglrender->cfrao = scene->r.cfra;
734         oglrender->nfra = PSFRA;
735         scene->r.cfra = PSFRA;
736
737         return 1;
738 }
739
740 static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
741 {
742         Main *bmain = CTX_data_main(C);
743         OGLRender *oglrender = op->customdata;
744         Scene *scene = oglrender->scene;
745         char name[FILE_MAX];
746         bool ok = false;
747         const bool view_context = (oglrender->v3d != NULL);
748         bool is_movie;
749         RenderResult *rr;
750
751         /* go to next frame */
752         if (CFRA < oglrender->nfra)
753                 CFRA++;
754         while (CFRA < oglrender->nfra) {
755                 unsigned int lay = screen_opengl_layers(oglrender);
756
757                 if (lay & 0xFF000000)
758                         lay &= 0xFF000000;
759
760                 BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, lay);
761                 CFRA++;
762         }
763
764         is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
765
766         if (!is_movie) {
767                 BKE_image_path_from_imformat(
768                         name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
769                         &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
770
771                 if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
772                         BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
773                         ok = true;
774                         goto finally;
775                 }
776         }
777
778         WM_cursor_time(oglrender->win, scene->r.cfra);
779
780         BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, screen_opengl_layers(oglrender));
781
782         if (view_context) {
783                 if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera && oglrender->v3d->scenelock) {
784                         /* since BKE_scene_update_for_newframe() is used rather
785                          * then ED_update_for_newframe() the camera needs to be set */
786                         if (BKE_scene_camera_switch_update(scene)) {
787                                 oglrender->v3d->camera = scene->camera;
788                         }
789                 }
790         }
791         else {
792                 BKE_scene_camera_switch_update(scene);
793         }
794
795         /* render into offscreen buffer */
796         screen_opengl_render_apply(oglrender);
797
798         /* save to disk */
799         rr = RE_AcquireResultRead(oglrender->re);
800
801         if (is_movie) {
802                 ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh, oglrender->sizex,
803                                               oglrender->sizey, oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0);
804                 if (ok) {
805                         printf("Append frame %d", scene->r.cfra);
806                         BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
807                 }
808         }
809         else {
810                 ok = RE_WriteRenderViewsImage(op->reports, rr, scene, true, name);
811                 if (ok) {
812                         printf("Saved: %s", name);
813                         BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
814                 }
815                 else {
816                         printf("Write error: cannot save %s\n", name);
817                         BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
818                 }
819         }
820
821         RE_ReleaseResult(oglrender->re);
822
823
824         /* movie stats prints have no line break */
825         printf("\n");
826
827
828 finally:  /* Step the frame and bail early if needed */
829
830         /* go to next frame */
831         oglrender->nfra += scene->r.frame_step;
832
833         /* stop at the end or on error */
834         if (CFRA >= PEFRA || !ok) {
835                 screen_opengl_render_end(C, op->customdata);
836                 return 0;
837         }
838
839         return 1;
840 }
841
842
843 static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
844 {
845         OGLRender *oglrender = op->customdata;
846         const bool anim = RNA_boolean_get(op->ptr, "animation");
847         bool ret;
848
849         switch (event->type) {
850                 case ESCKEY:
851                         /* cancel */
852                         screen_opengl_render_end(C, op->customdata);
853                         return OPERATOR_FINISHED;
854                 case TIMER:
855                         /* render frame? */
856                         if (oglrender->timer == event->customdata)
857                                 break;
858                         /* fall-through */
859                 default:
860                         /* nothing to do */
861                         return OPERATOR_RUNNING_MODAL;
862         }
863
864         /* run first because screen_opengl_render_anim_step can free oglrender */
865         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
866         
867         if (anim == 0) {
868                 screen_opengl_render_apply(op->customdata);
869                 screen_opengl_render_end(C, op->customdata);
870                 return OPERATOR_FINISHED;
871         }
872         else {
873                 ret = screen_opengl_render_anim_step(C, op);
874         }
875
876         /* stop at the end or on error */
877         if (ret == false) {
878                 return OPERATOR_FINISHED;
879         }
880
881         return OPERATOR_RUNNING_MODAL;
882 }
883
884 static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEvent *event)
885 {
886         OGLRender *oglrender;
887         const bool anim = RNA_boolean_get(op->ptr, "animation");
888
889         if (!screen_opengl_render_init(C, op))
890                 return OPERATOR_CANCELLED;
891
892         if (anim) {
893                 if (!screen_opengl_render_anim_initialize(C, op))
894                         return OPERATOR_CANCELLED;
895         }
896         
897         oglrender = op->customdata;
898         render_view_open(C, event->x, event->y);
899         
900         /* view may be changed above (R_OUTPUT_WINDOW) */
901         oglrender->win = CTX_wm_window(C);
902
903         WM_event_add_modal_handler(C, op);
904         oglrender->timer = WM_event_add_timer(oglrender->wm, oglrender->win, TIMER, 0.01f);
905         
906         return OPERATOR_RUNNING_MODAL;
907 }
908
909 /* executes blocking render */
910 static int screen_opengl_render_exec(bContext *C, wmOperator *op)
911 {
912         const bool is_animation = RNA_boolean_get(op->ptr, "animation");
913
914         if (!screen_opengl_render_init(C, op))
915                 return OPERATOR_CANCELLED;
916
917         if (!is_animation) { /* same as invoke */
918                 /* render image */
919                 screen_opengl_render_apply(op->customdata);
920                 screen_opengl_render_end(C, op->customdata);
921
922                 return OPERATOR_FINISHED;
923         }
924         else {
925                 bool ret = true;
926
927                 if (!screen_opengl_render_anim_initialize(C, op))
928                         return OPERATOR_CANCELLED;
929
930                 while (ret) {
931                         ret = screen_opengl_render_anim_step(C, op);
932                 }
933         }
934
935         /* no redraw needed, we leave state as we entered it */
936 //      ED_update_for_newframe(C, 1);
937         WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, CTX_data_scene(C));
938
939         return OPERATOR_FINISHED;
940 }
941
942 void RENDER_OT_opengl(wmOperatorType *ot)
943 {
944         PropertyRNA *prop;
945
946         /* identifiers */
947         ot->name = "OpenGL Render";
948         ot->description = "OpenGL render active viewport";
949         ot->idname = "RENDER_OT_opengl";
950
951         /* api callbacks */
952         ot->invoke = screen_opengl_render_invoke;
953         ot->exec = screen_opengl_render_exec; /* blocking */
954         ot->modal = screen_opengl_render_modal;
955         ot->cancel = screen_opengl_render_cancel;
956
957         ot->poll = ED_operator_screenactive;
958
959         prop = RNA_def_boolean(ot->srna, "animation", 0, "Animation", "Render files from the animation range of this scene");
960         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
961         prop = RNA_def_boolean(ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display");
962         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
963         prop = RNA_def_boolean(ot->srna, "write_still", 0, "Write Image", "Save rendered the image to the output path (used only when animation is disabled)");
964         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
965         prop = RNA_def_boolean(ot->srna, "view_context", 1, "View Context", "Use the current 3D view for rendering, else use scene settings");
966         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
967
968 }
969
970 /* function for getting an opengl buffer from a View3D, used by sequencer */
971 // extern void *sequencer_view3d_cb;