remove unused includes
[blender-staging.git] / source / blender / editors / render / render_opengl.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include <math.h>
28 #include <string.h>
29 #include <stddef.h>
30
31 #include <GL/glew.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_math.h"
36 #include "BLI_blenlib.h"
37 #include "BLI_editVert.h"
38 #include "BLI_dlrbTree.h"
39
40 #include "DNA_scene_types.h"
41 #include "DNA_object_types.h"
42
43 #include "BKE_context.h"
44 #include "BKE_image.h"
45 #include "BKE_main.h"
46 #include "BKE_report.h"
47 #include "BKE_scene.h"
48 #include "BKE_writeavi.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "ED_screen.h"
54 #include "ED_view3d.h"
55 #include "ED_image.h"
56
57 #include "RE_pipeline.h"
58 #include "IMB_imbuf_types.h"
59 #include "IMB_imbuf.h"
60
61 #include "RNA_access.h"
62 #include "RNA_define.h"
63
64
65 #include "GPU_extensions.h"
66
67 #include "wm_window.h"
68
69 #include "render_intern.h"
70
71 typedef struct OGLRender {
72         Render *re;
73         Scene *scene;
74
75         View3D *v3d;
76         RegionView3D *rv3d;
77         ARegion *ar;
78
79         Image *ima;
80         ImageUser iuser;
81
82         GPUOffScreen *ofs;
83         int sizex, sizey;
84
85         ReportList *reports;
86         bMovieHandle *mh;
87         int cfrao, nfra;
88
89         wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
90 } OGLRender;
91
92 /* added because v3d is not always valid */
93 static unsigned int screen_opengl_layers(OGLRender *oglrender)
94 {
95         if(oglrender->v3d) {
96                 return oglrender->scene->lay | oglrender->v3d->lay;
97         }
98         else {
99                 return oglrender->scene->lay;
100         }
101 }
102
103 static void screen_opengl_render_apply(OGLRender *oglrender)
104 {
105         Scene *scene= oglrender->scene;
106         ARegion *ar= oglrender->ar;
107         View3D *v3d= oglrender->v3d;
108         RegionView3D *rv3d= oglrender->rv3d;
109         RenderResult *rr;
110         ImBuf *ibuf;
111         void *lock;
112         float winmat[4][4];
113         int sizex= oglrender->sizex;
114         int sizey= oglrender->sizey;
115         int view_context = (v3d != NULL);
116
117         rr= RE_AcquireResultRead(oglrender->re);
118         
119         if(view_context) {
120                 GPU_offscreen_bind(oglrender->ofs); /* bind */
121
122                 /* render 3d view */
123                 if(rv3d->persp==RV3D_CAMOB && v3d->camera) {
124                         RE_GetCameraWindow(oglrender->re, v3d->camera, scene->r.cfra, winmat);
125                         ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat);
126                 }
127                 else {
128                         ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, NULL);
129                 }
130         
131                 glReadPixels(0, 0, sizex, sizey, GL_RGBA, GL_FLOAT, rr->rectf);
132
133                 GPU_offscreen_unbind(oglrender->ofs); /* unbind */
134         }
135         else {
136                 ImBuf *ibuf_view= ED_view3d_draw_offscreen_imbuf_simple(scene, oglrender->sizex, oglrender->sizey, OB_SOLID);
137                 IMB_float_from_rect(ibuf_view);
138
139                 memcpy(rr->rectf, ibuf_view->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
140
141                 IMB_freeImBuf(ibuf_view);
142         }
143         
144         /* rr->rectf is now filled with image data */
145
146         if((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
147                 BKE_stamp_buf(scene, NULL, rr->rectf, rr->rectx, rr->recty, 4);
148
149         RE_ReleaseResult(oglrender->re);
150
151         /* update byte from float buffer */
152         ibuf= BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
153         if(ibuf) image_buffer_rect_update(NULL, rr, ibuf, NULL);
154         BKE_image_release_ibuf(oglrender->ima, lock);
155 }
156
157 static int screen_opengl_render_init(bContext *C, wmOperator *op)
158 {
159         /* new render clears all callbacks */
160         Scene *scene= CTX_data_scene(C);
161         RenderResult *rr;
162         GPUOffScreen *ofs;
163         OGLRender *oglrender;
164         int sizex, sizey;
165         int view_context= RNA_boolean_get(op->ptr, "view_context");
166
167         /* ensure we have a 3d view */
168         
169         if(!ED_view3d_context_activate(C)) {
170                 RNA_boolean_set(op->ptr, "view_context", 0);
171                 view_context = 0;
172         }
173
174         /* only one render job at a time */
175         if(WM_jobs_test(CTX_wm_manager(C), scene))
176                 return 0;
177         
178         if(!view_context && scene->camera==NULL) {
179                 BKE_report(op->reports, RPT_ERROR, "Scene has no camera.");
180                 return 0;
181         }
182
183         /* stop all running jobs, currently previews frustrate Render */
184         WM_jobs_stop_all(CTX_wm_manager(C));
185
186         /* handle UI stuff */
187         WM_cursor_wait(1);
188
189         /* create offscreen buffer */
190         sizex= (scene->r.size*scene->r.xsch)/100;
191         sizey= (scene->r.size*scene->r.ysch)/100;
192
193         ofs= GPU_offscreen_create(sizex, sizey);
194
195         if(!ofs) {
196                 BKE_report(op->reports, RPT_ERROR, "Failed to create OpenGL offscreen buffer.");
197                 return 0;
198         }
199
200         /* allocate opengl render */
201         oglrender= MEM_callocN(sizeof(OGLRender), "OGLRender");
202         op->customdata= oglrender;
203
204         oglrender->ofs= ofs;
205         oglrender->sizex= sizex;
206         oglrender->sizey= sizey;
207         oglrender->scene= scene;
208
209         if(view_context) {
210                 oglrender->v3d= CTX_wm_view3d(C);
211                 oglrender->ar= CTX_wm_region(C);
212                 oglrender->rv3d= CTX_wm_region_view3d(C);
213         }
214
215         /* create image and image user */
216         oglrender->ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
217         BKE_image_signal(oglrender->ima, NULL, IMA_SIGNAL_FREE);
218
219         oglrender->iuser.scene= scene;
220         oglrender->iuser.ok= 1;
221
222         /* create render and render result */
223         oglrender->re= RE_NewRender(scene->id.name);
224         RE_InitState(oglrender->re, NULL, &scene->r, NULL, sizex, sizey, NULL);
225
226         rr= RE_AcquireResultWrite(oglrender->re);
227         if(rr->rectf==NULL)
228                 rr->rectf= MEM_callocN(sizeof(float)*4*sizex*sizey, "screen_opengl_render_init rect");
229         RE_ReleaseResult(oglrender->re);
230
231         return 1;
232 }
233
234 static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
235 {
236         Main *bmain= CTX_data_main(C);
237         Scene *scene= oglrender->scene;
238
239         if(oglrender->mh) {
240                 if(BKE_imtype_is_movie(scene->r.imtype))
241                         oglrender->mh->end_movie();
242         }
243
244         if(oglrender->timer) { /* exec will not have a timer */
245                 scene->r.cfra= oglrender->cfrao;
246                 scene_update_for_newframe(bmain, scene, screen_opengl_layers(oglrender));
247
248                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), oglrender->timer);
249         }
250
251         WM_cursor_wait(0);
252         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, oglrender->scene);
253
254         GPU_offscreen_free(oglrender->ofs);
255
256         MEM_freeN(oglrender);
257 }
258
259 static int screen_opengl_render_cancel(bContext *C, wmOperator *op)
260 {
261         screen_opengl_render_end(C, op->customdata);
262
263         return OPERATOR_CANCELLED;
264 }
265
266 /* share between invoke and exec */
267 static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
268 {
269         /* initialize animation */
270         OGLRender *oglrender;
271         Scene *scene;
272
273         oglrender= op->customdata;
274         scene= oglrender->scene;
275
276         oglrender->reports= op->reports;
277         oglrender->mh= BKE_get_movie_handle(scene->r.imtype);
278         if(BKE_imtype_is_movie(scene->r.imtype)) {
279                 if(!oglrender->mh->start_movie(scene, &scene->r, oglrender->sizex, oglrender->sizey, oglrender->reports)) {
280                         screen_opengl_render_end(C, oglrender);
281                         return 0;
282                 }
283         }
284
285         oglrender->cfrao= scene->r.cfra;
286         oglrender->nfra= SFRA;
287         scene->r.cfra= SFRA;
288
289         return 1;
290 }
291 static int screen_opengl_render_anim_step(bContext *C, wmOperator *op)
292 {
293         Main *bmain= CTX_data_main(C);
294         OGLRender *oglrender= op->customdata;
295         Scene *scene= oglrender->scene;
296         ImBuf *ibuf;
297         void *lock;
298         char name[FILE_MAXDIR+FILE_MAXFILE];
299         int ok= 0;
300         int view_context = (oglrender->v3d != NULL);
301
302         /* update animated image textures for gpu, etc,
303          * call before scene_update_for_newframe so modifiers with textuers dont lag 1 frame */
304         ED_image_update_frame(C);
305
306         /* go to next frame */
307         while(CFRA<oglrender->nfra) {
308                 unsigned int lay= screen_opengl_layers(oglrender);
309
310                 if(lay & 0xFF000000)
311                         lay &= 0xFF000000;
312
313                 scene_update_for_newframe(bmain, scene, lay);
314                 CFRA++;
315         }
316
317         scene_update_for_newframe(bmain, scene, screen_opengl_layers(oglrender));
318
319         if(view_context) {
320                 if(oglrender->rv3d->persp==RV3D_CAMOB && oglrender->v3d->camera && oglrender->v3d->scenelock) {
321                         /* since scene_update_for_newframe() is used rather
322                          * then ED_update_for_newframe() the camera needs to be set */
323                         if(scene_camera_switch_update(scene))
324                                 oglrender->v3d->camera= scene->camera;
325                 }
326         }
327         else {
328                 scene_camera_switch_update(scene);
329         }
330
331         /* render into offscreen buffer */
332         screen_opengl_render_apply(oglrender);
333
334         /* save to disk */
335         ibuf= BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
336
337         if(ibuf) {
338                 if(BKE_imtype_is_movie(scene->r.imtype)) {
339                         ok= oglrender->mh->append_movie(&scene->r, CFRA, (int*)ibuf->rect, oglrender->sizex, oglrender->sizey, oglrender->reports);
340                         if(ok) {
341                                 printf("Append frame %d", scene->r.cfra);
342                                 BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
343                         }
344                 }
345                 else {
346                         BKE_makepicstring(name, scene->r.pic, scene->r.cfra, scene->r.imtype, scene->r.scemode & R_EXTENSION);
347                         ok= BKE_write_ibuf(scene, ibuf, name, scene->r.imtype, scene->r.subimtype, scene->r.quality);
348
349                         if(ok==0) {
350                                 printf("Write error: cannot save %s\n", name);
351                                 BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
352                         }
353                         else {
354                                 printf("Saved: %s", name);
355                                 BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
356                         }
357                 }
358         }
359
360         BKE_image_release_ibuf(oglrender->ima, lock);
361
362         /* movie stats prints have no line break */
363         printf("\n");
364
365         /* go to next frame */
366         oglrender->nfra += scene->r.frame_step;
367         scene->r.cfra++;
368
369         /* stop at the end or on error */
370         if(scene->r.cfra > EFRA || !ok) {
371                 screen_opengl_render_end(C, op->customdata);
372                 return 0;
373         }
374
375         return 1;
376 }
377
378
379 static int screen_opengl_render_modal(bContext *C, wmOperator *op, wmEvent *event)
380 {
381         OGLRender *oglrender= op->customdata;
382
383         int ret;
384
385         switch(event->type) {
386                 case ESCKEY:
387                         /* cancel */
388                         screen_opengl_render_end(C, op->customdata);
389                         return OPERATOR_FINISHED;
390                 case TIMER:
391                         /* render frame? */
392                         if(oglrender->timer == event->customdata)
393                                 break;
394                 default:
395                         /* nothing to do */
396                         return OPERATOR_RUNNING_MODAL;
397         }
398
399         /* run first because screen_opengl_render_anim_step can free oglrender */
400         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, oglrender->scene);
401         
402         ret= screen_opengl_render_anim_step(C, op);
403
404         /* stop at the end or on error */
405         if(ret == 0) {
406                 return OPERATOR_FINISHED;
407         }
408
409         return OPERATOR_RUNNING_MODAL;
410 }
411
412 static int screen_opengl_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
413 {
414         int anim= RNA_boolean_get(op->ptr, "animation");
415
416         if(!screen_opengl_render_init(C, op))
417                 return OPERATOR_CANCELLED;
418
419         if(!anim) {
420                 /* render image */
421                 screen_opengl_render_apply(op->customdata);
422                 screen_opengl_render_end(C, op->customdata);
423                 screen_set_image_output(C, event->x, event->y);
424
425                 return OPERATOR_FINISHED;
426         }
427         else {
428                 OGLRender *oglrender= op->customdata;
429
430                 if(!screen_opengl_render_anim_initialize(C, op))
431                         return OPERATOR_CANCELLED;
432
433                 screen_set_image_output(C, event->x, event->y);
434
435                 WM_event_add_modal_handler(C, op);
436                 oglrender->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
437
438                 return OPERATOR_RUNNING_MODAL;
439         }
440 }
441
442 /* executes blocking render */
443 static int screen_opengl_render_exec(bContext *C, wmOperator *op)
444 {
445         int anim= RNA_boolean_get(op->ptr, "animation");
446
447         if(!screen_opengl_render_init(C, op))
448                 return OPERATOR_CANCELLED;
449
450         if(!anim) { /* same as invoke */
451                 /* render image */
452                 screen_opengl_render_apply(op->customdata);
453                 screen_opengl_render_end(C, op->customdata);
454
455                 return OPERATOR_FINISHED;
456         }
457         else {
458                 int ret= 1;
459
460                 if(!screen_opengl_render_anim_initialize(C, op))
461                         return OPERATOR_CANCELLED;
462
463                 while(ret) {
464                         ret= screen_opengl_render_anim_step(C, op);
465                 }
466         }
467
468         // no redraw needed, we leave state as we entered it
469 //      ED_update_for_newframe(C, 1);
470         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, CTX_data_scene(C));
471
472         return OPERATOR_FINISHED;
473 }
474
475 void RENDER_OT_opengl(wmOperatorType *ot)
476 {
477         /* identifiers */
478         ot->name= "OpenGL Render";
479         ot->description= "OpenGL render active viewport";
480         ot->idname= "RENDER_OT_opengl";
481
482         /* api callbacks */
483         ot->invoke= screen_opengl_render_invoke;
484         ot->exec= screen_opengl_render_exec; /* blocking */
485         ot->modal= screen_opengl_render_modal;
486         ot->cancel= screen_opengl_render_cancel;
487
488         ot->poll= ED_operator_screenactive;
489
490         RNA_def_boolean(ot->srna, "animation", 0, "Animation", "");
491         RNA_def_boolean(ot->srna, "view_context", 1, "View Context", "Use the current 3D view for rendering, else use scene settings.");
492 }
493
494 /* function for getting an opengl buffer from a View3D, used by sequencer */
495 // extern void *sequencer_view3d_cb;