diff options
Diffstat (limited to 'source/blender/editors/render')
-rw-r--r-- | source/blender/editors/render/CMakeLists.txt | 5 | ||||
-rw-r--r-- | source/blender/editors/render/SConscript | 5 | ||||
-rw-r--r-- | source/blender/editors/render/render_intern.h | 8 | ||||
-rw-r--r-- | source/blender/editors/render/render_internal.c | 87 | ||||
-rw-r--r-- | source/blender/editors/render/render_opengl.c | 440 | ||||
-rw-r--r-- | source/blender/editors/render/render_ops.c | 4 | ||||
-rw-r--r-- | source/blender/editors/render/render_preview.c | 275 | ||||
-rw-r--r-- | source/blender/editors/render/render_shading.c | 211 | ||||
-rw-r--r-- | source/blender/editors/render/render_update.c | 114 | ||||
-rw-r--r-- | source/blender/editors/render/render_view.c | 39 |
10 files changed, 838 insertions, 350 deletions
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt index 24015bd4ea3..971ab9f3458 100644 --- a/source/blender/editors/render/CMakeLists.txt +++ b/source/blender/editors/render/CMakeLists.txt @@ -20,10 +20,10 @@ set(INC ../include - ../../blenfont ../../blenkernel ../../blenlib ../../blenloader + ../../blentranslation ../../gpu ../../imbuf ../../bmesh @@ -32,6 +32,7 @@ set(INC ../../render/extern/include ../../windowmanager ../../../../intern/guardedalloc + ../../../../intern/glew-mx ) set(INC_SYS @@ -64,6 +65,8 @@ if(WITH_HEADLESS) add_definitions(-DWITH_HEADLESS) endif() +add_definitions(${GL_DEFINITIONS}) + if(WITH_FREESTYLE) list(APPEND INC ../../freestyle diff --git a/source/blender/editors/render/SConscript b/source/blender/editors/render/SConscript index 41576f9b485..24270ca2324 100644 --- a/source/blender/editors/render/SConscript +++ b/source/blender/editors/render/SConscript @@ -31,13 +31,15 @@ sources = env.Glob('*.c') incs = [ '#/intern/guardedalloc', - '#/extern/glew/include', + env['BF_GLEW_INC'], + '#/intern/glew-mx', '#/intern/elbeem/extern', '../include', '../../blenfont', '../../blenkernel', '../../blenlib', '../../blenloader', + '../../blentranslation', '../../bmesh', '../../gpu', '../../imbuf', @@ -49,6 +51,7 @@ incs = [ incs = ' '.join(incs) defs = [] +defs += env['BF_GL_DEFINITIONS'] if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): incs += ' ' + env['BF_PTHREADS_INC'] diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h index f9377d576bf..54429f9f066 100644 --- a/source/blender/editors/render/render_intern.h +++ b/source/blender/editors/render/render_intern.h @@ -32,9 +32,9 @@ #ifndef __RENDER_INTERN_H__ #define __RENDER_INTERN_H__ +struct bContext; +struct RenderEngine; struct wmOperatorType; -struct RenderResult; -struct Scene; struct ScrArea; /* render_shading.c */ @@ -44,6 +44,7 @@ void OBJECT_OT_material_slot_assign(struct wmOperatorType *ot); void OBJECT_OT_material_slot_select(struct wmOperatorType *ot); void OBJECT_OT_material_slot_deselect(struct wmOperatorType *ot); void OBJECT_OT_material_slot_copy(struct wmOperatorType *ot); +void OBJECT_OT_material_slot_move(struct wmOperatorType *ot); void MATERIAL_OT_new(struct wmOperatorType *ot); void TEXTURE_OT_new(struct wmOperatorType *ot); @@ -55,6 +56,9 @@ void MATERIAL_OT_paste(struct wmOperatorType *ot); void SCENE_OT_render_layer_add(struct wmOperatorType *ot); void SCENE_OT_render_layer_remove(struct wmOperatorType *ot); +void SCENE_OT_render_view_add(struct wmOperatorType *ot); +void SCENE_OT_render_view_remove(struct wmOperatorType *ot); + #ifdef WITH_FREESTYLE void SCENE_OT_freestyle_module_add(struct wmOperatorType *ot); void SCENE_OT_freestyle_module_remove(struct wmOperatorType *ot); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index baf25a49f7c..10de2d667ea 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -33,14 +33,16 @@ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" +#include "BLI_listbase.h" +#include "BLI_rect.h" +#include "BLI_timecode.h" #include "BLI_math.h" #include "BLI_threads.h" #include "BLI_utildefines.h" #include "PIL_time.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -48,6 +50,7 @@ #include "DNA_userdef_types.h" #include "BKE_blender.h" +#include "BKE_camera.h" #include "BKE_context.h" #include "BKE_colortools.h" #include "BKE_depsgraph.h" @@ -75,10 +78,8 @@ #include "RE_engine.h" #include "IMB_colormanagement.h" -#include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "GPU_extensions.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -86,7 +87,6 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "wm_window.h" #include "render_intern.h" @@ -119,7 +119,7 @@ typedef struct RenderJob { } RenderJob; /* called inside thread! */ -static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect) +static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect, const char *viewname) { Scene *scene = rj->scene; const float *rectf = NULL; @@ -191,11 +191,15 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu */ /* TODO(sergey): Need to check has_combined here? */ if (iuser->pass == 0) { + RenderView *rv; + size_t view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); + rv = RE_RenderViewGetById(rr, view_id); + /* find current float rect for display, first case is after composite... still weak */ - if (rr->rectf) - rectf = rr->rectf; + if (rv->rectf) + rectf = rv->rectf; else { - if (rr->rect32) { + if (rv->rect32) { /* special case, currently only happens with sequencer rendering, * which updates the whole frame, so we can only mark display buffer * as invalid here (sergey) @@ -204,8 +208,8 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu return; } else { - if (rr->renlay == NULL || rr->renlay->rectf == NULL) return; - rectf = rr->renlay->rectf; + if (rr->renlay == NULL) return; + rectf = RE_RenderLayerGetPass(rr->renlay, SCE_PASS_COMBINED, viewname); } } if (rectf == NULL) return; @@ -343,7 +347,11 @@ static void render_freejob(void *rjv) } /* str is IMA_MAX_RENDER_TEXT in size */ -static void make_renderinfo_string(RenderStats *rs, Scene *scene, bool v3d_override, char *str) +static void make_renderinfo_string(const RenderStats *rs, + const Scene *scene, + const bool v3d_override, + const char *error, + char *str) { char info_time_str[32]; // used to be extern to header_info.c uintptr_t mem_in_use, mmap_in_use, peak_memory; @@ -368,7 +376,7 @@ static void make_renderinfo_string(RenderStats *rs, Scene *scene, bool v3d_overr spos += sprintf(spos, IFACE_("Frame:%d "), (scene->r.cfra)); /* previous and elapsed time */ - BLI_timestr(rs->lastframetime, info_time_str, sizeof(info_time_str)); + BLI_timecode_string_from_time_simple(info_time_str, sizeof(info_time_str), rs->lastframetime); if (rs->infostr && rs->infostr[0]) { if (rs->lastframetime != 0.0) @@ -376,7 +384,7 @@ static void make_renderinfo_string(RenderStats *rs, Scene *scene, bool v3d_overr else spos += sprintf(spos, "| "); - BLI_timestr(PIL_check_seconds_timer() - rs->starttime, info_time_str, sizeof(info_time_str)); + BLI_timecode_string_from_time_simple(info_time_str, sizeof(info_time_str), PIL_check_seconds_timer() - rs->starttime); } else spos += sprintf(spos, "| "); @@ -416,8 +424,12 @@ static void make_renderinfo_string(RenderStats *rs, Scene *scene, bool v3d_overr spos += sprintf(spos, IFACE_("| Full Sample %d "), rs->curfsa); /* extra info */ - if (rs->infostr && rs->infostr[0]) + if (rs->infostr && rs->infostr[0]) { spos += sprintf(spos, "| %s ", rs->infostr); + } + else if (error && error[0]) { + spos += sprintf(spos, "| %s ", error); + } /* very weak... but 512 characters is quite safe */ if (spos >= str + IMA_MAX_RENDER_TEXT) @@ -438,7 +450,8 @@ static void image_renderinfo_cb(void *rjv, RenderStats *rs) if (rr->text == NULL) rr->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext"); - make_renderinfo_string(rs, rj->scene, rj->v3d_override, rr->text); + make_renderinfo_string(rs, rj->scene, rj->v3d_override, + rr->error, rr->text); } RE_ReleaseResult(rj->re); @@ -525,6 +538,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec Image *ima = rj->image; ImBuf *ibuf; void *lock; + const char *viewname = RE_GetActiveRenderView(rj->re); /* only update if we are displaying the slot being rendered */ if (ima->render_slot != ima->last_render_slot) { @@ -557,7 +571,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec ibuf->channels == 1 || U.image_draw_method != IMAGE_DRAW_METHOD_GLSL) { - image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect); + image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect, viewname); } /* make jobs timer to send notifier */ @@ -779,13 +793,13 @@ static void clean_viewport_memory(Main *bmain, Scene *scene, int renderlay) if ((base->lay & renderlay) == 0) { continue; } - if (RE_allow_render_generic_object(base->object)) { base->object->id.flag &= ~LIB_DOIT; } } - for (object = bmain->object.first; object; object = object->id.next) { + for (SETLOOPER(scene, sce_iter, base)) { + object = base->object; if ((object->id.flag & LIB_DOIT) == 0) { continue; } @@ -1121,7 +1135,7 @@ static void render_view3d_renderinfo_cb(void *rjp, RenderStats *rs) *rp->stop = 1; } else { - make_renderinfo_string(rs, rp->scene, false, rp->engine->text); + make_renderinfo_string(rs, rp->scene, false, NULL, rp->engine->text); /* make jobs timer to send notifier */ *(rp->do_update) = true; @@ -1140,8 +1154,8 @@ BLI_INLINE void rcti_scale_coords(rcti *scaled_rect, const rcti *rect, static void render_update_resolution(Render *re, const RenderPreview *rp, bool use_border, const rcti *clip_rect) { - int winx = rp->ar->winx / rp->resolution_divider, - winy = rp->ar->winy / rp->resolution_divider; + int winx = rp->ar->winx / rp->resolution_divider; + int winy = rp->ar->winy / rp->resolution_divider; if (use_border) { rcti scaled_cliprct; rcti_scale_coords(&scaled_cliprct, clip_rect, @@ -1221,10 +1235,10 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE)) || rstats->convertdone == 0) { RenderData rdata; - /* no osa, blur, seq, layers, etc for preview render */ + /* no osa, blur, seq, layers, savebuffer etc for preview render */ rdata = rp->scene->r; rdata.mode &= ~(R_OSA | R_MBLUR | R_BORDER | R_PANORAMA); - rdata.scemode &= ~(R_DOSEQ | R_DOCOMP | R_FREE_IMAGE); + rdata.scemode &= ~(R_DOSEQ | R_DOCOMP | R_FREE_IMAGE | R_EXR_TILE_FILE | R_FULL_SAMPLE); rdata.scemode |= R_VIEWPORT_PREVIEW; /* we do use layers, but only active */ @@ -1439,7 +1453,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) rp->bmain = CTX_data_main(C); rp->resolution_divider = divider; rp->start_resolution_divider = divider; - rp->has_freestyle = scene->r.mode & R_EDGE_FRS; + rp->has_freestyle = (scene->r.mode & R_EDGE_FRS) != 0; copy_m4_m4(rp->viewmat, rp->rv3d->viewmat); /* clear info text */ @@ -1455,7 +1469,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) engine->flag &= ~RE_ENGINE_DO_UPDATE; } -/* callback for render engine , on changes */ +/* callback for render engine, on changes */ void render_view3d_update(RenderEngine *engine, const bContext *C) { /* this shouldn't be needed and causes too many database rebuilds, but we @@ -1481,7 +1495,8 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) if (re == NULL) return; } - RE_AcquireResultImage(re, &rres); + /* Viewport render preview doesn't support multiview, view hardcoded to 0 */ + RE_AcquireResultImage(re, &rres, 0); if (rres.rectf) { RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -1551,10 +1566,10 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C) RE_ReleaseResultImage(re); } -void ED_viewport_render_kill_jobs(const bContext *C, bool free_database) +void ED_viewport_render_kill_jobs(wmWindowManager *wm, + Main *bmain, + bool free_database) { - wmWindowManager *wm = CTX_wm_manager(C); - Main *bmain = CTX_data_main(C); bScreen *sc; ScrArea *sa; ARegion *ar; @@ -1611,7 +1626,17 @@ Scene *ED_render_job_get_scene(const bContext *C) RenderJob *rj = (RenderJob *)WM_jobs_customdata_from_type(wm, WM_JOB_TYPE_RENDER); if (rj) - return rj->current_scene; + return rj->scene; return NULL; } + +Scene *ED_render_job_get_current_scene(const bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + RenderJob *rj = (RenderJob *)WM_jobs_customdata_from_type(wm, WM_JOB_TYPE_RENDER); + if (rj) { + return rj->current_scene; + } + return NULL; +} diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index ecf5e962c80..fe4022709de 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -31,19 +31,20 @@ #include <string.h> #include <stddef.h> -#include <GL/glew.h> - #include "MEM_guardedalloc.h" +#include "DNA_camera_types.h" #include "BLI_math.h" #include "BLI_math_color_blend.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_jitter.h" +#include "BLI_threads.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" +#include "BKE_camera.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_image.h" @@ -69,8 +70,9 @@ #include "RNA_define.h" #include "GPU_extensions.h" +#include "GPU_glew.h" +#include "GPU_compositing.h" -#include "wm_window.h" #include "render_intern.h" @@ -94,6 +96,7 @@ typedef struct OGLRender { ImageUser iuser; GPUOffScreen *ofs; + GPUFX *fx; int sizex, sizey; int write_still; @@ -101,11 +104,17 @@ typedef struct OGLRender { bMovieHandle *mh; int cfrao, nfra; + size_t totvideos; + + /* quick lookup */ + int view_id; + /* wm vars for timer and progress cursor */ wmWindowManager *wm; wmWindow *win; wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/ + void **movie_ctx_arr; } OGLRender; /* added because v3d is not always valid */ @@ -119,25 +128,144 @@ static unsigned int screen_opengl_layers(OGLRender *oglrender) } } -static void screen_opengl_render_apply(OGLRender *oglrender) +static bool screen_opengl_is_multiview(OGLRender *oglrender) +{ + View3D *v3d = oglrender->v3d; + RegionView3D *rv3d = oglrender->rv3d; + RenderData *rd = &oglrender->scene->r; + + if ((rd == NULL) || ((!oglrender->is_sequencer) && ((rv3d == NULL) || (v3d == NULL)))) + return false; + + return (rd->scemode & R_MULTIVIEW) && ((oglrender->is_sequencer) || (rv3d->persp == RV3D_CAMOB && v3d->camera)); +} + +static void screen_opengl_views_setup(OGLRender *oglrender) +{ + RenderResult *rr; + RenderView *rv; + SceneRenderView *srv; + bool is_multiview; + Object *camera; + View3D *v3d = oglrender->v3d; + + RenderData *rd = &oglrender->scene->r; + + rr = RE_AcquireResultWrite(oglrender->re); + + is_multiview = screen_opengl_is_multiview(oglrender); + + if (!is_multiview) { + /* we only have one view when multiview is off */ + rv = rr->views.first; + + if (rv == NULL) { + rv = MEM_callocN(sizeof(RenderView), "new opengl render view"); + BLI_addtail(&rr->views, rv); + } + + while (rv->next) { + RenderView *rv_del = rv->next; + BLI_remlink(&rr->views, rv_del); + + if (rv_del->rectf) + MEM_freeN(rv_del->rectf); + + if (rv_del->rectz) + MEM_freeN(rv_del->rectz); + + MEM_freeN(rv_del); + } + } + else { + if (!oglrender->is_sequencer) + RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d)); + + /* remove all the views that are not needed */ + rv = rr->views.last; + while (rv) { + srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name)); + if (BKE_scene_multiview_is_render_view_active(rd, srv)) { + if (rv->rectf == NULL) + rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect"); + rv = rv->prev; + } + else { + RenderView *rv_del = rv; + rv = rv_del->prev; + + BLI_remlink(&rr->views, rv_del); + + if (rv_del->rectf) + MEM_freeN(rv_del->rectf); + + if (rv_del->rectz) + MEM_freeN(rv_del->rectz); + + MEM_freeN(rv_del); + } + } + + /* create all the views that are needed */ + for (srv = rd->views.first; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) + continue; + + rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name)); + + if (rv == NULL) { + rv = MEM_callocN(sizeof(RenderView), "new opengl render view"); + BLI_strncpy(rv->name, srv->name, sizeof(rv->name)); + BLI_addtail(&rr->views, rv); + } + } + } + + for (rv = rr->views.first; rv; rv = rv->next) { + if (rv->rectf == NULL) { + rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect"); + } + } + + BLI_lock_thread(LOCK_DRAW_IMAGE); + if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) { + oglrender->ima->flag |= IMA_IS_STEREO; + } + else { + oglrender->ima->flag &= ~IMA_IS_STEREO; + oglrender->iuser.flag &= ~IMA_SHOW_STEREO; + } + BLI_unlock_thread(LOCK_DRAW_IMAGE); + + /* will only work for non multiview correctly */ + if (v3d) { + camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, "new opengl render view"); + BKE_render_result_stamp_info(oglrender->scene, camera, rr, false); + } + else { + BKE_render_result_stamp_info(oglrender->scene, oglrender->scene->camera, rr, false); + } + + RE_ReleaseResult(oglrender->re); +} + +static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) { Scene *scene = oglrender->scene; ARegion *ar = oglrender->ar; View3D *v3d = oglrender->v3d; RegionView3D *rv3d = oglrender->rv3d; - RenderResult *rr; Object *camera = NULL; ImBuf *ibuf; - void *lock; float winmat[4][4]; + float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf; int sizex = oglrender->sizex; int sizey = oglrender->sizey; const short view_context = (v3d != NULL); bool draw_bgpic = true; bool draw_sky = (scene->r.alphamode == R_ADDSKY); unsigned char *rect = NULL; - - rr = RE_AcquireResultRead(oglrender->re); + const char *viewname = RE_GetActiveRenderView(oglrender->re); if (oglrender->is_sequencer) { SeqRenderData context; @@ -145,9 +273,12 @@ static void screen_opengl_render_apply(OGLRender *oglrender) int chanshown = sseq ? sseq->chanshown : 0; struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL; - context = BKE_sequencer_new_render_data(oglrender->bmain->eval_ctx, oglrender->bmain, - scene, oglrender->sizex, oglrender->sizey, 100.0f); + BKE_sequencer_new_render_data( + oglrender->bmain->eval_ctx, oglrender->bmain, scene, + oglrender->sizex, oglrender->sizey, 100.0f, + &context); + context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname); ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown); if (ibuf) { @@ -171,7 +302,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender) BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf); } - memcpy(rr->rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey); + memcpy(rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey); IMB_freeImBuf(linear_ibuf); } @@ -180,7 +311,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender) int i; unsigned char *gp_rect; - GPU_offscreen_bind(oglrender->ofs); + GPU_offscreen_bind(oglrender->ofs, true); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -188,32 +319,48 @@ static void screen_opengl_render_apply(OGLRender *oglrender) wmOrtho2(0, sizex, 0, sizey); glTranslatef(sizex / 2, sizey / 2, 0.0f); - ED_gpencil_draw_ex(gpd, sizex, sizey, scene->r.cfra); + G.f |= G_RENDER_OGL; + ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ); + G.f &= ~G_RENDER_OGL; gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect); + BLI_assert(rectf != NULL); + for (i = 0; i < sizex * sizey * 4; i += 4) { float col_src[4]; rgba_uchar_to_float(col_src, &gp_rect[i]); - blend_color_mix_float(&rr->rectf[i], &rr->rectf[i], col_src); + blend_color_mix_float(&rectf[i], &rectf[i], col_src); } - GPU_offscreen_unbind(oglrender->ofs); + GPU_offscreen_unbind(oglrender->ofs, true); MEM_freeN(gp_rect); } } else if (view_context) { + bool is_persp; + /* full copy */ + GPUFXSettings fx_settings = v3d->fx_settings; + ED_view3d_draw_offscreen_init(scene, v3d); - GPU_offscreen_bind(oglrender->ofs); /* bind */ + GPU_offscreen_bind(oglrender->ofs, true); /* bind */ /* render 3d view */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { - /*int is_ortho = scene->r.mode & R_ORTHO;*/ - camera = v3d->camera; +#if 0 + const bool is_ortho = (scene->r.mode & R_ORTHO) != 0; +#endif + camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname); RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat); - + if (camera->type == OB_CAMERA) { + Camera *cam = camera->data; + is_persp = cam->type == CAM_PERSP; + } + else + is_persp = true; + BKE_camera_to_gpu_dof(camera, &fx_settings); } else { rctf viewplane; @@ -222,12 +369,17 @@ static void screen_opengl_render_apply(OGLRender *oglrender) bool is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); if (is_ortho) orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend); else perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); + + is_persp = !is_ortho; } rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); if ((scene->r.mode & R_OSA) == 0) { - ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, draw_bgpic, draw_sky); + ED_view3d_draw_offscreen( + scene, v3d, ar, sizex, sizey, NULL, winmat, + draw_bgpic, draw_sky, is_persp, + oglrender->ofs, oglrender->fx, &fx_settings, viewname); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); } else { @@ -240,7 +392,10 @@ static void screen_opengl_render_apply(OGLRender *oglrender) BLI_jitter_init(jit_ofs, scene->r.osa); /* first sample buffer, also initializes 'rv3d->persmat' */ - ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat, draw_bgpic, draw_sky); + ED_view3d_draw_offscreen( + scene, v3d, ar, sizex, sizey, NULL, winmat, + draw_bgpic, draw_sky, is_persp, + oglrender->ofs, oglrender->fx, &fx_settings, viewname); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); for (i = 0; i < sizex * sizey * 4; i++) @@ -253,7 +408,10 @@ static void screen_opengl_render_apply(OGLRender *oglrender) (jit_ofs[j][0] * 2.0f) / sizex, (jit_ofs[j][1] * 2.0f) / sizey); - ED_view3d_draw_offscreen(scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, draw_bgpic, draw_sky); + ED_view3d_draw_offscreen( + scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, + draw_bgpic, draw_sky, is_persp, + oglrender->ofs, oglrender->fx, &fx_settings, viewname); GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect); for (i = 0; i < sizex * sizey * 4; i++) @@ -266,14 +424,14 @@ static void screen_opengl_render_apply(OGLRender *oglrender) MEM_freeN(accum_buffer); } - GPU_offscreen_unbind(oglrender->ofs); /* unbind */ + GPU_offscreen_unbind(oglrender->ofs, true); /* unbind */ } else { /* shouldnt suddenly give errors mid-render but possible */ char err_out[256] = "unknown"; ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey, - IB_rect, OB_SOLID, false, true, - (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, err_out); + IB_rect, OB_SOLID, false, true, true, + (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, viewname, err_out); camera = scene->camera; if (ibuf_view) { @@ -298,7 +456,8 @@ static void screen_opengl_render_apply(OGLRender *oglrender) if (rect) { int profile_to; - + float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf; + if (BKE_scene_check_color_management_enabled(scene)) profile_to = IB_PROFILE_LINEAR_RGB; else @@ -306,45 +465,68 @@ static void screen_opengl_render_apply(OGLRender *oglrender) /* sequencer has got trickier conversion happened above * also assume opengl's space matches byte buffer color space */ - IMB_buffer_float_from_byte(rr->rectf, rect, + IMB_buffer_float_from_byte(rectf, rect, profile_to, IB_PROFILE_SRGB, true, oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex); + + /* rr->rectf is now filled with image data */ + + if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) + BKE_image_stamp_buf(scene, camera, rect, rectf, rr->rectx, rr->recty, 4); + + MEM_freeN(rect); } +} - /* rr->rectf is now filled with image data */ +static void screen_opengl_render_write(OGLRender *oglrender) +{ + Scene *scene = oglrender->scene; + RenderResult *rr; + bool ok; + char name[FILE_MAX]; - if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) - BKE_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4); + rr = RE_AcquireResultRead(oglrender->re); - RE_ReleaseResult(oglrender->re); + BKE_image_path_from_imformat( + name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL); - /* update byte from float buffer */ - ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock); + /* write images as individual images or stereo */ + BKE_render_result_stamp_info(scene, scene->camera, rr, false); + ok = RE_WriteRenderViewsImage(oglrender->reports, rr, scene, false, name); - if (ibuf) { - ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + RE_ReleaseResultImage(oglrender->re); - /* write file for animation */ - if (oglrender->write_still) { - char name[FILE_MAX]; - int ok; + if (ok) printf("OpenGL Render written to '%s'\n", name); + else printf("OpenGL Render failed to write '%s'\n", name); +} - if (scene->r.im_format.planes == R_IMF_CHAN_DEPTH_8) { - IMB_color_to_bw(ibuf); - } +static void screen_opengl_render_apply(OGLRender *oglrender) +{ + RenderResult *rr; + RenderView *rv; + int view_id; + ImBuf *ibuf; + void *lock; - BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false); - ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, true); /* no need to stamp here */ - if (ok) printf("OpenGL Render written to '%s'\n", name); - else printf("OpenGL Render failed to write '%s'\n", name); - } + rr = RE_AcquireResultRead(oglrender->re); + for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) { + RE_SetActiveRenderView(oglrender->re, rv->name); + oglrender->view_id = view_id; + screen_opengl_render_doit(oglrender, rr); + } + + RE_ReleaseResult(oglrender->re); + + ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock); + if (ibuf) { + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; } - BKE_image_release_ibuf(oglrender->ima, ibuf, lock); - if (rect) - MEM_freeN(rect); + if (oglrender->write_still) { + screen_opengl_render_write(oglrender); + } } static bool screen_opengl_render_init(bContext *C, wmOperator *op) @@ -356,7 +538,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ScrArea *prevsa = CTX_wm_area(C); ARegion *prevar = CTX_wm_region(C); - RenderResult *rr; GPUOffScreen *ofs; OGLRender *oglrender; int sizex, sizey; @@ -429,7 +610,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) oglrender->sseq = CTX_wm_space_seq(C); } - oglrender->prevsa = prevsa; oglrender->prevar = prevar; @@ -444,6 +624,9 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) * running notifiers again will overwrite */ oglrender->scene->customdata_mask |= oglrender->scene->customdata_mask_modal; + if (oglrender->v3d->fx_settings.fx_flag & (GPU_FX_FLAG_DOF | GPU_FX_FLAG_SSAO)) { + oglrender->fx = GPU_fx_compositor_create(); + } } /* create render */ @@ -460,15 +643,17 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) /* create render result */ RE_InitState(oglrender->re, NULL, &scene->r, NULL, sizex, sizey, NULL); - rr = RE_AcquireResultWrite(oglrender->re); - if (rr->rectf == NULL) - rr->rectf = MEM_callocN(sizeof(float) * 4 * sizex * sizey, "screen_opengl_render_init rect"); - RE_ReleaseResult(oglrender->re); + /* create render views */ + screen_opengl_views_setup(oglrender); /* wm vars */ oglrender->wm = wm; oglrender->win = win; + oglrender->totvideos = 0; + oglrender->mh = NULL; + oglrender->movie_ctx_arr = NULL; + return true; } @@ -476,10 +661,19 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) { Main *bmain = CTX_data_main(C); Scene *scene = oglrender->scene; + size_t i; if (oglrender->mh) { - if (BKE_imtype_is_movie(scene->r.im_format.imtype)) - oglrender->mh->end_movie(); + if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { + for (i = 0; i < oglrender->totvideos; i++) { + oglrender->mh->end_movie(oglrender->movie_ctx_arr[i]); + oglrender->mh->context_free(oglrender->movie_ctx_arr[i]); + } + } + + if (oglrender->movie_ctx_arr) { + MEM_freeN(oglrender->movie_ctx_arr); + } } if (oglrender->timer) { /* exec will not have a timer */ @@ -493,6 +687,9 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene); + if (oglrender->fx) + GPU_fx_compositor_destroy(oglrender->fx); + GPU_offscreen_free(oglrender->ofs); oglrender->scene->customdata_mask_modal = 0; @@ -509,7 +706,7 @@ static void screen_opengl_render_cancel(bContext *C, wmOperator *op) } /* share between invoke and exec */ -static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) +static bool screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) { /* initialize animation */ OGLRender *oglrender; @@ -517,13 +714,34 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) oglrender = op->customdata; scene = oglrender->scene; + oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r); oglrender->reports = op->reports; - oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype); + if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { - if (!oglrender->mh->start_movie(scene, &scene->r, oglrender->sizex, oglrender->sizey, oglrender->reports)) { + size_t i, width, height; + + BKE_scene_multiview_videos_dimensions_get(&scene->r, oglrender->sizex, oglrender->sizey, &width, &height); + oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype); + + if (oglrender->mh == NULL) { + BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported"); screen_opengl_render_end(C, oglrender); - return 0; + return false; + } + + oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"); + + for (i = 0; i < oglrender->totvideos; i++) { + const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i); + + oglrender->movie_ctx_arr[i] = oglrender->mh->context_create(); + if (!oglrender->mh->start_movie(oglrender->movie_ctx_arr[i], scene, &scene->r, oglrender->sizex, + oglrender->sizey, oglrender->reports, PRVRANGEON != 0, suffix)) + { + screen_opengl_render_end(C, oglrender); + return false; + } } } @@ -531,20 +749,19 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op) oglrender->nfra = PSFRA; scene->r.cfra = PSFRA; - return 1; + return true; } + static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); OGLRender *oglrender = op->customdata; Scene *scene = oglrender->scene; - ImBuf *ibuf, *ibuf_save = NULL; - void *lock; char name[FILE_MAX]; bool ok = false; const bool view_context = (oglrender->v3d != NULL); - Object *camera = NULL; bool is_movie; + RenderResult *rr; /* go to next frame */ if (CFRA < oglrender->nfra) @@ -562,8 +779,9 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype); if (!is_movie) { - BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true); + BKE_image_path_from_imformat( + name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) { BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name); @@ -583,89 +801,41 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) if (BKE_scene_camera_switch_update(scene)) { oglrender->v3d->camera = scene->camera; } - - camera = oglrender->v3d->camera; } } else { BKE_scene_camera_switch_update(scene); - - camera = scene->camera; } /* render into offscreen buffer */ screen_opengl_render_apply(oglrender); /* save to disk */ - ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock); - - if (ibuf) { - bool needs_free = false; - - ibuf_save = ibuf; - - if (is_movie || !BKE_imtype_requires_linear_float(scene->r.im_format.imtype)) { - ibuf_save = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &scene->view_settings, - &scene->display_settings, &scene->r.im_format); - - needs_free = true; - } - - /* color -> grayscale */ - /* editing directly would alter the render view */ - if (scene->r.im_format.planes == R_IMF_PLANES_BW) { - ImBuf *ibuf_bw = IMB_dupImBuf(ibuf_save); - IMB_color_to_bw(ibuf_bw); - - if (needs_free) - IMB_freeImBuf(ibuf_save); - - ibuf_save = ibuf_bw; - } - else { - /* this is lightweight & doesnt re-alloc the buffers, only do this - * to save the correct bit depth since the image is always RGBA */ - ImBuf *ibuf_cpy = IMB_allocImBuf(ibuf_save->x, ibuf_save->y, scene->r.im_format.planes, 0); - - ibuf_cpy->rect = ibuf_save->rect; - ibuf_cpy->rect_float = ibuf_save->rect_float; - ibuf_cpy->zbuf_float = ibuf_save->zbuf_float; - - if (needs_free) { - ibuf_cpy->mall = ibuf_save->mall; - ibuf_save->mall = 0; - IMB_freeImBuf(ibuf_save); - } + rr = RE_AcquireResultRead(oglrender->re); - ibuf_save = ibuf_cpy; + if (is_movie) { + ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh, oglrender->sizex, + oglrender->sizey, oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0); + if (ok) { + printf("Append frame %d", scene->r.cfra); + BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra); } - - if (is_movie) { - ok = oglrender->mh->append_movie(&scene->r, PSFRA, CFRA, (int *)ibuf_save->rect, - oglrender->sizex, oglrender->sizey, oglrender->reports); - if (ok) { - printf("Append frame %d", scene->r.cfra); - BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra); - } + } + else { + BKE_render_result_stamp_info(scene, scene->camera, rr, false); + ok = RE_WriteRenderViewsImage(op->reports, rr, scene, true, name); + if (ok) { + printf("Saved: %s", name); + BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name); } else { - ok = BKE_imbuf_write_stamp(scene, camera, ibuf_save, name, &scene->r.im_format); - - if (ok == 0) { - printf("Write error: cannot save %s\n", name); - BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name); - } - else { - printf("Saved: %s", name); - BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name); - } + printf("Write error: cannot save %s\n", name); + BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name); } - - if (needs_free) - IMB_freeImBuf(ibuf_save); } - BKE_image_release_ibuf(oglrender->ima, ibuf, lock); + RE_ReleaseResult(oglrender->re); + /* movie stats prints have no line break */ printf("\n"); diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c index 0d334082a2b..f98083f7e74 100644 --- a/source/blender/editors/render/render_ops.c +++ b/source/blender/editors/render/render_ops.c @@ -47,6 +47,7 @@ void ED_operatortypes_render(void) WM_operatortype_append(OBJECT_OT_material_slot_select); WM_operatortype_append(OBJECT_OT_material_slot_deselect); WM_operatortype_append(OBJECT_OT_material_slot_copy); + WM_operatortype_append(OBJECT_OT_material_slot_move); WM_operatortype_append(MATERIAL_OT_new); WM_operatortype_append(TEXTURE_OT_new); @@ -58,6 +59,9 @@ void ED_operatortypes_render(void) WM_operatortype_append(SCENE_OT_render_layer_add); WM_operatortype_append(SCENE_OT_render_layer_remove); + WM_operatortype_append(SCENE_OT_render_view_add); + WM_operatortype_append(SCENE_OT_render_view_remove); + #ifdef WITH_FREESTYLE WM_operatortype_append(SCENE_OT_freestyle_module_add); WM_operatortype_append(SCENE_OT_freestyle_module_remove); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 01f00a8458a..6dfd2b31d30 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -60,6 +60,7 @@ #include "DNA_brush_types.h" #include "DNA_screen_types.h" +#include "BKE_appdir.h" #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_colortools.h" @@ -78,16 +79,14 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "IMB_colormanagement.h" - -#include "GPU_extensions.h" +#include "IMB_thumbs.h" #include "BIF_gl.h" #include "BIF_glutil.h" -#include "PIL_time.h" #include "RE_pipeline.h" +#include "RE_engine.h" #include "WM_api.h" #include "WM_types.h" @@ -95,9 +94,10 @@ #include "ED_datafiles.h" #include "ED_render.h" -#include "UI_interface.h" - -#include "render_intern.h" +#ifndef NDEBUG +/* Used for database init assert(). */ +# include "BLI_threads.h" +#endif ImBuf *get_brush_icon(Brush *brush) { @@ -120,7 +120,7 @@ ImBuf *get_brush_icon(Brush *brush) // otherwise lets try to find it in other directories if (!(brush->icon_imbuf)) { - folder = BLI_get_folder(BLENDER_DATAFILES, "brushicons"); + folder = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons"); BLI_make_file_string(G.main->name, path, folder, brush->icon_filepath); @@ -131,7 +131,7 @@ ImBuf *get_brush_icon(Brush *brush) } if (brush->icon_imbuf) - BKE_icon_changed(BKE_icon_getid(&brush->id)); + BKE_icon_changed(BKE_icon_id_ensure(&brush->id)); } } } @@ -164,6 +164,7 @@ typedef struct ShaderPreview { unsigned int *pr_rect; int pr_method; + Main *bmain; Main *pr_main; } ShaderPreview; @@ -174,6 +175,7 @@ typedef struct IconPreviewSize { } IconPreviewSize; typedef struct IconPreview { + Main *bmain; Scene *scene; void *owner; ID *id; @@ -205,14 +207,25 @@ static Main *load_main_from_memory(const void *blend, int blend_size) } #endif -void ED_preview_init_dbase(void) +void ED_preview_ensure_dbase(void) { #ifndef WITH_HEADLESS - G_pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size); - G_pr_main_cycles = load_main_from_memory(datatoc_preview_cycles_blend, datatoc_preview_cycles_blend_size); + static bool base_initialized = false; + BLI_assert(BLI_thread_is_main()); + if (!base_initialized) { + G_pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size); + G_pr_main_cycles = load_main_from_memory(datatoc_preview_cycles_blend, datatoc_preview_cycles_blend_size); + base_initialized = true; + } #endif } +static bool check_engine_supports_textures(Scene *scene) +{ + RenderEngineType *type = RE_engines_find(scene->r.engine); + return type->flag & RE_USE_TEXTURE_PREVIEW; +} + void ED_preview_free_dbase(void) { if (G_pr_main) @@ -258,12 +271,14 @@ static Scene *preview_get_scene(Main *pr_main) /* call this with a pointer to initialize preview scene */ /* 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) +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) { @@ -299,12 +314,12 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre sce->r.cfra = scene->r.cfra; - if (id_type == ID_TE) { + 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, "BLENDER_RENDER", sizeof(sce->r.engine)); + 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)); @@ -356,7 +371,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre 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) { + if (!STREQ(base->object->id.name + 2, "Lamp.002")) { if (mat->material_type == MA_TYPE_VOLUME) base->object->restrictflag |= OB_RESTRICT_RENDER; else @@ -420,7 +435,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre Tex *tex = NULL, *origtex = (Tex *)id; if (origtex) { - tex = localize_texture(origtex); + tex = BKE_texture_localize(origtex); sp->texcopy = tex; BLI_addtail(&pr_main->tex, tex); } @@ -518,10 +533,11 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre } /* new UI convention: draw is in pixel space already. */ -/* uses ROUNDBOX button in block to get the rect */ +/* uses UI_BTYPE_ROUNDBOX button in block to get the rect */ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, rcti *newrect) { Render *re; + RenderView *rv; RenderResult rres; char name[32]; int offx = 0; @@ -545,9 +561,22 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, /* test if something rendered ok */ re = RE_GetRender(name); - RE_AcquireResultImage(re, &rres); - if (rres.rectf) { + if (re == NULL) + return false; + + RE_AcquireResultImageViews(re, &rres); + + if (!BLI_listbase_is_empty(&rres.views)) { + /* material preview only needs monoscopy (view 0) */ + rv = RE_RenderViewGetById(&rres, 0); + } + else { + /* possible the job clears the views but we're still drawing T45496 */ + rv = NULL; + } + + if (rv && rv->rectf) { if (ABS(rres.rectx - newx) < 2 && ABS(rres.recty - newy) < 2) { @@ -558,8 +587,11 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"); float fx = rect->xmin + offx; float fy = rect->ymin; - - RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte); + + /* material preview only needs monoscopy (view 0) */ + if (re) + RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte, 0); + glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte); MEM_freeN(rect_byte); @@ -569,7 +601,7 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, } } - RE_ReleaseResultImage(re); + RE_ReleaseResultImageViews(re, &rres); return ok; } @@ -698,7 +730,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs } /* get the stuff from the builtin preview dbase */ - sce = preview_prepare_scene(sp->scene, id, idtype, sp); + sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp); if (sce == NULL) return; if (!split || first) sprintf(name, "Preview %p", sp->owner); @@ -751,15 +783,9 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs 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); + preview_prepare_scene(sp->bmain, 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) { @@ -927,65 +953,87 @@ static void set_alpha(char *cp, int sizex, int sizey, char alpha) static void icon_preview_startjob(void *customdata, short *stop, short *do_update) { ShaderPreview *sp = customdata; - ID *id = sp->id; - short idtype = GS(id->name); - - if (idtype == ID_IM) { - Image *ima = (Image *)id; - ImBuf *ibuf = NULL; - ImageUser iuser = {NULL}; - /* ima->ok is zero when Image cannot load */ - if (ima == NULL || ima->ok == 0) - return; + if (sp->pr_method == PR_ICON_DEFERRED) { + PreviewImage *prv = sp->owner; + ImBuf *thumb; + char *deferred_data = PRV_DEFERRED_DATA(prv); + int source = deferred_data[0]; + char *path = &deferred_data[1]; - /* setup dummy image user */ - iuser.ok = iuser.framenr = 1; - iuser.scene = sp->scene; - - /* elubie: this needs to be changed: here image is always loaded if not - * already there. Very expensive for large images. Need to find a way to - * only get existing ibuf */ - ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); - if (ibuf == NULL || ibuf->rect == NULL) { - BKE_image_release_ibuf(ima, ibuf, NULL); - return; - } - - icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect); +// printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path); - *do_update = true; + thumb = IMB_thumb_manage(path, THB_LARGE, source); - BKE_image_release_ibuf(ima, ibuf, NULL); + if (thumb) { + /* PreviewImage assumes premultiplied alhpa... */ + IMB_premultiply_alpha(thumb); + + icon_copy_rect(thumb, sp->sizex, sp->sizey, sp->pr_rect); + IMB_freeImBuf(thumb); + } } - else if (idtype == ID_BR) { - Brush *br = (Brush *)id; + else { + ID *id = sp->id; + short idtype = GS(id->name); + + if (idtype == ID_IM) { + Image *ima = (Image *)id; + ImBuf *ibuf = NULL; + ImageUser iuser = {NULL}; + + /* ima->ok is zero when Image cannot load */ + if (ima == NULL || ima->ok == 0) + return; + + /* setup dummy image user */ + iuser.ok = iuser.framenr = 1; + iuser.scene = sp->scene; + + /* elubie: this needs to be changed: here image is always loaded if not + * already there. Very expensive for large images. Need to find a way to + * only get existing ibuf */ + ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); + if (ibuf == NULL || ibuf->rect == NULL) { + BKE_image_release_ibuf(ima, ibuf, NULL); + return; + } - br->icon_imbuf = get_brush_icon(br); + icon_copy_rect(ibuf, sp->sizex, sp->sizey, sp->pr_rect); - memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int)); + *do_update = true; - if (!(br->icon_imbuf) || !(br->icon_imbuf->rect)) - return; + BKE_image_release_ibuf(ima, ibuf, NULL); + } + else if (idtype == ID_BR) { + Brush *br = (Brush *)id; - icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect); + br->icon_imbuf = get_brush_icon(br); - *do_update = true; - } - else { - /* re-use shader job */ - shader_preview_startjob(customdata, stop, do_update); + memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int)); + + if (!(br->icon_imbuf) || !(br->icon_imbuf->rect)) + return; - /* world is rendered with alpha=0, so it wasn't displayed - * this could be render option for sky to, for later */ - if (idtype == ID_WO) { - set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255); + icon_copy_rect(br->icon_imbuf, sp->sizex, sp->sizey, sp->pr_rect); + + *do_update = true; } - else if (idtype == ID_MA) { - Material *ma = (Material *)id; + else { + /* re-use shader job */ + shader_preview_startjob(customdata, stop, do_update); - if (ma->material_type == MA_TYPE_HALO) + /* world is rendered with alpha=0, so it wasn't displayed + * this could be render option for sky to, for later */ + if (idtype == ID_WO) { set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255); + } + else if (idtype == ID_MA) { + Material *ma = (Material *)id; + + if (ma->material_type == MA_TYPE_HALO) + set_alpha((char *)sp->pr_rect, sp->sizex, sp->sizey, 255); + } } } } @@ -997,7 +1045,7 @@ static void common_preview_startjob(void *customdata, short *stop, short *do_upd { ShaderPreview *sp = customdata; - if (sp->pr_method == PR_ICON_RENDER) + if (ELEM(sp->pr_method, PR_ICON_RENDER, PR_ICON_DEFERRED)) icon_preview_startjob(customdata, stop, do_update); else shader_preview_startjob(customdata, stop, do_update); @@ -1033,29 +1081,35 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short const bool use_new_shading = BKE_scene_use_new_shading_nodes(ip->scene); while (cur_size) { + PreviewImage *prv = ip->owner; ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview"); + const bool is_render = !prv->use_deferred; /* construct shader preview from image size and previewcustomdata */ sp->scene = ip->scene; sp->owner = ip->owner; sp->sizex = cur_size->sizex; sp->sizey = cur_size->sizey; - sp->pr_method = PR_ICON_RENDER; + sp->pr_method = is_render ? PR_ICON_RENDER : PR_ICON_DEFERRED; sp->pr_rect = cur_size->rect; sp->id = ip->id; - - if (use_new_shading) { - /* texture icon rendering is hardcoded to use BI, - * so don't even think of using cycle's bmain for - * texture icons - */ - if (GS(ip->id->name) != ID_TE) - sp->pr_main = G_pr_main_cycles; - else + sp->bmain = ip->bmain; + + if (is_render) { + BLI_assert(ip->id); + if (use_new_shading) { + /* texture icon rendering is hardcoded to use BI, + * so don't even think of using cycle's bmain for + * texture icons + */ + if (GS(ip->id->name) != ID_TE) + sp->pr_main = G_pr_main_cycles; + else + sp->pr_main = G_pr_main; + } + else { sp->pr_main = G_pr_main; - } - else { - sp->pr_main = G_pr_main; + } } common_preview_startjob(sp, stop, do_update, progress); @@ -1100,11 +1154,35 @@ static void icon_preview_free(void *customdata) MEM_freeN(ip); } +void ED_preview_icon_render(Main *bmain, Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey) +{ + IconPreview ip = {NULL}; + short stop = false, update = false; + float progress = 0.0f; + + ED_preview_ensure_dbase(); + + ip.bmain = bmain; + ip.scene = scene; + ip.owner = id; + ip.id = id; + + icon_preview_add_size(&ip, rect, sizex, sizey); + + icon_preview_startjob_all_sizes(&ip, &stop, &update, &progress); + + icon_preview_endjob(&ip); + + BLI_freelistN(&ip.sizes); +} + void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey) { wmJob *wm_job; IconPreview *ip, *old_ip; - + + ED_preview_ensure_dbase(); + /* suspended start means it starts after 1 timer step, see WM_jobs_timer below */ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Icon Preview", WM_JOB_EXCL_RENDER | WM_JOB_SUSPEND, WM_JOB_TYPE_RENDER_PREVIEW); @@ -1117,8 +1195,9 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r BLI_movelisttolist(&ip->sizes, &old_ip->sizes); /* customdata for preview thread */ + ip->bmain = CTX_data_main(C); ip->scene = CTX_data_scene(C); - ip->owner = id; + ip->owner = owner; ip->id = id; icon_preview_add_size(ip, rect, sizex, sizey); @@ -1145,6 +1224,8 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M return; } + ED_preview_ensure_dbase(); + wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Shader Preview", WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); sp = MEM_callocN(sizeof(ShaderPreview), "shader preview"); @@ -1158,6 +1239,7 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M sp->id = id; sp->parent = parent; sp->slot = slot; + sp->bmain = CTX_data_main(C); /* hardcoded preview .blend for cycles/internal, this should be solved * once with custom preview .blend path for external engines */ @@ -1179,12 +1261,11 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M WM_jobs_start(CTX_wm_manager(C), wm_job); } -void ED_preview_kill_jobs(const struct bContext *C) +void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain) { - wmWindowManager *wm = CTX_wm_manager(C); if (wm) WM_jobs_kill(wm, NULL, common_preview_startjob); - - ED_viewport_render_kill_jobs(C, false); + + ED_viewport_render_kill_jobs(wm, bmain, false); } diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 72b4da64c3e..2e07e19e366 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -41,40 +41,39 @@ #include "DNA_space_types.h" #include "DNA_world_types.h" -#include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_listbase.h" +#include "BLI_math_vector.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" #include "BKE_font.h" -#include "BKE_freestyle.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_library.h" #include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_paint.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_texture.h" #include "BKE_world.h" #include "BKE_editmesh.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" -#include "GPU_material.h" #ifdef WITH_FREESTYLE +# include "BKE_freestyle.h" # include "FRS_freestyle.h" +# include "RNA_enum_types.h" #endif #include "RNA_access.h" -#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" @@ -102,8 +101,15 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op)) if (!ob) return OPERATOR_CANCELLED; - + object_add_material_slot(ob); + + if (ob->mode & OB_MODE_TEXTURE_PAINT) { + Scene *scene = CTX_data_scene(C); + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); + } + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob); WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_PREVIEW, ob); @@ -138,8 +144,15 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "Unable to remove material slot in edit mode"); return OPERATOR_CANCELLED; } - + object_remove_material_slot(ob); + + if (ob->mode & OB_MODE_TEXTURE_PAINT) { + Scene *scene = CTX_data_scene(C); + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); + } + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob); @@ -188,9 +201,11 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op)) ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data); if (nurbs) { - for (nu = nurbs->first; nu; nu = nu->next) - if (isNurbsel(nu)) - nu->mat_nr = nu->charidx = ob->actcol - 1; + for (nu = nurbs->first; nu; nu = nu->next) { + if (ED_curve_nurb_select_check(ob->data, nu)) { + nu->mat_nr = ob->actcol - 1; + } + } } } else if (ob->type == OB_FONT) { @@ -369,6 +384,74 @@ void OBJECT_OT_material_slot_copy(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } +static int material_slot_move_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_context(C); + + unsigned int *slot_remap; + int index_pair[2]; + + int dir = RNA_enum_get(op->ptr, "direction"); + + if (!ob || ob->totcol < 2) { + return OPERATOR_CANCELLED; + } + + /* up */ + if (dir == 1 && ob->actcol > 1) { + index_pair[0] = ob->actcol - 2; + index_pair[1] = ob->actcol - 1; + ob->actcol--; + } + /* down */ + else if (dir == -1 && ob->actcol < ob->totcol) { + index_pair[0] = ob->actcol - 1; + index_pair[1] = ob->actcol - 0; + ob->actcol++; + } + else { + return OPERATOR_CANCELLED; + } + + slot_remap = MEM_mallocN(sizeof(unsigned int) * ob->totcol, __func__); + + range_vn_u(slot_remap, ob->totcol, 0); + + slot_remap[index_pair[0]] = index_pair[1]; + slot_remap[index_pair[1]] = index_pair[0]; + + BKE_material_remap_object(ob, slot_remap); + + MEM_freeN(slot_remap); + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | ND_DATA, ob); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_material_slot_move(wmOperatorType *ot) +{ + static EnumPropertyItem material_slot_move[] = { + {1, "UP", 0, "Up", ""}, + {-1, "DOWN", 0, "Down", ""}, + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name = "Move Material"; + ot->idname = "OBJECT_OT_material_slot_move"; + ot->description = "Move the active material up/down in the list"; + + /* api callbacks */ + ot->exec = material_slot_move_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "direction", material_slot_move, 0, "Direction", "Direction to move, UP or DOWN"); +} + /********************** new material operator *********************/ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) @@ -393,11 +476,11 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) } /* hook into UI */ - uiIDContextProperty(C, &ptr, &prop); + UI_context_active_but_prop_get_templateID(C, &ptr, &prop); if (prop) { /* when creating new ID blocks, use is already 1, but RNA - * pointer se also increases user, so this compensates it */ + * pointer use also increases user, so this compensates it */ ma->id.us--; RNA_id_pointer_create(&ma->id, &idptr); @@ -438,11 +521,11 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) tex = BKE_texture_copy(tex); } else { - tex = add_texture(bmain, DATA_("Texture")); + tex = BKE_texture_add(bmain, DATA_("Texture")); } /* hook into UI */ - uiIDContextProperty(C, &ptr, &prop); + UI_context_active_but_prop_get_templateID(C, &ptr, &prop); if (prop) { /* when creating new ID blocks, use is already 1, but RNA @@ -505,7 +588,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) } /* hook into UI */ - uiIDContextProperty(C, &ptr, &prop); + UI_context_active_but_prop_get_templateID(C, &ptr, &prop); if (prop) { /* when creating new ID blocks, use is already 1, but RNA @@ -543,7 +626,7 @@ static int render_layer_add_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); BKE_scene_add_render_layer(scene, NULL); - scene->r.actlay = BLI_countlist(&scene->r.layers) - 1; + scene->r.actlay = BLI_listbase_count(&scene->r.layers) - 1; DAG_id_tag_update(&scene->id, 0); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); @@ -593,6 +676,70 @@ void SCENE_OT_render_layer_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } +/********************** render view operators *********************/ + +static int render_view_remove_poll(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + + /* don't allow user to remove "left" and "right" views */ + return scene->r.actview > 1; +} + +static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + + BKE_scene_add_render_view(scene, NULL); + scene->r.actview = BLI_listbase_count(&scene->r.views) - 1; + + WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); + + return OPERATOR_FINISHED; +} + +void SCENE_OT_render_view_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Render View"; + ot->idname = "SCENE_OT_render_view_add"; + ot->description = "Add a render view"; + + /* api callbacks */ + ot->exec = render_view_add_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview); + + if (!BKE_scene_remove_render_view(scene, rv)) + return OPERATOR_CANCELLED; + + WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); + + return OPERATOR_FINISHED; +} + +void SCENE_OT_render_view_remove(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Render View"; + ot->idname = "SCENE_OT_render_view_remove"; + ot->description = "Remove the selected render view"; + + /* api callbacks */ + ot->exec = render_view_remove_exec; + ot->poll = render_view_remove_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + #ifdef WITH_FREESTYLE static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportList *reports) @@ -719,10 +866,11 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot) static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay); - BKE_freestyle_lineset_add(&srl->freestyleConfig, NULL); + BKE_freestyle_lineset_add(bmain, &srl->freestyleConfig, NULL); DAG_id_tag_update(&scene->id, 0); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); @@ -881,6 +1029,7 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot) static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay); FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&srl->freestyleConfig); @@ -891,10 +1040,10 @@ static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op) } if (lineset->linestyle) { lineset->linestyle->id.us--; - lineset->linestyle = BKE_linestyle_copy(lineset->linestyle); + lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle); } else { - lineset->linestyle = BKE_linestyle_new("LineStyle", NULL); + lineset->linestyle = BKE_linestyle_new(bmain, "LineStyle"); } DAG_id_tag_update(&lineset->linestyle->id, 0); WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle); @@ -1374,11 +1523,15 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot) static int save_envmap(wmOperator *op, Scene *scene, EnvMap *env, char *path, const char imtype) { + PropertyRNA *prop; float layout[12]; - if (RNA_struct_find_property(op->ptr, "layout") ) - RNA_float_get_array(op->ptr, "layout", layout); - else + + if ((prop = RNA_struct_find_property(op->ptr, "layout"))) { + RNA_property_float_get_array(op->ptr, prop, layout); + } + else { memcpy(layout, default_envmap_layout, sizeof(layout)); + } if (RE_WriteEnvmapResult(op->reports, scene, env, path, imtype, layout)) { return OPERATOR_FINISHED; @@ -1400,7 +1553,7 @@ static int envmap_save_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", path); if (scene->r.scemode & R_EXTENSION) { - BKE_add_image_extension(path, &scene->r.im_format); + BKE_image_path_ensure_ext_from_imformat(path, &scene->r.im_format); } WM_cursor_wait(1); @@ -1466,15 +1619,15 @@ void TEXTURE_OT_envmap_save(wmOperatorType *ot) "(use -1 to skip a face)", 0.0f, 0.0f); RNA_def_property_flag(prop, PROP_HIDDEN); - WM_operator_properties_filesel(ot, FOLDERFILE | IMAGEFILE | MOVIEFILE, FILE_SPECIAL, FILE_SAVE, - WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE, + WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); } static int envmap_clear_exec(bContext *C, wmOperator *UNUSED(op)) { Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; - BKE_free_envmapdata(tex->env); + BKE_texture_envmap_free_data(tex->env); WM_event_add_notifier(C, NC_TEXTURE | NA_EDITED, tex); @@ -1517,7 +1670,7 @@ static int envmap_clear_all_exec(bContext *C, wmOperator *UNUSED(op)) for (tex = bmain->tex.first; tex; tex = tex->id.next) if (tex->env) - BKE_free_envmapdata(tex->env); + BKE_texture_envmap_free_data(tex->env); WM_event_add_notifier(C, NC_TEXTURE | NA_EDITED, tex); diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 6b58d3d55aa..f11a8177bf8 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -41,17 +41,18 @@ #include "DNA_world_types.h" #include "DNA_windowmanager_types.h" +#include "BLI_listbase.h" #include "BLI_threads.h" #include "BLI_utildefines.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_icons.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" #include "BKE_paint.h" +#include "BKE_scene.h" #include "GPU_material.h" #include "GPU_buffers.h" @@ -61,6 +62,7 @@ #include "ED_node.h" #include "ED_render.h" +#include "ED_view3d.h" #include "render_intern.h" // own include @@ -85,7 +87,11 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated) /* don't call this recursively for frame updates */ if (recursive_check) return; - + + /* Do not call if no WM available, see T42688. */ + if (BLI_listbase_is_empty(&bmain->wm)) + return; + recursive_check = true; C = CTX_create(); @@ -137,26 +143,36 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated) recursive_check = false; } -void ED_render_engine_area_exit(ScrArea *sa) +void ED_render_scene_update_pre(Main *bmain, Scene *scene, bool time) +{ + /* Blender internal might access to the data which is gonna to be freed + * by the scene update functions. This applies for example to simulation + * data like smoke and fire. + */ + if (time && !BKE_scene_use_new_shading_nodes(scene)) { + bScreen *sc; + ScrArea *sa; + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + for (sa = sc->areabase.first; sa; sa = sa->next) { + ED_render_engine_area_exit(bmain, sa); + } + } + } +} + +void ED_render_engine_area_exit(Main *bmain, ScrArea *sa) { /* clear all render engines in this area */ ARegion *ar; + wmWindowManager *wm = bmain->wm.first; if (sa->spacetype != SPACE_VIEW3D) return; for (ar = sa->regionbase.first; ar; ar = ar->next) { - RegionView3D *rv3d; - if (ar->regiontype != RGN_TYPE_WINDOW || !(ar->regiondata)) continue; - - rv3d = ar->regiondata; - - if (rv3d->render_engine) { - RE_engine_free(rv3d->render_engine); - rv3d->render_engine = NULL; - } + ED_view3d_stop_render_preview(wm, ar); } } @@ -166,23 +182,15 @@ void ED_render_engine_changed(Main *bmain) bScreen *sc; ScrArea *sa; Scene *scene; - Material *ma; for (sc = bmain->screen.first; sc; sc = sc->id.next) for (sa = sc->areabase.first; sa; sa = sa->next) - ED_render_engine_area_exit(sa); + ED_render_engine_area_exit(bmain, sa); RE_FreePersistentData(); for (scene = bmain->scene.first; scene; scene = scene->id.next) ED_render_id_flush_update(bmain, &scene->id); - - /* reset texture painting. Sending one dependency graph signal for any material should - * refresh any texture slots */ - ma = bmain->mat.first; - if (ma) { - DAG_id_tag_update(&ma->id, 0); - } } /***************************** Updates *********************************** @@ -280,11 +288,11 @@ static void material_changed(Main *bmain, Material *ma) int texture_draw = false; /* icons */ - BKE_icon_changed(BKE_icon_getid(&ma->id)); + BKE_icon_changed(BKE_icon_id_ensure(&ma->id)); /* glsl */ if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); /* find node materials using this */ for (parent = bmain->mat.first; parent; parent = parent->id.next) { @@ -295,10 +303,10 @@ static void material_changed(Main *bmain, Material *ma) continue; } - BKE_icon_changed(BKE_icon_getid(&parent->id)); + BKE_icon_changed(BKE_icon_id_ensure(&parent->id)); if (parent->gpumaterial.first) - GPU_material_free(parent); + GPU_material_free(&parent->gpumaterial); } /* find if we have a scene with textured display */ @@ -310,7 +318,7 @@ static void material_changed(Main *bmain, Material *ma) } /* find textured objects */ - if (texture_draw && !(U.gameflags & USER_DISABLE_VBO)) { + if (texture_draw) { for (ob = bmain->object.first; ob; ob = ob->id.next) { DerivedMesh *dm = ob->derivedFinal; Material ***material = give_matarar(ob); @@ -335,7 +343,7 @@ static void lamp_changed(Main *bmain, Lamp *la) Material *ma; /* icons */ - BKE_icon_changed(BKE_icon_getid(&la->id)); + BKE_icon_changed(BKE_icon_id_ensure(&la->id)); /* glsl */ for (ob = bmain->object.first; ob; ob = ob->id.next) @@ -344,10 +352,10 @@ static void lamp_changed(Main *bmain, Lamp *la) for (ma = bmain->mat.first; ma; ma = ma->id.next) if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); if (defmaterial.gpumaterial.first) - GPU_material_free(&defmaterial); + GPU_material_free(&defmaterial.gpumaterial); } static int material_uses_texture(Material *ma, Tex *tex) @@ -371,7 +379,7 @@ static void texture_changed(Main *bmain, Tex *tex) bool texture_draw = false; /* icons */ - BKE_icon_changed(BKE_icon_getid(&tex->id)); + BKE_icon_changed(BKE_icon_id_ensure(&tex->id)); /* paint overlays */ for (scene = bmain->scene.first; scene; scene = scene->id.next) @@ -382,10 +390,10 @@ static void texture_changed(Main *bmain, Tex *tex) if (!material_uses_texture(ma, tex)) continue; - BKE_icon_changed(BKE_icon_getid(&ma->id)); + BKE_icon_changed(BKE_icon_id_ensure(&ma->id)); if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); } /* find lamps */ @@ -413,7 +421,10 @@ static void texture_changed(Main *bmain, Tex *tex) continue; } - BKE_icon_changed(BKE_icon_getid(&wo->id)); + BKE_icon_changed(BKE_icon_id_ensure(&wo->id)); + + if (wo->gpumaterial.first) + GPU_material_free(&wo->gpumaterial); } /* find compositing nodes */ @@ -430,7 +441,7 @@ static void texture_changed(Main *bmain, Tex *tex) } /* find textured objects */ - if (texture_draw && !(U.gameflags & USER_DISABLE_VBO)) { + if (texture_draw) { for (ob = bmain->object.first; ob; ob = ob->id.next) { DerivedMesh *dm = ob->derivedFinal; Material ***material = give_matarar(ob); @@ -458,15 +469,18 @@ static void world_changed(Main *bmain, World *wo) Material *ma; /* icons */ - BKE_icon_changed(BKE_icon_getid(&wo->id)); - + BKE_icon_changed(BKE_icon_id_ensure(&wo->id)); + /* glsl */ for (ma = bmain->mat.first; ma; ma = ma->id.next) if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); if (defmaterial.gpumaterial.first) - GPU_material_free(&defmaterial); + GPU_material_free(&defmaterial.gpumaterial); + + if (wo->gpumaterial.first) + GPU_material_free(&wo->gpumaterial); } static void image_changed(Main *bmain, Image *ima) @@ -474,7 +488,7 @@ static void image_changed(Main *bmain, Image *ima) Tex *tex; /* icons */ - BKE_icon_changed(BKE_icon_getid(&ima->id)); + BKE_icon_changed(BKE_icon_id_ensure(&ima->id)); /* textures */ for (tex = bmain->tex.first; tex; tex = tex->id.next) @@ -482,22 +496,34 @@ static void image_changed(Main *bmain, Image *ima) texture_changed(bmain, tex); } -static void scene_changed(Main *bmain, Scene *UNUSED(scene)) +static void scene_changed(Main *bmain, Scene *scene) { Object *ob; Material *ma; + World *wo; /* glsl */ - for (ob = bmain->object.first; ob; ob = ob->id.next) + for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->gpulamp.first) GPU_lamp_free(ob); + + if (ob->mode & OB_MODE_TEXTURE_PAINT) { + BKE_texpaint_slots_refresh_object(scene, ob); + BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + GPU_drawobject_free(ob->derivedFinal); + } + } for (ma = bmain->mat.first; ma; ma = ma->id.next) if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); + for (wo = bmain->world.first; wo; wo = wo->id.next) + if (wo->gpumaterial.first) + GPU_material_free(&wo->gpumaterial); + if (defmaterial.gpumaterial.first) - GPU_material_free(&defmaterial); + GPU_material_free(&defmaterial.gpumaterial); } void ED_render_id_flush_update(Main *bmain, ID *id) @@ -539,7 +565,7 @@ void ED_render_id_flush_update(Main *bmain, ID *id) void ED_render_internal_init(void) { - RenderEngineType *ret = RE_engines_find("BLENDER_RENDER"); + RenderEngineType *ret = RE_engines_find(RE_engine_id_BLENDER_RENDER); ret->view_update = render_view3d_update; ret->view_draw = render_view3d_draw; diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c index 0beb5737ec7..f6690296890 100644 --- a/source/blender/editors/render/render_view.c +++ b/source/blender/editors/render/render_view.c @@ -63,7 +63,7 @@ static ScrArea *biggest_non_image_area(bContext *C) for (sa = sc->areabase.first; sa; sa = sa->next) { if (sa->winx > 30 && sa->winy > 30) { size = sa->winx * sa->winy; - if (sa->spacetype == SPACE_BUTS) { + if (!sa->full && sa->spacetype == SPACE_BUTS) { if (foundwin == 0 && size > bwmaxsize) { bwmaxsize = size; big = sa; @@ -161,11 +161,19 @@ ScrArea *render_view_open(bContext *C, int mx, int my) } else if (scene->r.displaymode == R_OUTPUT_SCREEN) { sa = CTX_wm_area(C); - if (sa && sa->spacetype == SPACE_IMAGE) - area_was_image = true; - /* this function returns with changed context */ - sa = ED_screen_full_newspace(C, sa, SPACE_IMAGE); + /* if the active screen is already in fullscreen mode, skip this and + * unset the area, so that the fullscreen area is just changed later */ + if (sa && sa->full) { + sa = NULL; + } + else { + if (sa && sa->spacetype == SPACE_IMAGE) + area_was_image = true; + + /* this function returns with changed context */ + sa = ED_screen_full_newspace(C, sa, SPACE_IMAGE); + } } if (!sa) { @@ -186,10 +194,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my) /* makes ESC go back to prev space */ sima->flag |= SI_PREVSPACE; + + /* we already had a fullscreen here -> mark new space as a stacked fullscreen */ + if (sa->full) { + sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE); + } } else { /* use any area of decent size */ - sa = BKE_screen_find_big_area(CTX_wm_screen(C), -1, 0); + sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0); if (sa->spacetype != SPACE_IMAGE) { // XXX newspace(sa, SPACE_IMAGE); sima = sa->spacedata.first; @@ -232,6 +245,11 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op)) ScrArea *sa = CTX_wm_area(C); SpaceImage *sima = sa->spacedata.first; + /* ensure image editor fullscreen and area fullscreen states are in sync */ + if ((sima->flag & SI_FULLWINDOW) && !sa->full) { + sima->flag &= ~SI_FULLWINDOW; + } + /* test if we have a temp screen in front */ if (win->screen->temp) { wm_window_lower(win); @@ -243,16 +261,17 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op)) if (sima->flag & SI_FULLWINDOW) { sima->flag &= ~SI_FULLWINDOW; - ED_screen_full_prevspace(C, sa); + ED_screen_full_prevspace(C, sa, false); } - else + else { ED_area_prevspace(C, sa); + } return OPERATOR_FINISHED; } else if (sima->flag & SI_FULLWINDOW) { sima->flag &= ~SI_FULLWINDOW; - ED_screen_full_toggle(C, win, sa); + ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED); return OPERATOR_FINISHED; } @@ -307,7 +326,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), const wm if (sima->flag & SI_FULLWINDOW) { sima->flag &= ~SI_FULLWINDOW; - ED_screen_full_prevspace(C, sa); + ED_screen_full_prevspace(C, sa, false); } else if (sima->next) { /* workaround for case of double prevspace, render window |