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