Reports: writing movies now uses the reports mechanism to throw errors.
[blender-staging.git] / source / blender / editors / screen / screendump.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  * Making screendumps.
27  */
28
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "BLI_blenlib.h"
34
35 #include "IMB_imbuf_types.h"
36 #include "IMB_imbuf.h"
37
38 #include "DNA_scene_types.h"
39 #include "DNA_screen_types.h"
40 #include "DNA_space_types.h"
41
42 #include "BKE_context.h"
43 #include "BKE_global.h"
44 #include "BKE_image.h"
45 #include "BKE_report.h"
46 #include "BKE_utildefines.h"
47 #include "BKE_writeavi.h"
48
49 #include "BIF_gl.h"
50
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53
54 #include "WM_types.h"
55 #include "WM_api.h"
56
57 #include "PIL_time.h"
58
59 #include "ED_fileselect.h"
60 #include "ED_screen.h"
61 #include "ED_screen_types.h"
62
63 #include "screen_intern.h"
64
65 typedef struct ScreenshotData {
66         unsigned int *dumprect;
67         int dumpsx, dumpsy;
68 } ScreenshotData;
69
70 static int screenshot_exec(bContext *C, wmOperator *op)
71 {
72         ScreenshotData *scd= op->customdata;
73         
74         if(scd && scd->dumprect) {
75                 Scene *scene= CTX_data_scene(C);
76                 ImBuf *ibuf;
77                 char path[FILE_MAX];
78         
79                 RNA_string_get(op->ptr, "path", path);
80         
81                 strcpy(G.ima, path);
82                 BLI_convertstringcode(path, G.sce);
83                 
84                 /* BKE_add_image_extension() checks for if extension was already set */
85                 if(scene->r.scemode & R_EXTENSION) 
86                         if(strlen(path)<FILE_MAXDIR+FILE_MAXFILE-5)
87                                 BKE_add_image_extension(scene, path, scene->r.imtype);
88                 
89                 ibuf= IMB_allocImBuf(scd->dumpsx, scd->dumpsy, 24, 0, 0);
90                 ibuf->rect= scd->dumprect;
91                 
92                 if(scene->r.planes == 8) IMB_cspace(ibuf, rgb_to_bw);
93                 
94                 BKE_write_ibuf(scene, ibuf, path, scene->r.imtype, scene->r.subimtype, scene->r.quality);
95
96                 IMB_freeImBuf(ibuf);
97
98                 MEM_freeN(scd->dumprect);
99                 MEM_freeN(scd);
100                 op->customdata= NULL;
101         }
102         return OPERATOR_FINISHED;
103 }
104
105 /* get shot from frontbuffer */
106 static unsigned int *screenshot(bContext *C, int *dumpsx, int *dumpsy, int fscreen)
107 {
108         wmWindow *win= CTX_wm_window(C);
109         ScrArea *curarea= CTX_wm_area(C);
110         int x=0, y=0;
111         unsigned int *dumprect= NULL;
112         
113         if(fscreen) {   /* full screen */
114                 x= 0;
115                 y= 0;
116                 *dumpsx= win->sizex;
117                 *dumpsy= win->sizey;
118         } 
119         else {
120                 x= curarea->totrct.xmin;
121                 y= curarea->totrct.ymin;
122                 *dumpsx= curarea->totrct.xmax-x;
123                 *dumpsy= curarea->totrct.ymax-y;
124         }
125
126         if (*dumpsx && *dumpsy) {
127                 
128                 dumprect= MEM_mallocN(sizeof(int) * dumpsx[0] * dumpsy[0], "dumprect");
129                 glReadBuffer(GL_FRONT);
130                 glReadPixels(x, y, *dumpsx, *dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, dumprect);
131                 glFinish();
132                 glReadBuffer(GL_BACK);
133         }
134
135         return dumprect;
136 }
137
138
139 static int screenshot_invoke(bContext *C, wmOperator *op, wmEvent *event)
140 {
141         unsigned int *dumprect;
142         int dumpsx, dumpsy;
143         
144         dumprect= screenshot(C, &dumpsx, &dumpsy, RNA_boolean_get(op->ptr, "full"));
145         if(dumprect) {
146                 ScreenshotData *scd= MEM_callocN(sizeof(ScreenshotData), "screenshot");
147                 
148                 scd->dumpsx= dumpsx;
149                 scd->dumpsy= dumpsy;
150                 scd->dumprect= dumprect;
151                 op->customdata= scd;
152                 
153                 if(RNA_property_is_set(op->ptr, "path"))
154                         return screenshot_exec(C, op);
155                 
156                 RNA_string_set(op->ptr, "path", G.ima);
157                 
158                 WM_event_add_fileselect(C, op);
159         
160                 return OPERATOR_RUNNING_MODAL;
161         }       
162         return OPERATOR_CANCELLED;
163 }
164
165
166 void SCREEN_OT_screenshot(wmOperatorType *ot)
167 {
168         ot->name= "Save Screenshot"; /* weak: opname starting with 'save' makes filewindow give save-over */
169         ot->idname= "SCREEN_OT_screenshot";
170         
171         ot->invoke= screenshot_invoke;
172         ot->exec= screenshot_exec;
173         ot->poll= WM_operator_winactive;
174         
175         ot->flag= 0;
176         
177         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE, FILE_SPECIAL);
178         RNA_def_boolean(ot->srna, "full", 1, "Full Screen", "");
179 }
180
181 /* *************** screenshot movie job ************************* */
182
183 typedef struct ScreenshotJob {
184         Scene *scene;
185         unsigned int *dumprect;
186         int x, y, dumpsx, dumpsy;
187         short *stop;
188         short *do_update;
189         ReportList reports;
190 } ScreenshotJob;
191
192
193 static void screenshot_freejob(void *sjv)
194 {
195         ScreenshotJob *sj= sjv;
196         
197         if(sj->dumprect)
198                 MEM_freeN(sj->dumprect);
199         
200         MEM_freeN(sj);
201 }
202
203
204 /* called before redraw notifiers, copies a new dumprect */
205 static void screenshot_updatejob(void *sjv)
206 {
207         ScreenshotJob *sj= sjv;
208         unsigned int *dumprect;
209         
210         if(sj->dumprect==NULL) {
211                 dumprect= MEM_mallocN(sizeof(int) * sj->dumpsx * sj->dumpsy, "dumprect");
212                 glReadPixels(sj->x, sj->y, sj->dumpsx, sj->dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, dumprect);
213                 glFinish();
214                 
215                 sj->dumprect= dumprect;
216         }
217 }
218
219
220 /* only this runs inside thread */
221 static void screenshot_startjob(void *sjv, short *stop, short *do_update)
222 {
223         ScreenshotJob *sj= sjv;
224         RenderData rd= sj->scene->r;
225         bMovieHandle *mh= BKE_get_movie_handle(sj->scene->r.imtype);
226         int cfra= 1;
227         
228         /* we need this as local variables for renderdata */
229         rd.frs_sec= 10;
230         rd.frs_sec_base= 1.0f;
231         
232         if(BKE_imtype_is_movie(rd.imtype)) {
233                 if(!mh->start_movie(sj->scene, &rd, sj->dumpsx, sj->dumpsy, &sj->reports)) {
234                         printf("screencast job stopped\n");
235                         return;
236                 }
237         }
238         else
239                 mh= NULL;
240         
241         sj->stop= stop;
242         sj->do_update= do_update;
243         
244         *do_update= 1; // wait for opengl rect
245         
246         while(*stop==0) {
247                 
248                 if(sj->dumprect) {
249                         
250                         if(mh) {
251                                 if(mh->append_movie(&rd, cfra, (int *)sj->dumprect, sj->dumpsx, sj->dumpsy, &sj->reports))
252                                         printf("Append frame %d\n", cfra);
253                                 else
254                                         break;
255                         }
256                         else {
257                                 ImBuf *ibuf= IMB_allocImBuf(sj->dumpsx, sj->dumpsy, rd.planes, 0, 0);
258                                 char name[FILE_MAXDIR+FILE_MAXFILE];
259                                 int ok;
260                                 
261                                 BKE_makepicstring(sj->scene, name, rd.pic, cfra, rd.imtype);
262                                 
263                                 ibuf->rect= sj->dumprect;
264                                 ok= BKE_write_ibuf(sj->scene, ibuf, name, rd.imtype, rd.subimtype, rd.quality);
265                                 
266                                 if(ok==0) {
267                                         printf("Write error: cannot save %s\n", name);
268                                         break;
269                                 }
270                                 else printf("Saved: %s\n", name);
271                                 
272                 /* imbuf knows which rects are not part of ibuf */
273                                 IMB_freeImBuf(ibuf);    
274                         }
275                         
276                         MEM_freeN(sj->dumprect);
277                         sj->dumprect= NULL;
278                         
279                         *do_update= 1;
280                         
281                         cfra++;
282                 }
283                 else 
284                         PIL_sleep_ms(50);
285         }
286         
287         if(mh)
288                 mh->end_movie();
289         printf("screencast job stopped\n");
290 }
291
292 static int screencast_exec(bContext *C, wmOperator *op)
293 {
294         bScreen *screen= CTX_wm_screen(C);
295         wmJob *steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), screen, 0);
296         ScreenshotJob *sj= MEM_callocN(sizeof(ScreenshotJob), "screenshot job");
297
298         /* setup sj */
299         if(RNA_boolean_get(op->ptr, "full")) {
300                 wmWindow *win= CTX_wm_window(C);
301                 sj->x= 0;
302                 sj->y= 0;
303                 sj->dumpsx= win->sizex;
304                 sj->dumpsy= win->sizey;
305         } 
306         else {
307                 ScrArea *curarea= CTX_wm_area(C);
308                 sj->x= curarea->totrct.xmin;
309                 sj->y= curarea->totrct.ymin;
310                 sj->dumpsx= curarea->totrct.xmax - sj->x;
311                 sj->dumpsy= curarea->totrct.ymax - sj->y;
312         }
313         sj->scene= CTX_data_scene(C);
314
315         BKE_reports_init(&sj->reports, RPT_PRINT);
316
317         /* setup job */
318         WM_jobs_customdata(steve, sj, screenshot_freejob);
319         WM_jobs_timer(steve, 0.1, 0, NC_SCREEN|ND_SCREENCAST);
320         WM_jobs_callbacks(steve, screenshot_startjob, NULL, screenshot_updatejob);
321         
322         WM_jobs_start(CTX_wm_manager(C), steve);
323         
324         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENCAST, screen);
325         
326         return OPERATOR_FINISHED;
327 }
328
329 void SCREEN_OT_screencast(wmOperatorType *ot)
330 {
331         ot->name= "Make Screencast";
332         ot->idname= "SCREEN_OT_screencast";
333         
334         ot->invoke= WM_operator_confirm;
335         ot->exec= screencast_exec;
336         ot->poll= WM_operator_winactive;
337         
338         ot->flag= 0;
339         
340         RNA_def_property(ot->srna, "path", PROP_STRING, PROP_FILEPATH);
341         RNA_def_boolean(ot->srna, "full", 1, "Full Screen", "");
342 }
343
344
345