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