Blender V2.61 - r43446

screendump.c

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