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