/* call this with NULL to restore assigned ID pointers in preview scene */ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPreview *sp) { Scene *sce; Base *base; Main *pr_main = sp->pr_main; sce = preview_get_scene(pr_main); if (sce) { /* this flag tells render to not execute depsgraph or ipos etc */ sce->r.scemode |= R_PREVIEWBUTS; /* 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 && sp->pr_method == PR_ICON_RENDER) { /* force blender internal for texture icons render, * seems commonly used render engines does not support * such kind of rendering */ BLI_strncpy(sce->r.engine, "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->mode & MA_SHADBUF) shadmat->septex = 0; else shadmat->septex |= 1; } } } /* turn off bounce lights for volume, * doesn't make much visual difference and slows it down too */ if (mat->material_type == MA_TYPE_VOLUME) { 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 (strcmp(base->object->id.name + 2, "Lamp.002") != 0) { 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 = localize_texture(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; }
static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int first) { Render *re; Scene *sce; float oldlens; short idtype = GS(id->name); char name[32]; int sizex; Main *pr_main = sp->pr_main; /* in case of split preview, use border render */ if (split) { if (first) sizex = sp->sizex / 2; else sizex = sp->sizex - sp->sizex / 2; } else { sizex = sp->sizex; } /* we have to set preview variables first */ sce = preview_get_scene(pr_main); if (sce) { sce->r.xsch = sizex; sce->r.ysch = sp->sizey; sce->r.size = 100; } /* get the stuff from the builtin preview dbase */ sce = preview_prepare_scene(sp->scene, id, idtype, sp); if (sce == NULL) return; if (!split || first) sprintf(name, "Preview %p", sp->owner); else sprintf(name, "SecondPreview %p", sp->owner); re = RE_GetRender(name); /* full refreshed render from first tile */ if (re == NULL) re = RE_NewRender(name); /* sce->r gets copied in RE_InitState! */ sce->r.scemode &= ~(R_MATNODE_PREVIEW | R_TEXNODE_PREVIEW); sce->r.scemode &= ~R_NO_IMAGE_LOAD; if (sp->pr_method == PR_ICON_RENDER) { sce->r.scemode |= R_NO_IMAGE_LOAD; sce->r.mode |= R_OSA; } else if (sp->pr_method == PR_NODE_RENDER) { if (idtype == ID_MA) sce->r.scemode |= R_MATNODE_PREVIEW; else if (idtype == ID_TE) sce->r.scemode |= R_TEXNODE_PREVIEW; sce->r.mode &= ~R_OSA; } else { /* PR_BUTS_RENDER */ sce->r.mode |= R_OSA; } /* callbacs are cleared on GetRender() */ if (ELEM(sp->pr_method, PR_BUTS_RENDER, PR_NODE_RENDER)) { RE_display_draw_cb(re, sp, shader_preview_draw); } /* set this for all previews, default is react to G.is_break still */ RE_test_break_cb(re, sp, shader_preview_break); /* lens adjust */ oldlens = ((Camera *)sce->camera->data)->lens; if (sizex > sp->sizey) ((Camera *)sce->camera->data)->lens *= (float)sp->sizey / (float)sizex; /* entire cycle for render engine */ RE_PreviewRender(re, pr_main, sce); ((Camera *)sce->camera->data)->lens = oldlens; /* handle results */ if (sp->pr_method == PR_ICON_RENDER) { // char *rct= (char *)(sp->pr_rect + 32*16 + 16); if (sp->pr_rect) RE_ResultGet32(re, sp->pr_rect); } else { /* validate owner */ //if (ri->rect == NULL) // ri->rect= MEM_mallocN(sizeof(int) * ri->pr_rectx*ri->pr_recty, "BIF_previewrender"); //RE_ResultGet32(re, ri->rect); } /* unassign the pointers, reset vars */ preview_prepare_scene(sp->scene, NULL, GS(id->name), sp); /* XXX bad exception, end-exec is not being called in render, because it uses local main */ // if (idtype == ID_TE) { // Tex *tex= (Tex *)id; // if (tex->use_nodes && tex->nodetree) // ntreeEndExecTree(tex->nodetree); // } }
/* 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; Main *pr_main = sp->pr_main; memcpy(pr_main->name, BKE_main_blendfile_path(bmain), sizeof(pr_main->name)); sce = preview_get_scene(pr_main); if (sce) { ViewLayer *view_layer = sce->view_layers.first; /* 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->worlds.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) { /* Texture is not actually rendered with engine, just set dummy value. */ BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, 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 */ BLI_assert(sp->id_copy != NULL); mat = sp->matcopy = (Material *)sp->id_copy; sp->id_copy = NULL; BLI_addtail(&pr_main->materials, mat); /* Use current scene world for lighting. */ if (mat->pr_flag == MA_PREVIEW_WORLD && sp->pr_method == PR_BUTS_RENDER) { /* Use current scene world to light sphere. */ sce->world = preview_get_localized_world(sp, scene->world); } else if (sce->world) { /* Use a default world color. Using the current * scene world can be slow if it has big textures. */ sce->world->use_nodes = false; sce->world->horr = 0.05f; sce->world->horg = 0.05f; sce->world->horb = 0.05f; } if (sp->pr_method == PR_ICON_RENDER && sp->pr_main == G_pr_main_grease_pencil) { /* For grease pencil, always use sphere for icon renders. */ set_preview_visibility(sce, view_layer, MA_SPHERE_A, sp->pr_method); } else { /* Use specified preview shape for both preview panel and icon previews. */ set_preview_visibility(sce, view_layer, mat->pr_type, sp->pr_method); } if (sp->pr_method != PR_ICON_RENDER) { 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); /* WATCH: Accessing origmat is not safe! */ BKE_node_preview_init_tree(origmat->nodetree, sp->sizex, sp->sizey, true); } } } else { sce->display.render_aa = SCE_DISPLAY_AA_OFF; } for (Base *base = view_layer->object_bases.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->color, sp->color); 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->flag |= BASE_VISIBLE; } } } } else if (id_type == ID_TE) { Tex *tex = NULL, *origtex = (Tex *)id; if (origtex) { BLI_assert(sp->id_copy != NULL); tex = sp->texcopy = (Tex *)sp->id_copy; sp->id_copy = NULL; BLI_addtail(&pr_main->textures, tex); } if (tex && tex->nodetree && sp->pr_method == PR_NODE_RENDER) { /* two previews, they get copied by wmJob */ BKE_node_preview_init_tree(tex->nodetree, sp->sizex, sp->sizey, true); /* WATCH: Accessing origtex is not safe! */ BKE_node_preview_init_tree(origtex->nodetree, sp->sizex, sp->sizey, true); } } else if (id_type == ID_LA) { Light *la = NULL, *origla = (Light *)id; /* work on a copy */ if (origla) { BLI_assert(sp->id_copy != NULL); la = sp->lampcopy = (Light *)sp->id_copy; sp->id_copy = NULL; BLI_addtail(&pr_main->lights, la); } set_preview_visibility(sce, view_layer, MA_LAMP, sp->pr_method); if (sce->world) { /* Only use lighting from the light. */ sce->world->use_nodes = false; sce->world->horr = 0.0f; sce->world->horg = 0.0f; sce->world->horb = 0.0f; } for (Base *base = view_layer->object_bases.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(la->nodetree, sp->sizex, sp->sizey, true); /* WATCH: Accessing origla is not safe! */ BKE_node_preview_init_tree(origla->nodetree, sp->sizex, sp->sizey, true); } } else if (id_type == ID_WO) { World *wrld = NULL, *origwrld = (World *)id; if (origwrld) { BLI_assert(sp->id_copy != NULL); wrld = sp->worldcopy = (World *)sp->id_copy; sp->id_copy = NULL; BLI_addtail(&pr_main->worlds, wrld); } set_preview_visibility(sce, view_layer, MA_SKY, sp->pr_method); 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); /* WATCH: Accessing origwrld is not safe! */ BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true); } } return sce; } return NULL; }