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