Blender V2.61 - r43446
|
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