Blender V2.61 - r43446
|
00001 /* 00002 * 00003 * ***** BEGIN GPL LICENSE BLOCK ***** 00004 * 00005 * This program is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU General Public License 00007 * as published by the Free Software Foundation; either version 2 00008 * of the License, or (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software Foundation, 00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 * 00019 * The Original Code is Copyright (C) Blender Foundation. 00020 * All rights reserved. 00021 * 00022 * The Original Code is: all of this file. 00023 * 00024 * Contributor(s): none yet. 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00034 /* global includes */ 00035 00036 #include <stdlib.h> 00037 #include <math.h> 00038 #include <string.h> 00039 00040 #ifndef WIN32 00041 #include <unistd.h> 00042 #else 00043 #include <io.h> 00044 #endif 00045 #include "MEM_guardedalloc.h" 00046 00047 #include "BLO_readfile.h" 00048 00049 #include "BLI_math.h" 00050 #include "BLI_blenlib.h" 00051 #include "BLI_threads.h" 00052 #include "BLI_utildefines.h" 00053 00054 #include "DNA_world_types.h" 00055 #include "DNA_camera_types.h" 00056 #include "DNA_material_types.h" 00057 #include "DNA_node_types.h" 00058 #include "DNA_object_types.h" 00059 #include "DNA_lamp_types.h" 00060 #include "DNA_space_types.h" 00061 #include "DNA_view3d_types.h" 00062 #include "DNA_scene_types.h" 00063 #include "DNA_brush_types.h" 00064 #include "DNA_screen_types.h" 00065 00066 #include "BKE_brush.h" 00067 #include "BKE_context.h" 00068 #include "BKE_depsgraph.h" 00069 #include "BKE_global.h" 00070 #include "BKE_idprop.h" 00071 #include "BKE_image.h" 00072 #include "BKE_icons.h" 00073 #include "BKE_lamp.h" 00074 #include "BKE_library.h" 00075 #include "BKE_main.h" 00076 #include "BKE_material.h" 00077 #include "BKE_node.h" 00078 #include "BKE_object.h" 00079 #include "BKE_texture.h" 00080 #include "BKE_world.h" 00081 00082 #include "IMB_imbuf.h" 00083 #include "IMB_imbuf_types.h" 00084 00085 #include "BIF_gl.h" 00086 #include "BIF_glutil.h" 00087 00088 #include "PIL_time.h" 00089 00090 #include "RE_pipeline.h" 00091 00092 00093 #include "WM_api.h" 00094 #include "WM_types.h" 00095 00096 #include "ED_render.h" 00097 #include "ED_view3d.h" 00098 00099 #include "UI_interface.h" 00100 00101 #include "render_intern.h" 00102 00103 ImBuf* get_brush_icon(Brush *brush) 00104 { 00105 static const int flags = IB_rect|IB_multilayer|IB_metadata; 00106 00107 char path[FILE_MAX]; 00108 char *folder; 00109 00110 if (!(brush->icon_imbuf)) { 00111 if (brush->flag & BRUSH_CUSTOM_ICON) { 00112 00113 if (brush->icon_filepath[0]) { 00114 // first use the path directly to try and load the file 00115 00116 BLI_strncpy(path, brush->icon_filepath, sizeof(brush->icon_filepath)); 00117 BLI_path_abs(path, G.main->name); 00118 00119 brush->icon_imbuf= IMB_loadiffname(path, flags); 00120 00121 // otherwise lets try to find it in other directories 00122 if (!(brush->icon_imbuf)) { 00123 folder= BLI_get_folder(BLENDER_DATAFILES, "brushicons"); 00124 00125 BLI_make_file_string(G.main->name, path, folder, brush->icon_filepath); 00126 00127 if (path[0]) 00128 brush->icon_imbuf= IMB_loadiffname(path, flags); 00129 } 00130 00131 if (brush->icon_imbuf) 00132 BKE_icon_changed(BKE_icon_getid(&brush->id)); 00133 } 00134 } 00135 } 00136 00137 if (!(brush->icon_imbuf)) 00138 brush->id.icon_id = 0; 00139 00140 return brush->icon_imbuf; 00141 } 00142 00143 typedef struct ShaderPreview { 00144 /* from wmJob */ 00145 void *owner; 00146 short *stop, *do_update; 00147 00148 Scene *scene; 00149 ID *id; 00150 ID *parent; 00151 MTex *slot; 00152 00153 /* datablocks with nodes need full copy during preview render, glsl uses it too */ 00154 Material *matcopy; 00155 Tex *texcopy; 00156 Lamp *lampcopy; 00157 World *worldcopy; 00158 00159 float col[4]; /* active object color */ 00160 00161 int sizex, sizey; 00162 unsigned int *pr_rect; 00163 int pr_method; 00164 00165 } ShaderPreview; 00166 00167 /* *************************** Preview for buttons *********************** */ 00168 00169 static Main *pr_main= NULL; 00170 00171 void ED_preview_init_dbase(void) 00172 { 00173 #ifndef WITH_HEADLESS 00174 BlendFileData *bfd; 00175 extern int datatoc_preview_blend_size; 00176 extern char datatoc_preview_blend[]; 00177 const int fileflags= G.fileflags; 00178 00179 G.fileflags |= G_FILE_NO_UI; 00180 bfd= BLO_read_from_memory(datatoc_preview_blend, datatoc_preview_blend_size, NULL); 00181 if (bfd) { 00182 pr_main= bfd->main; 00183 00184 MEM_freeN(bfd); 00185 } 00186 G.fileflags= fileflags; 00187 #endif 00188 } 00189 00190 void ED_preview_free_dbase(void) 00191 { 00192 if(pr_main) 00193 free_main(pr_main); 00194 } 00195 00196 static int preview_mat_has_sss(Material *mat, bNodeTree *ntree) 00197 { 00198 if(mat) { 00199 if(mat->sss_flag & MA_DIFF_SSS) 00200 return 1; 00201 if(mat->nodetree) 00202 if( preview_mat_has_sss(NULL, mat->nodetree)) 00203 return 1; 00204 } 00205 else if(ntree) { 00206 bNode *node; 00207 for(node= ntree->nodes.first; node; node= node->next) { 00208 if(node->type==NODE_GROUP && node->id) { 00209 if( preview_mat_has_sss(NULL, (bNodeTree *)node->id)) 00210 return 1; 00211 } 00212 else if(node->id && ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) { 00213 mat= (Material *)node->id; 00214 if(mat->sss_flag & MA_DIFF_SSS) 00215 return 1; 00216 } 00217 } 00218 } 00219 return 0; 00220 } 00221 00222 /* call this with a pointer to initialize preview scene */ 00223 /* call this with NULL to restore assigned ID pointers in preview scene */ 00224 static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPreview *sp) 00225 { 00226 Scene *sce; 00227 Base *base; 00228 00229 if(pr_main==NULL) return NULL; 00230 00231 sce= pr_main->scene.first; 00232 if(sce) { 00233 00234 /* this flag tells render to not execute depsgraph or ipos etc */ 00235 sce->r.scemode |= R_PREVIEWBUTS; 00236 /* set world always back, is used now */ 00237 sce->world= pr_main->world.first; 00238 /* now: exposure copy */ 00239 if(scene->world) { 00240 sce->world->exp= scene->world->exp; 00241 sce->world->range= scene->world->range; 00242 } 00243 00244 sce->r.color_mgt_flag = scene->r.color_mgt_flag; 00245 00246 /* prevent overhead for small renders and icons (32) */ 00247 if(id && sp->sizex < 40) 00248 sce->r.xparts= sce->r.yparts= 1; 00249 else 00250 sce->r.xparts= sce->r.yparts= 4; 00251 00252 /* exception: don't color manage texture previews or icons */ 00253 if((id && sp->pr_method==PR_ICON_RENDER) || id_type == ID_TE) 00254 sce->r.color_mgt_flag &= ~R_COLOR_MANAGEMENT; 00255 00256 if((id && sp->pr_method==PR_ICON_RENDER) && id_type != ID_WO) 00257 sce->r.alphamode= R_ALPHAPREMUL; 00258 else 00259 sce->r.alphamode= R_ADDSKY; 00260 00261 sce->r.cfra= scene->r.cfra; 00262 BLI_strncpy(sce->r.engine, scene->r.engine, sizeof(sce->r.engine)); 00263 00264 if(id_type==ID_MA) { 00265 Material *mat= NULL, *origmat= (Material *)id; 00266 00267 if(origmat) { 00268 /* work on a copy */ 00269 mat= localize_material(origmat); 00270 sp->matcopy= mat; 00271 BLI_addtail(&pr_main->mat, mat); 00272 00273 init_render_material(mat, 0, NULL); /* call that retrieves mode_l */ 00274 end_render_material(mat); 00275 00276 /* un-useful option */ 00277 if(sp->pr_method==PR_ICON_RENDER) 00278 mat->shade_flag &= ~MA_OBCOLOR; 00279 00280 /* turn on raytracing if needed */ 00281 if(mat->mode_l & MA_RAYMIRROR) 00282 sce->r.mode |= R_RAYTRACE; 00283 if(mat->material_type == MA_TYPE_VOLUME) 00284 sce->r.mode |= R_RAYTRACE; 00285 if((mat->mode_l & MA_RAYTRANSP) && (mat->mode_l & MA_TRANSP)) 00286 sce->r.mode |= R_RAYTRACE; 00287 if(preview_mat_has_sss(mat, NULL)) 00288 sce->r.mode |= R_SSS; 00289 00290 /* turn off fake shadows if needed */ 00291 /* this only works in a specific case where the preview.blend contains 00292 * an object starting with 'c' which has a material linked to it (not the obdata) 00293 * and that material has a fake shadow texture in the active texture slot */ 00294 for(base= sce->base.first; base; base= base->next) { 00295 if(base->object->id.name[2]=='c') { 00296 Material *shadmat= give_current_material(base->object, base->object->actcol); 00297 if(shadmat) { 00298 if (mat->mode & MA_SHADBUF) shadmat->septex = 0; 00299 else shadmat->septex |= 1; 00300 } 00301 } 00302 } 00303 00304 /* turn off bounce lights for volume, 00305 * doesn't make much visual difference and slows it down too */ 00306 if(mat->material_type == MA_TYPE_VOLUME) { 00307 for(base= sce->base.first; base; base= base->next) { 00308 if(base->object->type == OB_LAMP) { 00309 /* if doesn't match 'Lamp.002' --> main key light */ 00310 if( strcmp(base->object->id.name+2, "Lamp.002") != 0 ) { 00311 base->object->restrictflag |= OB_RESTRICT_RENDER; 00312 } 00313 } 00314 } 00315 } 00316 00317 00318 if(sp->pr_method==PR_ICON_RENDER) { 00319 if (mat->material_type == MA_TYPE_HALO) { 00320 sce->lay= 1<<MA_FLAT; 00321 } 00322 else { 00323 sce->lay= 1<<MA_SPHERE_A; 00324 } 00325 } 00326 else { 00327 sce->lay= 1<<mat->pr_type; 00328 if(mat->nodetree && sp->pr_method==PR_NODE_RENDER) { 00329 /* two previews, they get copied by wmJob */ 00330 ntreeInitPreview(mat->nodetree, sp->sizex, sp->sizey); 00331 ntreeInitPreview(origmat->nodetree, sp->sizex, sp->sizey); 00332 } 00333 } 00334 } 00335 else { 00336 sce->r.mode &= ~(R_OSA|R_RAYTRACE|R_SSS); 00337 00338 } 00339 00340 for(base= sce->base.first; base; base= base->next) { 00341 if(base->object->id.name[2]=='p') { 00342 /* copy over object color, in case material uses it */ 00343 copy_v4_v4(base->object->col, sp->col); 00344 00345 if(OB_TYPE_SUPPORT_MATERIAL(base->object->type)) { 00346 /* don't use assign_material, it changed mat->id.us, which shows in the UI */ 00347 Material ***matar= give_matarar(base->object); 00348 int actcol= MAX2(base->object->actcol > 0, 1) - 1; 00349 00350 if(matar && actcol < base->object->totcol) 00351 (*matar)[actcol]= mat; 00352 } else if (base->object->type == OB_LAMP) { 00353 base->object->restrictflag &= ~OB_RESTRICT_RENDER; 00354 } 00355 } 00356 } 00357 } 00358 else if(id_type==ID_TE) { 00359 Tex *tex= NULL, *origtex= (Tex *)id; 00360 00361 if(origtex) { 00362 tex= localize_texture(origtex); 00363 sp->texcopy= tex; 00364 BLI_addtail(&pr_main->tex, tex); 00365 } 00366 sce->lay= 1<<MA_TEXTURE; 00367 00368 for(base= sce->base.first; base; base= base->next) { 00369 if(base->object->id.name[2]=='t') { 00370 Material *mat= give_current_material(base->object, base->object->actcol); 00371 if(mat && mat->mtex[0]) { 00372 mat->mtex[0]->tex= tex; 00373 00374 if(tex && sp->slot) 00375 mat->mtex[0]->which_output = sp->slot->which_output; 00376 00377 /* show alpha in this case */ 00378 if(tex==NULL || (tex->flag & TEX_PRV_ALPHA)) { 00379 mat->mtex[0]->mapto |= MAP_ALPHA; 00380 mat->alpha= 0.0f; 00381 } 00382 else { 00383 mat->mtex[0]->mapto &= ~MAP_ALPHA; 00384 mat->alpha= 1.0f; 00385 } 00386 } 00387 } 00388 } 00389 00390 if(tex && tex->nodetree && sp->pr_method==PR_NODE_RENDER) { 00391 /* two previews, they get copied by wmJob */ 00392 ntreeInitPreview(origtex->nodetree, sp->sizex, sp->sizey); 00393 ntreeInitPreview(tex->nodetree, sp->sizex, sp->sizey); 00394 } 00395 } 00396 else if(id_type==ID_LA) { 00397 Lamp *la= NULL, *origla= (Lamp *)id; 00398 00399 /* work on a copy */ 00400 if(origla) { 00401 la= localize_lamp(origla); 00402 sp->lampcopy= la; 00403 BLI_addtail(&pr_main->lamp, la); 00404 } 00405 00406 if(la && la->type==LA_SUN && (la->sun_effect_type & LA_SUN_EFFECT_SKY)) { 00407 sce->lay= 1<<MA_ATMOS; 00408 sce->world= scene->world; 00409 sce->camera= (Object *)BLI_findstring(&pr_main->object, "CameraAtmo", offsetof(ID, name)+2); 00410 } 00411 else { 00412 sce->lay= 1<<MA_LAMP; 00413 sce->world= NULL; 00414 sce->camera= (Object *)BLI_findstring(&pr_main->object, "Camera", offsetof(ID, name)+2); 00415 } 00416 sce->r.mode &= ~R_SHADOW; 00417 00418 for(base= sce->base.first; base; base= base->next) { 00419 if(base->object->id.name[2]=='p') { 00420 if(base->object->type==OB_LAMP) 00421 base->object->data= la; 00422 } 00423 } 00424 00425 if(la && la->nodetree && sp->pr_method==PR_NODE_RENDER) { 00426 /* two previews, they get copied by wmJob */ 00427 ntreeInitPreview(origla->nodetree, sp->sizex, sp->sizey); 00428 ntreeInitPreview(la->nodetree, sp->sizex, sp->sizey); 00429 } 00430 } 00431 else if(id_type==ID_WO) { 00432 World *wrld= NULL, *origwrld= (World *)id; 00433 00434 if(origwrld) { 00435 wrld= localize_world(origwrld); 00436 sp->worldcopy= wrld; 00437 BLI_addtail(&pr_main->world, wrld); 00438 } 00439 00440 sce->lay= 1<<MA_SKY; 00441 sce->world= wrld; 00442 00443 if(wrld && wrld->nodetree && sp->pr_method==PR_NODE_RENDER) { 00444 /* two previews, they get copied by wmJob */ 00445 ntreeInitPreview(wrld->nodetree, sp->sizex, sp->sizey); 00446 ntreeInitPreview(origwrld->nodetree, sp->sizex, sp->sizey); 00447 } 00448 } 00449 00450 return sce; 00451 } 00452 00453 return NULL; 00454 } 00455 00456 /* new UI convention: draw is in pixel space already. */ 00457 /* uses ROUNDBOX button in block to get the rect */ 00458 static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int first, rcti *rect, rcti *newrect) 00459 { 00460 Render *re; 00461 RenderResult rres; 00462 char name[32]; 00463 int do_gamma_correct=0, do_predivide=0; 00464 int offx=0, newx= rect->xmax-rect->xmin, newy= rect->ymax-rect->ymin; 00465 00466 if (id && GS(id->name) != ID_TE) { 00467 /* exception: don't color manage texture previews - show the raw values */ 00468 if (sce) { 00469 do_gamma_correct = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT; 00470 do_predivide = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE; 00471 } 00472 } 00473 00474 if(!split || first) sprintf(name, "Preview %p", (void *)sa); 00475 else sprintf(name, "SecondPreview %p", (void *)sa); 00476 00477 if(split) { 00478 if(first) { 00479 offx= 0; 00480 newx= newx/2; 00481 } 00482 else { 00483 offx= newx/2; 00484 newx= newx - newx/2; 00485 } 00486 } 00487 00488 re= RE_GetRender(name); 00489 RE_AcquireResultImage(re, &rres); 00490 00491 if(rres.rectf) { 00492 00493 if(ABS(rres.rectx-newx)<2 && ABS(rres.recty-newy)<2) { 00494 00495 newrect->xmax= MAX2(newrect->xmax, rect->xmin + rres.rectx + offx); 00496 newrect->ymax= MAX2(newrect->ymax, rect->ymin + rres.recty); 00497 00498 if(rres.rectx && rres.recty) { 00499 /* temporary conversion to byte for drawing */ 00500 float fx= rect->xmin + offx; 00501 float fy= rect->ymin; 00502 int profile_from= (do_gamma_correct)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; 00503 int dither= 0; 00504 unsigned char *rect_byte; 00505 00506 rect_byte= MEM_mallocN(rres.rectx*rres.recty*sizeof(int), "ed_preview_draw_rect"); 00507 00508 IMB_buffer_byte_from_float(rect_byte, rres.rectf, 00509 4, dither, IB_PROFILE_SRGB, profile_from, do_predivide, 00510 rres.rectx, rres.recty, rres.rectx, rres.rectx); 00511 00512 glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte); 00513 00514 MEM_freeN(rect_byte); 00515 } 00516 00517 RE_ReleaseResultImage(re); 00518 return 1; 00519 } 00520 } 00521 00522 RE_ReleaseResultImage(re); 00523 return 0; 00524 } 00525 00526 void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, rcti *rect) 00527 { 00528 if(idp) { 00529 ScrArea *sa= CTX_wm_area(C); 00530 Scene *sce = CTX_data_scene(C); 00531 ID *id = (ID *)idp; 00532 ID *parent= (ID *)parentp; 00533 MTex *slot= (MTex *)slotp; 00534 SpaceButs *sbuts= sa->spacedata.first; 00535 rcti newrect; 00536 int ok; 00537 int newx= rect->xmax-rect->xmin, newy= rect->ymax-rect->ymin; 00538 00539 newrect.xmin= rect->xmin; 00540 newrect.xmax= rect->xmin; 00541 newrect.ymin= rect->ymin; 00542 newrect.ymax= rect->ymin; 00543 00544 if(parent) { 00545 ok = ed_preview_draw_rect(sa, sce, id, 1, 1, rect, &newrect); 00546 ok &= ed_preview_draw_rect(sa, sce, parent, 1, 0, rect, &newrect); 00547 } 00548 else 00549 ok = ed_preview_draw_rect(sa, sce, id, 0, 0, rect, &newrect); 00550 00551 if(ok) 00552 *rect= newrect; 00553 00554 /* check for spacetype... */ 00555 if(sbuts->spacetype==SPACE_BUTS && sbuts->preview) { 00556 sbuts->preview= 0; 00557 ok= 0; 00558 } 00559 00560 if(ok==0) { 00561 ED_preview_shader_job(C, sa, id, parent, slot, newx, newy, PR_BUTS_RENDER); 00562 } 00563 } 00564 } 00565 00566 /* **************************** new shader preview system ****************** */ 00567 00568 /* inside thread, called by renderer, sets job update value */ 00569 static void shader_preview_draw(void *spv, RenderResult *UNUSED(rr), volatile struct rcti *UNUSED(rect)) 00570 { 00571 ShaderPreview *sp= spv; 00572 00573 *(sp->do_update)= 1; 00574 } 00575 00576 /* called by renderer, checks job value */ 00577 static int shader_preview_break(void *spv) 00578 { 00579 ShaderPreview *sp= spv; 00580 00581 return *(sp->stop); 00582 } 00583 00584 /* outside thread, called before redraw notifiers, it moves finished preview over */ 00585 static void shader_preview_updatejob(void *spv) 00586 { 00587 ShaderPreview *sp= spv; 00588 00589 if(sp->id) { 00590 if(sp->pr_method==PR_NODE_RENDER) { 00591 if( GS(sp->id->name) == ID_MA) { 00592 Material *mat= (Material *)sp->id; 00593 00594 if(sp->matcopy && mat->nodetree && sp->matcopy->nodetree) 00595 ntreeLocalSync(sp->matcopy->nodetree, mat->nodetree); 00596 } 00597 else if( GS(sp->id->name) == ID_TE) { 00598 Tex *tex= (Tex *)sp->id; 00599 00600 if(sp->texcopy && tex->nodetree && sp->texcopy->nodetree) 00601 ntreeLocalSync(sp->texcopy->nodetree, tex->nodetree); 00602 } 00603 else if( GS(sp->id->name) == ID_WO) { 00604 World *wrld= (World *)sp->id; 00605 00606 if(sp->worldcopy && wrld->nodetree && sp->worldcopy->nodetree) 00607 ntreeLocalSync(sp->worldcopy->nodetree, wrld->nodetree); 00608 } 00609 else if( GS(sp->id->name) == ID_LA) { 00610 Lamp *la= (Lamp *)sp->id; 00611 00612 if(sp->lampcopy && la->nodetree && sp->lampcopy->nodetree) 00613 ntreeLocalSync(sp->lampcopy->nodetree, la->nodetree); 00614 } 00615 } 00616 } 00617 } 00618 00619 static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int first) 00620 { 00621 Render *re; 00622 Scene *sce; 00623 float oldlens; 00624 short idtype= GS(id->name); 00625 char name[32]; 00626 int sizex; 00627 00628 /* get the stuff from the builtin preview dbase */ 00629 sce= preview_prepare_scene(sp->scene, id, idtype, sp); // XXX sizex 00630 if(sce==NULL) return; 00631 00632 if(!split || first) sprintf(name, "Preview %p", sp->owner); 00633 else sprintf(name, "SecondPreview %p", sp->owner); 00634 re= RE_GetRender(name); 00635 00636 /* full refreshed render from first tile */ 00637 if(re==NULL) 00638 re= RE_NewRender(name); 00639 00640 /* sce->r gets copied in RE_InitState! */ 00641 sce->r.scemode &= ~(R_MATNODE_PREVIEW|R_TEXNODE_PREVIEW); 00642 sce->r.scemode &= ~R_NO_IMAGE_LOAD; 00643 00644 if(sp->pr_method==PR_ICON_RENDER) { 00645 sce->r.scemode |= R_NO_IMAGE_LOAD; 00646 sce->r.mode |= R_OSA; 00647 } 00648 else if(sp->pr_method==PR_NODE_RENDER) { 00649 if(idtype == ID_MA) sce->r.scemode |= R_MATNODE_PREVIEW; 00650 else if(idtype == ID_TE) sce->r.scemode |= R_TEXNODE_PREVIEW; 00651 sce->r.mode &= ~R_OSA; 00652 } 00653 else { /* PR_BUTS_RENDER */ 00654 sce->r.mode |= R_OSA; 00655 } 00656 00657 /* in case of split preview, use border render */ 00658 if(split) { 00659 if(first) sizex= sp->sizex/2; 00660 else sizex= sp->sizex - sp->sizex/2; 00661 } 00662 else sizex= sp->sizex; 00663 00664 /* allocates or re-uses render result */ 00665 sce->r.xsch= sizex; 00666 sce->r.ysch= sp->sizey; 00667 sce->r.size= 100; 00668 00669 /* callbacs are cleared on GetRender() */ 00670 if(ELEM(sp->pr_method, PR_BUTS_RENDER, PR_NODE_RENDER)) { 00671 RE_display_draw_cb(re, sp, shader_preview_draw); 00672 } 00673 /* set this for all previews, default is react to G.afbreek still */ 00674 RE_test_break_cb(re, sp, shader_preview_break); 00675 00676 /* lens adjust */ 00677 oldlens= ((Camera *)sce->camera->data)->lens; 00678 if(sizex > sp->sizey) 00679 ((Camera *)sce->camera->data)->lens *= (float)sp->sizey/(float)sizex; 00680 00681 /* entire cycle for render engine */ 00682 RE_PreviewRender(re, pr_main, sce); 00683 00684 ((Camera *)sce->camera->data)->lens= oldlens; 00685 00686 /* handle results */ 00687 if(sp->pr_method==PR_ICON_RENDER) { 00688 // char *rct= (char *)(sp->pr_rect + 32*16 + 16); 00689 00690 if(sp->pr_rect) 00691 RE_ResultGet32(re, sp->pr_rect); 00692 } 00693 else { 00694 /* validate owner */ 00695 //if(ri->rect==NULL) 00696 // ri->rect= MEM_mallocN(sizeof(int)*ri->pr_rectx*ri->pr_recty, "BIF_previewrender"); 00697 //RE_ResultGet32(re, ri->rect); 00698 } 00699 00700 /* unassign the pointers, reset vars */ 00701 preview_prepare_scene(sp->scene, NULL, GS(id->name), sp); 00702 00703 /* XXX bad exception, end-exec is not being called in render, because it uses local main */ 00704 // if(idtype == ID_TE) { 00705 // Tex *tex= (Tex *)id; 00706 // if(tex->use_nodes && tex->nodetree) 00707 // ntreeEndExecTree(tex->nodetree); 00708 // } 00709 00710 } 00711 00712 /* runs inside thread for material and icons */ 00713 static void shader_preview_startjob(void *customdata, short *stop, short *do_update) 00714 { 00715 ShaderPreview *sp= customdata; 00716 00717 sp->stop= stop; 00718 sp->do_update= do_update; 00719 00720 if(sp->parent) { 00721 shader_preview_render(sp, sp->id, 1, 1); 00722 shader_preview_render(sp, sp->parent, 1, 0); 00723 } 00724 else 00725 shader_preview_render(sp, sp->id, 0, 0); 00726 00727 *do_update= 1; 00728 } 00729 00730 static void shader_preview_free(void *customdata) 00731 { 00732 ShaderPreview *sp= customdata; 00733 00734 if(sp->matcopy) { 00735 struct IDProperty *properties; 00736 int a; 00737 00738 /* node previews */ 00739 shader_preview_updatejob(sp); 00740 00741 /* get rid of copied material */ 00742 BLI_remlink(&pr_main->mat, sp->matcopy); 00743 00744 /* free_material decrements texture, prevent this. hack alert! */ 00745 for(a=0; a<MAX_MTEX; a++) { 00746 MTex *mtex= sp->matcopy->mtex[a]; 00747 if(mtex && mtex->tex) mtex->tex= NULL; 00748 } 00749 00750 free_material(sp->matcopy); 00751 00752 properties= IDP_GetProperties((ID *)sp->matcopy, FALSE); 00753 if (properties) { 00754 IDP_FreeProperty(properties); 00755 MEM_freeN(properties); 00756 } 00757 MEM_freeN(sp->matcopy); 00758 } 00759 if(sp->texcopy) { 00760 struct IDProperty *properties; 00761 /* node previews */ 00762 shader_preview_updatejob(sp); 00763 00764 /* get rid of copied texture */ 00765 BLI_remlink(&pr_main->tex, sp->texcopy); 00766 free_texture(sp->texcopy); 00767 00768 properties= IDP_GetProperties((ID *)sp->texcopy, FALSE); 00769 if (properties) { 00770 IDP_FreeProperty(properties); 00771 MEM_freeN(properties); 00772 } 00773 MEM_freeN(sp->texcopy); 00774 } 00775 if(sp->worldcopy) { 00776 struct IDProperty *properties; 00777 /* node previews */ 00778 shader_preview_updatejob(sp); 00779 00780 /* get rid of copied world */ 00781 BLI_remlink(&pr_main->world, sp->worldcopy); 00782 free_world(sp->worldcopy); 00783 00784 properties= IDP_GetProperties((ID *)sp->worldcopy, FALSE); 00785 if (properties) { 00786 IDP_FreeProperty(properties); 00787 MEM_freeN(properties); 00788 } 00789 MEM_freeN(sp->worldcopy); 00790 } 00791 if(sp->lampcopy) { 00792 struct IDProperty *properties; 00793 /* node previews */ 00794 shader_preview_updatejob(sp); 00795 00796 /* get rid of copied lamp */ 00797 BLI_remlink(&pr_main->lamp, sp->lampcopy); 00798 free_lamp(sp->lampcopy); 00799 00800 properties= IDP_GetProperties((ID *)sp->lampcopy, FALSE); 00801 if (properties) { 00802 IDP_FreeProperty(properties); 00803 MEM_freeN(properties); 00804 } 00805 MEM_freeN(sp->lampcopy); 00806 } 00807 00808 MEM_freeN(sp); 00809 } 00810 00811 /* ************************* icon preview ********************** */ 00812 00813 static void icon_copy_rect(ImBuf *ibuf, unsigned int w, unsigned int h, unsigned int *rect) 00814 { 00815 struct ImBuf *ima; 00816 unsigned int *drect, *srect; 00817 float scaledx, scaledy; 00818 short ex, ey, dx, dy; 00819 00820 /* paranoia test */ 00821 if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) 00822 return; 00823 00824 /* waste of cpu cyles... but the imbuf API has no other way to scale fast (ton) */ 00825 ima = IMB_dupImBuf(ibuf); 00826 00827 if (!ima) 00828 return; 00829 00830 if (ima->x > ima->y) { 00831 scaledx = (float)w; 00832 scaledy = ( (float)ima->y/(float)ima->x )*(float)w; 00833 } 00834 else { 00835 scaledx = ( (float)ima->x/(float)ima->y )*(float)h; 00836 scaledy = (float)h; 00837 } 00838 00839 ex = (short)scaledx; 00840 ey = (short)scaledy; 00841 00842 dx = (w - ex) / 2; 00843 dy = (h - ey) / 2; 00844 00845 IMB_scalefastImBuf(ima, ex, ey); 00846 00847 /* if needed, convert to 32 bits */ 00848 if(ima->rect==NULL) 00849 IMB_rect_from_float(ima); 00850 00851 srect = ima->rect; 00852 drect = rect; 00853 00854 drect+= dy*w+dx; 00855 for (;ey > 0; ey--){ 00856 memcpy(drect,srect, ex * sizeof(int)); 00857 drect += w; 00858 srect += ima->x; 00859 } 00860 00861 IMB_freeImBuf(ima); 00862 } 00863 00864 static void set_alpha(char *cp, int sizex, int sizey, char alpha) 00865 { 00866 int a, size= sizex*sizey; 00867 00868 for(a=0; a<size; a++, cp+=4) 00869 cp[3]= alpha; 00870 } 00871 00872 static void icon_preview_startjob(void *customdata, short *stop, short *do_update) 00873 { 00874 ShaderPreview *sp= customdata; 00875 ID *id= sp->id; 00876 short idtype= GS(id->name); 00877 00878 if(idtype == ID_IM) { 00879 Image *ima= (Image*)id; 00880 ImBuf *ibuf= NULL; 00881 ImageUser iuser= {NULL}; 00882 00883 /* ima->ok is zero when Image cannot load */ 00884 if(ima==NULL || ima->ok==0) 00885 return; 00886 00887 /* setup dummy image user */ 00888 iuser.ok= iuser.framenr= 1; 00889 iuser.scene= sp->scene; 00890 00891 /* elubie: this needs to be changed: here image is always loaded if not 00892 already there. Very expensive for large images. Need to find a way to 00893 only get existing ibuf */ 00894 ibuf = BKE_image_get_ibuf(ima, &iuser); 00895 if(ibuf==NULL || ibuf->rect==NULL) 00896 return; 00897 00898 icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect); 00899 00900 *do_update= 1; 00901 } 00902 else if(idtype == ID_BR) { 00903 Brush *br= (Brush*)id; 00904 00905 br->icon_imbuf= get_brush_icon(br); 00906 00907 memset(sp->pr_rect, 0x888888, sp->sizex*sp->sizey*sizeof(unsigned int)); 00908 00909 if(!(br->icon_imbuf) || !(br->icon_imbuf->rect)) 00910 return; 00911 00912 icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect); 00913 00914 *do_update= 1; 00915 } 00916 else { 00917 /* re-use shader job */ 00918 shader_preview_startjob(customdata, stop, do_update); 00919 00920 /* world is rendered with alpha=0, so it wasn't displayed 00921 this could be render option for sky to, for later */ 00922 if(idtype == ID_WO) { 00923 set_alpha((char*)sp->pr_rect, sp->sizex, sp->sizey, 255); 00924 } 00925 else if(idtype == ID_MA) { 00926 Material* ma = (Material*)id; 00927 00928 if(ma->material_type == MA_TYPE_HALO) 00929 set_alpha((char*)sp->pr_rect, sp->sizex, sp->sizey, 255); 00930 } 00931 } 00932 } 00933 00934 /* use same function for icon & shader, so the job manager 00935 does not run two of them at the same time. */ 00936 00937 static void common_preview_startjob(void *customdata, short *stop, short *do_update, float *UNUSED(progress)) 00938 { 00939 ShaderPreview *sp= customdata; 00940 00941 if(sp->pr_method == PR_ICON_RENDER) 00942 icon_preview_startjob(customdata, stop, do_update); 00943 else 00944 shader_preview_startjob(customdata, stop, do_update); 00945 } 00946 00947 static void common_preview_endjob(void *customdata) 00948 { 00949 ShaderPreview *sp= customdata; 00950 00951 if(sp->id && GS(sp->id->name) == ID_BR) 00952 WM_main_add_notifier(NC_BRUSH|NA_EDITED, sp->id); 00953 } 00954 00955 /* exported functions */ 00956 00957 void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey) 00958 { 00959 wmJob *steve; 00960 ShaderPreview *sp; 00961 00962 /* suspended start means it starts after 1 timer step, see WM_jobs_timer below */ 00963 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Icon Preview", WM_JOB_EXCL_RENDER|WM_JOB_SUSPEND); 00964 sp= MEM_callocN(sizeof(ShaderPreview), "shader preview"); 00965 00966 /* customdata for preview thread */ 00967 sp->scene= CTX_data_scene(C); 00968 sp->owner= id; 00969 sp->sizex= sizex; 00970 sp->sizey= sizey; 00971 sp->pr_method= PR_ICON_RENDER; 00972 sp->pr_rect= rect; 00973 sp->id = id; 00974 00975 /* setup job */ 00976 WM_jobs_customdata(steve, sp, shader_preview_free); 00977 WM_jobs_timer(steve, 0.25, NC_MATERIAL, NC_MATERIAL); 00978 WM_jobs_callbacks(steve, common_preview_startjob, NULL, NULL, common_preview_endjob); 00979 00980 WM_jobs_start(CTX_wm_manager(C), steve); 00981 } 00982 00983 void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, MTex *slot, int sizex, int sizey, int method) 00984 { 00985 Object *ob= CTX_data_active_object(C); 00986 wmJob *steve; 00987 ShaderPreview *sp; 00988 00989 steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Shader Preview", WM_JOB_EXCL_RENDER); 00990 sp= MEM_callocN(sizeof(ShaderPreview), "shader preview"); 00991 00992 /* customdata for preview thread */ 00993 sp->scene= CTX_data_scene(C); 00994 sp->owner= owner; 00995 sp->sizex= sizex; 00996 sp->sizey= sizey; 00997 sp->pr_method= method; 00998 sp->id = id; 00999 sp->parent= parent; 01000 sp->slot= slot; 01001 if(ob && ob->totcol) copy_v4_v4(sp->col, ob->col); 01002 else sp->col[0]= sp->col[1]= sp->col[2]= sp->col[3]= 1.0f; 01003 01004 /* setup job */ 01005 WM_jobs_customdata(steve, sp, shader_preview_free); 01006 WM_jobs_timer(steve, 0.1, NC_MATERIAL, NC_MATERIAL); 01007 WM_jobs_callbacks(steve, common_preview_startjob, NULL, shader_preview_updatejob, NULL); 01008 01009 WM_jobs_start(CTX_wm_manager(C), steve); 01010 } 01011 01012 void ED_preview_kill_jobs(const struct bContext *C) 01013 { 01014 wmWindowManager *wm= CTX_wm_manager(C); 01015 if(wm) 01016 WM_jobs_kill(wm, NULL, common_preview_startjob); 01017 } 01018