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