Blender  V2.59
screendump.c
Go to the documentation of this file.
00001 /*
00002  * $Id: screendump.c 36770 2011-05-19 11:13:35Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * Contributor(s): Blender Foundation
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  * Making screendumps.
00027  */
00028 
00034 #include <string.h>
00035 
00036 #include "MEM_guardedalloc.h"
00037 
00038 #include "BLI_blenlib.h"
00039 #include "BLI_utildefines.h"
00040 
00041 #include "IMB_imbuf_types.h"
00042 #include "IMB_imbuf.h"
00043 
00044 #include "DNA_scene_types.h"
00045 #include "DNA_screen_types.h"
00046 #include "DNA_space_types.h"
00047 #include "DNA_userdef_types.h"
00048 
00049 #include "BKE_context.h"
00050 #include "BKE_global.h"
00051 #include "BKE_main.h"
00052 #include "BKE_image.h"
00053 #include "BKE_report.h"
00054 #include "BKE_writeavi.h"
00055 
00056 #include "BIF_gl.h"
00057 
00058 #include "RNA_access.h"
00059 #include "RNA_define.h"
00060 
00061 #include "WM_types.h"
00062 #include "WM_api.h"
00063 
00064 #include "PIL_time.h"
00065 
00066 #include "ED_screen_types.h"
00067 
00068 #include "screen_intern.h"
00069 
00070 typedef struct ScreenshotData {
00071         unsigned int *dumprect;
00072         int dumpsx, dumpsy;
00073 } ScreenshotData;
00074 
00075 /* get shot from frontbuffer */
00076 static unsigned int *screenshot(bContext *C, int *dumpsx, int *dumpsy, int fscreen)
00077 {
00078         wmWindow *win= CTX_wm_window(C);
00079         ScrArea *curarea= CTX_wm_area(C);
00080         int x=0, y=0;
00081         unsigned int *dumprect= NULL;
00082         
00083         if(fscreen) {   /* full screen */
00084                 x= 0;
00085                 y= 0;
00086                 *dumpsx= win->sizex;
00087                 *dumpsy= win->sizey;
00088         } 
00089         else {
00090                 x= curarea->totrct.xmin;
00091                 y= curarea->totrct.ymin;
00092                 *dumpsx= curarea->totrct.xmax-x;
00093                 *dumpsy= curarea->totrct.ymax-y;
00094         }
00095 
00096         if (*dumpsx && *dumpsy) {
00097                 
00098                 dumprect= MEM_mallocN(sizeof(int) * (*dumpsx) * (*dumpsy), "dumprect");
00099                 glReadBuffer(GL_FRONT);
00100                 glReadPixels(x, y, *dumpsx, *dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, dumprect);
00101                 glFinish();
00102                 glReadBuffer(GL_BACK);
00103         }
00104 
00105         return dumprect;
00106 }
00107 
00108 /* call from both exec and invoke */
00109 static int screenshot_data_create(bContext *C, wmOperator *op)
00110 {
00111         unsigned int *dumprect;
00112         int dumpsx, dumpsy;
00113         
00114         dumprect= screenshot(C, &dumpsx, &dumpsy, RNA_boolean_get(op->ptr, "full"));
00115         if(dumprect) {
00116                 ScreenshotData *scd= MEM_callocN(sizeof(ScreenshotData), "screenshot");
00117                 
00118                 scd->dumpsx= dumpsx;
00119                 scd->dumpsy= dumpsy;
00120                 scd->dumprect= dumprect;
00121                 op->customdata= scd;
00122                 return TRUE;
00123         }
00124         else {
00125                 op->customdata= NULL;
00126                 return FALSE;
00127         }
00128 }
00129 
00130 static void screenshot_data_free(wmOperator *op)
00131 {
00132         ScreenshotData *scd= op->customdata;
00133 
00134         if(scd) {
00135                 if(scd->dumprect)
00136                         MEM_freeN(scd->dumprect);
00137                 MEM_freeN(scd);
00138                 op->customdata= NULL;
00139         }
00140 }
00141 
00142 static int screenshot_exec(bContext *C, wmOperator *op)
00143 {
00144         ScreenshotData *scd= op->customdata;
00145 
00146         if(scd == NULL) {
00147                 /* when running exec directly */
00148                 screenshot_data_create(C, op);
00149                 scd= op->customdata;
00150         }
00151 
00152         if(scd) {
00153                 if(scd->dumprect) {
00154                         Scene *scene= CTX_data_scene(C);
00155                         ImBuf *ibuf;
00156                         char path[FILE_MAX];
00157 
00158                         RNA_string_get(op->ptr, "filepath", path);
00159 
00160                         strcpy(G.ima, path);
00161                         BLI_path_abs(path, G.main->name);
00162 
00163                         /* BKE_add_image_extension() checks for if extension was already set */
00164                         if(scene->r.scemode & R_EXTENSION)
00165                                 if(strlen(path)<FILE_MAXDIR+FILE_MAXFILE-5)
00166                                         BKE_add_image_extension(path, scene->r.imtype);
00167 
00168                         ibuf= IMB_allocImBuf(scd->dumpsx, scd->dumpsy, 24, 0);
00169                         ibuf->rect= scd->dumprect;
00170 
00171                         BKE_write_ibuf(ibuf, path, scene->r.imtype, scene->r.subimtype, scene->r.quality);
00172 
00173                         IMB_freeImBuf(ibuf);
00174                 }
00175         }
00176 
00177         screenshot_data_free(op);
00178         return OPERATOR_FINISHED;
00179 }
00180 
00181 static int screenshot_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
00182 {
00183         if(screenshot_data_create(C, op)) {
00184                 if(RNA_property_is_set(op->ptr, "filepath"))
00185                         return screenshot_exec(C, op);
00186                 
00187                 RNA_string_set(op->ptr, "filepath", G.ima);
00188                 
00189                 WM_event_add_fileselect(C, op);
00190         
00191                 return OPERATOR_RUNNING_MODAL;
00192         }       
00193         return OPERATOR_CANCELLED;
00194 }
00195 
00196 static int screenshot_cancel(bContext *UNUSED(C), wmOperator *op)
00197 {
00198         screenshot_data_free(op);
00199         return OPERATOR_CANCELLED;
00200 }
00201 
00202 void SCREEN_OT_screenshot(wmOperatorType *ot)
00203 {
00204         PropertyRNA *prop;
00205 
00206         ot->name= "Save Screenshot"; /* weak: opname starting with 'save' makes filewindow give save-over */
00207         ot->idname= "SCREEN_OT_screenshot";
00208         
00209         ot->invoke= screenshot_invoke;
00210         ot->exec= screenshot_exec;
00211         ot->poll= WM_operator_winactive;
00212         ot->cancel= screenshot_cancel;
00213         
00214         ot->flag= 0;
00215         
00216         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH);
00217         prop= RNA_def_boolean(ot->srna, "full", 1, "Full Screen", "");
00218         RNA_def_property_flag(prop, PROP_HIDDEN); /* hide because once the file sel is displayed, the option no longer does anything */
00219 }
00220 
00221 /* *************** screenshot movie job ************************* */
00222 
00223 typedef struct ScreenshotJob {
00224         Scene *scene;
00225         unsigned int *dumprect;
00226         int x, y, dumpsx, dumpsy;
00227         short *stop;
00228         short *do_update;
00229         ReportList reports;
00230 } ScreenshotJob;
00231 
00232 
00233 static void screenshot_freejob(void *sjv)
00234 {
00235         ScreenshotJob *sj= sjv;
00236         
00237         if(sj->dumprect)
00238                 MEM_freeN(sj->dumprect);
00239         
00240         MEM_freeN(sj);
00241 }
00242 
00243 
00244 /* called before redraw notifiers, copies a new dumprect */
00245 static void screenshot_updatejob(void *sjv)
00246 {
00247         ScreenshotJob *sj= sjv;
00248         unsigned int *dumprect;
00249         
00250         if(sj->dumprect==NULL) {
00251                 dumprect= MEM_mallocN(sizeof(int) * sj->dumpsx * sj->dumpsy, "dumprect");
00252                 glReadPixels(sj->x, sj->y, sj->dumpsx, sj->dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, dumprect);
00253                 glFinish();
00254                 
00255                 sj->dumprect= dumprect;
00256         }
00257 }
00258 
00259 
00260 /* only this runs inside thread */
00261 static void screenshot_startjob(void *sjv, short *stop, short *do_update, float *UNUSED(progress))
00262 {
00263         ScreenshotJob *sj= sjv;
00264         RenderData rd= sj->scene->r;
00265         bMovieHandle *mh= BKE_get_movie_handle(sj->scene->r.imtype);
00266         int cfra= 1;
00267         
00268         /* we need this as local variables for renderdata */
00269         rd.frs_sec= U.scrcastfps;
00270         rd.frs_sec_base= 1.0f;
00271         
00272         if(BKE_imtype_is_movie(rd.imtype)) {
00273                 if(!mh->start_movie(sj->scene, &rd, sj->dumpsx, sj->dumpsy, &sj->reports)) {
00274                         printf("screencast job stopped\n");
00275                         return;
00276                 }
00277         }
00278         else
00279                 mh= NULL;
00280         
00281         sj->stop= stop;
00282         sj->do_update= do_update;
00283         
00284         *do_update= 1; // wait for opengl rect
00285         
00286         while(*stop==0) {
00287                 
00288                 if(sj->dumprect) {
00289                         
00290                         if(mh) {
00291                                 if(mh->append_movie(&rd, cfra, (int *)sj->dumprect, sj->dumpsx, sj->dumpsy, &sj->reports)) {
00292                                         BKE_reportf(&sj->reports, RPT_INFO, "Appended frame: %d", cfra);
00293                                         printf("Appended frame %d\n", cfra);
00294                                 } else
00295                                         break;
00296                         }
00297                         else {
00298                                 ImBuf *ibuf= IMB_allocImBuf(sj->dumpsx, sj->dumpsy, rd.planes, 0);
00299                                 char name[FILE_MAXDIR+FILE_MAXFILE];
00300                                 int ok;
00301                                 
00302                                 BKE_makepicstring(name, rd.pic, cfra, rd.imtype, rd.scemode & R_EXTENSION, TRUE);
00303                                 
00304                                 ibuf->rect= sj->dumprect;
00305                                 ok= BKE_write_ibuf(ibuf, name, rd.imtype, rd.subimtype, rd.quality);
00306                                 
00307                                 if(ok==0) {
00308                                         printf("Write error: cannot save %s\n", name);
00309                                         BKE_reportf(&sj->reports, RPT_INFO, "Write error: cannot save %s\n", name);
00310                                         break;
00311                                 }
00312                                 else {
00313                                         printf("Saved file: %s\n", name);
00314                                         BKE_reportf(&sj->reports, RPT_INFO, "Saved file: %s", name);
00315                                 }
00316                                 
00317                                 /* imbuf knows which rects are not part of ibuf */
00318                                 IMB_freeImBuf(ibuf);    
00319                         }
00320                         
00321                         MEM_freeN(sj->dumprect);
00322                         sj->dumprect= NULL;
00323                         
00324                         *do_update= 1;
00325                         
00326                         cfra++;
00327 
00328                 }
00329                 else 
00330                         PIL_sleep_ms(U.scrcastwait);
00331         }
00332         
00333         if(mh)
00334                 mh->end_movie();
00335 
00336         BKE_report(&sj->reports, RPT_INFO, "Screencast job stopped");
00337 }
00338 
00339 static int screencast_exec(bContext *C, wmOperator *op)
00340 {
00341         bScreen *screen= CTX_wm_screen(C);
00342         wmJob *steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), screen, "Screencast", 0);
00343         ScreenshotJob *sj= MEM_callocN(sizeof(ScreenshotJob), "screenshot job");
00344 
00345         /* setup sj */
00346         if(RNA_boolean_get(op->ptr, "full")) {
00347                 wmWindow *win= CTX_wm_window(C);
00348                 sj->x= 0;
00349                 sj->y= 0;
00350                 sj->dumpsx= win->sizex;
00351                 sj->dumpsy= win->sizey;
00352         } 
00353         else {
00354                 ScrArea *curarea= CTX_wm_area(C);
00355                 sj->x= curarea->totrct.xmin;
00356                 sj->y= curarea->totrct.ymin;
00357                 sj->dumpsx= curarea->totrct.xmax - sj->x;
00358                 sj->dumpsy= curarea->totrct.ymax - sj->y;
00359         }
00360         sj->scene= CTX_data_scene(C);
00361 
00362         BKE_reports_init(&sj->reports, RPT_PRINT);
00363 
00364         /* setup job */
00365         WM_jobs_customdata(steve, sj, screenshot_freejob);
00366         WM_jobs_timer(steve, 0.1, 0, NC_SCREEN|ND_SCREENCAST);
00367         WM_jobs_callbacks(steve, screenshot_startjob, NULL, screenshot_updatejob, NULL);
00368         
00369         WM_jobs_start(CTX_wm_manager(C), steve);
00370         
00371         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENCAST, screen);
00372         
00373         return OPERATOR_FINISHED;
00374 }
00375 
00376 void SCREEN_OT_screencast(wmOperatorType *ot)
00377 {
00378         ot->name= "Make Screencast";
00379         ot->idname= "SCREEN_OT_screencast";
00380         
00381         ot->invoke= WM_operator_confirm;
00382         ot->exec= screencast_exec;
00383         ot->poll= WM_operator_winactive;
00384         
00385         ot->flag= 0;
00386         
00387         RNA_def_property(ot->srna, "filepath", PROP_STRING, PROP_FILEPATH);
00388         RNA_def_boolean(ot->srna, "full", 1, "Full Screen", "");
00389 }
00390 
00391 
00392