diff options
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/include/ED_render.h | 4 | ||||
-rw-r--r-- | source/blender/editors/render/render_intern.h | 2 | ||||
-rw-r--r-- | source/blender/editors/render/render_internal.c | 362 | ||||
-rw-r--r-- | source/blender/editors/render/render_preview.c | 1 | ||||
-rw-r--r-- | source/blender/editors/render/render_update.c | 40 | ||||
-rw-r--r-- | source/blender/editors/space_api/spacetypes.c | 2 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_view.c | 3 |
7 files changed, 411 insertions, 3 deletions
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index 39e2c28a61a..c1ddd9a6294 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -38,6 +38,8 @@ struct Render; struct RenderInfo; struct Scene; struct ScrArea; +struct RegionView3D; +struct RenderEngine; /* render_ops.c */ @@ -85,4 +87,6 @@ void ED_preview_draw(const struct bContext *C, void *idp, void *parentp, void *s void ED_render_clear_mtex_copybuf(void); +void ED_render_internal_init(void); + #endif diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h index 88c00601933..edd61bfc5c3 100644 --- a/source/blender/editors/render/render_intern.h +++ b/source/blender/editors/render/render_intern.h @@ -83,6 +83,8 @@ void TEXTURE_OT_envmap_clear_all(struct wmOperatorType *ot); /* render_internal.c */ void RENDER_OT_render(struct wmOperatorType *ot); +void render_view3d(struct RenderEngine *engine, const struct bContext *C); +void render_view3d_draw(struct RenderEngine *engine, const struct bContext *C); /* render_opengl.c uses this */ void image_buffer_rect_update(struct Scene *scene, struct RenderResult *rr, struct ImBuf *ibuf, volatile struct rcti *renrect); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 6832cd5baa0..f599fa1bde8 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -42,9 +42,11 @@ #include "BLF_translation.h" #include "DNA_scene_types.h" +#include "DNA_view3d_types.h" #include "BKE_blender.h" #include "BKE_context.h" +#include "BKE_freestyle.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_library.h" @@ -59,14 +61,23 @@ #include "WM_api.h" #include "WM_types.h" -#include "ED_screen.h" #include "ED_object.h" +#include "ED_render.h" +#include "ED_screen.h" +#include "ED_view3d.h" #include "RE_pipeline.h" +#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" + #include "RNA_access.h" #include "RNA_define.h" @@ -681,3 +692,352 @@ void RENDER_OT_render(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } + +/* ************** preview for 3d viewport ***************** */ + +#define PR_UPDATE_VIEW 1 +#define PR_UPDATE_RENDERSIZE 2 +#define PR_UPDATE_MATERIAL 4 + +typedef struct RenderPreview { + /* from wmJob */ + void *owner; + short *stop, *do_update; + + Scene *scene; + ScrArea *sa; + ARegion *ar; + View3D *v3d; + RegionView3D *rv3d; + Main *bmain; + RenderEngine *engine; + + int keep_data; +} RenderPreview; + +static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect) +{ + /* copied code from view3d_draw.c */ + rctf viewborder; + int draw_border; + + if (rv3d->persp == RV3D_CAMOB) + draw_border = (scene->r.mode & R_BORDER) != 0; + else + draw_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0; + + if (draw_border) { + if (rv3d->persp == RV3D_CAMOB) { + ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); + + disprect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder); + disprect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder); + disprect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder); + disprect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder); + } + else { + disprect->xmin = v3d->render_border.xmin * ar->winx; + disprect->xmax = v3d->render_border.xmax * ar->winx; + disprect->ymin = v3d->render_border.ymin * ar->winy; + disprect->ymax = v3d->render_border.ymax * ar->winy; + } + + return 1; + } + + BLI_rcti_init(disprect, 0, 0, 0, 0); + return 0; +} + +/* returns 1 if OK */ +static int render_view3d_get_rects(ARegion *ar, View3D *v3d, RegionView3D *rv3d, rctf *viewplane, RenderEngine *engine, float *clipsta, float *clipend, int *ortho) +{ + + if (ar->winx < 4 || ar->winy < 4) return 0; + + *ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, viewplane, clipsta, clipend); + + engine->resolution_x = ar->winx; + engine->resolution_y = ar->winy; + + return 1; +} + +/* called by renderer, checks job value */ +static int render_view3d_break(void *rpv) +{ + RenderPreview *rp = rpv; + + if (G.is_break) + return 1; + + /* during render, rv3d->engine can get freed */ + if (rp->rv3d->render_engine == NULL) + *rp->stop = 1; + + return *(rp->stop); +} + +static void render_view3d_draw_update(void *rpv, RenderResult *UNUSED(rr), volatile struct rcti *UNUSED(rect)) +{ + RenderPreview *rp = rpv; + + *(rp->do_update) = TRUE; +} + +static void render_view3d_renderinfo_cb(void *rjp, RenderStats *rs) +{ + RenderPreview *rp = rjp; + + /* during render, rv3d->engine can get freed */ + if (rp->rv3d->render_engine == NULL) + *rp->stop = 1; + else if (rp->engine->text) { + make_renderinfo_string(rs, rp->scene, rp->engine->text); + + /* make jobs timer to send notifier */ + *(rp->do_update) = TRUE; + } +} + + +static void render_view3d_startjob(void *customdata, short *stop, short *do_update, float *UNUSED(progress)) +{ + RenderPreview *rp = customdata; + Render *re; + RenderStats *rstats; + RenderData rdata; + rctf viewplane; + rcti cliprct; + float clipsta, clipend; + int orth, restore = 0; + char name[32]; + + G.is_break = FALSE; + + if (0 == render_view3d_get_rects(rp->ar, rp->v3d, rp->rv3d, &viewplane, rp->engine, &clipsta, &clipend, &orth)) + return; + + rp->stop = stop; + rp->do_update = do_update; + +// printf("Enter previewrender\n"); + + /* ok, are we rendering all over? */ + sprintf(name, "View3dPreview %p", (void *)rp->ar); + re= rp->engine->re = RE_GetRender(name); + + if (rp->engine->re == NULL) { + + re = rp->engine->re= RE_NewRender(name); + + rp->keep_data = 0; + } + + /* set this always, rp is different for each job */ + RE_test_break_cb(re, rp, render_view3d_break); + RE_display_draw_cb(re, rp, render_view3d_draw_update); + RE_stats_draw_cb(re, rp, render_view3d_renderinfo_cb); + + rstats= RE_GetStats(re); + + if (rp->keep_data == 0 || rstats->convertdone == 0 || (rp->keep_data & PR_UPDATE_RENDERSIZE)) { + /* no osa, blur, seq, layers, 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_PREVIEWBUTS; + + /* we do use layers, but only active */ + rdata.scemode |= R_SINGLE_LAYER; + + /* initalize always */ + if (render_view3d_disprect(rp->scene, rp->ar, rp->v3d, rp->rv3d, &cliprct)) { + rdata.mode |= R_BORDER; + RE_InitState(re, NULL, &rdata, NULL, rp->sa->winx, rp->sa->winy, &cliprct); + } + else + RE_InitState(re, NULL, &rdata, NULL, rp->sa->winx, rp->sa->winy, NULL); + } + + if (orth) + RE_SetOrtho(re, &viewplane, clipsta, clipend); + else + RE_SetWindow(re, &viewplane, clipsta, clipend); + + /* database free can crash on a empty Render... */ + if (rp->keep_data == 0 && rstats->convertdone) + RE_Database_Free(re); + + if (rstats->convertdone == 0) { + unsigned int lay = rp->scene->lay; + + /* allow localview render for objects with lights in normal layers */ + if (rp->v3d->lay & 0xFF000000) + lay |= rp->v3d->lay; + else lay = rp->v3d->lay; + + RE_SetView(re, rp->rv3d->viewmat); + + RE_Database_FromScene(re, rp->bmain, rp->scene, lay, 0); // 0= dont use camera view +// printf("dbase update\n"); + } + else { +// printf("dbase rotate\n"); + RE_DataBase_IncrementalView(re, rp->rv3d->viewmat, 0); + restore = 1; + } + + RE_DataBase_ApplyWindow(re); + + /* OK, can we enter render code? */ + if (rstats->convertdone) { + RE_TileProcessor(re); +// printf("tile processor\n"); + + if (restore) + RE_DataBase_IncrementalView(re, rp->rv3d->viewmat, 1); + + rp->engine->flag &= ~RE_ENGINE_DO_UPDATE; + } + +// printf("done\n\n"); +} + +static void render_view3d_free(void *customdata) +{ + RenderPreview *rp = customdata; + + MEM_freeN(rp); +} + +static void render_view3d_do(RenderEngine *engine, const bContext *C, int keep_data) +{ + wmJob *wm_job; + RenderPreview *rp; + Scene *scene = CTX_data_scene(C); + + if (CTX_wm_window(C) == NULL) { + engine->flag |= RE_ENGINE_DO_UPDATE; + + return; + } + + wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_region(C), "Render Preview", + WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); + rp = MEM_callocN(sizeof(RenderPreview), "render preview"); + + /* customdata for preview thread */ + rp->scene = scene; + rp->engine = engine; + rp->sa = CTX_wm_area(C); + rp->ar = CTX_wm_region(C); + rp->v3d = rp->sa->spacedata.first; + rp->rv3d = CTX_wm_region_view3d(C); + rp->bmain = CTX_data_main(C); + rp->keep_data = keep_data; + + /* dont alloc in threads */ + if (engine->text == NULL) + engine->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext"); + + /* setup job */ + WM_jobs_customdata_set(wm_job, rp, render_view3d_free); + WM_jobs_timer(wm_job, 0.1, NC_SPACE|ND_SPACE_VIEW3D, NC_SPACE|ND_SPACE_VIEW3D); + WM_jobs_callbacks(wm_job, render_view3d_startjob, NULL, NULL, NULL); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + + engine->flag &= ~RE_ENGINE_DO_UPDATE; + +} + +/* callback for render engine , on changes */ +void render_view3d(RenderEngine *engine, const bContext *C) +{ + render_view3d_do(engine, C, 0); +} + +static int render_view3d_changed(RenderEngine *engine, const bContext *C) +{ + ARegion *ar = CTX_wm_region(C); + Render *re; + int update = 0; + char name[32]; + + sprintf(name, "View3dPreview %p", (void *)ar); + re = RE_GetRender(name); + + if (re) { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); + rctf viewplane, viewplane1; + rcti disprect, disprect1; + float mat[4][4]; + float clipsta, clipend; + int orth; + + if (engine->update_flag == RE_ENGINE_UPDATE_MA) + update |= PR_UPDATE_MATERIAL; + engine->update_flag = 0; + + if (engine->resolution_x != ar->winx || engine->resolution_y != ar->winy) + update |= PR_UPDATE_RENDERSIZE; + + /* view updating fails on raytrace */ + RE_GetView(re, mat); + if (compare_m4m4(mat, rv3d->viewmat, 0.00001f) == 0) { + if ((scene->r.mode & R_RAYTRACE)==0) + update |= PR_UPDATE_VIEW; + else + engine->flag |= RE_ENGINE_DO_UPDATE; + } + + render_view3d_get_rects(ar, v3d, rv3d, &viewplane, engine, &clipsta, &clipend, &orth); + RE_GetViewPlane(re, &viewplane1, &disprect1); + + if (BLI_rctf_compare(&viewplane, &viewplane1, 0.00001f) == 0) + update |= PR_UPDATE_VIEW; + + render_view3d_disprect(scene, ar, v3d, rv3d, &disprect); + if (BLI_rcti_compare(&disprect, &disprect1) == 0) + update |= PR_UPDATE_RENDERSIZE; + + if (update) + engine->flag |= RE_ENGINE_DO_UPDATE; +// if (update) +// printf("changed ma %d res %d view %d\n", update & PR_UPDATE_MATERIAL, update & PR_UPDATE_RENDERSIZE, update & PR_UPDATE_VIEW); + + } + + return update; +} + +void render_view3d_draw(RenderEngine *engine, const bContext *C) +{ + Render *re = engine->re; + RenderResult rres; + int keep_data = render_view3d_changed(engine, C); + + if (engine->flag & RE_ENGINE_DO_UPDATE) + render_view3d_do(engine, C, keep_data); + + if (re == NULL) return; + + RE_AcquireResultImage(re, &rres); + RE_ReleaseResultImage(re); + + if (rres.rectf) { + unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"); + + RE_ResultGet32(re, (unsigned int *)rect_byte); + + glEnable(GL_BLEND); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glaDrawPixelsTex(rres.xof, rres.yof, rres.rectx, rres.recty, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, rect_byte); + glDisable(GL_BLEND); + + MEM_freeN(rect_byte); + } +} diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 0caf4a7351f..7ef84b9d6eb 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -93,7 +93,6 @@ #include "RE_pipeline.h" - #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index f19ea08f381..5653d14e590 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -116,6 +116,7 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated) engine = rv3d->render_engine; if (engine && (updated || (engine->flag & RE_ENGINE_DO_UPDATE))) { + CTX_wm_screen_set(C, sc); CTX_wm_area_set(C, sa); CTX_wm_region_set(C, ar); @@ -177,6 +178,32 @@ void ED_render_engine_changed(Main *bmain) * editor level updates when the ID changes. when these ID blocks are in * * the dependency graph, we can get rid of the manual dependency checks */ +static void render_engine_flag_changed(Main *bmain, int update_flag) +{ + bScreen *sc; + ScrArea *sa; + ARegion *ar; + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + for (sa = sc->areabase.first; sa; sa = sa->next) { + if (sa->spacetype != SPACE_VIEW3D) + continue; + + for (ar = sa->regionbase.first; ar; ar = ar->next) { + RegionView3D *rv3d; + + if (ar->regiontype != RGN_TYPE_WINDOW) + continue; + + rv3d = ar->regiondata; + if (rv3d->render_engine) + rv3d->render_engine->update_flag |= update_flag; + + } + } + } +} + static int mtex_use_tex(MTex **mtex, int tot, Tex *tex) { int a; @@ -472,6 +499,7 @@ void ED_render_id_flush_update(Main *bmain, ID *id) switch (GS(id->name)) { case ID_MA: material_changed(bmain, (Material *)id); + render_engine_flag_changed(bmain, RE_ENGINE_UPDATE_MA); break; case ID_TE: texture_changed(bmain, (Tex *)id); @@ -487,9 +515,21 @@ void ED_render_id_flush_update(Main *bmain, ID *id) break; case ID_SCE: scene_changed(bmain, (Scene *)id); + render_engine_flag_changed(bmain, RE_ENGINE_UPDATE_OTHER); break; default: + render_engine_flag_changed(bmain, RE_ENGINE_UPDATE_OTHER); break; } + } + +void ED_render_internal_init(void) +{ + RenderEngineType *ret = RE_engines_find("BLENDER_RENDER"); + + ret->view_update = render_view3d; + ret->view_draw = render_view3d_draw; + +} diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 35344f2c5a4..2739d41a73d 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -149,6 +149,8 @@ void ED_spacetypes_init(void) type->dropboxes(); } + /* register internal render callbacks */ + ED_render_internal_init(); } /* called in wm.c */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index b227d32d987..7552e09ebbd 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -199,7 +199,8 @@ void view3d_smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera sms.to_camera = true; /* restore view3d values in end */ } - if (C && U.smooth_viewtx) { + /* skip smooth viewing for render engine draw */ + if (C && U.smooth_viewtx && v3d->drawtype != OB_RENDER) { bool changed = false; /* zero means no difference */ if (oldcamera != camera) |