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, 2002-2009, Xavier Thomas 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 */ 00025 00031 #include <stddef.h> 00032 #include <string.h> 00033 #include <stdlib.h> 00034 #include <errno.h> 00035 00036 #include "MEM_guardedalloc.h" 00037 00038 #include "BLI_math.h" 00039 #include "BLI_blenlib.h" 00040 #include "BLI_utildefines.h" 00041 00042 #include "DNA_object_types.h" 00043 #include "DNA_node_types.h" 00044 #include "DNA_packedFile_types.h" 00045 #include "DNA_scene_types.h" 00046 00047 #include "BKE_colortools.h" 00048 #include "BKE_context.h" 00049 #include "BKE_image.h" 00050 #include "BKE_global.h" 00051 #include "BKE_library.h" 00052 #include "BKE_main.h" 00053 #include "BKE_node.h" 00054 #include "BKE_packedFile.h" 00055 #include "BKE_report.h" 00056 #include "BKE_screen.h" 00057 00058 #include "IMB_imbuf.h" 00059 #include "IMB_imbuf_types.h" 00060 00061 #include "RE_pipeline.h" 00062 00063 #include "RNA_access.h" 00064 #include "RNA_define.h" 00065 #include "RNA_enum_types.h" 00066 00067 #include "ED_image.h" 00068 #include "ED_render.h" 00069 #include "ED_screen.h" 00070 #include "ED_space_api.h" 00071 #include "ED_uvedit.h" 00072 #include "ED_util.h" 00073 00074 #include "UI_interface.h" 00075 #include "UI_resources.h" 00076 #include "UI_view2d.h" 00077 00078 #include "WM_api.h" 00079 #include "WM_types.h" 00080 00081 #include "image_intern.h" 00082 00083 /******************** view navigation utilities *********************/ 00084 00085 static void sima_zoom_set(SpaceImage *sima, ARegion *ar, float zoom) 00086 { 00087 float oldzoom= sima->zoom; 00088 int width, height; 00089 00090 sima->zoom= zoom; 00091 00092 if (sima->zoom > 0.1f && sima->zoom < 4.0f) 00093 return; 00094 00095 /* check zoom limits */ 00096 ED_space_image_size(sima, &width, &height); 00097 00098 width *= sima->zoom; 00099 height *= sima->zoom; 00100 00101 if((width < 4) && (height < 4)) 00102 sima->zoom= oldzoom; 00103 else if((ar->winrct.xmax - ar->winrct.xmin) <= sima->zoom) 00104 sima->zoom= oldzoom; 00105 else if((ar->winrct.ymax - ar->winrct.ymin) <= sima->zoom) 00106 sima->zoom= oldzoom; 00107 } 00108 00109 static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac) 00110 { 00111 sima_zoom_set(sima, ar, sima->zoom*zoomfac); 00112 } 00113 00114 #if 0 // currently unused 00115 static int image_poll(bContext *C) 00116 { 00117 return (CTX_data_edit_image(C) != NULL); 00118 } 00119 #endif 00120 00121 static int space_image_buffer_exists_poll(bContext *C) 00122 { 00123 SpaceImage *sima= CTX_wm_space_image(C); 00124 if(sima && sima->spacetype==SPACE_IMAGE) 00125 if(ED_space_image_has_buffer(sima)) 00126 return 1; 00127 return 0; 00128 } 00129 00130 static int space_image_file_exists_poll(bContext *C) 00131 { 00132 if(space_image_buffer_exists_poll(C)) { 00133 Main *bmain= CTX_data_main(C); 00134 SpaceImage *sima= CTX_wm_space_image(C); 00135 ImBuf *ibuf; 00136 void *lock; 00137 int ret= FALSE; 00138 char name[FILE_MAX]; 00139 00140 ibuf= ED_space_image_acquire_buffer(sima, &lock); 00141 if(ibuf) { 00142 BLI_strncpy(name, ibuf->name, FILE_MAX); 00143 BLI_path_abs(name, bmain->name); 00144 00145 if(BLI_exists(name) == FALSE) { 00146 CTX_wm_operator_poll_msg_set(C, "image file not found"); 00147 } 00148 else if (BLI_file_is_writable(name) == FALSE) { 00149 CTX_wm_operator_poll_msg_set(C, "image path can't be written to"); 00150 } 00151 else { 00152 ret= TRUE; 00153 } 00154 } 00155 ED_space_image_release_buffer(sima, lock); 00156 00157 return ret; 00158 } 00159 return 0; 00160 } 00161 00162 static int space_image_poll(bContext *C) 00163 { 00164 SpaceImage *sima= CTX_wm_space_image(C); 00165 if(sima && sima->spacetype==SPACE_IMAGE && sima->image) 00166 return 1; 00167 return 0; 00168 } 00169 00170 int space_image_main_area_poll(bContext *C) 00171 { 00172 SpaceImage *sima= CTX_wm_space_image(C); 00173 // XXX ARegion *ar= CTX_wm_region(C); 00174 00175 if(sima) 00176 return 1; // XXX (ar && ar->type->regionid == RGN_TYPE_WINDOW); 00177 00178 return 0; 00179 } 00180 00181 /********************** view pan operator *********************/ 00182 00183 typedef struct ViewPanData { 00184 float x, y; 00185 float xof, yof; 00186 int event_type; 00187 } ViewPanData; 00188 00189 static void image_view_pan_init(bContext *C, wmOperator *op, wmEvent *event) 00190 { 00191 SpaceImage *sima= CTX_wm_space_image(C); 00192 ViewPanData *vpd; 00193 00194 op->customdata= vpd= MEM_callocN(sizeof(ViewPanData), "ImageViewPanData"); 00195 WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR); 00196 00197 vpd->x= event->x; 00198 vpd->y= event->y; 00199 vpd->xof= sima->xof; 00200 vpd->yof= sima->yof; 00201 vpd->event_type= event->type; 00202 00203 WM_event_add_modal_handler(C, op); 00204 } 00205 00206 static void image_view_pan_exit(bContext *C, wmOperator *op, int cancel) 00207 { 00208 SpaceImage *sima= CTX_wm_space_image(C); 00209 ViewPanData *vpd= op->customdata; 00210 00211 if(cancel) { 00212 sima->xof= vpd->xof; 00213 sima->yof= vpd->yof; 00214 ED_region_tag_redraw(CTX_wm_region(C)); 00215 } 00216 00217 WM_cursor_restore(CTX_wm_window(C)); 00218 MEM_freeN(op->customdata); 00219 } 00220 00221 static int image_view_pan_exec(bContext *C, wmOperator *op) 00222 { 00223 SpaceImage *sima= CTX_wm_space_image(C); 00224 float offset[2]; 00225 00226 RNA_float_get_array(op->ptr, "offset", offset); 00227 sima->xof += offset[0]; 00228 sima->yof += offset[1]; 00229 00230 ED_region_tag_redraw(CTX_wm_region(C)); 00231 00232 /* XXX notifier? */ 00233 #if 0 00234 if(image_preview_active(curarea, NULL, NULL)) { 00235 /* recalculates new preview rect */ 00236 scrarea_do_windraw(curarea); 00237 image_preview_event(2); 00238 } 00239 #endif 00240 00241 return OPERATOR_FINISHED; 00242 } 00243 00244 static int image_view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event) 00245 { 00246 if (event->type == MOUSEPAN) { 00247 SpaceImage *sima= CTX_wm_space_image(C); 00248 float offset[2]; 00249 00250 offset[0]= (event->x - event->prevx)/sima->zoom; 00251 offset[1]= (event->y - event->prevy)/sima->zoom; 00252 RNA_float_set_array(op->ptr, "offset", offset); 00253 00254 image_view_pan_exec(C, op); 00255 return OPERATOR_FINISHED; 00256 } 00257 else { 00258 image_view_pan_init(C, op, event); 00259 return OPERATOR_RUNNING_MODAL; 00260 } 00261 } 00262 00263 static int image_view_pan_modal(bContext *C, wmOperator *op, wmEvent *event) 00264 { 00265 SpaceImage *sima= CTX_wm_space_image(C); 00266 ViewPanData *vpd= op->customdata; 00267 float offset[2]; 00268 00269 switch(event->type) { 00270 case MOUSEMOVE: 00271 sima->xof= vpd->xof; 00272 sima->yof= vpd->yof; 00273 offset[0]= (vpd->x - event->x)/sima->zoom; 00274 offset[1]= (vpd->y - event->y)/sima->zoom; 00275 RNA_float_set_array(op->ptr, "offset", offset); 00276 image_view_pan_exec(C, op); 00277 break; 00278 default: 00279 if(event->type==vpd->event_type && event->val==KM_RELEASE) { 00280 image_view_pan_exit(C, op, 0); 00281 return OPERATOR_FINISHED; 00282 } 00283 break; 00284 } 00285 00286 return OPERATOR_RUNNING_MODAL; 00287 } 00288 00289 static int image_view_pan_cancel(bContext *C, wmOperator *op) 00290 { 00291 image_view_pan_exit(C, op, 1); 00292 return OPERATOR_CANCELLED; 00293 } 00294 00295 void IMAGE_OT_view_pan(wmOperatorType *ot) 00296 { 00297 /* identifiers */ 00298 ot->name= "View Pan"; 00299 ot->idname= "IMAGE_OT_view_pan"; 00300 00301 /* api callbacks */ 00302 ot->exec= image_view_pan_exec; 00303 ot->invoke= image_view_pan_invoke; 00304 ot->modal= image_view_pan_modal; 00305 ot->cancel= image_view_pan_cancel; 00306 ot->poll= space_image_main_area_poll; 00307 00308 /* flags */ 00309 ot->flag= OPTYPE_BLOCKING; 00310 00311 /* properties */ 00312 RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX, 00313 "Offset", "Offset in floating point units, 1.0 is the width and height of the image", -FLT_MAX, FLT_MAX); 00314 } 00315 00316 /********************** view zoom operator *********************/ 00317 00318 typedef struct ViewZoomData { 00319 float x, y; 00320 float zoom; 00321 int event_type; 00322 } ViewZoomData; 00323 00324 static void image_view_zoom_init(bContext *C, wmOperator *op, wmEvent *event) 00325 { 00326 SpaceImage *sima= CTX_wm_space_image(C); 00327 ViewZoomData *vpd; 00328 00329 op->customdata= vpd= MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData"); 00330 WM_cursor_modal(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR); 00331 00332 vpd->x= event->x; 00333 vpd->y= event->y; 00334 vpd->zoom= sima->zoom; 00335 vpd->event_type= event->type; 00336 00337 WM_event_add_modal_handler(C, op); 00338 } 00339 00340 static void image_view_zoom_exit(bContext *C, wmOperator *op, int cancel) 00341 { 00342 SpaceImage *sima= CTX_wm_space_image(C); 00343 ViewZoomData *vpd= op->customdata; 00344 00345 if(cancel) { 00346 sima->zoom= vpd->zoom; 00347 ED_region_tag_redraw(CTX_wm_region(C)); 00348 } 00349 00350 WM_cursor_restore(CTX_wm_window(C)); 00351 MEM_freeN(op->customdata); 00352 } 00353 00354 static int image_view_zoom_exec(bContext *C, wmOperator *op) 00355 { 00356 SpaceImage *sima= CTX_wm_space_image(C); 00357 ARegion *ar= CTX_wm_region(C); 00358 00359 sima_zoom_set_factor(sima, ar, RNA_float_get(op->ptr, "factor")); 00360 00361 ED_region_tag_redraw(CTX_wm_region(C)); 00362 00363 /* XXX notifier? */ 00364 #if 0 00365 if(image_preview_active(curarea, NULL, NULL)) { 00366 /* recalculates new preview rect */ 00367 scrarea_do_windraw(curarea); 00368 image_preview_event(2); 00369 } 00370 #endif 00371 00372 return OPERATOR_FINISHED; 00373 } 00374 00375 static int image_view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event) 00376 { 00377 if (event->type == MOUSEZOOM) { 00378 SpaceImage *sima= CTX_wm_space_image(C); 00379 ARegion *ar= CTX_wm_region(C); 00380 float factor; 00381 00382 factor= 1.0f + (event->x-event->prevx+event->y-event->prevy)/300.0f; 00383 RNA_float_set(op->ptr, "factor", factor); 00384 sima_zoom_set(sima, ar, sima->zoom*factor); 00385 ED_region_tag_redraw(CTX_wm_region(C)); 00386 00387 return OPERATOR_FINISHED; 00388 } 00389 else { 00390 image_view_zoom_init(C, op, event); 00391 return OPERATOR_RUNNING_MODAL; 00392 } 00393 } 00394 00395 static int image_view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event) 00396 { 00397 SpaceImage *sima= CTX_wm_space_image(C); 00398 ARegion *ar= CTX_wm_region(C); 00399 ViewZoomData *vpd= op->customdata; 00400 float factor; 00401 00402 switch(event->type) { 00403 case MOUSEMOVE: 00404 factor= 1.0f + (vpd->x-event->x+vpd->y-event->y)/300.0f; 00405 RNA_float_set(op->ptr, "factor", factor); 00406 sima_zoom_set(sima, ar, vpd->zoom*factor); 00407 ED_region_tag_redraw(CTX_wm_region(C)); 00408 break; 00409 default: 00410 if(event->type==vpd->event_type && event->val==KM_RELEASE) { 00411 image_view_zoom_exit(C, op, 0); 00412 return OPERATOR_FINISHED; 00413 } 00414 break; 00415 } 00416 00417 return OPERATOR_RUNNING_MODAL; 00418 } 00419 00420 static int image_view_zoom_cancel(bContext *C, wmOperator *op) 00421 { 00422 image_view_zoom_exit(C, op, 1); 00423 return OPERATOR_CANCELLED; 00424 } 00425 00426 void IMAGE_OT_view_zoom(wmOperatorType *ot) 00427 { 00428 /* identifiers */ 00429 ot->name= "View Zoom"; 00430 ot->idname= "IMAGE_OT_view_zoom"; 00431 00432 /* api callbacks */ 00433 ot->exec= image_view_zoom_exec; 00434 ot->invoke= image_view_zoom_invoke; 00435 ot->modal= image_view_zoom_modal; 00436 ot->cancel= image_view_zoom_cancel; 00437 ot->poll= space_image_main_area_poll; 00438 00439 /* flags */ 00440 ot->flag= OPTYPE_BLOCKING; 00441 00442 /* properties */ 00443 RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, FLT_MAX, 00444 "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX); 00445 } 00446 00447 /********************** NDOF operator *********************/ 00448 00449 /* Combined pan/zoom from a 3D mouse device. 00450 * Z zooms, XY pans 00451 * "view" (not "paper") control -- user moves the viewpoint, not the image being viewed 00452 * that explains the negative signs in the code below 00453 */ 00454 00455 static int image_view_ndof_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) 00456 { 00457 if (event->type != NDOF_MOTION) 00458 return OPERATOR_CANCELLED; 00459 else { 00460 SpaceImage *sima= CTX_wm_space_image(C); 00461 ARegion *ar= CTX_wm_region(C); 00462 00463 wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata; 00464 00465 float dt = ndof->dt; 00466 /* tune these until it feels right */ 00467 const float zoom_sensitivity = 0.5f; // 50% per second (I think) 00468 const float pan_sensitivity = 300.f; // screen pixels per second 00469 00470 float pan_x = pan_sensitivity * dt * ndof->tvec[0] / sima->zoom; 00471 float pan_y = pan_sensitivity * dt * ndof->tvec[1] / sima->zoom; 00472 00473 /* "mouse zoom" factor = 1 + (dx + dy) / 300 00474 * what about "ndof zoom" factor? should behave like this: 00475 * at rest -> factor = 1 00476 * move forward -> factor > 1 00477 * move backward -> factor < 1 00478 */ 00479 float zoom_factor = 1.f + zoom_sensitivity * dt * -ndof->tvec[2]; 00480 00481 if (U.ndof_flag & NDOF_ZOOM_INVERT) 00482 zoom_factor = -zoom_factor; 00483 00484 sima_zoom_set_factor(sima, ar, zoom_factor); 00485 sima->xof += pan_x; 00486 sima->yof += pan_y; 00487 00488 ED_region_tag_redraw(ar); 00489 00490 return OPERATOR_FINISHED; 00491 } 00492 } 00493 00494 void IMAGE_OT_view_ndof(wmOperatorType *ot) 00495 { 00496 /* identifiers */ 00497 ot->name= "NDOF Pan/Zoom"; 00498 ot->idname= "IMAGE_OT_view_ndof"; 00499 00500 /* api callbacks */ 00501 ot->invoke= image_view_ndof_invoke; 00502 } 00503 00504 /********************** view all operator *********************/ 00505 00506 /* Updates the fields of the View2D member of the SpaceImage struct. 00507 * Default behavior is to reset the position of the image and set the zoom to 1 00508 * If the image will not fit within the window rectangle, the zoom is adjusted */ 00509 00510 static int image_view_all_exec(bContext *C, wmOperator *UNUSED(op)) 00511 { 00512 SpaceImage *sima; 00513 ARegion *ar; 00514 float aspx, aspy, zoomx, zoomy, w, h; 00515 int width, height; 00516 00517 /* retrieve state */ 00518 sima= CTX_wm_space_image(C); 00519 ar= CTX_wm_region(C); 00520 00521 ED_space_image_size(sima, &width, &height); 00522 ED_space_image_aspect(sima, &aspx, &aspy); 00523 00524 w= width*aspx; 00525 h= height*aspy; 00526 00527 /* check if the image will fit in the image with zoom==1 */ 00528 width = ar->winrct.xmax - ar->winrct.xmin + 1; 00529 height = ar->winrct.ymax - ar->winrct.ymin + 1; 00530 00531 if((w >= width || h >= height) && (width > 0 && height > 0)) { 00532 /* find the zoom value that will fit the image in the image space */ 00533 zoomx= width/w; 00534 zoomy= height/h; 00535 sima_zoom_set(sima, ar, 1.0f/power_of_2(1/MIN2(zoomx, zoomy))); 00536 } 00537 else 00538 sima_zoom_set(sima, ar, 1.0f); 00539 00540 sima->xof= sima->yof= 0.0f; 00541 00542 ED_region_tag_redraw(CTX_wm_region(C)); 00543 00544 return OPERATOR_FINISHED; 00545 } 00546 00547 void IMAGE_OT_view_all(wmOperatorType *ot) 00548 { 00549 /* identifiers */ 00550 ot->name= "View All"; 00551 ot->idname= "IMAGE_OT_view_all"; 00552 00553 /* api callbacks */ 00554 ot->exec= image_view_all_exec; 00555 ot->poll= space_image_main_area_poll; 00556 } 00557 00558 /********************** view selected operator *********************/ 00559 00560 static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) 00561 { 00562 SpaceImage *sima; 00563 ARegion *ar; 00564 Scene *scene; 00565 Object *obedit; 00566 Image *ima; 00567 float size, min[2], max[2], d[2], aspx, aspy; 00568 int width, height; 00569 00570 /* retrieve state */ 00571 sima= CTX_wm_space_image(C); 00572 ar= CTX_wm_region(C); 00573 scene= (Scene*)CTX_data_scene(C); 00574 obedit= CTX_data_edit_object(C); 00575 00576 ima= ED_space_image(sima); 00577 ED_space_image_size(sima, &width, &height); 00578 ED_image_aspect(ima, &aspx, &aspy); 00579 00580 width= width*aspx; 00581 height= height*aspy; 00582 00583 /* get bounds */ 00584 if(!ED_uvedit_minmax(scene, ima, obedit, min, max)) 00585 return OPERATOR_CANCELLED; 00586 00587 /* adjust offset and zoom */ 00588 sima->xof= (int)(((min[0] + max[0])*0.5f - 0.5f)*width); 00589 sima->yof= (int)(((min[1] + max[1])*0.5f - 0.5f)*height); 00590 00591 d[0]= max[0] - min[0]; 00592 d[1]= max[1] - min[1]; 00593 size= 0.5f*MAX2(d[0], d[1])*MAX2(width, height)/256.0f; 00594 00595 if(size<=0.01f) size= 0.01f; 00596 sima_zoom_set(sima, ar, 0.7f/size); 00597 00598 ED_region_tag_redraw(CTX_wm_region(C)); 00599 00600 return OPERATOR_FINISHED; 00601 } 00602 00603 static int image_view_selected_poll(bContext *C) 00604 { 00605 return (space_image_main_area_poll(C) && ED_operator_uvedit(C)); 00606 } 00607 00608 void IMAGE_OT_view_selected(wmOperatorType *ot) 00609 { 00610 /* identifiers */ 00611 ot->name= "View Center"; 00612 ot->idname= "IMAGE_OT_view_selected"; 00613 00614 /* api callbacks */ 00615 ot->exec= image_view_selected_exec; 00616 ot->poll= image_view_selected_poll; 00617 } 00618 00619 /********************** view zoom in/out operator *********************/ 00620 00621 static int image_view_zoom_in_exec(bContext *C, wmOperator *UNUSED(op)) 00622 { 00623 SpaceImage *sima= CTX_wm_space_image(C); 00624 ARegion *ar= CTX_wm_region(C); 00625 00626 sima_zoom_set_factor(sima, ar, 1.25f); 00627 00628 ED_region_tag_redraw(CTX_wm_region(C)); 00629 00630 return OPERATOR_FINISHED; 00631 } 00632 00633 void IMAGE_OT_view_zoom_in(wmOperatorType *ot) 00634 { 00635 /* identifiers */ 00636 ot->name= "View Zoom In"; 00637 ot->idname= "IMAGE_OT_view_zoom_in"; 00638 00639 /* api callbacks */ 00640 ot->exec= image_view_zoom_in_exec; 00641 ot->poll= space_image_main_area_poll; 00642 } 00643 00644 static int image_view_zoom_out_exec(bContext *C, wmOperator *UNUSED(op)) 00645 { 00646 SpaceImage *sima= CTX_wm_space_image(C); 00647 ARegion *ar= CTX_wm_region(C); 00648 00649 sima_zoom_set_factor(sima, ar, 0.8f); 00650 00651 ED_region_tag_redraw(CTX_wm_region(C)); 00652 00653 return OPERATOR_FINISHED; 00654 } 00655 00656 void IMAGE_OT_view_zoom_out(wmOperatorType *ot) 00657 { 00658 /* identifiers */ 00659 ot->name= "View Zoom Out"; 00660 ot->idname= "IMAGE_OT_view_zoom_out"; 00661 00662 /* api callbacks */ 00663 ot->exec= image_view_zoom_out_exec; 00664 ot->poll= space_image_main_area_poll; 00665 } 00666 00667 /********************** view zoom ratio operator *********************/ 00668 00669 static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op) 00670 { 00671 SpaceImage *sima= CTX_wm_space_image(C); 00672 ARegion *ar= CTX_wm_region(C); 00673 00674 sima_zoom_set(sima, ar, RNA_float_get(op->ptr, "ratio")); 00675 00676 /* ensure pixel exact locations for draw */ 00677 sima->xof= (int)sima->xof; 00678 sima->yof= (int)sima->yof; 00679 00680 /* XXX notifier? */ 00681 #if 0 00682 if(image_preview_active(curarea, NULL, NULL)) { 00683 /* recalculates new preview rect */ 00684 scrarea_do_windraw(curarea); 00685 image_preview_event(2); 00686 } 00687 #endif 00688 00689 ED_region_tag_redraw(CTX_wm_region(C)); 00690 00691 return OPERATOR_FINISHED; 00692 } 00693 00694 void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot) 00695 { 00696 /* identifiers */ 00697 ot->name= "View Zoom Ratio"; 00698 ot->idname= "IMAGE_OT_view_zoom_ratio"; 00699 00700 /* api callbacks */ 00701 ot->exec= image_view_zoom_ratio_exec; 00702 ot->poll= space_image_main_area_poll; 00703 00704 /* properties */ 00705 RNA_def_float(ot->srna, "ratio", 0.0f, 0.0f, FLT_MAX, 00706 "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out", -FLT_MAX, FLT_MAX); 00707 } 00708 00709 /**************** load/replace/save callbacks ******************/ 00710 static void image_filesel(bContext *C, wmOperator *op, const char *path) 00711 { 00712 RNA_string_set(op->ptr, "filepath", path); 00713 WM_event_add_fileselect(C, op); 00714 } 00715 00716 /******************** open image operator ********************/ 00717 00718 static void image_open_init(bContext *C, wmOperator *op) 00719 { 00720 PropertyPointerRNA *pprop; 00721 00722 op->customdata= pprop= MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA"); 00723 uiIDContextProperty(C, &pprop->ptr, &pprop->prop); 00724 } 00725 00726 static int image_open_cancel(bContext *UNUSED(C), wmOperator *op) 00727 { 00728 MEM_freeN(op->customdata); 00729 op->customdata= NULL; 00730 return OPERATOR_CANCELLED; 00731 } 00732 00733 static int image_open_exec(bContext *C, wmOperator *op) 00734 { 00735 SpaceImage *sima= CTX_wm_space_image(C); /* XXX other space types can call */ 00736 Scene *scene= CTX_data_scene(C); 00737 Object *obedit= CTX_data_edit_object(C); 00738 ImageUser *iuser= NULL; 00739 PropertyPointerRNA *pprop; 00740 PointerRNA idptr; 00741 Image *ima= NULL; 00742 char str[FILE_MAX]; 00743 00744 RNA_string_get(op->ptr, "filepath", str); 00745 /* default to frame 1 if there's no scene in context */ 00746 00747 errno= 0; 00748 00749 ima= BKE_add_image_file(str); 00750 00751 if(!ima) { 00752 if(op->customdata) MEM_freeN(op->customdata); 00753 BKE_reportf(op->reports, RPT_ERROR, "Can't read: \"%s\", %s", str, errno ? strerror(errno) : "Unsupported image format"); 00754 return OPERATOR_CANCELLED; 00755 } 00756 00757 if(!op->customdata) 00758 image_open_init(C, op); 00759 00760 /* hook into UI */ 00761 pprop= op->customdata; 00762 00763 if(pprop->prop) { 00764 /* when creating new ID blocks, use is already 1, but RNA 00765 * pointer se also increases user, so this compensates it */ 00766 ima->id.us--; 00767 00768 RNA_id_pointer_create(&ima->id, &idptr); 00769 RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); 00770 RNA_property_update(C, &pprop->ptr, pprop->prop); 00771 } 00772 else if(sima) { 00773 ED_space_image_set(sima, scene, obedit, ima); 00774 iuser= &sima->iuser; 00775 } 00776 else { 00777 Tex *tex= CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; 00778 if(tex && tex->type==TEX_IMAGE) 00779 iuser= &tex->iuser; 00780 00781 } 00782 00783 /* initialize because of new image */ 00784 if(iuser) { 00785 iuser->sfra= 1; 00786 iuser->offset= 0; 00787 iuser->fie_ima= 2; 00788 } 00789 00790 /* XXX unpackImage frees image buffers */ 00791 ED_preview_kill_jobs(C); 00792 00793 BKE_image_signal(ima, iuser, IMA_SIGNAL_RELOAD); 00794 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima); 00795 00796 MEM_freeN(op->customdata); 00797 00798 return OPERATOR_FINISHED; 00799 } 00800 00801 static int image_open_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00802 { 00803 SpaceImage *sima= CTX_wm_space_image(C); /* XXX other space types can call */ 00804 char *path=U.textudir; 00805 Image *ima= NULL; 00806 00807 if(sima) { 00808 ima= sima->image; 00809 } 00810 00811 if (ima==NULL) { 00812 Tex *tex= CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; 00813 if(tex && tex->type==TEX_IMAGE) 00814 ima= tex->ima; 00815 } 00816 00817 if(ima) 00818 path= ima->name; 00819 00820 if(RNA_struct_property_is_set(op->ptr, "filepath")) 00821 return image_open_exec(C, op); 00822 00823 image_open_init(C, op); 00824 00825 image_filesel(C, op, path); 00826 00827 return OPERATOR_RUNNING_MODAL; 00828 } 00829 00830 /* called by other space types too */ 00831 void IMAGE_OT_open(wmOperatorType *ot) 00832 { 00833 /* identifiers */ 00834 ot->name= "Open Image"; 00835 ot->description= "Open image"; 00836 ot->idname= "IMAGE_OT_open"; 00837 00838 /* api callbacks */ 00839 ot->exec= image_open_exec; 00840 ot->invoke= image_open_invoke; 00841 ot->cancel= image_open_cancel; 00842 00843 /* flags */ 00844 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00845 00846 /* properties */ 00847 WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH); 00848 } 00849 00850 /******************** replace image operator ********************/ 00851 00852 static int image_replace_exec(bContext *C, wmOperator *op) 00853 { 00854 SpaceImage *sima= CTX_wm_space_image(C); 00855 char str[FILE_MAX]; 00856 00857 if(!sima->image) 00858 return OPERATOR_CANCELLED; 00859 00860 RNA_string_get(op->ptr, "filepath", str); 00861 00862 /* we cant do much if the str is longer then FILE_MAX :/ */ 00863 BLI_strncpy(sima->image->name, str, sizeof(sima->image->name)); 00864 00865 /* XXX unpackImage frees image buffers */ 00866 ED_preview_kill_jobs(C); 00867 00868 BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD); 00869 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image); 00870 00871 return OPERATOR_FINISHED; 00872 } 00873 00874 static int image_replace_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00875 { 00876 SpaceImage *sima= CTX_wm_space_image(C); 00877 00878 if(!sima->image) 00879 return OPERATOR_CANCELLED; 00880 00881 if(RNA_struct_property_is_set(op->ptr, "filepath")) 00882 return image_replace_exec(C, op); 00883 00884 if(!RNA_struct_property_is_set(op->ptr, "relative_path")) 00885 RNA_boolean_set(op->ptr, "relative_path", (strncmp(sima->image->name, "//", 2))==0); 00886 00887 image_filesel(C, op, sima->image->name); 00888 00889 return OPERATOR_RUNNING_MODAL; 00890 } 00891 00892 void IMAGE_OT_replace(wmOperatorType *ot) 00893 { 00894 /* identifiers */ 00895 ot->name= "Replace Image"; 00896 ot->idname= "IMAGE_OT_replace"; 00897 00898 /* api callbacks */ 00899 ot->exec= image_replace_exec; 00900 ot->invoke= image_replace_invoke; 00901 ot->poll= space_image_poll; 00902 00903 /* flags */ 00904 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00905 00906 /* properties */ 00907 WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH); 00908 } 00909 00910 /******************** save image as operator ********************/ 00911 00912 typedef struct { 00913 /* matching scene->r settings */ 00914 //short planes, imtype, subimtype, quality; 00915 ImageFormatData im_format; 00916 char filepath[FILE_MAX]; /* keep absolute */ 00917 } SaveImageOptions; 00918 00919 static void save_image_options_defaults(SaveImageOptions *simopts) 00920 { 00921 memset(&simopts->im_format, 0, sizeof(simopts->im_format)); 00922 simopts->im_format.planes= R_IMF_PLANES_RGB; 00923 simopts->im_format.imtype= R_IMF_IMTYPE_PNG; 00924 simopts->im_format.quality= 90; 00925 simopts->im_format.compress= 90; 00926 simopts->filepath[0]= '\0'; 00927 } 00928 00929 static char imtype_best_depth(ImBuf *ibuf, const char imtype) 00930 { 00931 const char depth_ok= BKE_imtype_valid_depths(imtype); 00932 00933 if (ibuf->rect_float) { 00934 if (depth_ok & R_IMF_CHAN_DEPTH_32) return R_IMF_CHAN_DEPTH_32; 00935 if (depth_ok & R_IMF_CHAN_DEPTH_24) return R_IMF_CHAN_DEPTH_24; 00936 if (depth_ok & R_IMF_CHAN_DEPTH_16) return R_IMF_CHAN_DEPTH_16; 00937 if (depth_ok & R_IMF_CHAN_DEPTH_12) return R_IMF_CHAN_DEPTH_12; 00938 return R_IMF_CHAN_DEPTH_8; 00939 } 00940 else { 00941 if (depth_ok & R_IMF_CHAN_DEPTH_8) return R_IMF_CHAN_DEPTH_8; 00942 if (depth_ok & R_IMF_CHAN_DEPTH_12) return R_IMF_CHAN_DEPTH_12; 00943 if (depth_ok & R_IMF_CHAN_DEPTH_16) return R_IMF_CHAN_DEPTH_16; 00944 if (depth_ok & R_IMF_CHAN_DEPTH_24) return R_IMF_CHAN_DEPTH_24; 00945 if (depth_ok & R_IMF_CHAN_DEPTH_32) return R_IMF_CHAN_DEPTH_32; 00946 return R_IMF_CHAN_DEPTH_8; /* fallback, should not get here */ 00947 } 00948 } 00949 00950 static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima, Scene *scene, const short guess_path) 00951 { 00952 void *lock; 00953 ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock); 00954 00955 if(ibuf) { 00956 Image *ima= sima->image; 00957 short is_depth_set= FALSE; 00958 00959 simopts->im_format.planes= ibuf->planes; 00960 00961 if(ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) { 00962 /* imtype */ 00963 simopts->im_format= scene->r.im_format; 00964 is_depth_set= TRUE; 00965 } 00966 else if (ima->source == IMA_SRC_GENERATED) { 00967 simopts->im_format.imtype= R_IMF_IMTYPE_PNG; 00968 } 00969 else { 00970 simopts->im_format.imtype= BKE_ftype_to_imtype(ibuf->ftype); 00971 } 00972 //simopts->subimtype= scene->r.subimtype; /* XXX - this is lame, we need to make these available too! */ 00973 simopts->im_format.quality= ibuf->ftype & 0xff; 00974 00975 BLI_strncpy(simopts->filepath, ibuf->name, sizeof(simopts->filepath)); 00976 00977 /* sanitize all settings */ 00978 00979 /* unlikely but just incase */ 00980 if (ELEM3(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) { 00981 simopts->im_format.planes= R_IMF_PLANES_RGBA; 00982 } 00983 00984 /* depth, account for float buffer and format support */ 00985 if (is_depth_set == FALSE) { 00986 simopts->im_format.depth= imtype_best_depth(ibuf, simopts->im_format.imtype); 00987 } 00988 00989 /* some formats dont use quality so fallback to scenes quality */ 00990 if (simopts->im_format.quality == 0) { 00991 simopts->im_format.quality= scene->r.im_format.quality; 00992 } 00993 00994 /* check for empty path */ 00995 if(guess_path && simopts->filepath[0]==0) { 00996 if ( (G.ima[0] == '/') && (G.ima[1] == '/') && (G.ima[2] == '\0') ) { 00997 BLI_strncpy(simopts->filepath, "//untitled", FILE_MAX); 00998 } else { 00999 BLI_strncpy(simopts->filepath, G.ima, FILE_MAX); 01000 } 01001 BLI_path_abs(simopts->filepath, G.main->name); 01002 } 01003 } 01004 01005 ED_space_image_release_buffer(sima, lock); 01006 01007 return (ibuf != NULL); 01008 } 01009 01010 static void save_image_options_from_op(SaveImageOptions *simopts, wmOperator *op) 01011 { 01012 if (op->customdata) { 01013 simopts->im_format= *(ImageFormatData *)op->customdata; 01014 } 01015 01016 if (RNA_struct_property_is_set(op->ptr, "filepath")) { 01017 RNA_string_get(op->ptr, "filepath", simopts->filepath); 01018 BLI_path_abs(simopts->filepath, G.main->name); 01019 } 01020 } 01021 01022 static void save_image_options_to_op(SaveImageOptions *simopts, wmOperator *op) 01023 { 01024 if (op->customdata) { 01025 *(ImageFormatData *)op->customdata= simopts->im_format; 01026 } 01027 01028 RNA_string_set(op->ptr, "filepath", simopts->filepath); 01029 } 01030 01031 /* assumes name is FILE_MAX */ 01032 /* ima->name and ibuf->name should end up the same */ 01033 static void save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, int do_newpath) 01034 { 01035 Image *ima= ED_space_image(sima); 01036 void *lock; 01037 ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock); 01038 01039 if (ibuf) { 01040 const char *relbase= ID_BLEND_PATH(CTX_data_main(C), &ima->id); 01041 const short relative= (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path")); 01042 const short save_copy= (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy")); 01043 short ok= FALSE; 01044 01045 /* old global to ensure a 2nd save goes to same dir */ 01046 BLI_strncpy(G.ima, simopts->filepath, sizeof(G.ima)); 01047 01048 WM_cursor_wait(1); 01049 01050 if(ima->type == IMA_TYPE_R_RESULT) { 01051 /* enforce user setting for RGB or RGBA, but skip BW */ 01052 if(simopts->im_format.planes==R_IMF_PLANES_RGBA) { 01053 ibuf->planes= R_IMF_PLANES_RGBA; 01054 } 01055 else if(simopts->im_format.planes==R_IMF_PLANES_RGB) { 01056 ibuf->planes= R_IMF_PLANES_RGB; 01057 } 01058 } 01059 else { 01060 /* TODO, better solution, if a 24bit image is painted onto it may contain alpha */ 01061 if(ibuf->userflags & IB_BITMAPDIRTY) { /* it has been painted onto */ 01062 /* checks each pixel, not ideal */ 01063 ibuf->planes= BKE_alphatest_ibuf(ibuf) ? 32 : 24; 01064 } 01065 } 01066 01067 if(simopts->im_format.imtype==R_IMF_IMTYPE_MULTILAYER) { 01068 Scene *scene= CTX_data_scene(C); 01069 RenderResult *rr= BKE_image_acquire_renderresult(scene, ima); 01070 if(rr) { 01071 RE_WriteRenderResult(op->reports, rr, simopts->filepath, simopts->im_format.quality); 01072 ok= TRUE; 01073 } 01074 else { 01075 BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image"); 01076 } 01077 BKE_image_release_renderresult(scene, ima); 01078 } 01079 else { 01080 if (BKE_write_ibuf_as(ibuf, simopts->filepath, &simopts->im_format, save_copy)) { 01081 ok= TRUE; 01082 } 01083 } 01084 01085 if (ok) { 01086 if(!save_copy) { 01087 if(do_newpath) { 01088 BLI_strncpy(ibuf->name, simopts->filepath, sizeof(ibuf->name)); 01089 BLI_strncpy(ima->name, simopts->filepath, sizeof(ima->name)); 01090 } 01091 01092 ibuf->userflags &= ~IB_BITMAPDIRTY; 01093 01094 /* change type? */ 01095 if(ima->type==IMA_TYPE_R_RESULT) { 01096 ima->type= IMA_TYPE_IMAGE; 01097 01098 /* workaround to ensure the render result buffer is no longer used 01099 * by this image, otherwise can crash when a new render result is 01100 * created. */ 01101 if(ibuf->rect && !(ibuf->mall & IB_rect)) 01102 imb_freerectImBuf(ibuf); 01103 if(ibuf->rect_float && !(ibuf->mall & IB_rectfloat)) 01104 imb_freerectfloatImBuf(ibuf); 01105 if(ibuf->zbuf && !(ibuf->mall & IB_zbuf)) 01106 IMB_freezbufImBuf(ibuf); 01107 if(ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat)) 01108 IMB_freezbuffloatImBuf(ibuf); 01109 } 01110 if( ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) { 01111 ima->source= IMA_SRC_FILE; 01112 ima->type= IMA_TYPE_IMAGE; 01113 } 01114 01115 /* only image path, never ibuf */ 01116 if(relative) { 01117 BLI_path_rel(ima->name, relbase); /* only after saving */ 01118 } 01119 } 01120 } 01121 else { 01122 BKE_reportf(op->reports, RPT_ERROR, "Couldn't write image: %s", simopts->filepath); 01123 } 01124 01125 01126 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image); 01127 01128 WM_cursor_wait(0); 01129 } 01130 01131 ED_space_image_release_buffer(sima, lock); 01132 } 01133 01134 static void image_save_as_free(wmOperator *op) 01135 { 01136 if (op->customdata) { 01137 MEM_freeN(op->customdata); 01138 op->customdata= NULL; 01139 } 01140 } 01141 01142 static int image_save_as_exec(bContext *C, wmOperator *op) 01143 { 01144 SpaceImage *sima= CTX_wm_space_image(C); 01145 SaveImageOptions simopts; 01146 01147 save_image_options_defaults(&simopts); 01148 01149 /* just incase to initialize values, 01150 * these should be set on invoke or by the caller. */ 01151 save_image_options_init(&simopts, sima, CTX_data_scene(C), 0); 01152 01153 save_image_options_from_op(&simopts, op); 01154 01155 save_image_doit(C, sima, op, &simopts, TRUE); 01156 01157 image_save_as_free(op); 01158 return OPERATOR_FINISHED; 01159 } 01160 01161 01162 static int image_save_as_check(bContext *UNUSED(C), wmOperator *op) 01163 { 01164 ImageFormatData *imf= op->customdata; 01165 char filepath[FILE_MAX]; 01166 RNA_string_get(op->ptr, "filepath", filepath); 01167 if(BKE_add_image_extension(filepath, imf->imtype)) { 01168 RNA_string_set(op->ptr, "filepath", filepath); 01169 return TRUE; 01170 } 01171 return FALSE; 01172 } 01173 01174 static int image_save_as_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01175 { 01176 SpaceImage *sima= CTX_wm_space_image(C); 01177 Image *ima = ED_space_image(sima); 01178 Scene *scene= CTX_data_scene(C); 01179 SaveImageOptions simopts; 01180 01181 if(RNA_struct_property_is_set(op->ptr, "filepath")) 01182 return image_save_as_exec(C, op); 01183 01184 if (save_image_options_init(&simopts, sima, scene, TRUE) == 0) 01185 return OPERATOR_CANCELLED; 01186 save_image_options_to_op(&simopts, op); 01187 01188 /* enable save_copy by default for render results */ 01189 if(ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) && !RNA_struct_property_is_set(op->ptr, "copy")) { 01190 RNA_boolean_set(op->ptr, "copy", TRUE); 01191 } 01192 01193 op->customdata= MEM_mallocN(sizeof(simopts.im_format), __func__); 01194 memcpy(op->customdata, &simopts.im_format, sizeof(simopts.im_format)); 01195 01196 image_filesel(C, op, simopts.filepath); 01197 01198 return OPERATOR_RUNNING_MODAL; 01199 } 01200 01201 static int image_save_as_cancel(bContext *UNUSED(C), wmOperator *op) 01202 { 01203 image_save_as_free(op); 01204 01205 return OPERATOR_CANCELLED; 01206 } 01207 01208 static int image_save_as_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) 01209 { 01210 const char *prop_id= RNA_property_identifier(prop); 01211 01212 return !(strcmp(prop_id, "filepath") == 0 || 01213 strcmp(prop_id, "directory") == 0 || 01214 strcmp(prop_id, "filename") == 0 || 01215 /* when saving a copy, relative path has no effect */ 01216 ((strcmp(prop_id, "relative_path") == 0) && RNA_boolean_get(ptr, "copy")) 01217 ); 01218 } 01219 01220 static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op) 01221 { 01222 uiLayout *layout= op->layout; 01223 ImageFormatData *imf= op->customdata; 01224 PointerRNA ptr; 01225 01226 /* image template */ 01227 RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &ptr); 01228 uiTemplateImageSettings(layout, &ptr); 01229 01230 /* main draw call */ 01231 RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); 01232 uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, '\0'); 01233 } 01234 01235 void IMAGE_OT_save_as(wmOperatorType *ot) 01236 { 01237 // PropertyRNA *prop; 01238 01239 /* identifiers */ 01240 ot->name= "Save As Image"; 01241 ot->idname= "IMAGE_OT_save_as"; 01242 01243 /* api callbacks */ 01244 ot->exec= image_save_as_exec; 01245 ot->check= image_save_as_check; 01246 ot->invoke= image_save_as_invoke; 01247 ot->cancel= image_save_as_cancel; 01248 ot->ui= image_save_as_draw; 01249 ot->poll= space_image_buffer_exists_poll; 01250 01251 /* flags */ 01252 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01253 01254 /* properties */ 01255 RNA_def_boolean(ot->srna, "copy", 0, "Copy", "Create a new image file without modifying the current image in blender"); 01256 01257 WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH); 01258 } 01259 01260 /******************** save image operator ********************/ 01261 01262 static int image_save_exec(bContext *C, wmOperator *op) 01263 { 01264 SpaceImage *sima= CTX_wm_space_image(C); 01265 Scene *scene= CTX_data_scene(C); 01266 SaveImageOptions simopts; 01267 01268 if (save_image_options_init(&simopts, sima, scene, FALSE) == 0) 01269 return OPERATOR_CANCELLED; 01270 save_image_options_from_op(&simopts, op); 01271 01272 if (BLI_exists(simopts.filepath) && BLI_file_is_writable(simopts.filepath)) { 01273 save_image_doit(C, sima, op, &simopts, FALSE); 01274 } 01275 else { 01276 BKE_reportf(op->reports, RPT_ERROR, "Can not save image, path '%s' is not writable", simopts.filepath); 01277 return OPERATOR_CANCELLED; 01278 } 01279 01280 return OPERATOR_FINISHED; 01281 } 01282 01283 void IMAGE_OT_save(wmOperatorType *ot) 01284 { 01285 /* identifiers */ 01286 ot->name= "Save Image"; 01287 ot->idname= "IMAGE_OT_save"; 01288 01289 /* api callbacks */ 01290 ot->exec= image_save_exec; 01291 ot->poll= space_image_file_exists_poll; 01292 01293 /* flags */ 01294 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01295 } 01296 01297 /******************* save sequence operator ********************/ 01298 01299 static int image_save_sequence_exec(bContext *C, wmOperator *op) 01300 { 01301 Main *bmain= CTX_data_main(C); 01302 SpaceImage *sima= CTX_wm_space_image(C); 01303 ImBuf *ibuf; 01304 int tot= 0; 01305 char di[FILE_MAX], fi[FILE_MAX]; 01306 01307 if(sima->image==NULL) 01308 return OPERATOR_CANCELLED; 01309 01310 if(sima->image->source!=IMA_SRC_SEQUENCE) { 01311 BKE_report(op->reports, RPT_ERROR, "Can only save sequence on image sequences"); 01312 return OPERATOR_CANCELLED; 01313 } 01314 01315 if(sima->image->type==IMA_TYPE_MULTILAYER) { 01316 BKE_report(op->reports, RPT_ERROR, "Can't save multilayer sequences"); 01317 return OPERATOR_CANCELLED; 01318 } 01319 01320 /* get total */ 01321 for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) 01322 if(ibuf->userflags & IB_BITMAPDIRTY) 01323 tot++; 01324 01325 if(tot==0) { 01326 BKE_report(op->reports, RPT_WARNING, "No images have been changed"); 01327 return OPERATOR_CANCELLED; 01328 } 01329 01330 /* get a filename for menu */ 01331 for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) 01332 if(ibuf->userflags & IB_BITMAPDIRTY) 01333 break; 01334 01335 BLI_strncpy(di, ibuf->name, FILE_MAX); 01336 BLI_splitdirstring(di, fi); 01337 01338 BKE_reportf(op->reports, RPT_INFO, "%d Image(s) will be saved in %s", tot, di); 01339 01340 for(ibuf= sima->image->ibufs.first; ibuf; ibuf= ibuf->next) { 01341 if(ibuf->userflags & IB_BITMAPDIRTY) { 01342 char name[FILE_MAX]; 01343 BLI_strncpy(name, ibuf->name, sizeof(name)); 01344 01345 BLI_path_abs(name, bmain->name); 01346 01347 if(0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) { 01348 BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", name); 01349 break; 01350 } 01351 01352 BKE_reportf(op->reports, RPT_INFO, "Saved: %s\n", ibuf->name); 01353 ibuf->userflags &= ~IB_BITMAPDIRTY; 01354 } 01355 } 01356 01357 return OPERATOR_FINISHED; 01358 } 01359 01360 void IMAGE_OT_save_sequence(wmOperatorType *ot) 01361 { 01362 /* identifiers */ 01363 ot->name= "Save Sequence"; 01364 ot->idname= "IMAGE_OT_save_sequence"; 01365 01366 /* api callbacks */ 01367 ot->exec= image_save_sequence_exec; 01368 ot->poll= space_image_buffer_exists_poll; 01369 01370 /* flags */ 01371 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01372 } 01373 01374 /******************** reload image operator ********************/ 01375 01376 static int image_reload_exec(bContext *C, wmOperator *UNUSED(op)) 01377 { 01378 Image *ima= CTX_data_edit_image(C); 01379 SpaceImage *sima= CTX_wm_space_image(C); 01380 01381 if(!ima) 01382 return OPERATOR_CANCELLED; 01383 01384 /* XXX unpackImage frees image buffers */ 01385 ED_preview_kill_jobs(C); 01386 01387 // XXX other users? 01388 BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_RELOAD); 01389 01390 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima); 01391 01392 return OPERATOR_FINISHED; 01393 } 01394 01395 void IMAGE_OT_reload(wmOperatorType *ot) 01396 { 01397 /* identifiers */ 01398 ot->name= "Reload Image"; 01399 ot->idname= "IMAGE_OT_reload"; 01400 01401 /* api callbacks */ 01402 ot->exec= image_reload_exec; 01403 01404 /* flags */ 01405 ot->flag= OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */ 01406 } 01407 01408 /********************** new image operator *********************/ 01409 01410 static int image_new_exec(bContext *C, wmOperator *op) 01411 { 01412 SpaceImage *sima; 01413 Scene *scene; 01414 Object *obedit; 01415 Image *ima; 01416 PointerRNA ptr, idptr; 01417 PropertyRNA *prop; 01418 char name[MAX_ID_NAME-2]; 01419 float color[4]; 01420 int width, height, floatbuf, uvtestgrid, alpha; 01421 01422 /* retrieve state */ 01423 sima= CTX_wm_space_image(C); 01424 scene= (Scene*)CTX_data_scene(C); 01425 obedit= CTX_data_edit_object(C); 01426 01427 RNA_string_get(op->ptr, "name", name); 01428 width= RNA_int_get(op->ptr, "width"); 01429 height= RNA_int_get(op->ptr, "height"); 01430 floatbuf= RNA_boolean_get(op->ptr, "float"); 01431 uvtestgrid= RNA_boolean_get(op->ptr, "uv_test_grid"); 01432 RNA_float_get_array(op->ptr, "color", color); 01433 alpha= RNA_boolean_get(op->ptr, "alpha"); 01434 01435 if (!floatbuf && scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) 01436 linearrgb_to_srgb_v3_v3(color, color); 01437 01438 if(!alpha) 01439 color[3]= 1.0f; 01440 01441 ima = BKE_add_image_size(width, height, name, alpha ? 32 : 24, floatbuf, uvtestgrid, color); 01442 01443 if(!ima) 01444 return OPERATOR_CANCELLED; 01445 01446 /* hook into UI */ 01447 uiIDContextProperty(C, &ptr, &prop); 01448 01449 if(prop) { 01450 /* when creating new ID blocks, use is already 1, but RNA 01451 * pointer se also increases user, so this compensates it */ 01452 ima->id.us--; 01453 01454 RNA_id_pointer_create(&ima->id, &idptr); 01455 RNA_property_pointer_set(&ptr, prop, idptr); 01456 RNA_property_update(C, &ptr, prop); 01457 } 01458 else if(sima) 01459 ED_space_image_set(sima, scene, obedit, ima); 01460 01461 // XXX other users? 01462 BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_USER_NEW_IMAGE); 01463 01464 return OPERATOR_FINISHED; 01465 } 01466 01467 /* XXX, Ton is not a fan of OK buttons but using this function to avoid undo/redo bug while in mesh-editmode, - campbell */ 01468 static int image_new_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01469 { 01470 return WM_operator_props_dialog_popup(C, op, 300, 100); 01471 01472 } 01473 01474 void IMAGE_OT_new(wmOperatorType *ot) 01475 { 01476 PropertyRNA *prop; 01477 static float default_color[4]= {0.0f, 0.0f, 0.0f, 1.0f}; 01478 01479 /* identifiers */ 01480 ot->name= "New Image"; 01481 ot->description= "Create a new image"; 01482 ot->idname= "IMAGE_OT_new"; 01483 01484 /* api callbacks */ 01485 ot->exec= image_new_exec; 01486 ot->invoke= image_new_invoke; 01487 01488 /* flags */ 01489 ot->flag= OPTYPE_UNDO; 01490 01491 /* properties */ 01492 RNA_def_string(ot->srna, "name", "untitled", MAX_ID_NAME-2, "Name", "Image datablock name"); 01493 RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384); 01494 RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384); 01495 prop= RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f); 01496 RNA_def_property_float_array_default(prop, default_color); 01497 RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel"); 01498 RNA_def_boolean(ot->srna, "uv_test_grid", 0, "UV Test Grid", "Fill the image with a grid for UV map testing"); 01499 RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); 01500 } 01501 01502 /********************* invert operators *********************/ 01503 01504 static int image_invert_poll(bContext *C) 01505 { 01506 Image *ima= CTX_data_edit_image(C); 01507 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 01508 01509 if( ibuf != NULL ) 01510 return 1; 01511 return 0; 01512 } 01513 01514 static int image_invert_exec(bContext *C, wmOperator *op) 01515 { 01516 Image *ima= CTX_data_edit_image(C); 01517 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 01518 01519 // flags indicate if this channel should be inverted 01520 const short r= RNA_boolean_get(op->ptr, "invert_r"); 01521 const short g= RNA_boolean_get(op->ptr, "invert_g"); 01522 const short b= RNA_boolean_get(op->ptr, "invert_b"); 01523 const short a= RNA_boolean_get(op->ptr, "invert_a"); 01524 01525 int i; 01526 01527 if( ibuf == NULL) // TODO: this should actually never happen, but does for render-results -> cleanup 01528 return OPERATOR_CANCELLED; 01529 01530 /* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */ 01531 if (ibuf->rect_float) { 01532 01533 float *fp = (float *) ibuf->rect_float; 01534 for( i = ibuf->x * ibuf->y; i > 0; i--, fp+=4 ) { 01535 if( r ) fp[0] = 1.0f - fp[0]; 01536 if( g ) fp[1] = 1.0f - fp[1]; 01537 if( b ) fp[2] = 1.0f - fp[2]; 01538 if( a ) fp[3] = 1.0f - fp[3]; 01539 } 01540 01541 if(ibuf->rect) { 01542 IMB_rect_from_float(ibuf); 01543 } 01544 } 01545 else if(ibuf->rect) { 01546 01547 char *cp = (char *) ibuf->rect; 01548 for( i = ibuf->x * ibuf->y; i > 0; i--, cp+=4 ) { 01549 if( r ) cp[0] = 255 - cp[0]; 01550 if( g ) cp[1] = 255 - cp[1]; 01551 if( b ) cp[2] = 255 - cp[2]; 01552 if( a ) cp[3] = 255 - cp[3]; 01553 } 01554 } 01555 else { 01556 return OPERATOR_CANCELLED; 01557 } 01558 01559 ibuf->userflags |= IB_BITMAPDIRTY; 01560 if(ibuf->mipmap[0]) 01561 ibuf->userflags |= IB_MIPMAP_INVALID; 01562 01563 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima); 01564 return OPERATOR_FINISHED; 01565 } 01566 01567 void IMAGE_OT_invert(wmOperatorType *ot) 01568 { 01569 /* identifiers */ 01570 ot->name= "Invert Channels"; 01571 ot->idname= "IMAGE_OT_invert"; 01572 01573 /* api callbacks */ 01574 ot->exec= image_invert_exec; 01575 ot->poll= image_invert_poll; 01576 01577 /* properties */ 01578 RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel"); 01579 RNA_def_boolean(ot->srna, "invert_g", 0, "Green", "Invert Green Channel"); 01580 RNA_def_boolean(ot->srna, "invert_b", 0, "Blue", "Invert Blue Channel"); 01581 RNA_def_boolean(ot->srna, "invert_a", 0, "Alpha", "Invert Alpha Channel"); 01582 01583 /* flags */ 01584 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01585 } 01586 01587 /********************* pack operator *********************/ 01588 01589 static int image_pack_test(bContext *C, wmOperator *op) 01590 { 01591 Image *ima= CTX_data_edit_image(C); 01592 int as_png= RNA_boolean_get(op->ptr, "as_png"); 01593 01594 if(!ima) 01595 return 0; 01596 if(!as_png && ima->packedfile) 01597 return 0; 01598 01599 if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) { 01600 BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported"); 01601 return 0; 01602 } 01603 01604 return 1; 01605 } 01606 01607 static int image_pack_exec(bContext *C, wmOperator *op) 01608 { 01609 struct Main *bmain= CTX_data_main(C); 01610 Image *ima= CTX_data_edit_image(C); 01611 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 01612 int as_png= RNA_boolean_get(op->ptr, "as_png"); 01613 01614 if(!image_pack_test(C, op)) 01615 return OPERATOR_CANCELLED; 01616 01617 if(!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) { 01618 BKE_report(op->reports, RPT_ERROR, "Can't pack edited image from disk, only as internal PNG"); 01619 return OPERATOR_CANCELLED; 01620 } 01621 01622 if(as_png) 01623 BKE_image_memorypack(ima); 01624 else 01625 ima->packedfile= newPackedFile(op->reports, ima->name, ID_BLEND_PATH(bmain, &ima->id)); 01626 01627 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima); 01628 01629 return OPERATOR_FINISHED; 01630 } 01631 01632 static int image_pack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01633 { 01634 Image *ima= CTX_data_edit_image(C); 01635 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); 01636 uiPopupMenu *pup; 01637 uiLayout *layout; 01638 int as_png= RNA_boolean_get(op->ptr, "as_png"); 01639 01640 if(!image_pack_test(C, op)) 01641 return OPERATOR_CANCELLED; 01642 01643 if(!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) { 01644 pup= uiPupMenuBegin(C, "OK", ICON_QUESTION); 01645 layout= uiPupMenuLayout(pup); 01646 uiItemBooleanO(layout, "Can't pack edited image from disk. Pack as internal PNG?", ICON_NONE, op->idname, "as_png", 1); 01647 uiPupMenuEnd(C, pup); 01648 01649 return OPERATOR_CANCELLED; 01650 } 01651 01652 return image_pack_exec(C, op); 01653 } 01654 01655 void IMAGE_OT_pack(wmOperatorType *ot) 01656 { 01657 /* identifiers */ 01658 ot->name= "Pack Image"; 01659 ot->description= "Pack an image as embedded data into the .blend file"; 01660 ot->idname= "IMAGE_OT_pack"; 01661 01662 /* api callbacks */ 01663 ot->exec= image_pack_exec; 01664 ot->invoke= image_pack_invoke; 01665 01666 /* flags */ 01667 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01668 01669 /* properties */ 01670 RNA_def_boolean(ot->srna, "as_png", 0, "Pack As PNG", "Pack image as lossless PNG"); 01671 } 01672 01673 /********************* unpack operator *********************/ 01674 01675 static int image_unpack_exec(bContext *C, wmOperator *op) 01676 { 01677 Image *ima= CTX_data_edit_image(C); 01678 int method= RNA_enum_get(op->ptr, "method"); 01679 01680 /* find the suppplied image by name */ 01681 if (RNA_struct_property_is_set(op->ptr, "id")) { 01682 char imaname[MAX_ID_NAME-2]; 01683 RNA_string_get(op->ptr, "id", imaname); 01684 ima = BLI_findstring(&CTX_data_main(C)->image, imaname, offsetof(ID, name) + 2); 01685 if (!ima) ima = CTX_data_edit_image(C); 01686 } 01687 01688 if(!ima || !ima->packedfile) 01689 return OPERATOR_CANCELLED; 01690 01691 if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) { 01692 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported"); 01693 return OPERATOR_CANCELLED; 01694 } 01695 01696 if(G.fileflags & G_AUTOPACK) 01697 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save"); 01698 01699 /* XXX unpackImage frees image buffers */ 01700 ED_preview_kill_jobs(C); 01701 01702 unpackImage(op->reports, ima, method); 01703 01704 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima); 01705 01706 return OPERATOR_FINISHED; 01707 } 01708 01709 static int image_unpack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 01710 { 01711 Image *ima= CTX_data_edit_image(C); 01712 01713 if(RNA_struct_property_is_set(op->ptr, "id")) 01714 return image_unpack_exec(C, op); 01715 01716 if(!ima || !ima->packedfile) 01717 return OPERATOR_CANCELLED; 01718 01719 if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) { 01720 BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported"); 01721 return OPERATOR_CANCELLED; 01722 } 01723 01724 if(G.fileflags & G_AUTOPACK) 01725 BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save"); 01726 01727 unpack_menu(C, "IMAGE_OT_unpack", ima->id.name+2, ima->name, "textures", ima->packedfile); 01728 01729 return OPERATOR_FINISHED; 01730 } 01731 01732 void IMAGE_OT_unpack(wmOperatorType *ot) 01733 { 01734 /* identifiers */ 01735 ot->name= "Unpack Image"; 01736 ot->description= "Save an image packed in the .blend file to disk"; 01737 ot->idname= "IMAGE_OT_unpack"; 01738 01739 /* api callbacks */ 01740 ot->exec= image_unpack_exec; 01741 ot->invoke= image_unpack_invoke; 01742 01743 /* flags */ 01744 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01745 01746 /* properties */ 01747 RNA_def_enum(ot->srna, "method", unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack"); 01748 RNA_def_string(ot->srna, "id", "", MAX_ID_NAME-2, "Image Name", "Image datablock name to unpack"); /* XXX, weark!, will fail with library, name collisions */ 01749 } 01750 01751 /******************** sample image operator ********************/ 01752 01753 typedef struct ImageSampleInfo { 01754 ARegionType *art; 01755 void *draw_handle; 01756 int x, y; 01757 int channels; 01758 01759 char col[4]; 01760 float colf[4]; 01761 int z; 01762 float zf; 01763 01764 char *colp; 01765 float *colfp; 01766 int *zp; 01767 float *zfp; 01768 01769 int draw; 01770 } ImageSampleInfo; 01771 01772 static void image_sample_draw(const bContext *UNUSED(C), ARegion *ar, void *arg_info) 01773 { 01774 ImageSampleInfo *info= arg_info; 01775 if(info->draw) { 01776 /* no color management needed for images (color_manage=0) */ 01777 ED_image_draw_info(ar, 0, info->channels, info->x, info->y, info->colp, info->colfp, info->zp, info->zfp); 01778 } 01779 } 01780 01781 static void image_sample_apply(bContext *C, wmOperator *op, wmEvent *event) 01782 { 01783 SpaceImage *sima= CTX_wm_space_image(C); 01784 ARegion *ar= CTX_wm_region(C); 01785 void *lock; 01786 ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock); 01787 ImageSampleInfo *info= op->customdata; 01788 float fx, fy; 01789 01790 if(ibuf == NULL) { 01791 ED_space_image_release_buffer(sima, lock); 01792 return; 01793 } 01794 01795 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy); 01796 01797 if(fx>=0.0f && fy>=0.0f && fx<1.0f && fy<1.0f) { 01798 float *fp; 01799 char *cp; 01800 int x= (int)(fx*ibuf->x), y= (int)(fy*ibuf->y); 01801 01802 CLAMP(x, 0, ibuf->x-1); 01803 CLAMP(y, 0, ibuf->y-1); 01804 01805 info->x= x; 01806 info->y= y; 01807 info->draw= 1; 01808 info->channels= ibuf->channels; 01809 01810 info->colp= NULL; 01811 info->colfp= NULL; 01812 info->zp= NULL; 01813 info->zfp= NULL; 01814 01815 if(ibuf->rect) { 01816 cp= (char *)(ibuf->rect + y*ibuf->x + x); 01817 01818 info->col[0]= cp[0]; 01819 info->col[1]= cp[1]; 01820 info->col[2]= cp[2]; 01821 info->col[3]= cp[3]; 01822 info->colp= info->col; 01823 01824 info->colf[0]= (float)cp[0]/255.0f; 01825 info->colf[1]= (float)cp[1]/255.0f; 01826 info->colf[2]= (float)cp[2]/255.0f; 01827 info->colf[3]= (float)cp[3]/255.0f; 01828 info->colfp= info->colf; 01829 } 01830 if(ibuf->rect_float) { 01831 fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x)); 01832 01833 info->colf[0]= fp[0]; 01834 info->colf[1]= fp[1]; 01835 info->colf[2]= fp[2]; 01836 info->colf[3]= fp[3]; 01837 info->colfp= info->colf; 01838 } 01839 01840 if(ibuf->zbuf) { 01841 info->z= ibuf->zbuf[y*ibuf->x + x]; 01842 info->zp= &info->z; 01843 } 01844 if(ibuf->zbuf_float) { 01845 info->zf= ibuf->zbuf_float[y*ibuf->x + x]; 01846 info->zfp= &info->zf; 01847 } 01848 01849 if(sima->cumap && ibuf->channels==4) { 01850 /* we reuse this callback for set curves point operators */ 01851 if(RNA_struct_find_property(op->ptr, "point")) { 01852 int point= RNA_enum_get(op->ptr, "point"); 01853 01854 if(point == 1) { 01855 curvemapping_set_black_white(sima->cumap, NULL, info->colfp); 01856 if(ibuf->rect_float) 01857 curvemapping_do_ibuf(sima->cumap, ibuf); 01858 } 01859 else if(point == 0) { 01860 curvemapping_set_black_white(sima->cumap, info->colfp, NULL); 01861 if(ibuf->rect_float) 01862 curvemapping_do_ibuf(sima->cumap, ibuf); 01863 } 01864 } 01865 } 01866 01867 // XXX node curve integration .. 01868 #if 0 01869 { 01870 ScrArea *sa, *cur= curarea; 01871 01872 node_curvemap_sample(fp); /* sends global to node editor */ 01873 for(sa= G.curscreen->areabase.first; sa; sa= sa->next) { 01874 if(sa->spacetype==SPACE_NODE) { 01875 areawinset(sa->win); 01876 scrarea_do_windraw(sa); 01877 } 01878 } 01879 node_curvemap_sample(NULL); /* clears global in node editor */ 01880 curarea= cur; 01881 } 01882 #endif 01883 } 01884 else 01885 info->draw= 0; 01886 01887 ED_space_image_release_buffer(sima, lock); 01888 ED_area_tag_redraw(CTX_wm_area(C)); 01889 } 01890 01891 static void image_sample_exit(bContext *C, wmOperator *op) 01892 { 01893 ImageSampleInfo *info= op->customdata; 01894 01895 ED_region_draw_cb_exit(info->art, info->draw_handle); 01896 ED_area_tag_redraw(CTX_wm_area(C)); 01897 MEM_freeN(info); 01898 } 01899 01900 static int image_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) 01901 { 01902 SpaceImage *sima= CTX_wm_space_image(C); 01903 ARegion *ar= CTX_wm_region(C); 01904 ImageSampleInfo *info; 01905 01906 if(!ED_space_image_has_buffer(sima)) 01907 return OPERATOR_CANCELLED; 01908 01909 info= MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo"); 01910 info->art= ar->type; 01911 info->draw_handle = ED_region_draw_cb_activate(ar->type, image_sample_draw, info, REGION_DRAW_POST_PIXEL); 01912 op->customdata= info; 01913 01914 image_sample_apply(C, op, event); 01915 01916 WM_event_add_modal_handler(C, op); 01917 01918 return OPERATOR_RUNNING_MODAL; 01919 } 01920 01921 static int image_sample_modal(bContext *C, wmOperator *op, wmEvent *event) 01922 { 01923 switch(event->type) { 01924 case LEFTMOUSE: 01925 case RIGHTMOUSE: // XXX hardcoded 01926 image_sample_exit(C, op); 01927 return OPERATOR_CANCELLED; 01928 case MOUSEMOVE: 01929 image_sample_apply(C, op, event); 01930 break; 01931 } 01932 01933 return OPERATOR_RUNNING_MODAL; 01934 } 01935 01936 static int image_sample_cancel(bContext *C, wmOperator *op) 01937 { 01938 image_sample_exit(C, op); 01939 return OPERATOR_CANCELLED; 01940 } 01941 01942 void IMAGE_OT_sample(wmOperatorType *ot) 01943 { 01944 /* identifiers */ 01945 ot->name= "Sample Color"; 01946 ot->idname= "IMAGE_OT_sample"; 01947 01948 /* api callbacks */ 01949 ot->invoke= image_sample_invoke; 01950 ot->modal= image_sample_modal; 01951 ot->cancel= image_sample_cancel; 01952 ot->poll= space_image_main_area_poll; 01953 01954 /* flags */ 01955 ot->flag= OPTYPE_BLOCKING; 01956 } 01957 01958 /******************** sample line operator ********************/ 01959 static int image_sample_line_exec(bContext *C, wmOperator *op) 01960 { 01961 SpaceImage *sima= CTX_wm_space_image(C); 01962 ARegion *ar= CTX_wm_region(C); 01963 Scene *scene= CTX_data_scene(C); 01964 01965 int x_start= RNA_int_get(op->ptr, "xstart"); 01966 int y_start= RNA_int_get(op->ptr, "ystart"); 01967 int x_end= RNA_int_get(op->ptr, "xend"); 01968 int y_end= RNA_int_get(op->ptr, "yend"); 01969 01970 void *lock; 01971 ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock); 01972 Histogram *hist= &sima->sample_line_hist; 01973 01974 float x1f, y1f, x2f, y2f; 01975 int x1, y1, x2, y2; 01976 int i, x, y; 01977 float *fp; 01978 float rgb[3]; 01979 unsigned char *cp; 01980 01981 if (ibuf == NULL) { 01982 ED_space_image_release_buffer(sima, lock); 01983 return OPERATOR_CANCELLED; 01984 } 01985 /* hmmmm */ 01986 if (ibuf->channels < 3) { 01987 ED_space_image_release_buffer(sima, lock); 01988 return OPERATOR_CANCELLED; 01989 } 01990 01991 UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f); 01992 UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f); 01993 x1= 0.5f+ x1f*ibuf->x; 01994 x2= 0.5f+ x2f*ibuf->x; 01995 y1= 0.5f+ y1f*ibuf->y; 01996 y2= 0.5f+ y2f*ibuf->y; 01997 01998 hist->channels = 3; 01999 hist->x_resolution = 256; 02000 hist->xmax = 1.0f; 02001 hist->ymax = 1.0f; 02002 02003 for (i=0; i<256; i++) { 02004 x= (int)(0.5f + x1 + (float)i*(x2-x1)/255.0f); 02005 y= (int)(0.5f + y1 + (float)i*(y2-y1)/255.0f); 02006 02007 if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y) { 02008 hist->data_luma[i] = hist->data_r[i] = hist->data_g[i]= hist->data_b[i] = 0.0f; 02009 } else { 02010 if (ibuf->rect_float) { 02011 fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x)); 02012 02013 if (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) 02014 linearrgb_to_srgb_v3_v3(rgb, fp); 02015 else 02016 copy_v3_v3(rgb, fp); 02017 02018 hist->data_r[i] = rgb[0]; 02019 hist->data_g[i] = rgb[1]; 02020 hist->data_b[i] = rgb[2]; 02021 hist->data_luma[i] = rgb_to_luma(rgb); 02022 } 02023 else if (ibuf->rect) { 02024 cp= (unsigned char *)(ibuf->rect + y*ibuf->x + x); 02025 hist->data_r[i] = (float)cp[0]/255.0f; 02026 hist->data_g[i] = (float)cp[1]/255.0f; 02027 hist->data_b[i] = (float)cp[2]/255.0f; 02028 hist->data_luma[i] = (float)rgb_to_luma_byte(cp)/255.0f; 02029 } 02030 } 02031 } 02032 02033 ED_space_image_release_buffer(sima, lock); 02034 02035 ED_area_tag_redraw(CTX_wm_area(C)); 02036 02037 return OPERATOR_FINISHED; 02038 } 02039 02040 static int image_sample_line_invoke(bContext *C, wmOperator *op, wmEvent *event) 02041 { 02042 SpaceImage *sima= CTX_wm_space_image(C); 02043 02044 if(!ED_space_image_has_buffer(sima)) 02045 return OPERATOR_CANCELLED; 02046 02047 return WM_gesture_straightline_invoke(C, op, event); 02048 } 02049 02050 void IMAGE_OT_sample_line(wmOperatorType *ot) 02051 { 02052 /* identifiers */ 02053 ot->name= "Sample Line"; 02054 ot->idname= "IMAGE_OT_sample_line"; 02055 02056 /* api callbacks */ 02057 ot->invoke= image_sample_line_invoke; 02058 ot->modal= WM_gesture_straightline_modal; 02059 ot->exec= image_sample_line_exec; 02060 ot->poll= space_image_main_area_poll; 02061 ot->cancel= WM_gesture_straightline_cancel; 02062 02063 /* flags */ 02064 ot->flag= 0; /* no undo/register since this operates on the space */ 02065 02066 WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); 02067 } 02068 02069 /******************** set curve point operator ********************/ 02070 02071 void IMAGE_OT_curves_point_set(wmOperatorType *ot) 02072 { 02073 static EnumPropertyItem point_items[]= { 02074 {0, "BLACK_POINT", 0, "Black Point", ""}, 02075 {1, "WHITE_POINT", 0, "White Point", ""}, 02076 {0, NULL, 0, NULL, NULL}}; 02077 02078 /* identifiers */ 02079 ot->name= "Set Curves Point"; 02080 ot->idname= "IMAGE_OT_curves_point_set"; 02081 02082 /* flags */ 02083 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02084 02085 /* api callbacks */ 02086 ot->invoke= image_sample_invoke; 02087 ot->modal= image_sample_modal; 02088 ot->cancel= image_sample_cancel; 02089 ot->poll= space_image_main_area_poll; 02090 02091 /* properties */ 02092 RNA_def_enum(ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves"); 02093 } 02094 02095 /******************** record composite operator *********************/ 02096 02097 typedef struct RecordCompositeData { 02098 wmTimer *timer; 02099 int old_cfra; 02100 int sfra, efra; 02101 } RecordCompositeData; 02102 02103 static int image_record_composite_apply(bContext *C, wmOperator *op) 02104 { 02105 SpaceImage *sima= CTX_wm_space_image(C); 02106 RecordCompositeData *rcd= op->customdata; 02107 Scene *scene= CTX_data_scene(C); 02108 ImBuf *ibuf; 02109 02110 WM_timecursor(CTX_wm_window(C), scene->r.cfra); 02111 02112 // XXX scene->nodetree->test_break= blender_test_break; 02113 // XXX scene->nodetree->test_break= NULL; 02114 02115 BKE_image_all_free_anim_ibufs(scene->r.cfra); 02116 ntreeCompositTagAnimated(scene->nodetree); 02117 ntreeCompositExecTree(scene->nodetree, &scene->r, scene->r.cfra != rcd->old_cfra); /* 1 is no previews */ 02118 02119 ED_area_tag_redraw(CTX_wm_area(C)); 02120 02121 ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser); 02122 /* save memory in flipbooks */ 02123 if(ibuf) 02124 imb_freerectfloatImBuf(ibuf); 02125 02126 scene->r.cfra++; 02127 02128 return (scene->r.cfra <= rcd->efra); 02129 } 02130 02131 static int image_record_composite_init(bContext *C, wmOperator *op) 02132 { 02133 SpaceImage *sima= CTX_wm_space_image(C); 02134 Scene *scene= CTX_data_scene(C); 02135 RecordCompositeData *rcd; 02136 02137 if(sima->iuser.frames < 2) 02138 return 0; 02139 if(scene->nodetree == NULL) 02140 return 0; 02141 02142 op->customdata= rcd= MEM_callocN(sizeof(RecordCompositeData), "ImageRecordCompositeData"); 02143 02144 rcd->old_cfra= scene->r.cfra; 02145 rcd->sfra= sima->iuser.sfra; 02146 rcd->efra= sima->iuser.sfra + sima->iuser.frames-1; 02147 scene->r.cfra= rcd->sfra; 02148 02149 return 1; 02150 } 02151 02152 static void image_record_composite_exit(bContext *C, wmOperator *op) 02153 { 02154 Scene *scene= CTX_data_scene(C); 02155 SpaceImage *sima= CTX_wm_space_image(C); 02156 RecordCompositeData *rcd= op->customdata; 02157 02158 scene->r.cfra= rcd->old_cfra; 02159 02160 WM_cursor_restore(CTX_wm_window(C)); 02161 02162 if(rcd->timer) 02163 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rcd->timer); 02164 02165 WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image); 02166 02167 // XXX play_anim(0); 02168 // XXX allqueue(REDRAWNODE, 1); 02169 02170 MEM_freeN(rcd); 02171 } 02172 02173 static int image_record_composite_exec(bContext *C, wmOperator *op) 02174 { 02175 if(!image_record_composite_init(C, op)) 02176 return OPERATOR_CANCELLED; 02177 02178 while(image_record_composite_apply(C, op)) 02179 ; 02180 02181 image_record_composite_exit(C, op); 02182 02183 return OPERATOR_FINISHED; 02184 } 02185 02186 static int image_record_composite_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 02187 { 02188 RecordCompositeData *rcd; 02189 02190 if(!image_record_composite_init(C, op)) 02191 return OPERATOR_CANCELLED; 02192 02193 rcd= op->customdata; 02194 rcd->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.0f); 02195 WM_event_add_modal_handler(C, op); 02196 02197 if(!image_record_composite_apply(C, op)) 02198 return OPERATOR_FINISHED; 02199 02200 return OPERATOR_RUNNING_MODAL; 02201 } 02202 02203 static int image_record_composite_modal(bContext *C, wmOperator *op, wmEvent *event) 02204 { 02205 RecordCompositeData *rcd= op->customdata; 02206 02207 switch(event->type) { 02208 case TIMER: 02209 if(rcd->timer == event->customdata) { 02210 if(!image_record_composite_apply(C, op)) { 02211 image_record_composite_exit(C, op); 02212 return OPERATOR_FINISHED; 02213 } 02214 } 02215 break; 02216 case ESCKEY: 02217 image_record_composite_exit(C, op); 02218 return OPERATOR_FINISHED; 02219 } 02220 02221 return OPERATOR_RUNNING_MODAL; 02222 } 02223 02224 static int image_record_composite_cancel(bContext *C, wmOperator *op) 02225 { 02226 image_record_composite_exit(C, op); 02227 return OPERATOR_CANCELLED; 02228 } 02229 02230 void IMAGE_OT_record_composite(wmOperatorType *ot) 02231 { 02232 /* identifiers */ 02233 ot->name= "Record Composite"; 02234 ot->idname= "IMAGE_OT_record_composite"; 02235 02236 /* api callbacks */ 02237 ot->exec= image_record_composite_exec; 02238 ot->invoke= image_record_composite_invoke; 02239 ot->modal= image_record_composite_modal; 02240 ot->cancel= image_record_composite_cancel; 02241 ot->poll= space_image_buffer_exists_poll; 02242 } 02243 02244 /********************* cycle render slot operator *********************/ 02245 02246 static int image_cycle_render_slot_poll(bContext *C) 02247 { 02248 Image *ima= CTX_data_edit_image(C); 02249 02250 return (ima && ima->type == IMA_TYPE_R_RESULT); 02251 } 02252 02253 static int image_cycle_render_slot_exec(bContext *C, wmOperator *op) 02254 { 02255 Image *ima= CTX_data_edit_image(C); 02256 int a, slot, cur= ima->render_slot; 02257 const short use_reverse= RNA_boolean_get(op->ptr, "reverse"); 02258 02259 for(a=1; a<IMA_MAX_RENDER_SLOT; a++) { 02260 slot= (cur + (use_reverse ? -a:a))%IMA_MAX_RENDER_SLOT; 02261 if(slot<0) slot+=IMA_MAX_RENDER_SLOT; 02262 02263 if(ima->renders[slot] || slot == ima->last_render_slot) { 02264 ima->render_slot= slot; 02265 break; 02266 } 02267 else if((slot - 1) == ima->last_render_slot && slot < IMA_MAX_RENDER_SLOT) { 02268 ima->render_slot= slot; 02269 break; 02270 } 02271 } 02272 02273 if(a == IMA_MAX_RENDER_SLOT) 02274 ima->render_slot= ((cur == 1)? 0: 1); 02275 02276 WM_event_add_notifier(C, NC_IMAGE|ND_DRAW, NULL); 02277 02278 /* no undo push for browsing existing */ 02279 if(ima->renders[ima->render_slot] || ima->render_slot==ima->last_render_slot) 02280 return OPERATOR_CANCELLED; 02281 02282 return OPERATOR_FINISHED; 02283 } 02284 02285 void IMAGE_OT_cycle_render_slot(wmOperatorType *ot) 02286 { 02287 /* identifiers */ 02288 ot->name= "Cycle Render Slot"; 02289 ot->idname= "IMAGE_OT_cycle_render_slot"; 02290 02291 /* api callbacks */ 02292 ot->exec= image_cycle_render_slot_exec; 02293 ot->poll= image_cycle_render_slot_poll; 02294 02295 /* flags */ 02296 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02297 02298 RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", ""); 02299 } 02300 02301 /******************** TODO ********************/ 02302 02303 /* XXX notifier? */ 02304 02305 /* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */ 02306 02307 void ED_image_update_frame(const Main *mainp, int cfra) 02308 { 02309 wmWindowManager *wm; 02310 wmWindow *win; 02311 Tex *tex; 02312 02313 /* texture users */ 02314 for(tex= mainp->tex.first; tex; tex= tex->id.next) { 02315 if(tex->type==TEX_IMAGE && tex->ima) { 02316 if(ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { 02317 if(tex->iuser.flag & IMA_ANIM_ALWAYS) 02318 BKE_image_user_calc_frame(&tex->iuser, cfra, 0); 02319 } 02320 } 02321 } 02322 02323 /* image window, compo node users */ 02324 for(wm=mainp->wm.first; wm; wm= wm->id.next) { /* only 1 wm */ 02325 for(win= wm->windows.first; win; win= win->next) { 02326 ScrArea *sa; 02327 for(sa= win->screen->areabase.first; sa; sa= sa->next) { 02328 if(sa->spacetype==SPACE_VIEW3D) { 02329 View3D *v3d= sa->spacedata.first; 02330 BGpic *bgpic; 02331 for(bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) 02332 if(bgpic->iuser.flag & IMA_ANIM_ALWAYS) 02333 BKE_image_user_calc_frame(&bgpic->iuser, cfra, 0); 02334 } 02335 else if(sa->spacetype==SPACE_IMAGE) { 02336 SpaceImage *sima= sa->spacedata.first; 02337 if(sima->iuser.flag & IMA_ANIM_ALWAYS) 02338 BKE_image_user_calc_frame(&sima->iuser, cfra, 0); 02339 } 02340 else if(sa->spacetype==SPACE_NODE) { 02341 SpaceNode *snode= sa->spacedata.first; 02342 if((snode->treetype==NTREE_COMPOSIT) && (snode->nodetree)) { 02343 bNode *node; 02344 for(node= snode->nodetree->nodes.first; node; node= node->next) { 02345 if(node->id && node->type==CMP_NODE_IMAGE) { 02346 Image *ima= (Image *)node->id; 02347 ImageUser *iuser= node->storage; 02348 if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) 02349 if(iuser->flag & IMA_ANIM_ALWAYS) 02350 BKE_image_user_calc_frame(iuser, cfra, 0); 02351 } 02352 } 02353 } 02354 } 02355 } 02356 } 02357 } 02358 } 02359