static ID *duplicate_ids(ID *id) { if (id == NULL) { /* Non-ID preview render. */ return NULL; } switch (GS(id->name)) { case ID_MA: return (ID *)BKE_material_localize((Material *)id); case ID_TE: return (ID *)BKE_texture_localize((Tex *)id); case ID_LA: return (ID *)BKE_light_localize((Light *)id); case ID_WO: return (ID *)BKE_world_localize((World *)id); case ID_IM: case ID_BR: case ID_SCR: return NULL; default: BLI_assert(!"ID type preview not supported."); return NULL; } }
/* call this with NULL to restore assigned ID pointers in preview scene */ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp) { Scene *sce; Base *base; Main *pr_main = sp->pr_main; memcpy(pr_main->name, bmain->name, sizeof(pr_main->name)); sce = preview_get_scene(pr_main); if (sce) { /* this flag tells render to not execute depsgraph or ipos etc */ sce->r.scemode |= R_BUTS_PREVIEW; /* set world always back, is used now */ sce->world = pr_main->world.first; /* now: exposure copy */ if (scene->world) { sce->world->exp = scene->world->exp; sce->world->range = scene->world->range; } sce->r.color_mgt_flag = scene->r.color_mgt_flag; BKE_color_managed_display_settings_copy(&sce->display_settings, &scene->display_settings); BKE_color_managed_view_settings_free(&sce->view_settings); BKE_color_managed_view_settings_copy(&sce->view_settings, &scene->view_settings); /* prevent overhead for small renders and icons (32) */ if (id && sp->sizex < 40) { sce->r.tilex = sce->r.tiley = 64; } else { sce->r.tilex = sce->r.xsch / 4; sce->r.tiley = sce->r.ysch / 4; } if ((id && sp->pr_method == PR_ICON_RENDER) && id_type != ID_WO) sce->r.alphamode = R_ALPHAPREMUL; else sce->r.alphamode = R_ADDSKY; sce->r.cfra = scene->r.cfra; if (id_type == ID_TE && !check_engine_supports_textures(scene)) { /* Force blender internal for texture icons and nodes render, * seems commonly used render engines does not support * such kind of rendering. */ BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_RENDER, sizeof(sce->r.engine)); } else { BLI_strncpy(sce->r.engine, scene->r.engine, sizeof(sce->r.engine)); } if (id_type == ID_MA) { Material *mat = NULL, *origmat = (Material *)id; if (origmat) { /* work on a copy */ mat = localize_material(origmat); sp->matcopy = mat; BLI_addtail(&pr_main->mat, mat); if (!BKE_scene_use_new_shading_nodes(scene)) { init_render_material(mat, 0, NULL); /* call that retrieves mode_l */ end_render_material(mat); /* un-useful option */ if (sp->pr_method == PR_ICON_RENDER) mat->shade_flag &= ~MA_OBCOLOR; /* turn on raytracing if needed */ if (mat->mode_l & MA_RAYMIRROR) sce->r.mode |= R_RAYTRACE; if (mat->material_type == MA_TYPE_VOLUME) sce->r.mode |= R_RAYTRACE; if ((mat->mode_l & MA_RAYTRANSP) && (mat->mode_l & MA_TRANSP)) sce->r.mode |= R_RAYTRACE; if (preview_mat_has_sss(mat, NULL)) sce->r.mode |= R_SSS; /* turn off fake shadows if needed */ /* this only works in a specific case where the preview.blend contains * an object starting with 'c' which has a material linked to it (not the obdata) * and that material has a fake shadow texture in the active texture slot */ for (base = sce->base.first; base; base = base->next) { if (base->object->id.name[2] == 'c') { Material *shadmat = give_current_material(base->object, base->object->actcol); if (shadmat) { if (mat->mode2 & MA_CASTSHADOW) shadmat->septex = 0; else shadmat->septex |= 1; } } } /* turn off bounce lights for volume, * doesn't make much visual difference and slows it down too */ for (base = sce->base.first; base; base = base->next) { if (base->object->type == OB_LAMP) { /* if doesn't match 'Lamp.002' --> main key light */ if (!STREQ(base->object->id.name + 2, "Lamp.002")) { if (mat->material_type == MA_TYPE_VOLUME) base->object->restrictflag |= OB_RESTRICT_RENDER; else base->object->restrictflag &= ~OB_RESTRICT_RENDER; } } } } else { /* use current scene world to light sphere */ if (mat->pr_type == MA_SPHERE_A) sce->world = scene->world; } if (sp->pr_method == PR_ICON_RENDER) { if (mat->material_type == MA_TYPE_HALO) { sce->lay = 1 << MA_FLAT; } else { sce->lay = 1 << MA_SPHERE_A; /* same as above, use current scene world to light sphere */ if (BKE_scene_use_new_shading_nodes(scene)) sce->world = scene->world; } } else { sce->lay = 1 << mat->pr_type; if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) { /* two previews, they get copied by wmJob */ BKE_node_preview_init_tree(mat->nodetree, sp->sizex, sp->sizey, true); BKE_node_preview_init_tree(origmat->nodetree, sp->sizex, sp->sizey, true); } } } else { sce->r.mode &= ~(R_OSA | R_RAYTRACE | R_SSS); } for (base = sce->base.first; base; base = base->next) { if (base->object->id.name[2] == 'p') { /* copy over object color, in case material uses it */ copy_v4_v4(base->object->col, sp->col); if (OB_TYPE_SUPPORT_MATERIAL(base->object->type)) { /* don't use assign_material, it changed mat->id.us, which shows in the UI */ Material ***matar = give_matarar(base->object); int actcol = max_ii(base->object->actcol - 1, 0); if (matar && actcol < base->object->totcol) (*matar)[actcol] = mat; } else if (base->object->type == OB_LAMP) { base->object->restrictflag &= ~OB_RESTRICT_RENDER; } } } } else if (id_type == ID_TE) { Tex *tex = NULL, *origtex = (Tex *)id; if (origtex) { tex = BKE_texture_localize(origtex); sp->texcopy = tex; BLI_addtail(&pr_main->tex, tex); } sce->lay = 1 << MA_TEXTURE; for (base = sce->base.first; base; base = base->next) { if (base->object->id.name[2] == 't') { Material *mat = give_current_material(base->object, base->object->actcol); if (mat && mat->mtex[0]) { mat->mtex[0]->tex = tex; if (tex && sp->slot) mat->mtex[0]->which_output = sp->slot->which_output; mat->mtex[0]->mapto &= ~MAP_ALPHA; mat->alpha = 1.0f; /* show alpha in this case */ if (tex == NULL || (tex->flag & TEX_PRV_ALPHA)) { if (!(tex && tex->type == TEX_IMAGE && (tex->imaflag & (TEX_USEALPHA | TEX_CALCALPHA)) == 0)) { mat->mtex[0]->mapto |= MAP_ALPHA; mat->alpha = 0.0f; } } } } } if (tex && tex->nodetree && sp->pr_method == PR_NODE_RENDER) { /* two previews, they get copied by wmJob */ BKE_node_preview_init_tree(origtex->nodetree, sp->sizex, sp->sizey, true); BKE_node_preview_init_tree(tex->nodetree, sp->sizex, sp->sizey, true); } } else if (id_type == ID_LA) { Lamp *la = NULL, *origla = (Lamp *)id; /* work on a copy */ if (origla) { la = localize_lamp(origla); sp->lampcopy = la; BLI_addtail(&pr_main->lamp, la); } sce->lay = 1 << MA_LAMP; if (!BKE_scene_use_new_shading_nodes(scene)) { if (la && la->type == LA_SUN && (la->sun_effect_type & LA_SUN_EFFECT_SKY)) { sce->lay = 1 << MA_ATMOS; sce->world = scene->world; sce->camera = (Object *)BLI_findstring(&pr_main->object, "CameraAtmo", offsetof(ID, name) + 2); } else { sce->world = NULL; sce->camera = (Object *)BLI_findstring(&pr_main->object, "Camera", offsetof(ID, name) + 2); } } for (base = sce->base.first; base; base = base->next) { if (base->object->id.name[2] == 'p') { if (base->object->type == OB_LAMP) base->object->data = la; } } if (la && la->nodetree && sp->pr_method == PR_NODE_RENDER) { /* two previews, they get copied by wmJob */ BKE_node_preview_init_tree(origla->nodetree, sp->sizex, sp->sizey, true); BKE_node_preview_init_tree(la->nodetree, sp->sizex, sp->sizey, true); } } else if (id_type == ID_WO) { World *wrld = NULL, *origwrld = (World *)id; if (origwrld) { wrld = localize_world(origwrld); sp->worldcopy = wrld; BLI_addtail(&pr_main->world, wrld); } sce->lay = 1 << MA_SKY; sce->world = wrld; if (wrld && wrld->nodetree && sp->pr_method == PR_NODE_RENDER) { /* two previews, they get copied by wmJob */ BKE_node_preview_init_tree(wrld->nodetree, sp->sizex, sp->sizey, true); BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true); } } return sce; } return NULL; }