diff options
Diffstat (limited to 'source/blender/render')
53 files changed, 3063 insertions, 1614 deletions
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index 8e326e770fc..9e40ab02ee4 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -27,12 +27,14 @@ set(INC extern/include intern/include - ../blenfont ../blenkernel ../blenlib + ../blentranslation ../imbuf + ../depsgraph ../makesdna ../makesrna + ../physics ../../../intern/guardedalloc ../../../intern/mikktspace ../../../intern/smoke/extern @@ -162,6 +164,10 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() +if(WITH_CYCLES AND WITH_CYCLES_DEBUG) + add_definitions(-DWITH_CYCLES_DEBUG) +endif() + if(APPLE) # SSE math is enabled by default on x86_64 if(CMAKE_OSX_ARCHITECTURES MATCHES "i386") diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript index 297e4fcecd4..16d9b4a832d 100644 --- a/source/blender/render/SConscript +++ b/source/blender/render/SConscript @@ -34,13 +34,14 @@ incs = [ 'extern/include', 'intern/include', '#/intern/guardedalloc', - '../blenfont', '../blenkernel', '../blenlib', + '../blentranslation', '../imbuf', - '../include', + '../depsgraph', '../makesdna', '../makesrna', + '../physics', '../../../intern/mikktspace', '../../../intern/smoke/extern', ] @@ -103,6 +104,9 @@ if env['WITH_BF_GAMEENGINE']: if env['WITH_BF_INTERNATIONAL']: defs.append('WITH_INTERNATIONAL') +if env['WITH_BF_CYCLES'] and env['WITH_BF_CYCLES_DEBUG']: + defs.append('WITH_CYCLES_DEBUG') + if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): incs += ' ' + env['BF_PTHREADS_INC'] diff --git a/source/blender/render/extern/include/RE_bake.h b/source/blender/render/extern/include/RE_bake.h index 481da452529..0750ea1aa28 100644 --- a/source/blender/render/extern/include/RE_bake.h +++ b/source/blender/render/extern/include/RE_bake.h @@ -32,6 +32,7 @@ #ifndef __RE_BAKE_H__ #define __RE_BAKE_H__ +struct ImBuf; struct Render; struct Mesh; @@ -49,29 +50,28 @@ typedef struct BakeImages { } BakeImages; typedef struct BakePixel { - int primitive_id; + int primitive_id, object_id; float uv[2]; float du_dx, du_dy; float dv_dx, dv_dy; } BakePixel; typedef struct BakeHighPolyData { - struct BakePixel *pixel_array; struct Object *ob; struct ModifierData *tri_mod; struct Mesh *me; char restrict_flag; + bool is_flip_object; float obmat[4][4]; float imat[4][4]; - float rotmat[4][4]; } BakeHighPolyData; /* external_engine.c */ bool RE_bake_has_engine(struct Render *re); bool RE_bake_engine( - struct Render *re, struct Object *object, const BakePixel pixel_array[], + struct Render *re, struct Object *object, const int object_id, const BakePixel pixel_array[], const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]); /* bake.c */ @@ -81,7 +81,7 @@ bool RE_bake_internal( const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]); bool RE_bake_pixels_populate_from_objects( - struct Mesh *me_low, BakePixel pixel_array_from[], + struct Mesh *me_low, BakePixel pixel_array_from[], BakePixel pixel_array_to[], BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage, const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage); diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index 24f8cbee401..4e48060c54f 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -60,6 +60,8 @@ struct BakePixel; #define RE_USE_SHADING_NODES 16 #define RE_USE_EXCLUDE_LAYERS 32 #define RE_USE_SAVE_BUFFERS 64 +#define RE_USE_TEXTURE_PREVIEW 128 +#define RE_USE_SHADING_NODES_CUSTOM 256 /* RenderEngine.flag */ #define RE_ENGINE_ANIMATION 1 @@ -87,7 +89,7 @@ typedef struct RenderEngineType { void (*update)(struct RenderEngine *engine, struct Main *bmain, struct Scene *scene); void (*render)(struct RenderEngine *engine, struct Scene *scene); - void (*bake)(struct RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type, const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result); + void (*bake)(struct RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type, const int object_id, const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result); void (*view_update)(struct RenderEngine *engine, const struct bContext *context); void (*view_draw)(struct RenderEngine *engine, const struct bContext *context); @@ -134,15 +136,20 @@ void RE_engine_free(RenderEngine *engine); void RE_layer_load_from_file(struct RenderLayer *layer, struct ReportList *reports, const char *filename, int x, int y); void RE_result_load_from_file(struct RenderResult *result, struct ReportList *reports, const char *filename); -struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername); +struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname); void RE_engine_update_result(RenderEngine *engine, struct RenderResult *result); void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int merge_results); +void RE_engine_active_view_set(RenderEngine *engine, const char *viewname); +float RE_engine_get_camera_shift_x(RenderEngine *engine, struct Object *camera); +void RE_engine_get_camera_model_matrix(RenderEngine *engine, struct Object *camera, float *r_modelmat); + int RE_engine_test_break(RenderEngine *engine); void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info); void RE_engine_update_progress(RenderEngine *engine, float progress); void RE_engine_update_memory_stats(RenderEngine *engine, float mem_used, float mem_peak); void RE_engine_report(RenderEngine *engine, int type, const char *msg); +void RE_engine_set_error_message(RenderEngine *engine, const char *msg); int RE_engine_render(struct Render *re, int do_all); @@ -157,7 +164,7 @@ void RE_engines_exit(void); RenderEngineType *RE_engines_find(const char *idname); -void RE_engine_get_current_tiles(struct Render *re, int *total_tiles_r, rcti **tiles_r); +rcti* RE_engine_get_current_tiles(struct Render *re, int *r_total_tiles, bool *r_needs_free); struct RenderData *RE_engine_get_render_data(struct Render *re); void RE_bake_engine_set_engine_parameters(struct Render *re, struct Main *bmain, struct Scene *scene); diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 3b54de4c943..fd56c47c309 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -35,8 +35,10 @@ #include "DNA_listBase.h" #include "DNA_vec_types.h" +struct bMovieHandle; struct bNodeTree; struct Image; +struct ImageFormatData; struct Main; struct NodeBlurData; struct Object; @@ -46,6 +48,8 @@ struct ReportList; struct Scene; struct SceneRenderLayer; struct EnvMap; +struct RenderResult; +struct StampData; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* this include is what is exposed of render to outside world */ @@ -65,6 +69,19 @@ typedef struct Render Render; * and how it's converted */ +typedef struct RenderView { + struct RenderView *next, *prev; + char name[64]; /* EXR_VIEW_MAXNAME */ + + /* if this exists, result of composited layers */ + float *rectf; + /* if this exists, result of composited layers */ + float *rectz; + /* optional, 32 bits version of picture, used for sequencer, ogl render and image curves */ + int *rect32; + +} RenderView; + typedef struct RenderPass { struct RenderPass *next, *prev; int passtype, channels; @@ -72,11 +89,23 @@ typedef struct RenderPass { char chan_id[8]; /* amount defined in openexr_multi.h */ float *rect; int rectx, recty; + + char internal_name[64]; /* EXR_PASS_MAXNAME */ + char view[64]; /* EXR_VIEW_MAXNAME */ + int view_id; /* quick lookup */ + + int debug_type; } RenderPass; +enum { + RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS = 0, + RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES = 1, + RENDER_PASS_DEBUG_RAY_BOUNCES = 2, +}; + /* a renderlayer is a full image, but with all passes and samples */ /* size of the rects is defined in RenderResult */ -/* after render, the Combined pass is in rectf, for renderlayers read from files it is a real pass */ +/* after render, the Combined pass is in combined, for renderlayers read from files it is a real pass */ typedef struct RenderLayer { struct RenderLayer *next, *prev; @@ -87,8 +116,10 @@ typedef struct RenderLayer { struct Material *mat_override; struct Group *light_override; - - float *rectf; /* 4 float, standard rgba buffer (read not above!) */ + + /* MULTIVIEW_TODO: acolrect and scolrect are not supported by multiview at the moment. + * If they are really required they should be in RenderView instead */ + float *acolrect; /* 4 float, optional transparent buffer, needs storage for display updates */ float *scolrect; /* 4 float, optional strand buffer, needs storage for display updates */ int *display_buffer; /* 4 char, optional color managed display buffer which is used when @@ -109,6 +140,9 @@ typedef struct RenderResult { int rectx, recty; short crop, sample_nr; + /* the following rect32, rectf and rectz buffers are for temporary storage only, for RenderResult structs + * created in #RE_AcquireResultImage - which do not have RenderView */ + /* optional, 32 bits version of picture, used for ogl render and image curves */ int *rect32; /* if this exists, a copy of one of layers, or result of composited layers */ @@ -124,6 +158,9 @@ typedef struct RenderResult { /* the main buffers */ ListBase layers; + /* multiView maps to a StringVector in OpenEXR */ + ListBase views; + /* allowing live updates: */ volatile rcti renrect; volatile RenderLayer *renlay; @@ -139,7 +176,9 @@ typedef struct RenderResult { /* render info text */ char *text; - + char *error; + + struct StampData *stamp_data; } RenderResult; @@ -168,6 +207,10 @@ void RE_InitRenderCB(struct Render *re); void RE_FreeRender(struct Render *re); /* only called on exit */ void RE_FreeAllRender(void); +/* Free memory used by persistent data. + * Invoked when loading new file. + */ +void RE_FreeAllPersistentData(void); /* only call on file load */ void RE_FreeAllRenderResults(void); /* for external render engines that can keep persistent data */ @@ -178,16 +221,18 @@ void RE_FreeRenderResult(struct RenderResult *rr); struct RenderResult *RE_AcquireResultRead(struct Render *re); struct RenderResult *RE_AcquireResultWrite(struct Render *re); void RE_ReleaseResult(struct Render *re); -void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr); +void RE_AcquireResultImageViews(struct Render *re, struct RenderResult *rr); +void RE_ReleaseResultImageViews(struct Render *re, struct RenderResult *rr); +void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr, const int view_id); void RE_ReleaseResultImage(struct Render *re); void RE_SwapResult(struct Render *re, struct RenderResult **rr); struct RenderStats *RE_GetStats(struct Render *re); void RE_ResultGet32(struct Render *re, unsigned int *rect); -void RE_AcquiredResultGet32(struct Render *re, struct RenderResult *result, unsigned int *rect); +void RE_AcquiredResultGet32(struct Render *re, struct RenderResult *result, unsigned int *rect, const int view_id); struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name); -float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype); +float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname); /* obligatory initialize call, disprect is optional */ void RE_InitState(struct Render *re, struct Render *source, struct RenderData *rd, @@ -198,6 +243,7 @@ void RE_ChangeModeFlag(struct Render *re, int flag, bool clear); /* set up the viewplane/perspective matrix, three choices */ struct Object *RE_GetCamera(struct Render *re); /* return camera override if set */ +void RE_SetOverrideCamera(struct Render *re, struct Object *camera); void RE_SetCamera(struct Render *re, struct Object *camera); void RE_SetEnvmapCamera(struct Render *re, struct Object *cam_ob, float viewscale, float clipsta, float clipend); void RE_SetWindow(struct Render *re, rctf *viewplane, float clipsta, float clipend); @@ -227,6 +273,11 @@ void RE_init_threadcount(Render *re); /* the main processor, assumes all was set OK! */ void RE_TileProcessor(struct Render *re); +bool RE_WriteRenderViewsImage(struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, const bool stamp, char *name); +bool RE_WriteRenderViewsMovie(struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, struct RenderData *rd, + struct bMovieHandle *mh, const size_t width, const size_t height, void **movie_ctx_arr, + const size_t totvideos, bool preview); + /* only RE_NewRender() needed, main Blender render calls */ void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene, struct SceneRenderLayer *srl, struct Object *camera_override, @@ -238,6 +289,9 @@ void RE_RenderFreestyleStrokes(struct Render *re, struct Main *bmain, struct Sce void RE_RenderFreestyleExternal(struct Render *re); #endif +void RE_SetActiveRenderView(struct Render *re, const char *viewname); +const char *RE_GetActiveRenderView(struct Render *re); + /* error reporting */ void RE_SetReports(struct Render *re, struct ReportList *reports); @@ -245,7 +299,7 @@ void RE_SetReports(struct Render *re, struct ReportList *reports); void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene); bool RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode); -bool RE_WriteRenderResult(struct ReportList *reports, RenderResult *rr, const char *filename, int compress); +bool RE_WriteRenderResult(struct ReportList *reports, RenderResult *rr, const char *filename, struct ImageFormatData *imf, const bool multiview, const char *view); struct RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty); extern const float default_envmap_layout[]; @@ -271,6 +325,10 @@ void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, int RE_seq_render_active(struct Scene *scene, struct RenderData *rd); +bool RE_layers_have_name(struct RenderResult *result); + +struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname); + /* shaded view or baking options */ #define RE_BAKE_LIGHT 0 /* not listed in rna_scene.c -> can't be enabled! */ #define RE_BAKE_ALL 1 @@ -292,6 +350,7 @@ void RE_Database_Baking(struct Render *re, struct Main *bmain, struct Scene *sce void RE_DataBase_GetView(struct Render *re, float mat[4][4]); void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4]); +void RE_GetCameraModelMatrix(struct Render *re, struct Object *camera, float r_mat[4][4]); struct Scene *RE_GetScene(struct Render *re); bool RE_force_single_renderlayer(struct Scene *scene); @@ -299,5 +358,20 @@ bool RE_is_rendering_allowed(struct Scene *scene, struct Object *camera_override bool RE_allow_render_generic_object(struct Object *ob); +/******* defined in render_result.c *********/ + +bool RE_HasFakeLayer(RenderResult *res); +bool RE_RenderResult_is_stereo(RenderResult *res); +struct RenderView *RE_RenderViewGetById(struct RenderResult *res, const int view_id); +struct RenderView *RE_RenderViewGetByName(struct RenderResult *res, const char *viewname); + +/******* Debug pass helper functions *********/ + +#ifdef WITH_CYCLES_DEBUG +int RE_debug_pass_num_channels_get(int pass_type); +const char *RE_debug_pass_name_get(int pass_type); +int RE_debug_pass_type_get(struct Render *re); +#endif + #endif /* __RE_PIPELINE_H__ */ diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h index eb861d440d8..6e1f128b7a5 100644 --- a/source/blender/render/extern/include/RE_render_ext.h +++ b/source/blender/render/extern/include/RE_render_ext.h @@ -39,13 +39,11 @@ /* called by meshtools */ struct DerivedMesh; struct ImagePool; -struct LinkNode; struct MTex; struct Scene; -struct View3D; /* particle.c, effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */ -int externtex(struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool); +int externtex(struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool, const bool skip_load_image); /* particle.c */ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype); @@ -58,8 +56,16 @@ void antialias_tagbuf(int xsize, int ysize, char *rectmove); /* dynamicpaint.c */ struct Material *RE_init_sample_material(struct Material *orig_mat, struct Scene *scene); void RE_free_sample_material(struct Material *mat); -void RE_sample_material_color(struct Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3], - int face_index, short hit_quad, struct DerivedMesh *orcoDm, struct Object *ob); +void RE_sample_material_color( + struct Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3], + int tri_index, struct DerivedMesh *orcoDm, struct Object *ob); +/* pointdensity.c */ +struct PointDensity; + +void RE_sample_point_density(struct Scene *scene, struct PointDensity *pd, int resolution, float *values); + +void RE_init_texture_rng(void); +void RE_exit_texture_rng(void); #endif /* __RE_RENDER_EXT_H__ */ diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index da847d235f2..f78c0aa8cb2 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -86,12 +86,12 @@ struct ShadeInputCopy { typedef struct ShadeInputUV { float dxuv[3], dyuv[3], uv[3]; - char *name; + const char *name; } ShadeInputUV; typedef struct ShadeInputCol { float col[4]; - char *name; + const char *name; } ShadeInputCol; /* localized renderloop data */ @@ -178,7 +178,7 @@ typedef struct ShadeInput { int layflag, passflag, combinedflag; struct Group *light_override; struct Material *mat_override; - + #ifdef RE_RAYCOUNTER RayCounter raycounter; #endif @@ -198,14 +198,15 @@ struct ImagePool; struct Object; /* this one uses nodes */ -int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage); +int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image); /* nodes disabled */ -int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage); +int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image); /* only for internal node usage */ int multitex_nodes(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, const short thread, short which_output, struct ShadeInput *shi, struct MTex *mtex, struct ImagePool *pool); float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]); +void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]); /* shaded view and bake */ struct Render; diff --git a/source/blender/render/intern/include/envmap.h b/source/blender/render/intern/include/envmap.h index c813e88c656..627e6c0e1e6 100644 --- a/source/blender/render/intern/include/envmap.h +++ b/source/blender/render/intern/include/envmap.h @@ -47,7 +47,7 @@ struct TexResult; struct ImagePool; void make_envmaps(struct Render *re); -int envmaptex(struct Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool); +int envmaptex(struct Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, const bool skip_image_load); void env_rotate_scene(struct Render *re, float mat[4][4], int do_rotate); #endif /* __ENVMAP_H__ */ diff --git a/source/blender/render/intern/include/initrender.h b/source/blender/render/intern/include/initrender.h index 1f11cdc6729..87e2d2519d5 100644 --- a/source/blender/render/intern/include/initrender.h +++ b/source/blender/render/intern/include/initrender.h @@ -33,7 +33,6 @@ #ifndef __INITRENDER_H__ #define __INITRENDER_H__ -struct Object; /* Functions */ diff --git a/source/blender/render/intern/include/occlusion.h b/source/blender/render/intern/include/occlusion.h index 2f3ac2a7bff..4a70d691436 100644 --- a/source/blender/render/intern/include/occlusion.h +++ b/source/blender/render/intern/include/occlusion.h @@ -35,11 +35,8 @@ struct Render; struct ShadeInput; -struct ShadeResult; struct RenderPart; struct ShadeSample; -struct DerivedMesh; -struct ObjectRen; void make_occ_tree(struct Render *re); void free_occ(struct Render *re); diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h index faf8c5f54f5..8f23455564f 100644 --- a/source/blender/render/intern/include/pixelshading.h +++ b/source/blender/render/intern/include/pixelshading.h @@ -32,7 +32,6 @@ #ifndef __PIXELSHADING_H__ #define __PIXELSHADING_H__ -struct ImagePool; /** * Render the pixel at (x,y) for object ap. Apply the jitter mask. diff --git a/source/blender/render/intern/include/pointdensity.h b/source/blender/render/intern/include/pointdensity.h index e0c293e2473..1d1e808e8d3 100644 --- a/source/blender/render/intern/include/pointdensity.h +++ b/source/blender/render/intern/include/pointdensity.h @@ -37,10 +37,12 @@ * Make point density kd-trees for all point density textures in the scene */ +struct PointDensity; struct Render; struct TexResult; -void cache_pointdensity(struct Render *re, struct Tex *tex); +void free_pointdensity(struct PointDensity *pd); +void cache_pointdensity(struct Render *re, struct PointDensity *pd); void make_pointdensities(struct Render *re); void free_pointdensities(struct Render *re); int pointdensitytex(struct Tex *tex, const float texvec[3], struct TexResult *texres); diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h index 9c0835af56f..3607e66a237 100644 --- a/source/blender/render/intern/include/rayintersection.h +++ b/source/blender/render/intern/include/rayintersection.h @@ -121,7 +121,7 @@ typedef struct Isect { /* arbitrary, but can't use e.g. FLT_MAX because of precision issues */ #define RE_RAYTRACE_MAXDIST 1e15f -#define RE_RAYTRACE_EPSILON -FLT_EPSILON +#define RE_RAYTRACE_EPSILON 0.0f #ifdef __cplusplus } diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h index 90ff69dbfbe..90ad0fa30d7 100644 --- a/source/blender/render/intern/include/render_result.h +++ b/source/blender/render/intern/include/render_result.h @@ -38,6 +38,7 @@ #define RR_USE_EXR 1 #define RR_ALL_LAYERS NULL +#define RR_ALL_VIEWS NULL struct ImBuf; struct ListBase; @@ -53,12 +54,15 @@ struct ColorManagedViewSettings; /* New */ struct RenderResult *render_result_new(struct Render *re, - struct rcti *partrct, int crop, int savebuffers, const char *layername); + struct rcti *partrct, int crop, int savebuffers, const char *layername, const char *viewname); struct RenderResult *render_result_new_full_sample(struct Render *re, - struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers); + struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers, const char *viewname); struct RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty); +void render_result_view_new(struct RenderResult *rr, const char *viewname); +void render_result_views_new(struct RenderResult *rr, struct RenderData *rd); + /* Merge */ void render_result_merge(struct RenderResult *rr, struct RenderResult *rrpart); @@ -75,10 +79,11 @@ void render_result_single_layer_end(struct Render *re); /* EXR Tile File Render */ +void render_result_save_empty_result_tiles(struct Render *re); void render_result_exr_file_begin(struct Render *re); void render_result_exr_file_end(struct Render *re); -void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart); +void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart, const char *viewname); void render_result_exr_file_path(struct Scene *scene, const char *layname, int sample, char *filepath); int render_result_exr_file_read_sample(struct Render *re, int sample); @@ -91,15 +96,19 @@ bool render_result_exr_file_cache_read(struct Render *re); /* Combined Pixel Rect */ -struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr, struct RenderData *rd); +struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr, struct RenderData *rd, const int view_id); void render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd, - struct ImBuf *ibuf); + struct ImBuf *ibuf, const int view_id); -void render_result_rect_fill_zero(struct RenderResult *rr); +void render_result_rect_fill_zero(struct RenderResult *rr, const int view_id); void render_result_rect_get_pixels(struct RenderResult *rr, unsigned int *rect, int rectx, int recty, const struct ColorManagedViewSettings *view_settings, - const struct ColorManagedDisplaySettings *display_settings); + const struct ColorManagedDisplaySettings *display_settings, + const int view_id); + +void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResult *src); +void render_result_views_shallowdelete(struct RenderResult *rr); #endif /* __RENDER_RESULT_H__ */ diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index b87b1e6f367..3569cb2c168 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -58,7 +58,6 @@ struct MemArena; struct VertTableNode; struct VlakTableNode; struct GHash; -struct RenderBuckets; struct ObjectInstanceRen; struct RayObject; struct RayFace; @@ -123,8 +122,7 @@ enum { }; /* controls state of render, everything that's read-only during render stage */ -struct Render -{ +struct Render { struct Render *next, *prev; char name[RE_MAXNAME]; int slot; @@ -194,6 +192,7 @@ struct Render struct Object *camera_override; unsigned int lay, layer_override; + ThreadRWMutex partsmutex; ListBase parts; /* render engine */ @@ -275,6 +274,9 @@ struct Render struct ImagePool *pool; struct EvaluationContext *eval_ctx; + + void **movie_ctx_arr; + char viewname[MAX_NAME]; }; /* ------------------------------------------------------------------------- */ @@ -365,6 +367,14 @@ typedef struct ObjectInstanceRen { struct RayObject *raytree; int transform_primitives; + /* Particle info */ + float part_index; + float part_age; + float part_lifetime; + float part_size; + float part_co[3]; + float part_vel[3]; + float part_avel[3]; } ObjectInstanceRen; /* ------------------------------------------------------------------------- */ @@ -388,7 +398,6 @@ struct halosort { /* ------------------------------------------------------------------------- */ struct Material; -struct MTFace; struct ImagePool; typedef struct RadFace { @@ -424,6 +433,7 @@ typedef struct HaloRen { unsigned int lay; struct Material *mat; struct ImagePool *pool; + bool skip_load_image; } HaloRen; /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h index 88b639c4ba9..308903c6c6d 100644 --- a/source/blender/render/intern/include/rendercore.h +++ b/source/blender/render/intern/include/rendercore.h @@ -34,14 +34,11 @@ #include "render_types.h" -struct HaloRen; struct ShadeInput; struct ShadeResult; struct World; struct RenderPart; struct RenderLayer; -struct ObjectRen; -struct ListBase; struct RayObject; /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/include/shadbuf.h b/source/blender/render/intern/include/shadbuf.h index 7c168baada7..ddf5de8d974 100644 --- a/source/blender/render/intern/include/shadbuf.h +++ b/source/blender/render/intern/include/shadbuf.h @@ -34,7 +34,6 @@ #include "render_types.h" -struct ObjectRen; /** * Calculates shadowbuffers for a vector of shadow-giving lamps @@ -57,8 +56,7 @@ void threaded_makeshadowbufs(struct Render *re); float testshadowbuf(struct Render *re, struct ShadBuf *shb, const float rco[3], const float dxco[3], const float dyco[3], float inp, float mat_bias); /** - * Determines the shadow factor for lamp <lar>, between <p1> - * and <p2>. (Which CS?) + * Determines the shadow factor for lamp \a lar, between \a p1 and \a p2. (Which CS?) */ float shadow_halo(LampRen *lar, const float p1[3], const float p2[3]); diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h index 4f6e005d742..11dcc9d9e80 100644 --- a/source/blender/render/intern/include/shading.h +++ b/source/blender/render/intern/include/shading.h @@ -33,7 +33,6 @@ struct RenderLayer; struct PixStr; struct LampRen; struct VlakRen; -struct StrandSegment; struct StrandPoint; struct ObjectInstanceRen; struct Isect; diff --git a/source/blender/render/intern/include/sss.h b/source/blender/render/intern/include/sss.h index 91a8b91e638..0952c6bff65 100644 --- a/source/blender/render/intern/include/sss.h +++ b/source/blender/render/intern/include/sss.h @@ -55,7 +55,6 @@ void scatter_tree_free(ScatterTree *tree); struct Render; struct Material; -struct VlakRen; void make_sss_tree(struct Render *re); void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint); diff --git a/source/blender/render/intern/include/strand.h b/source/blender/render/intern/include/strand.h index fdcce687f54..5687ef3c837 100644 --- a/source/blender/render/intern/include/strand.h +++ b/source/blender/render/intern/include/strand.h @@ -34,9 +34,6 @@ struct StrandBuffer; struct ShadeSample; struct StrandPart; struct Render; -struct RenderPart; -struct RenderBuckets; -struct RenderPrimitiveIterator; struct ZSpan; struct ObjectInstanceRen; struct StrandSurface; diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h index ff5004fd7f0..ed161e186b8 100644 --- a/source/blender/render/intern/include/texture.h +++ b/source/blender/render/intern/include/texture.h @@ -56,6 +56,11 @@ _hsv[1] *= tex->saturation; \ hsv_to_rgb(_hsv[0], _hsv[1], _hsv[2], \ &texres->tr, &texres->tg, &texres->tb); \ + if ((tex->saturation > 1.0f) && !(tex->flag & TEX_NO_CLAMP)) { \ + if (texres->tr < 0.0f) texres->tr= 0.0f; \ + if (texres->tg < 0.0f) texres->tg= 0.0f; \ + if (texres->tb < 0.0f) texres->tb= 0.0f; \ + } \ } \ struct HaloRen; @@ -81,8 +86,8 @@ void render_realtime_texture(struct ShadeInput *shi, struct Image *ima); /* imagetexture.h */ -int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], const float dxt[2], const float dyt[2], struct TexResult *texres, struct ImagePool *pool); -int imagewrap(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], struct TexResult *texres, struct ImagePool *pool); +int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], const float dxt[2], const float dyt[2], struct TexResult *texres, struct ImagePool *pool, const bool skip_load_image); +int imagewrap(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], struct TexResult *texres, struct ImagePool *pool, const bool skip_load_image); void image_sample(struct Image *ima, float fx, float fy, float dx, float dy, float result[4], struct ImagePool *pool); #endif /* __TEXTURE_H__ */ diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h index ec30c3241ab..cf804d75d70 100644 --- a/source/blender/render/intern/include/zbuf.h +++ b/source/blender/render/intern/include/zbuf.h @@ -36,7 +36,6 @@ struct RenderPart; struct RenderLayer; struct LampRen; -struct VlakRen; struct ListBase; struct ZSpan; struct APixstrand; diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp index 01e592cba0c..d080ddcc375 100644 --- a/source/blender/render/intern/raytrace/rayobject_instance.cpp +++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp @@ -197,7 +197,7 @@ static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max) //There must be a faster way than rotating all the 8 vertexs of the BB for (i = 0; i < 8; i++) { - for (j = 0; j < 3; j++) t[j] = i & (1 << j) ? M[j] : m[j]; + for (j = 0; j < 3; j++) t[j] = (i & (1 << j)) ? M[j] : m[j]; mul_m4_v3(obj->target2global, t); DO_MINMAX(t, min, max); } diff --git a/source/blender/render/intern/raytrace/rayobject_octree.cpp b/source/blender/render/intern/raytrace/rayobject_octree.cpp index 6cbb0761358..b21197e728d 100644 --- a/source/blender/render/intern/raytrace/rayobject_octree.cpp +++ b/source/blender/render/intern/raytrace/rayobject_octree.cpp @@ -119,7 +119,8 @@ static RayObjectAPI octree_api = /* within one octree node, a set of 3x15 bits defines a 'boundbox' to OR with */ #define OCVALRES 15 -#define BROW16(min, max) (((max) >= OCVALRES ? 0xFFFF : (1 << (max + 1)) - 1) - ((min > 0) ? ((1 << (min)) - 1) : 0)) +#define BROW16(min, max) \ + (((max) >= OCVALRES ? 0xFFFF : (1 << ((max) + 1)) - 1) - (((min) > 0) ? ((1 << (min)) - 1) : 0)) static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x, short y, short z, OcVal *ov) { diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c index 15634c93491..0210bec5ab4 100644 --- a/source/blender/render/intern/source/bake.c +++ b/source/blender/render/intern/source/bake.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" +#include "BLI_rand.h" #include "BLI_threads.h" #include "BLI_utildefines.h" @@ -54,8 +55,6 @@ #include "IMB_imbuf.h" #include "IMB_colormanagement.h" -#include "RE_bake.h" - /* local include */ #include "rayintersection.h" #include "rayobject.h" @@ -77,6 +76,8 @@ extern struct Render R; typedef struct BakeShade { + int thread; + ShadeSample ssamp; ObjectInstanceRen *obi; VlakRen *vlr; @@ -374,8 +375,8 @@ static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist, bs->vcol->b = col[2]; } else { - const char *imcol = (char *)(bs->rect + bs->rectx * y + x); - copy_v4_v4_char((char *)imcol, (char *)col); + char *imcol = (char *)(bs->rect + bs->rectx * y + x); + copy_v4_v4_char(imcol, (char *)col); } } if (bs->rect_mask) { @@ -613,6 +614,10 @@ static int get_next_bake_face(BakeShade *bs) for (; obi; obi = obi->next, v = 0) { obr = obi->obr; + /* only allow non instances here */ + if (obr->flag & R_INSTANCEABLE) + continue; + for (; v < obr->totvlak; v++) { vlr = RE_findOrAddVlak(obr, v); @@ -735,6 +740,9 @@ static void bake_single_vertex(BakeShade *bs, VertRen *vert, float u, float v) MLoopCol *basevcol; MLoop *mloop; + /* per vertex fixed seed */ + BLI_thread_srandom(bs->thread, vert->index); + origindex = RE_vertren_get_origindex(bs->obi->obr, vert, 0); if (!origindex || *origindex == ORIGINDEX_NONE) return; @@ -809,6 +817,9 @@ static void shade_tface(BakeShade *bs) Image *ima = tface->tpage; float vec[4][2]; int a, i1, i2, i3; + + /* per face fixed seed */ + BLI_thread_srandom(bs->thread, vlr->index); /* check valid zspan */ if (ima != bs->ima) { @@ -982,8 +993,12 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up int a, vdone = false, result = BAKE_RESULT_OK; bool use_mask = false; bool use_displacement_buffer = false; - bool do_manage = BKE_scene_check_color_management_enabled(re->scene); - + bool do_manage = false; + + if (ELEM(type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) { + do_manage = BKE_scene_check_color_management_enabled(re->scene); + } + re->scene_color_manage = BKE_scene_check_color_management_enabled(re->scene); /* initialize render global */ @@ -1031,6 +1046,8 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up /* get the threads running */ for (a = 0; a < re->r.threads; a++) { + handles[a].thread = a; + /* set defaults in handles */ handles[a].ssamp.shi[0].lay = re->lay; diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c index 90deac2de32..dee75d43f36 100644 --- a/source/blender/render/intern/source/bake_api.c +++ b/source/blender/render/intern/source/bake_api.c @@ -30,10 +30,11 @@ * * The Bake API is fully implemented with Python rna functions. The operator expects/call a function: * - * ``def bake(scene, object, pass_type, pixel_array, num_pixels, depth, result)`` + * ``def bake(scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result)`` * - scene: current scene (Python object) * - object: object to render (Python object) * - pass_type: pass to render (string, e.g., "COMBINED", "AO", "NORMAL", ...) + * - object_id: index of object to bake (to use with the pixel_array) * - pixel_array: list of primitive ids and barycentric coordinates to bake(Python object, see bake_pixel) * - num_pixels: size of pixel_array, number of pixels to bake (int) * - depth: depth of pixels to return (int, assuming always 4 now) @@ -45,17 +46,17 @@ * * pixel_array is a Python object storing BakePixel elements: * - * <pre> + * \code{.c} * struct BakePixel { - * int primitive_id; + * int primitive_id, object_id; * float uv[2]; * float du_dx, du_dy; * float dv_dx, dv_dy; * }; - * </pre> + * \endcode * * In python you have access to: - * - ``primitive_id``, ``uv``, ``du_dx``, ``du_dy``, ``next`` + * - ``primitive_id``, ``object_id``, ``uv``, ``du_dx``, ``du_dy``, ``next`` * - ``next()`` is a function that returns the next #BakePixel in the array. * * \note Pixels that should not be baked have ``primitive_id == -1`` @@ -63,6 +64,8 @@ * For a complete implementation example look at the Cycles Bake commit. */ +#include <limits.h> + #include "MEM_guardedalloc.h" #include "BLI_math.h" @@ -72,6 +75,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_image.h" #include "BKE_node.h" +#include "BKE_mesh.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -126,12 +130,16 @@ static void store_bake_pixel(void *handle, int x, int y, float u, float v) pixel = &bd->pixel_array[i]; pixel->primitive_id = bd->primitive_id; + /* At this point object_id is always 0, since this function runs for the + * lowpoly mesh only. The object_id lookup indices are set afterwards. */ + copy_v2_fl2(pixel->uv, u, v); pixel->du_dx = bd->du_dx; pixel->du_dy = bd->du_dy; pixel->dv_dx = bd->dv_dx; pixel->dv_dy = bd->dv_dy; + pixel->object_id = 0; } void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask) @@ -271,7 +279,7 @@ static void calc_barycentric_from_point( * This function populates pixel_array and returns TRUE if things are correct */ static bool cast_ray_highpoly( - BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakeHighPolyData *highpoly, + BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakePixel *pixel_array, BakeHighPolyData *highpoly, const float co[3], const float dir[3], const int pixel_id, const int tot_highpoly, const float du_dx, const float du_dy, const float dv_dx, const float dv_dy) { @@ -295,7 +303,7 @@ static bool cast_ray_highpoly( mul_v3_m4v3(co_high, highpoly[i].imat, co); /* rotates */ - mul_v3_m4v3(dir_high, highpoly[i].rotmat, dir); + mul_v3_mat3_m4v3(dir_high, highpoly[i].imat, dir); normalize_v3(dir_high); /* cast ray */ @@ -322,22 +330,22 @@ static bool cast_ray_highpoly( } } - for (i = 0; i < tot_highpoly; i++) { - if (hit_mesh == i) { - calc_barycentric_from_point(triangles[i], hits[i].index, hits[i].co, &primitive_id, uv); - highpoly[i].pixel_array[pixel_id].primitive_id = primitive_id; - copy_v2_v2(highpoly[i].pixel_array[pixel_id].uv, uv); - - /* the differentials are relative to the UV/image space, so the highpoly differentials - * are the same as the low poly differentials */ - highpoly[i].pixel_array[pixel_id].du_dx = du_dx; - highpoly[i].pixel_array[pixel_id].du_dy = du_dy; - highpoly[i].pixel_array[pixel_id].dv_dx = dv_dx; - highpoly[i].pixel_array[pixel_id].dv_dy = dv_dy; - } - else { - highpoly[i].pixel_array[pixel_id].primitive_id = -1; - } + if (hit_mesh != -1) { + calc_barycentric_from_point(triangles[hit_mesh], hits[hit_mesh].index, hits[hit_mesh].co, &primitive_id, uv); + pixel_array[pixel_id].primitive_id = primitive_id; + pixel_array[pixel_id].object_id = hit_mesh; + copy_v2_v2(pixel_array[pixel_id].uv, uv); + + /* the differentials are relative to the UV/image space, so the highpoly differentials + * are the same as the low poly differentials */ + pixel_array[pixel_id].du_dx = du_dx; + pixel_array[pixel_id].du_dy = du_dy; + pixel_array[pixel_id].dv_dx = dv_dx; + pixel_array[pixel_id].dv_dy = dv_dy; + } + else { + pixel_array[pixel_id].primitive_id = -1; + pixel_array[pixel_id].object_id = -1; } MEM_freeN(hits); @@ -352,99 +360,76 @@ static void mesh_calc_tri_tessface( TriTessFace *triangles, Mesh *me, bool tangent, DerivedMesh *dm) { int i; - int p_id; - MFace *mface; MVert *mvert; TSpace *tspace; float *precomputed_normals = NULL; bool calculate_normal; + const int tottri = poly_to_tri_count(me->totpoly, me->totloop); + MLoopTri *looptri; + /* calculate normal for each polygon only once */ + unsigned int mpoly_prev = UINT_MAX; + float no[3]; - mface = CustomData_get_layer(&me->fdata, CD_MFACE); mvert = CustomData_get_layer(&me->vdata, CD_MVERT); + looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__); if (tangent) { DM_ensure_normals(dm); - DM_add_tangent_layer(dm); + DM_calc_loop_tangents(dm); - precomputed_normals = dm->getTessFaceDataArray(dm, CD_NORMAL); + precomputed_normals = dm->getPolyDataArray(dm, CD_NORMAL); calculate_normal = precomputed_normals ? false : true; - //mface = dm->getTessFaceArray(dm); - //mvert = dm->getVertArray(dm); - - tspace = dm->getTessFaceDataArray(dm, CD_TANGENT); + tspace = dm->getLoopDataArray(dm, CD_TANGENT); BLI_assert(tspace); } - p_id = -1; - for (i = 0; i < me->totface; i++) { - MFace *mf = &mface[i]; - TSpace *ts = tangent ? &tspace[i * 4] : NULL; + BKE_mesh_recalc_looptri( + me->mloop, me->mpoly, + me->mvert, + me->totloop, me->totpoly, + looptri); - p_id++; + for (i = 0; i < tottri; i++) { + MLoopTri *lt = &looptri[i]; + MPoly *mp = &me->mpoly[lt->poly]; - triangles[p_id].mverts[0] = &mvert[mf->v1]; - triangles[p_id].mverts[1] = &mvert[mf->v2]; - triangles[p_id].mverts[2] = &mvert[mf->v3]; - triangles[p_id].is_smooth = (mf->flag & ME_SMOOTH) != 0; + triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v]; + triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v]; + triangles[i].mverts[2] = &mvert[me->mloop[lt->tri[2]].v]; + triangles[i].is_smooth = (mp->flag & ME_SMOOTH) != 0; if (tangent) { - triangles[p_id].tspace[0] = &ts[0]; - triangles[p_id].tspace[1] = &ts[1]; - triangles[p_id].tspace[2] = &ts[2]; + triangles[i].tspace[0] = &tspace[lt->tri[0]]; + triangles[i].tspace[1] = &tspace[lt->tri[1]]; + triangles[i].tspace[2] = &tspace[lt->tri[2]]; if (calculate_normal) { - if (mf->v4 != 0) { - normal_quad_v3(triangles[p_id].normal, - mvert[mf->v1].co, - mvert[mf->v2].co, - mvert[mf->v3].co, - mvert[mf->v4].co); - } - else { - normal_tri_v3(triangles[p_id].normal, - triangles[p_id].mverts[0]->co, - triangles[p_id].mverts[1]->co, - triangles[p_id].mverts[2]->co); + if (lt->poly != mpoly_prev) { + const MPoly *mp = &me->mpoly[lt->poly]; + BKE_mesh_calc_poly_normal(mp, &me->mloop[mp->loopstart], me->mvert, no); + mpoly_prev = lt->poly; } + copy_v3_v3(triangles[i].normal, no); } else { - copy_v3_v3(triangles[p_id].normal, &precomputed_normals[3 * i]); - } - } - - /* 4 vertices in the face */ - if (mf->v4 != 0) { - p_id++; - - triangles[p_id].mverts[0] = &mvert[mf->v1]; - triangles[p_id].mverts[1] = &mvert[mf->v3]; - triangles[p_id].mverts[2] = &mvert[mf->v4]; - triangles[p_id].is_smooth = (mf->flag & ME_SMOOTH) != 0; - - if (tangent) { - triangles[p_id].tspace[0] = &ts[0]; - triangles[p_id].tspace[1] = &ts[2]; - triangles[p_id].tspace[2] = &ts[3]; - - /* same normal as the other "triangle" */ - copy_v3_v3(triangles[p_id].normal, triangles[p_id - 1].normal); + copy_v3_v3(triangles[i].normal, &precomputed_normals[lt->poly]); } } } - BLI_assert(p_id < me->totface * 2); + MEM_freeN(looptri); } bool RE_bake_pixels_populate_from_objects( - struct Mesh *me_low, BakePixel pixel_array_from[], + struct Mesh *me_low, BakePixel pixel_array_from[], BakePixel pixel_array_to[], BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage, const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage) { size_t i; int primitive_id; float u, v; - float imat_low [4][4]; + float imat_low[4][4]; bool is_cage = me_cage != NULL; bool result = true; @@ -488,6 +473,7 @@ bool RE_bake_pixels_populate_from_objects( mesh_calc_tri_tessface(tris_high[i], highpoly[i].me, false, NULL); dm_highpoly[i] = CDDM_from_mesh(highpoly[i].me); + DM_ensure_tessface(dm_highpoly[i]); if (dm_highpoly[i]->getNumTessFaces(dm_highpoly[i]) != 0) { /* Create a bvh-tree for each highpoly object */ @@ -508,10 +494,7 @@ bool RE_bake_pixels_populate_from_objects( primitive_id = pixel_array_from[i].primitive_id; if (primitive_id == -1) { - int j; - for (j = 0; j < tot_highpoly; j++) { - highpoly[j].pixel_array[i].primitive_id = -1; - } + pixel_array_to[i].primitive_id = -1; continue; } @@ -530,7 +513,7 @@ bool RE_bake_pixels_populate_from_objects( } /* cast ray */ - if (!cast_ray_highpoly(treeData, tris_high, highpoly, co, dir, i, tot_highpoly, + if (!cast_ray_highpoly(treeData, tris_high, pixel_array_to, highpoly, co, dir, i, tot_highpoly, pixel_array_from[i].du_dx, pixel_array_from[i].du_dy, pixel_array_from[i].dv_dx, pixel_array_from[i].dv_dy)) { /* if it fails mask out the original pixel array */ @@ -928,7 +911,6 @@ bool RE_bake_internal( case SCE_PASS_UV: { return bake_uv(pixel_array, num_pixels, depth, result); - break; } default: break; diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 69dd9607c3b..ee28c3b286f 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -44,7 +44,7 @@ # include "BLI_edgehash.h" #endif -#include "BLF_translation.h" +#include "BLT_translation.h" #include "DNA_material_types.h" #include "DNA_curve_types.h" @@ -82,9 +82,7 @@ #include "BKE_particle.h" #include "BKE_scene.h" - #include "PIL_time.h" -#include "IMB_imbuf_types.h" #include "envmap.h" #include "occlusion.h" @@ -103,8 +101,6 @@ #include "zbuf.h" #include "sunsky.h" -#include "RE_render_ext.h" - /* 10 times larger than normal epsilon, test it on default nurbs sphere with ray_transp (for quad detection) */ /* or for checking vertex normal flips */ #define FLT_EPSILON10 1.19209290e-06F @@ -134,6 +130,9 @@ /* ------------------------------------------------------------------------- */ +#define CD_MASK_RENDER_INTERNAL \ + (CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL) + static void split_v_renderfaces(ObjectRen *obr, int startvlak, int UNUSED(startvert), int UNUSED(usize), int vsize, int uIndex, int UNUSED(cyclu), int cyclv) { int vLen = vsize-1+(!!cyclv); @@ -382,7 +381,7 @@ static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_verte { int a; - /* clear all vertex normals */ + /* clear all vertex normals */ if (do_vertex_normal) { for (a=0; a<obr->totvert; a++) { VertRen *ver= RE_findOrAddVert(obr, a); @@ -390,8 +389,8 @@ static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_verte } } - /* calculate cos of angles and point-masses, use as weight factor to - * add face normal to vertex */ + /* calculate cos of angles and point-masses, use as weight factor to + * add face normal to vertex */ for (a=0; a<obr->totvlak; a++) { VlakRen *vlr= RE_findOrAddVlak(obr, a); if (do_vertex_normal && vlr->flag & ME_SMOOTH) { @@ -408,7 +407,7 @@ static void calc_vertexnormals(Render *UNUSED(re), ObjectRen *obr, bool do_verte } } - /* do solid faces */ + /* do solid faces */ for (a=0; a<obr->totvlak; a++) { VlakRen *vlr= RE_findOrAddVlak(obr, a); @@ -581,6 +580,17 @@ static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], shor VlakRen *vlr; int a, totvert; + float rot[3][3]; + + /* Note: For normals, we only want rotation, not scaling component. + * Negative scales (aka mirroring) give wrong results, see T44102. */ + if (lnors) { + float mat3[3][3], size[3]; + + copy_m3_m4(mat3, mat); + mat3_to_rot_size(rot, size, mat3); + } + if (obr->totvert == 0) return; @@ -615,9 +625,8 @@ static void autosmooth(Render *UNUSED(re), ObjectRen *obr, float mat[4][4], shor ver = RE_findOrAddVert(obr, a); mul_m4_v3(mat, ver->co); if (lnors) { - mul_mat3_m4_v3(mat, ver->n); + mul_m3_v3(rot, ver->n); negate_v3(ver->n); - normalize_v3(ver->n); } } for (a = 0; a < obr->totvlak; a++) { @@ -1203,8 +1212,7 @@ static void particle_normal_ren(short ren_as, ParticleSettings *part, Render *re sd->time = 0.0f; sd->size = hasize; - copy_v3_v3(vel, state->vel); - mul_mat3_m4_v3(re->viewmat, vel); + mul_v3_mat3_m4v3(vel, re->viewmat, state->vel); normalize_v3(vel); if (part->draw & PART_DRAW_VEL_LENGTH) @@ -1245,7 +1253,7 @@ static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int /* get uvco */ if (sd->uvco && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { for (i=0; i<sd->totuv; i++) { - if (num != DMCACHE_NOTFOUND) { + if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) { MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE); MTFace *mtface = (MTFace*)CustomData_get_layer_n(&dm->faceData, CD_MTFACE, i); mtface += num; @@ -1262,7 +1270,7 @@ static void get_particle_uvco_mcol(short from, DerivedMesh *dm, float *fuv, int /* get mcol */ if (sd->mcol && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { for (i=0; i<sd->totcol; i++) { - if (num != DMCACHE_NOTFOUND) { + if (!ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) { MFace *mface = dm->getTessFaceData(dm, num, CD_MFACE); MCol *mc = (MCol*)CustomData_get_layer_n(&dm->faceData, CD_MCOL, i); mc += num * 4; @@ -1305,7 +1313,6 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem int totchild=0, step_nbr; int seed, path_nbr=0, orco1=0, num; int totface; - const char **uv_name = NULL; const int *index_mf_to_mpoly = NULL; const int *index_mp_to_orig = NULL; @@ -1326,6 +1333,9 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if ((re->r.scemode & R_VIEWPORT_PREVIEW) && (ob->mode & OB_MODE_PARTICLE_EDIT)) return 0; + if (part->ren_as == PART_DRAW_BB && part->bb_ob == NULL && RE_GetCamera(re) == NULL) + return 0; + /* 2. start initializing things */ /* last possibility to bail out! */ @@ -1349,11 +1359,13 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if (re->r.scemode & R_VIEWPORT_PREVIEW) { /* preview render */ totchild = (int)((float)totchild * (float)part->disp / 100.0f); - step_nbr = part->draw_step; + step_nbr = 1 << part->draw_step; } else { - step_nbr = part->ren_step; + step_nbr = 1 << part->ren_step; } + if (ELEM(part->kink, PART_KINK_SPIRAL)) + step_nbr += part->kink_extra_steps; psys->flag |= PSYS_DRAWING; @@ -1427,8 +1439,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem /* 2.5 setup matrices */ mul_m4_m4m4(mat, re->viewmat, ob->obmat); invert_m4_m4(ob->imat, mat); /* need to be that way, for imat texture */ - copy_m3_m4(nmat, ob->imat); - transpose_m3(nmat); + transpose_m3_m4(nmat, ob->imat); if (psys->flag & PSYS_USE_IMAT) { /* psys->imat is the original emitter's inverse matrix, ob->obmat is the duplicated object's matrix */ @@ -1438,7 +1449,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem /* 2.6 setup strand rendering */ if (part->ren_as == PART_DRAW_PATH && psys->pathcache) { - path_nbr=(int)pow(2.0, (double) step_nbr); + path_nbr = step_nbr; if (path_nbr) { if (!ELEM(ma->material_type, MA_TYPE_HALO, MA_TYPE_WIRE)) { @@ -1557,7 +1568,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if (path_nbr) { cache = psys->pathcache[a]; - max_k = (int)cache->steps; + max_k = (int)cache->segments; } if (totchild && (part->draw&PART_DRAW_PARENT)==0) continue; @@ -1568,10 +1579,10 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if (path_nbr) { cache = psys->childcache[a-totpart]; - if (cache->steps < 0) + if (cache->segments < 0) continue; - max_k = (int)cache->steps; + max_k = (int)cache->segments; } pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); @@ -1855,9 +1866,6 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if (sd.mcol) MEM_freeN(sd.mcol); - if (uv_name) - MEM_freeN(uv_name); - if (states) MEM_freeN(states); @@ -2652,8 +2660,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) negative_scale = is_negative_m4(mat); /* local object -> world space transform for normals */ - copy_m4_m4(nmat, mat); - transpose_m4(nmat); + transpose_m4_m4(nmat, mat); invert_m4(nmat); /* material array */ @@ -2731,12 +2738,13 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) vlr->v4= NULL; /* to prevent float accuracy issues, we calculate normal in local object space (not world) */ - if (area_tri_v3(co3, co2, co1)>FLT_EPSILON) { - if (negative_scale) - normal_tri_v3(tmp, co1, co2, co3); - else - normal_tri_v3(tmp, co3, co2, co1); - add_v3_v3(n, tmp); + if (normal_tri_v3(tmp, co1, co2, co3) > FLT_EPSILON) { + if (negative_scale == false) { + add_v3_v3(n, tmp); + } + else { + sub_v3_v3(n, tmp); + } } vlr->mat= matar[ dl->col ]; @@ -3170,7 +3178,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) /* origindex currently used when using autosmooth, or baking to vertex colors. */ need_origindex = (do_autosmooth || ((re->flag & R_BAKING) && (re->r.bake_flag & R_BAKE_VCOL))); - mask= CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; + mask = CD_MASK_RENDER_INTERNAL; if (!timeoffset) if (need_orco) mask |= CD_MASK_ORCO; @@ -3264,8 +3272,14 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) RE_set_customdata_names(obr, &dm->faceData); /* add tangent layer if we need one */ - if (need_nmap_tangent!=0 && CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) - DM_add_tangent_layer(dm); + if (need_nmap_tangent!=0 && CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) { + bool generate_data = false; + if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) { + dm->calcLoopTangents(dm); + generate_data = true; + } + DM_generate_tangent_tessface_data(dm, generate_data); + } /* still to do for keys: the correct local texture coordinate */ @@ -3274,12 +3288,13 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) for (a1=0; (a1<ob->totcol || (a1==0 && ob->totcol==0)); a1++) { ma= give_render_material(re, ob, a1+1); - + /* test for 100% transparent */ ok = 1; if ((ma->alpha == 0.0f) && (ma->spectra == 0.0f) && - (ma->filter == 0.0f) && + /* No need to test filter here, it's only active with MA_RAYTRANSP and we check against it below. */ + /* (ma->filter == 0.0f) && */ (ma->mode & MA_TRANSP) && (ma->mode & (MA_RAYTRANSP | MA_RAYMIRROR)) == 0) { @@ -3323,7 +3338,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) v2= mface->v2; v3= reverse_verts==0 ? mface->v3 : mface->v1; v4= mface->v4; - flag= mface->flag & ME_SMOOTH; + flag = do_autosmooth ? ME_SMOOTH : mface->flag & ME_SMOOTH; vlr= RE_findOrAddVlak(obr, obr->totvlak++); vlr->v1= RE_findOrAddVert(obr, vertofs+v1); @@ -3807,7 +3822,9 @@ static GroupObject *add_render_lamp(Render *re, Object *ob) } /* set flag for spothalo en initvars */ - if (la->type==LA_SPOT && (la->mode & LA_HALO) && (la->buftype != LA_SHADBUF_DEEP)) { + if ((la->type == LA_SPOT) && (la->mode & LA_HALO) && + (!(la->mode & LA_SHAD_BUF) || la->buftype != LA_SHADBUF_DEEP)) + { if (la->haint>0.0f) { re->flag |= R_LAMPHALO; @@ -3826,7 +3843,7 @@ static GroupObject *add_render_lamp(Render *re, Object *ob) lar->sh_invcampos[2]*= lar->sh_zfac; /* halfway shadow buffer doesn't work for volumetric effects */ - if (lar->buftype == LA_SHADBUF_HALFWAY) + if (ELEM(lar->buftype, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) lar->buftype = LA_SHADBUF_REGULAR; } @@ -3917,7 +3934,15 @@ static bool is_object_hidden(Render *re, Object *ob) if (re->r.scemode & R_VIEWPORT_PREVIEW) { /* Mesh deform cages and so on mess up the preview. To avoid the problem, * viewport doesn't show mesh object if its draw type is bounding box or wireframe. + * Unless it's an active smoke domain! */ + ModifierData *md = NULL; + + if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && + (modifier_isEnabled(re->scene, md, eModifierMode_Realtime))) + { + return false; + } return ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE); } else { @@ -4565,10 +4590,12 @@ static void init_render_object_data(Render *re, ObjectRen *obr, int timeoffset) /* the emitter mesh wasn't rendered so the modifier stack wasn't * evaluated with render settings */ DerivedMesh *dm; + const CustomDataMask mask = CD_MASK_RENDER_INTERNAL; + if (re->r.scemode & R_VIEWPORT_PREVIEW) - dm = mesh_create_derived_view(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); + dm = mesh_create_derived_view(re->scene, ob, mask); else - dm = mesh_create_derived_render(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); + dm = mesh_create_derived_render(re->scene, ob, mask); dm->release(dm); } @@ -4868,7 +4895,7 @@ static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, in /* this is to make sure we get render level duplis in groups: * the derivedmesh must be created before init_render_mesh, * since object_duplilist does dupliparticles before that */ - dm = mesh_create_derived_render(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); + dm = mesh_create_derived_render(re->scene, ob, CD_MASK_RENDER_INTERNAL); dm->release(dm); for (psys=ob->particlesystem.first; psys; psys=psys->next) @@ -4988,8 +5015,10 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp * system need to have render settings set for dupli particles */ dupli_render_particle_set(re, ob, timeoffset, 0, 1); duplilist = object_duplilist(re->eval_ctx, re->scene, ob); - duplilist_apply_data = duplilist_apply(ob, duplilist); - dupli_render_particle_set(re, ob, timeoffset, 0, 0); + duplilist_apply_data = duplilist_apply(ob, NULL, duplilist); + /* postpone 'dupli_render_particle_set', since RE_addRenderInstance reads + * index values from 'dob->persistent_id[0]', referencing 'psys->child' which + * may be smaller once the particle system is restored, see: T45563. */ for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) { DupliExtraData *dob_extra = &duplilist_apply_data->extra[i]; @@ -5082,6 +5111,9 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp if (re->test_break(re->tbh)) break; } + /* restore particle system */ + dupli_render_particle_set(re, ob, timeoffset, 0, false); + if (duplilist_apply_data) { duplilist_restore(duplilist, duplilist_apply_data); duplilist_free_apply_data(duplilist_apply_data); @@ -5136,8 +5168,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0; re->lights.first= re->lights.last= NULL; re->lampren.first= re->lampren.last= NULL; - - slurph_opt= 0; + re->i.partsdone = false; /* signal now in use for previewrender */ /* in localview, lamps are using normal layers, objects only local bits */ @@ -5156,8 +5187,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l * above call to BKE_scene_update_for_newframe, fixes bug. [#22702]. * following calls don't depend on 'RE_SetCamera' */ RE_SetCamera(re, camera); - - normalize_m4_m4(mat, camera->obmat); + RE_GetCameraModelMatrix(re, camera, mat); invert_m4(mat); RE_SetView(re, mat); @@ -5180,7 +5210,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l /* still bad... doing all */ init_render_textures(re); copy_v3_v3(amb, &re->wrld.ambr); - init_render_materials(re->main, re->r.mode, amb); + init_render_materials(re->main, re->r.mode, amb, (re->r.scemode & R_BUTS_PREVIEW) == 0); set_node_shader_lamp_loop(shade_material_loop); /* MAKE RENDER DATA */ @@ -5199,8 +5229,6 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l re->i.totlamp= re->totlamp; re->stats_draw(re->sdh, &re->i); } - - slurph_opt= 1; } void RE_Database_Preprocess(Render *re) @@ -5240,7 +5268,7 @@ void RE_Database_Preprocess(Render *re) } if (!re->test_break(re->tbh)) - project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1); + project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1); /* Occlusion */ if ((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh)) @@ -5318,8 +5346,6 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la re->totvlak=re->totvert=re->totstrand=re->totlamp=re->tothalo= 0; re->i.totface=re->i.totvert=re->i.totstrand=re->i.totlamp=re->i.tothalo= 0; re->lights.first= re->lights.last= NULL; - - slurph_opt= 0; /* in localview, lamps are using normal layers, objects only local bits */ if (re->lay & 0xFF000000) @@ -5331,7 +5357,8 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la /* if no camera, viewmat should have been set! */ if (camera) { - normalize_m4_m4(mat, camera->obmat); + RE_GetCameraModelMatrix(re, camera, mat); + normalize_m4(mat); invert_m4(mat); RE_SetView(re, mat); } @@ -5340,7 +5367,7 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la database_init_objects(re, lay, 0, 0, NULL, timeoffset); if (!re->test_break(re->tbh)) - project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1); + project_renderdata(re, projectverto, (re->r.mode & R_PANORAMA) != 0, 0, 1); /* do this in end, particles for example need cfra */ scene->r.cfra -= timeoffset; @@ -5842,9 +5869,11 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, /* renderdata setup and exceptions */ BLI_freelistN(&re->r.layers); + BLI_freelistN(&re->r.views); re->r = scene->r; BLI_duplicatelist(&re->r.layers, &scene->r.layers); - + BLI_duplicatelist(&re->r.views, &scene->r.views); + RE_init_threadcount(re); re->flag |= R_BAKING; @@ -5912,7 +5941,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, init_render_textures(re); copy_v3_v3(amb, &re->wrld.ambr); - init_render_materials(re->main, re->r.mode, amb); + init_render_materials(re->main, re->r.mode, amb, true); set_node_shader_lamp_loop(shade_material_loop); diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index 06be00a5a5e..b9b908f550b 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -37,7 +37,7 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" /* for rectcpy */ @@ -55,14 +55,10 @@ /* this module */ #include "render_types.h" -#include "renderpipeline.h" #include "envmap.h" -#include "rendercore.h" #include "renderdatabase.h" #include "texture.h" #include "zbuf.h" -#include "initrender.h" - /* ------------------------------------------------------------------------- */ @@ -74,7 +70,7 @@ static void envmap_split_ima(EnvMap *env, ImBuf *ibuf) BLI_lock_thread(LOCK_IMAGE); if (env->cube[1] == NULL) { - BKE_free_envmapdata(env); + BKE_texture_envmap_free_data(env); dx = ibuf->y; dx /= 2; @@ -145,6 +141,7 @@ static Render *envmap_render_copy(Render *re, EnvMap *env) envre->r = re->r; envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR); BLI_listbase_clear(&envre->r.layers); + BLI_listbase_clear(&envre->r.views); envre->r.filtertype = 0; envre->r.tilex = envre->r.xsch / 2; envre->r.tiley = envre->r.ysch / 2; @@ -499,9 +496,12 @@ static void render_envmap(Render *re, EnvMap *env) RenderLayer *rl = envre->result->layers.first; int y; float *alpha; - + float *rect; + + /* envmap is rendered independently of multiview */ + rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, ""); ibuf = IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect | IB_rectfloat); - memcpy(ibuf->rect_float, rl->rectf, ibuf->channels * ibuf->x * ibuf->y * sizeof(float)); + memcpy(ibuf->rect_float, rect, ibuf->channels * ibuf->x * ibuf->y * sizeof(float)); /* envmap renders without alpha */ alpha = ibuf->rect_float + 3; @@ -515,7 +515,7 @@ static void render_envmap(Render *re, EnvMap *env) } - if (re->test_break(re->tbh)) BKE_free_envmapdata(env); + if (re->test_break(re->tbh)) BKE_texture_envmap_free_data(env); else { if (envre->r.mode & R_OSA) env->ok = ENV_OSA; else env->ok = ENV_NORMAL; @@ -576,13 +576,13 @@ void make_envmaps(Render *re) if (env->ok) { /* free when OSA, and old one isn't OSA */ if ((re->r.mode & R_OSA) && env->ok == ENV_NORMAL) - BKE_free_envmapdata(env); + BKE_texture_envmap_free_data(env); /* free when size larger */ else if (env->lastsize < re->r.size) - BKE_free_envmapdata(env); + BKE_texture_envmap_free_data(env); /* free when env is in recalcmode */ else if (env->recalc) - BKE_free_envmapdata(env); + BKE_texture_envmap_free_data(env); } if (env->ok == 0 && depth == 0) env->recalc = 1; @@ -698,7 +698,7 @@ static void set_dxtdyt(float r_dxt[3], float r_dyt[3], const float dxt[3], const /* ------------------------------------------------------------------------- */ -int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool) +int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool, const bool skip_load_image) { extern Render R; /* only in this call */ /* texvec should be the already reflected normal */ @@ -754,7 +754,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o mul_mat3_m4_v3(R.viewinv, dyt); } set_dxtdyt(dxts, dyts, dxt, dyt, face); - imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool); + imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool, skip_load_image); /* edges? */ @@ -771,7 +771,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o if (face != face1) { ibuf = env->cube[face1]; set_dxtdyt(dxts, dyts, dxt, dyt, face1); - imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1, pool); + imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1, pool, skip_load_image); } else texr1.tr = texr1.tg = texr1.tb = texr1.ta = 0.0; @@ -784,7 +784,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o if (face != face1) { ibuf = env->cube[face1]; set_dxtdyt(dxts, dyts, dxt, dyt, face1); - imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2, pool); + imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2, pool, skip_load_image); } else texr2.tr = texr2.tg = texr2.tb = texr2.ta = 0.0; @@ -800,7 +800,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o } } else { - imagewrap(tex, NULL, ibuf, sco, texres, pool); + imagewrap(tex, NULL, ibuf, sco, texres, pool, skip_load_image); } return 1; diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 54f142184e1..fef453efce2 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -36,19 +36,17 @@ #include "MEM_guardedalloc.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_camera.h" #include "BKE_global.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - #include "RNA_access.h" #ifdef WITH_PYTHON @@ -184,7 +182,7 @@ static RenderPart *get_part_from_result(Render *re, RenderResult *result) return NULL; } -RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername) +RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname) { Render *re = engine->re; RenderResult *result; @@ -207,7 +205,7 @@ RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, disprect.ymin = y; disprect.ymax = y + h; - result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername); + result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername, viewname); /* todo: make this thread safe */ @@ -272,7 +270,7 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel if (!cancel || merge_results) { if (re->result->do_exr_tile) { if (!cancel) { - render_result_exr_file_merge(re->result, result); + render_result_exr_file_merge(re->result, result, re->viewname); } } else if (!(re->test_break(re->tbh) && (re->r.scemode & R_BUTS_PREVIEW))) @@ -358,28 +356,69 @@ void RE_engine_report(RenderEngine *engine, int type, const char *msg) BKE_report(engine->reports, type, msg); } -void RE_engine_get_current_tiles(Render *re, int *total_tiles_r, rcti **tiles_r) +void RE_engine_set_error_message(RenderEngine *engine, const char *msg) +{ + Render *re = engine->re; + if (re != NULL) { + RenderResult *rr = RE_AcquireResultRead(re); + if (rr->error != NULL) { + MEM_freeN(rr->error); + } + rr->error = BLI_strdup(msg); + RE_ReleaseResult(re); + } +} + +void RE_engine_active_view_set(RenderEngine *engine, const char *viewname) { + Render *re = engine->re; + RE_SetActiveRenderView(re, viewname); +} + +float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera) +{ + Render *re = engine->re; + return BKE_camera_multiview_shift_x(re ? &re->r : NULL, camera, re->viewname); +} + +void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, float *r_modelmat) +{ + Render *re = engine->re; + BKE_camera_multiview_model_matrix(re ? &re->r : NULL, camera, re->viewname, (float (*)[4])r_modelmat); +} + +rcti* RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_free) +{ + static rcti tiles_static[BLENDER_MAX_THREADS]; + const int allocation_step = BLENDER_MAX_THREADS; RenderPart *pa; int total_tiles = 0; - rcti *tiles = NULL; - int allocation_size = 0, allocation_step = BLENDER_MAX_THREADS; + rcti *tiles = tiles_static; + int allocation_size = BLENDER_MAX_THREADS; + + BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_READ); + + *r_needs_free = false; if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) { - *total_tiles_r = 0; - *tiles_r = NULL; - return; + *r_total_tiles = 0; + BLI_rw_mutex_unlock(&re->partsmutex); + return NULL; } for (pa = re->parts.first; pa; pa = pa->next) { if (pa->status == PART_STATUS_IN_PROGRESS) { if (total_tiles >= allocation_size) { - if (tiles == NULL) + /* Just in case we're using crazy network rendering with more + * slaves as BLENDER_MAX_THREADS. + */ + if (tiles == tiles_static) tiles = MEM_mallocN(allocation_step * sizeof(rcti), "current engine tiles"); else tiles = MEM_reallocN(tiles, (total_tiles + allocation_step) * sizeof(rcti)); allocation_size += allocation_step; + *r_needs_free = true; } tiles[total_tiles] = pa->disprect; @@ -394,9 +433,9 @@ void RE_engine_get_current_tiles(Render *re, int *total_tiles_r, rcti **tiles_r) total_tiles++; } } - - *total_tiles_r = total_tiles; - *tiles_r = tiles; + BLI_rw_mutex_unlock(&re->partsmutex); + *r_total_tiles = total_tiles; + return tiles; } RenderData *RE_engine_get_render_data(Render *re) @@ -415,6 +454,7 @@ void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene) * but it potentially leaves unfreed memory blocks * not sure how to fix this yet -- dfelinto */ BLI_listbase_clear(&re->r.layers); + BLI_listbase_clear(&re->r.views); } bool RE_bake_has_engine(Render *re) @@ -424,13 +464,14 @@ bool RE_bake_has_engine(Render *re) } bool RE_bake_engine( - Render *re, Object *object, const BakePixel pixel_array[], + Render *re, Object *object, + const int object_id, const BakePixel pixel_array[], const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]) { RenderEngineType *type = RE_engines_find(re->r.engine); RenderEngine *engine; - int persistent_data = re->r.mode & R_PERSISTENT_DATA; + bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0; /* set render info */ re->i.cfra = re->scene->r.cfra; @@ -462,12 +503,14 @@ bool RE_bake_engine( type->update(engine, re->main, re->scene); if (type->bake) - type->bake(engine, re->scene, object, pass_type, pixel_array, num_pixels, depth, result); + type->bake(engine, re->scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result); engine->tile_x = 0; engine->tile_y = 0; engine->flag &= ~RE_ENGINE_RENDERING; + BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE); + /* re->engine becomes zero if user changed active render engine during render */ if (!persistent_data || !re->engine) { RE_engine_free(engine); @@ -475,6 +518,7 @@ bool RE_bake_engine( } RE_parts_free(re); + BLI_rw_mutex_unlock(&re->partsmutex); if (BKE_reports_contain(re->reports, RPT_ERROR)) G.is_break = true; @@ -522,7 +566,7 @@ int RE_engine_render(Render *re, int do_all) { RenderEngineType *type = RE_engines_find(re->r.engine); RenderEngine *engine; - int persistent_data = re->r.mode & R_PERSISTENT_DATA; + bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0; /* verify if we can render */ if (!type->render) @@ -589,7 +633,7 @@ int RE_engine_render(Render *re, int do_all) if ((type->flag & RE_USE_SAVE_BUFFERS) && (re->r.scemode & R_EXR_TILE_FILE)) savebuffers = RR_USE_EXR; - re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS); } BLI_rw_mutex_unlock(&re->resultmutex); @@ -653,6 +697,8 @@ int RE_engine_render(Render *re, int do_all) render_result_free_list(&engine->fullresult, engine->fullresult.first); + BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE); + /* re->engine becomes zero if user changed active render engine during render */ if (!persistent_data || !re->engine) { RE_engine_free(engine); @@ -661,6 +707,7 @@ int RE_engine_render(Render *re, int do_all) if (re->result->do_exr_tile) { BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_save_empty_result_tiles(re); render_result_exr_file_end(re); BLI_rw_mutex_unlock(&re->resultmutex); } @@ -672,6 +719,7 @@ int RE_engine_render(Render *re, int do_all) } RE_parts_free(re); + BLI_rw_mutex_unlock(&re->partsmutex); if (BKE_reports_contain(re->reports, RPT_ERROR)) G.is_break = true; diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index 12701099e18..b44c0135420 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -50,12 +50,10 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" -#include "BKE_main.h" #include "BKE_image.h" #include "RE_render_ext.h" -#include "renderpipeline.h" #include "render_types.h" #include "texture.h" @@ -105,7 +103,7 @@ static void ibuf_get_color(float col[4], struct ImBuf *ibuf, int x, int y) } } -int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResult *texres, struct ImagePool *pool) +int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResult *texres, struct ImagePool *pool, const bool skip_load_image) { float fx, fy, val1, val2, val3; int x, y, retval; @@ -122,7 +120,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul if (ima) { /* hack for icon render */ - if ((R.r.scemode & R_NO_IMAGE_LOAD) && !BKE_image_has_loaded_ibuf(ima)) + if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) return retval; ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool); @@ -791,14 +789,6 @@ static void area_sample(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata texr->ta = texr->talpha ? texr->ta*xsd : (clip ? cw*xsd : 1.f); } -/* test if a float value is 'nan' - * there is a C99 function for this: isnan(), but blender seems to use C90 (according to gcc warns), - * and may not be supported by other compilers either */ -/* TODO(sergey): Consider using isnan(), it's used in the other areas. */ -#ifndef ISNAN -# define ISNAN(x) ((x) != (x)) -#endif - typedef struct ReadEWAData { ImBuf *ibuf; afdata_t *AFD; @@ -922,7 +912,7 @@ static void image_mipmap_test(Tex *tex, ImBuf *ibuf) } -static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres, struct ImagePool *pool) +static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres, struct ImagePool *pool, const bool skip_load_image) { TexResult texr; float fx, fy, minx, maxx, miny, maxy; @@ -952,7 +942,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex if (ibuf==NULL && ima==NULL) return retval; if (ima) { /* hack for icon render */ - if ((R.r.scemode & R_NO_IMAGE_LOAD) && !BKE_image_has_loaded_ibuf(ima)) { + if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) { return retval; } ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool); @@ -1155,7 +1145,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex ImBuf *previbuf, *curibuf; float levf; int maxlev; - ImBuf *mipmaps[IB_MIPMAP_LEVELS + 1]; + ImBuf *mipmaps[IMB_MIPMAP_LEVELS + 1]; /* modify ellipse minor axis if too eccentric, use for area sampling as well * scaling dxt/dyt as done in pbrt is not the same @@ -1195,7 +1185,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex curmap = 0; maxlev = 1; mipmaps[0] = ibuf; - while (curmap < IB_MIPMAP_LEVELS) { + while (curmap < IMB_MIPMAP_LEVELS) { mipmaps[curmap + 1] = ibuf->mipmap[curmap]; if (ibuf->mipmap[curmap]) maxlev++; curmap++; @@ -1212,7 +1202,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex if (tex->texfilter == TXF_FELINE) AFD.iProbes = 1; } else { - const int lev = ISNAN(levf) ? 0 : (int)levf; + const int lev = isnan(levf) ? 0 : (int)levf; curibuf = mipmaps[lev]; previbuf = mipmaps[lev + 1]; levf -= floorf(levf); @@ -1348,7 +1338,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex } -int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const float DXT[2], const float DYT[2], TexResult *texres, struct ImagePool *pool) +int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const float DXT[2], const float DYT[2], TexResult *texres, struct ImagePool *pool, const bool skip_load_image) { TexResult texr; float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[2], dyt[2]; @@ -1362,7 +1352,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const /* anisotropic filtering */ if (tex->texfilter != TXF_BOX) - return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres, pool); + return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres, pool, skip_load_image); texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f; @@ -1375,7 +1365,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const if (ima) { /* hack for icon render */ - if ((R.r.scemode & R_NO_IMAGE_LOAD) && !BKE_image_has_loaded_ibuf(ima)) + if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) return retval; ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool); @@ -1595,7 +1585,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const curmap= 0; previbuf= curibuf= ibuf; - while (curmap<IB_MIPMAP_LEVELS && ibuf->mipmap[curmap]) { + while (curmap < IMB_MIPMAP_LEVELS && ibuf->mipmap[curmap]) { if (maxd < pixsize) break; previbuf= curibuf; curibuf= ibuf->mipmap[curmap]; diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c index 353ba5d5caa..970a3937657 100644 --- a/source/blender/render/intern/source/initrender.c +++ b/source/blender/render/intern/source/initrender.c @@ -36,8 +36,6 @@ #include "MEM_guardedalloc.h" -#include "PIL_time.h" - #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_jitter.h" @@ -48,12 +46,8 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" - #include "BKE_camera.h" -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" - #ifdef WITH_QUICKTIME #include "quicktime_export.h" #endif @@ -62,10 +56,6 @@ #include "renderpipeline.h" #include "render_types.h" -#include "rendercore.h" -#include "pixelshading.h" -#include "zbuf.h" - /* Own includes */ #include "initrender.h" @@ -164,8 +154,11 @@ float RE_filter_value(int type, float x) return 1.0f - x; case R_FILTER_GAUSS: - x *= gaussfac; - return (1.0f / expf(x * x) - 1.0f / expf(gaussfac * gaussfac * 2.25f)); + { + const float two_gaussfac2 = 2.0f * gaussfac * gaussfac; + x *= 3.0f * gaussfac; + return 1.0f / sqrtf((float)M_PI * two_gaussfac2) * expf(-x*x / two_gaussfac2); + } case R_FILTER_MITCH: return filt_mitchell(x * gaussfac); @@ -433,10 +426,10 @@ void make_sample_tables(Render *re) /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - struct Object *RE_GetCamera(Render *re) { - return re->camera_override ? re->camera_override : re->scene->camera; + Object *camera = re->camera_override ? re->camera_override : re->scene->camera; + return BKE_camera_multiview_render(re->scene, camera, re->viewname); } static void re_camera_params_get(Render *re, CameraParams *params, Object *cam_ob) @@ -477,6 +470,16 @@ void RE_SetEnvmapCamera(Render *re, Object *cam_ob, float viewscale, float clips re_camera_params_get(re, ¶ms, cam_ob); } +void RE_SetOverrideCamera(Render *re, Object *camera) +{ + re->camera_override = camera; +} + +static void re_camera_params_stereo3d(Render *re, CameraParams *params, Object *cam_ob) +{ + BKE_camera_multiview_params(&re->r, params, cam_ob, re->viewname); +} + /* call this after InitState() */ /* per render, there's one persistent viewplane. Parts will set their own viewplanes */ void RE_SetCamera(Render *re, Object *cam_ob) @@ -486,6 +489,7 @@ void RE_SetCamera(Render *re, Object *cam_ob) /* setup parameters */ BKE_camera_params_init(¶ms); BKE_camera_params_from_object(¶ms, cam_ob); + re_camera_params_stereo3d(re, ¶ms, cam_ob); params.use_fields = (re->r.mode & R_FIELDS); params.field_second = (re->flag & R_SEC_FIELD); @@ -512,6 +516,11 @@ void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, flo copy_m4_m4(mat, re->winmat); } +void RE_GetCameraModelMatrix(Render *re, struct Object *camera, float r_mat[4][4]) +{ + BKE_camera_multiview_model_matrix(&re->r, camera, re->viewname, r_mat); +} + /* ~~~~~~~~~~~~~~~~ part (tile) calculus ~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c index 6ba85ea5329..dcc33b99742 100644 --- a/source/blender/render/intern/source/multires_bake.c +++ b/source/blender/render/intern/source/multires_bake.c @@ -45,6 +45,7 @@ #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_mesh.h" #include "BKE_multires.h" #include "BKE_modifier.h" #include "BKE_subsurf.h" @@ -73,13 +74,15 @@ typedef struct MultiresBakeResult { typedef struct { MVert *mvert; - MFace *mface; - MTFace *mtface; + MPoly *mpoly; + MLoop *mloop; + MLoopUV *mloopuv; + const MLoopTri *mlooptri; + MTexPoly *mtpoly; float *pvtangent; const float *precomputed_normals; int w, h; - int face_index; - int i0, i1, i2; + int tri_index; DerivedMesh *lores_dm, *hires_dm; int lvl; void *thread_data; @@ -102,12 +105,10 @@ typedef struct { float *heights; Image *ima; DerivedMesh *ssdm; - const int *orig_index_mf_to_mpoly; const int *orig_index_mp_to_orig; } MHeightBakeData; typedef struct { - const int *orig_index_mf_to_mpoly; const int *orig_index_mp_to_orig; } MNormalBakeData; @@ -121,42 +122,26 @@ typedef struct { RayObject *raytree; RayFace *rayfaces; - const int *orig_index_mf_to_mpoly; const int *orig_index_mp_to_orig; } MAOBakeData; -static void multiresbake_get_normal(const MResolvePixelData *data, float norm[],const int face_num, const int vert_index) +static void multiresbake_get_normal(const MResolvePixelData *data, float norm[],const int tri_num, const int vert_index) { - unsigned int indices[] = {data->mface[face_num].v1, data->mface[face_num].v2, - data->mface[face_num].v3, data->mface[face_num].v4}; - const int smoothnormal = (data->mface[face_num].flag & ME_SMOOTH); + const int poly_index = data->mlooptri[tri_num].poly; + const MPoly *mp = &data->mpoly[poly_index]; + const bool smoothnormal = (mp->flag & ME_SMOOTH) != 0; if (!smoothnormal) { /* flat */ if (data->precomputed_normals) { - copy_v3_v3(norm, &data->precomputed_normals[3 * face_num]); + copy_v3_v3(norm, &data->precomputed_normals[poly_index]); } else { - float nor[3]; - const float *p0, *p1, *p2; - const int iGetNrVerts = data->mface[face_num].v4 != 0 ? 4 : 3; - - p0 = data->mvert[indices[0]].co; - p1 = data->mvert[indices[1]].co; - p2 = data->mvert[indices[2]].co; - - if (iGetNrVerts == 4) { - const float *p3 = data->mvert[indices[3]].co; - normal_quad_v3(nor, p0, p1, p2, p3); - } - else { - normal_tri_v3(nor, p0, p1, p2); - } - - copy_v3_v3(norm, nor); + BKE_mesh_calc_poly_normal(mp, &data->mloop[mp->loopstart], data->mvert, norm); } } else { - const short *no = data->mvert[indices[vert_index]].no; + const int vi = data->mloop[data->mlooptri[tri_num].tri[vert_index]].v; + const short *no = data->mvert[vi].no; normal_short_to_float_v3(norm, no); normalize_v3(norm); @@ -188,17 +173,13 @@ static void flush_pixel(const MResolvePixelData *data, const int x, const int y) float u, v, w, sign; int r; - const int i0 = data->i0; - const int i1 = data->i1; - const int i2 = data->i2; + st0 = data->mloopuv[data->mlooptri[data->tri_index].tri[0]].uv; + st1 = data->mloopuv[data->mlooptri[data->tri_index].tri[1]].uv; + st2 = data->mloopuv[data->mlooptri[data->tri_index].tri[2]].uv; - st0 = data->mtface[data->face_index].uv[i0]; - st1 = data->mtface[data->face_index].uv[i1]; - st2 = data->mtface[data->face_index].uv[i2]; - - multiresbake_get_normal(data, no0, data->face_index, i0); /* can optimize these 3 into one call */ - multiresbake_get_normal(data, no1, data->face_index, i1); - multiresbake_get_normal(data, no2, data->face_index, i2); + multiresbake_get_normal(data, no0, data->tri_index, 0); /* can optimize these 3 into one call */ + multiresbake_get_normal(data, no1, data->tri_index, 1); + multiresbake_get_normal(data, no2, data->tri_index, 2); resolve_tri_uv_v2(fUV, st, st0, st1, st2); @@ -207,9 +188,9 @@ static void flush_pixel(const MResolvePixelData *data, const int x, const int y) w = 1 - u - v; if (data->pvtangent) { - tang0 = data->pvtangent + data->face_index * 16 + i0 * 4; - tang1 = data->pvtangent + data->face_index * 16 + i1 * 4; - tang2 = data->pvtangent + data->face_index * 16 + i2 * 4; + tang0 = data->pvtangent + data->mlooptri[data->tri_index].tri[0] * 4; + tang1 = data->pvtangent + data->mlooptri[data->tri_index].tri[1] * 4; + tang2 = data->pvtangent + data->mlooptri[data->tri_index].tri[2] * 4; /* the sign is the same at all face vertices for any non degenerate face. * Just in case we clamp the interpolated value though. */ @@ -231,7 +212,7 @@ static void flush_pixel(const MResolvePixelData *data, const int x, const int y) } data->pass_data(data->lores_dm, data->hires_dm, data->thread_data, data->bake_data, - data->ibuf, data->face_index, data->lvl, st, to_tang, x, y); + data->ibuf, data->tri_index, data->lvl, st, to_tang, x, y); } static void set_rast_triangle(const MBakeRast *bake_rast, const int x, const int y) @@ -344,8 +325,8 @@ static int multiresbake_test_break(MultiresBakeRender *bkr) /* **** Threading routines **** */ typedef struct MultiresBakeQueue { - int cur_face; - int tot_face; + int cur_tri; + int tot_tri; SpinLock spin; } MultiresBakeQueue; @@ -364,7 +345,7 @@ typedef struct MultiresBakeThread { float height_min, height_max; } MultiresBakeThread; -static int multires_bake_queue_next_face(MultiresBakeQueue *queue) +static int multires_bake_queue_next_tri(MultiresBakeQueue *queue) { int face = -1; @@ -373,9 +354,9 @@ static int multires_bake_queue_next_face(MultiresBakeQueue *queue) */ BLI_spin_lock(&queue->spin); - if (queue->cur_face < queue->tot_face) { - face = queue->cur_face; - queue->cur_face++; + if (queue->cur_tri < queue->tot_tri) { + face = queue->cur_tri; + queue->cur_tri++; } BLI_spin_unlock(&queue->spin); @@ -388,44 +369,28 @@ static void *do_multires_bake_thread(void *data_v) MResolvePixelData *data = &handle->data; MBakeRast *bake_rast = &handle->bake_rast; MultiresBakeRender *bkr = handle->bkr; - int f; + int tri_index; - while ((f = multires_bake_queue_next_face(handle->queue)) >= 0) { - MTFace *mtfate = &data->mtface[f]; - int verts[3][2], nr_tris, t; + while ((tri_index = multires_bake_queue_next_tri(handle->queue)) >= 0) { + const MLoopTri *lt = &data->mlooptri[tri_index]; + MTexPoly *mtpoly = &data->mtpoly[lt->poly]; + MLoopUV *mloopuv = data->mloopuv; if (multiresbake_test_break(bkr)) break; - if (mtfate->tpage != handle->image) + if (mtpoly->tpage != handle->image) continue; - data->face_index = f; - - /* might support other forms of diagonal splits later on such as - * split by shortest diagonal.*/ - verts[0][0] = 0; - verts[1][0] = 1; - verts[2][0] = 2; + data->tri_index = tri_index; - verts[0][1] = 0; - verts[1][1] = 2; - verts[2][1] = 3; + bake_rasterize(bake_rast, mloopuv[lt->tri[0]].uv, mloopuv[lt->tri[1]].uv, mloopuv[lt->tri[2]].uv); - nr_tris = data->mface[f].v4 != 0 ? 2 : 1; - for (t = 0; t < nr_tris; t++) { - data->i0 = verts[0][t]; - data->i1 = verts[1][t]; - data->i2 = verts[2][t]; + /* tag image buffer for refresh */ + if (data->ibuf->rect_float) + data->ibuf->userflags |= IB_RECT_INVALID; - bake_rasterize(bake_rast, mtfate->uv[data->i0], mtfate->uv[data->i1], mtfate->uv[data->i2]); - - /* tag image buffer for refresh */ - if (data->ibuf->rect_float) - data->ibuf->userflags |= IB_RECT_INVALID; - - data->ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; - } + data->ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; /* update progress */ BLI_spin_lock(&handle->queue->spin); @@ -435,7 +400,7 @@ static void *do_multires_bake_thread(void *data_v) *bkr->do_update = true; if (bkr->progress) - *bkr->progress = ((float)bkr->baked_objects + (float)bkr->baked_faces / handle->queue->tot_face) / bkr->tot_obj; + *bkr->progress = ((float)bkr->baked_objects + (float)bkr->baked_faces / handle->queue->tot_tri) / bkr->tot_obj; BLI_spin_unlock(&handle->queue->spin); } @@ -467,18 +432,21 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, bool require_t MInitBakeData initBakeData, MFreeBakeData freeBakeData, MultiresBakeResult *result) { DerivedMesh *dm = bkr->lores_dm; + const MLoopTri *mlooptri = dm->getLoopTriArray(dm); const int lvl = bkr->lvl; - const int tot_face = dm->getNumTessFaces(dm); + int tot_tri = dm->getNumLoopTri(dm); - if (tot_face > 0) { + if (tot_tri > 0) { MultiresBakeThread *handles; MultiresBakeQueue queue; ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); MVert *mvert = dm->getVertArray(dm); - MFace *mface = dm->getTessFaceArray(dm); - MTFace *mtface = dm->getTessFaceDataArray(dm, CD_MTFACE); - const float *precomputed_normals = dm->getTessFaceDataArray(dm, CD_NORMAL); + MPoly *mpoly = dm->getPolyArray(dm); + MLoop *mloop = dm->getLoopArray(dm); + MLoopUV *mloopuv = dm->getLoopDataArray(dm, CD_MLOOPUV); + MTexPoly *mtpoly = dm->getPolyDataArray(dm, CD_MTEXPOLY); + const float *precomputed_normals = dm->getPolyDataArray(dm, CD_NORMAL); float *pvtangent = NULL; ListBase threads; @@ -487,10 +455,10 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, bool require_t void *bake_data = NULL; if (require_tangent) { - if (CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) - DM_add_tangent_layer(dm); + if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) + DM_calc_loop_tangents(dm); - pvtangent = DM_get_tessface_data_layer(dm, CD_TANGENT); + pvtangent = DM_get_loop_data_layer(dm, CD_TANGENT); } /* all threads shares the same custom bake data */ @@ -505,8 +473,8 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, bool require_t init_ccgdm_arrays(bkr->hires_dm); /* faces queue */ - queue.cur_face = 0; - queue.tot_face = tot_face; + queue.cur_tri = 0; + queue.tot_tri = tot_tri; BLI_spin_init(&queue.spin); /* fill in threads handles */ @@ -517,9 +485,12 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image *ima, bool require_t handle->image = ima; handle->queue = &queue; - handle->data.mface = mface; + handle->data.mpoly = mpoly; handle->data.mvert = mvert; - handle->data.mtface = mtface; + handle->data.mloopuv = mloopuv; + handle->data.mlooptri = mlooptri; + handle->data.mtpoly = mtpoly; + handle->data.mloop = mloop; handle->data.pvtangent = pvtangent; handle->data.precomputed_normals = precomputed_normals; /* don't strictly need this */ handle->data.w = ibuf->x; @@ -602,40 +573,48 @@ static void interp_bilinear_grid(CCGKey *key, CCGElem *grid, float crn_x, float } static void get_ccgdm_data(DerivedMesh *lodm, DerivedMesh *hidm, - const int *index_mf_to_mpoly, const int *index_mp_to_orig, - const int lvl, const int face_index, const float u, const float v, float co[3], float n[3]) + const int *index_mp_to_orig, + const int lvl, const MLoopTri *lt, const float u, const float v, float co[3], float n[3]) { - MFace mface; CCGElem **grid_data; CCGKey key; float crn_x, crn_y; int grid_size, S, face_side; int *grid_offset, g_index; - - lodm->getTessFace(lodm, face_index, &mface); + int poly_index = lt->poly; grid_size = hidm->getGridSize(hidm); grid_data = hidm->getGridData(hidm); grid_offset = hidm->getGridOffset(hidm); hidm->getGridKey(hidm, &key); - face_side = (grid_size << 1) - 1; - if (lvl == 0) { - g_index = grid_offset[face_index]; - S = mdisp_rot_face_to_crn(mface.v4 ? 4 : 3, face_side, u * (face_side - 1), v * (face_side - 1), &crn_x, &crn_y); + MPoly *mpoly; + face_side = (grid_size << 1) - 1; + + mpoly = lodm->getPolyArray(lodm) + poly_index; + g_index = grid_offset[poly_index]; + S = mdisp_rot_face_to_crn(lodm->getVertArray(lodm), mpoly, lodm->getLoopArray(lodm), lt, face_side, u * (face_side - 1), v * (face_side - 1), &crn_x, &crn_y); } else { - int side = (1 << (lvl - 1)) + 1; - int grid_index = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, face_index); - int loc_offs = face_index % (1 << (2 * lvl)); - int cell_index = loc_offs % ((side - 1) * (side - 1)); - int cell_side = (grid_size - 1) / (side - 1); - int row = cell_index / (side - 1); - int col = cell_index % (side - 1); - - S = face_index / (1 << (2 * (lvl - 1))) - grid_offset[grid_index]; - g_index = grid_offset[grid_index]; + /* number of faces per grid side */ + int polys_per_grid_side = (1 << (lvl - 1)); + /* get the original cage face index */ + int cage_face_index = index_mp_to_orig ? index_mp_to_orig[poly_index] : poly_index; + /* local offset in total cage face grids + * (1 << (2 * lvl)) is number of all polys for one cage face */ + int loc_cage_poly_offs = poly_index % (1 << (2 * lvl)); + /* local offset in the vertex grid itself */ + int cell_index = loc_cage_poly_offs % (polys_per_grid_side * polys_per_grid_side); + int cell_side = (grid_size - 1) / polys_per_grid_side; + /* row and column based on grid side */ + int row = cell_index / polys_per_grid_side; + int col = cell_index % polys_per_grid_side; + + /* S is the vertex whose grid we are examining */ + S = poly_index / (1 << (2 * (lvl - 1))) - grid_offset[cage_face_index]; + /* get offset of grid data for original cage face */ + g_index = grid_offset[cage_face_index]; crn_y = (row * cell_side) + u * cell_side; crn_x = (col * cell_side) + v * cell_side; @@ -653,41 +632,40 @@ static void get_ccgdm_data(DerivedMesh *lodm, DerivedMesh *hidm, /* mode = 0: interpolate normals, * mode = 1: interpolate coord */ -static void interp_bilinear_mface(DerivedMesh *dm, MFace *mface, const float u, const float v, const int mode, float res[3]) + +static void interp_bilinear_mpoly(DerivedMesh *dm, MLoop *mloop, MPoly *mpoly, const float u, const float v, const int mode, float res[3]) { float data[4][3]; if (mode == 0) { - dm->getVertNo(dm, mface->v1, data[0]); - dm->getVertNo(dm, mface->v2, data[1]); - dm->getVertNo(dm, mface->v3, data[2]); - dm->getVertNo(dm, mface->v4, data[3]); + dm->getVertNo(dm, mloop[mpoly->loopstart].v, data[0]); + dm->getVertNo(dm, mloop[mpoly->loopstart + 1].v, data[1]); + dm->getVertNo(dm, mloop[mpoly->loopstart + 2].v, data[2]); + dm->getVertNo(dm, mloop[mpoly->loopstart + 3].v, data[3]); } else { - dm->getVertCo(dm, mface->v1, data[0]); - dm->getVertCo(dm, mface->v2, data[1]); - dm->getVertCo(dm, mface->v3, data[2]); - dm->getVertCo(dm, mface->v4, data[3]); + dm->getVertCo(dm, mloop[mpoly->loopstart].v, data[0]); + dm->getVertCo(dm, mloop[mpoly->loopstart + 1].v, data[1]); + dm->getVertCo(dm, mloop[mpoly->loopstart + 2].v, data[2]); + dm->getVertCo(dm, mloop[mpoly->loopstart + 3].v, data[3]); } interp_bilinear_quad_v3(data, u, v, res); } -/* mode = 0: interpolate normals, - * mode = 1: interpolate coord */ -static void interp_barycentric_mface(DerivedMesh *dm, MFace *mface, const float u, const float v, const int mode, float res[3]) +static void interp_barycentric_mlooptri(DerivedMesh *dm, MLoop *mloop, const MLoopTri *lt, const float u, const float v, const int mode, float res[3]) { float data[3][3]; if (mode == 0) { - dm->getVertNo(dm, mface->v1, data[0]); - dm->getVertNo(dm, mface->v2, data[1]); - dm->getVertNo(dm, mface->v3, data[2]); + dm->getVertNo(dm, mloop[lt->tri[0]].v, data[0]); + dm->getVertNo(dm, mloop[lt->tri[1]].v, data[1]); + dm->getVertNo(dm, mloop[lt->tri[2]].v, data[2]); } else { - dm->getVertCo(dm, mface->v1, data[0]); - dm->getVertCo(dm, mface->v2, data[1]); - dm->getVertCo(dm, mface->v3, data[2]); + dm->getVertCo(dm, mloop[lt->tri[0]].v, data[0]); + dm->getVertCo(dm, mloop[lt->tri[1]].v, data[1]); + dm->getVertCo(dm, mloop[lt->tri[2]].v, data[2]); } interp_barycentric_tri_v3(data, u, v, res); @@ -728,7 +706,6 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima) } } - height_data->orig_index_mf_to_mpoly = lodm->getTessFaceDataArray(lodm, CD_ORIGINDEX); height_data->orig_index_mp_to_orig = lodm->getPolyDataArray(lodm, CD_ORIGINDEX); BKE_image_release_ibuf(ima, ibuf, NULL); @@ -753,52 +730,55 @@ static void free_heights_data(void *bake_data) * mesh to make texture smoother) let's call this point p0 and n. * - height wound be dot(n, p1-p0) */ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *thread_data_v, void *bake_data, - ImBuf *ibuf, const int face_index, const int lvl, const float st[2], + ImBuf *ibuf, const int tri_index, const int lvl, const float st[2], float UNUSED(tangmat[3][3]), const int x, const int y) { - MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); - MFace mface; + const MLoopTri *lt = lores_dm->getLoopTriArray(lores_dm) + tri_index; + MLoop *mloop = lores_dm->getLoopArray(lores_dm); + MPoly *mpoly = lores_dm->getPolyArray(lores_dm) + lt->poly; + MLoopUV *mloopuv = lores_dm->getLoopDataArray(lores_dm, CD_MLOOPUV); MHeightBakeData *height_data = (MHeightBakeData *)bake_data; MultiresBakeThread *thread_data = (MultiresBakeThread *) thread_data_v; float uv[2], *st0, *st1, *st2, *st3; int pixel = ibuf->x * y + x; float vec[3], p0[3], p1[3], n[3], len; - lores_dm->getTessFace(lores_dm, face_index, &mface); - - st0 = mtface[face_index].uv[0]; - st1 = mtface[face_index].uv[1]; - st2 = mtface[face_index].uv[2]; - - if (mface.v4) { - st3 = mtface[face_index].uv[3]; + /* ideally we would work on triangles only, however, we rely on quads to get orthogonal + * coordinates for use in grid space (triangle barycentric is not orthogonal) */ + if (mpoly->totloop == 4) { + st0 = mloopuv[mpoly->loopstart].uv; + st1 = mloopuv[mpoly->loopstart + 1].uv; + st2 = mloopuv[mpoly->loopstart + 2].uv; + st3 = mloopuv[mpoly->loopstart + 3].uv; resolve_quad_uv_v2(uv, st, st0, st1, st2, st3); } - else + else { + st0 = mloopuv[lt->tri[0]].uv; + st1 = mloopuv[lt->tri[1]].uv; + st2 = mloopuv[lt->tri[2]].uv; resolve_tri_uv_v2(uv, st, st0, st1, st2); + } CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, - height_data->orig_index_mf_to_mpoly, height_data->orig_index_mp_to_orig, - lvl, face_index, uv[0], uv[1], p1, NULL); + height_data->orig_index_mp_to_orig, + lvl, lt, uv[0], uv[1], p1, NULL); if (height_data->ssdm) { get_ccgdm_data(lores_dm, height_data->ssdm, - height_data->orig_index_mf_to_mpoly, height_data->orig_index_mp_to_orig, - 0, face_index, uv[0], uv[1], p0, n); + height_data->orig_index_mp_to_orig, + 0, lt, uv[0], uv[1], p0, n); } else { - lores_dm->getTessFace(lores_dm, face_index, &mface); - - if (mface.v4) { - interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); - interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 0, n); + if (mpoly->totloop == 4) { + interp_bilinear_mpoly(lores_dm, mloop, mpoly, uv[0], uv[1], 1, p0); + interp_bilinear_mpoly(lores_dm, mloop, mpoly, uv[0], uv[1], 0, n); } else { - interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); - interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 0, n); + interp_barycentric_mlooptri(lores_dm, mloop, lt, uv[0], uv[1], 1, p0); + interp_barycentric_mlooptri(lores_dm, mloop, lt, uv[0], uv[1], 0, n); } } @@ -831,7 +811,6 @@ static void *init_normal_data(MultiresBakeRender *bkr, Image *UNUSED(ima)) normal_data = MEM_callocN(sizeof(MNormalBakeData), "MultiresBake normalData"); - normal_data->orig_index_mf_to_mpoly = lodm->getTessFaceDataArray(lodm, CD_ORIGINDEX); normal_data->orig_index_mp_to_orig = lodm->getPolyDataArray(lodm, CD_ORIGINDEX); return (void *)normal_data; @@ -850,35 +829,39 @@ static void free_normal_data(void *bake_data) * - multiply it by tangmat * - vector in color space would be norm(vec) /2 + (0.5, 0.5, 0.5) */ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *UNUSED(thread_data), - void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, + void *bake_data, ImBuf *ibuf, const int tri_index, const int lvl, const float st[2], float tangmat[3][3], const int x, const int y) { - MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); - MFace mface; + const MLoopTri *lt = lores_dm->getLoopTriArray(lores_dm) + tri_index; + MPoly *mpoly = lores_dm->getPolyArray(lores_dm) + lt->poly; + MLoopUV *mloopuv = lores_dm->getLoopDataArray(lores_dm, CD_MLOOPUV); MNormalBakeData *normal_data = (MNormalBakeData *)bake_data; float uv[2], *st0, *st1, *st2, *st3; int pixel = ibuf->x * y + x; float n[3], vec[3], tmp[3] = {0.5, 0.5, 0.5}; - lores_dm->getTessFace(lores_dm, face_index, &mface); - - st0 = mtface[face_index].uv[0]; - st1 = mtface[face_index].uv[1]; - st2 = mtface[face_index].uv[2]; - - if (mface.v4) { - st3 = mtface[face_index].uv[3]; + /* ideally we would work on triangles only, however, we rely on quads to get orthogonal + * coordinates for use in grid space (triangle barycentric is not orthogonal) */ + if (mpoly->totloop == 4) { + st0 = mloopuv[mpoly->loopstart].uv; + st1 = mloopuv[mpoly->loopstart + 1].uv; + st2 = mloopuv[mpoly->loopstart + 2].uv; + st3 = mloopuv[mpoly->loopstart + 3].uv; resolve_quad_uv_v2(uv, st, st0, st1, st2, st3); } - else + else { + st0 = mloopuv[lt->tri[0]].uv; + st1 = mloopuv[lt->tri[1]].uv; + st2 = mloopuv[lt->tri[2]].uv; resolve_tri_uv_v2(uv, st, st0, st1, st2); + } CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, - normal_data->orig_index_mf_to_mpoly, normal_data->orig_index_mp_to_orig, - lvl, face_index, uv[0], uv[1], NULL, n); + normal_data->orig_index_mp_to_orig, + lvl, lt, uv[0], uv[1], NULL, n); mul_v3_m3v3(vec, tangmat, n); normalize_v3(vec); @@ -1016,7 +999,6 @@ static void *init_ao_data(MultiresBakeRender *bkr, Image *UNUSED(ima)) ao_data->number_of_rays = bkr->number_of_rays; ao_data->bias = bkr->bias; - ao_data->orig_index_mf_to_mpoly = lodm->getTessFaceDataArray(lodm, CD_ORIGINDEX); ao_data->orig_index_mp_to_orig = lodm->getPolyDataArray(lodm, CD_ORIGINDEX); create_ao_raytree(bkr, ao_data); @@ -1088,12 +1070,13 @@ static int trace_ao_ray(MAOBakeData *ao_data, float ray_start[3], float ray_dire } static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void *UNUSED(thread_data), - void *bake_data, ImBuf *ibuf, const int face_index, const int lvl, + void *bake_data, ImBuf *ibuf, const int tri_index, const int lvl, const float st[2], float UNUSED(tangmat[3][3]), const int x, const int y) { + const MLoopTri *lt = lores_dm->getLoopTriArray(lores_dm) + tri_index; + MPoly *mpoly = lores_dm->getPolyArray(lores_dm) + lt->poly; + MLoopUV *mloopuv = lores_dm->getLoopDataArray(lores_dm, CD_MLOOPUV); MAOBakeData *ao_data = (MAOBakeData *) bake_data; - MTFace *mtface = CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); - MFace mface; int i, k, perm_offs; float pos[3], nrm[3]; @@ -1104,25 +1087,28 @@ static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void int pixel = ibuf->x * y + x; float uv[2], *st0, *st1, *st2, *st3; - lores_dm->getTessFace(lores_dm, face_index, &mface); - - st0 = mtface[face_index].uv[0]; - st1 = mtface[face_index].uv[1]; - st2 = mtface[face_index].uv[2]; - - if (mface.v4) { - st3 = mtface[face_index].uv[3]; + /* ideally we would work on triangles only, however, we rely on quads to get orthogonal + * coordinates for use in grid space (triangle barycentric is not orthogonal) */ + if (mpoly->totloop == 4) { + st0 = mloopuv[mpoly->loopstart].uv; + st1 = mloopuv[mpoly->loopstart + 1].uv; + st2 = mloopuv[mpoly->loopstart + 2].uv; + st3 = mloopuv[mpoly->loopstart + 3].uv; resolve_quad_uv_v2(uv, st, st0, st1, st2, st3); } - else + else { + st0 = mloopuv[lt->tri[0]].uv; + st1 = mloopuv[lt->tri[1]].uv; + st2 = mloopuv[lt->tri[2]].uv; resolve_tri_uv_v2(uv, st, st0, st1, st2); + } CLAMP(uv[0], 0.0f, 1.0f); CLAMP(uv[1], 0.0f, 1.0f); get_ccgdm_data(lores_dm, hires_dm, - ao_data->orig_index_mf_to_mpoly, ao_data->orig_index_mp_to_orig, - lvl, face_index, uv[0], uv[1], pos, nrm); + ao_data->orig_index_mp_to_orig, + lvl, lt, uv[0], uv[1], pos, nrm); /* offset ray origin by user bias along normal */ for (i = 0; i < 3; i++) @@ -1193,20 +1179,20 @@ static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void static void count_images(MultiresBakeRender *bkr) { - int a, totface; + int a, totpoly; DerivedMesh *dm = bkr->lores_dm; - MTFace *mtface = CustomData_get_layer(&dm->faceData, CD_MTFACE); + MTexPoly *mtexpoly = CustomData_get_layer(&dm->polyData, CD_MTEXPOLY); BLI_listbase_clear(&bkr->image); bkr->tot_image = 0; - totface = dm->getNumTessFaces(dm); + totpoly = dm->getNumPolys(dm); - for (a = 0; a < totface; a++) - mtface[a].tpage->id.flag &= ~LIB_DOIT; + for (a = 0; a < totpoly; a++) + mtexpoly[a].tpage->id.flag &= ~LIB_DOIT; - for (a = 0; a < totface; a++) { - Image *ima = mtface[a].tpage; + for (a = 0; a < totpoly; a++) { + Image *ima = mtexpoly[a].tpage; if ((ima->id.flag & LIB_DOIT) == 0) { LinkData *data = BLI_genericNodeN(ima); BLI_addtail(&bkr->image, data); @@ -1215,8 +1201,8 @@ static void count_images(MultiresBakeRender *bkr) } } - for (a = 0; a < totface; a++) - mtface[a].tpage->id.flag &= ~LIB_DOIT; + for (a = 0; a < totpoly; a++) + mtexpoly[a].tpage->id.flag &= ~LIB_DOIT; } static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result) diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index 0c6341fe9e5..c5c3b6bbf94 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -43,7 +43,7 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "BKE_node.h" #include "BKE_scene.h" @@ -56,9 +56,7 @@ #include "render_types.h" #include "rendercore.h" #include "renderdatabase.h" -#include "pixelshading.h" #include "shading.h" -#include "zbuf.h" /* ------------------------- Declarations --------------------------- */ @@ -476,9 +474,7 @@ static void occ_build_split(OcclusionTree *tree, int begin, int end, int *split) if (tree->co[a][axis] > mid) { enda--; SWAP(OccFace, tree->face[a], tree->face[enda]); - SWAP(float, tree->co[a][0], tree->co[enda][0]); - SWAP(float, tree->co[a][1], tree->co[enda][1]); - SWAP(float, tree->co[a][2], tree->co[enda][2]); + swap_v3_v3(tree->co[a], tree->co[enda]); } else a++; diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 2a07474a5dd..ad0856497c3 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -49,12 +49,13 @@ #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_path_util.h" +#include "BLI_timecode.h" #include "BLI_fileops.h" #include "BLI_threads.h" #include "BLI_rand.h" #include "BLI_callbacks.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "BKE_animsys.h" /* <------ should this be here?, needed for sequencer update */ #include "BKE_camera.h" @@ -70,6 +71,7 @@ #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */ +#include "BKE_object.h" #include "PIL_time.h" #include "IMB_colormanagement.h" @@ -83,6 +85,8 @@ # include "FRS_freestyle.h" #endif +#include "DEG_depsgraph.h" + /* internal */ #include "render_result.h" #include "render_types.h" @@ -90,7 +94,6 @@ #include "renderdatabase.h" #include "rendercore.h" #include "initrender.h" -#include "shadbuf.h" #include "pixelblending.h" #include "zbuf.h" @@ -132,7 +135,7 @@ Render R; /* ********* alloc and free ******** */ -static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override); +static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override); static volatile int g_break = 0; static int thread_break(void *UNUSED(arg)) @@ -152,6 +155,7 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs) { uintptr_t mem_in_use, mmap_in_use, peak_memory; float megs_used_memory, mmap_used_memory, megs_peak_memory; + char info_time_str[32]; mem_in_use = MEM_get_memory_in_use(); mmap_in_use = MEM_get_mapped_memory_in_use(); @@ -169,8 +173,11 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs) if (rs->curblur) fprintf(stdout, IFACE_("Blur %d "), rs->curblur); + BLI_timecode_string_from_time_simple(info_time_str, sizeof(info_time_str), PIL_check_seconds_timer() - rs->starttime); + fprintf(stdout, IFACE_("| Time:%s | "), info_time_str); + if (rs->infostr) { - fprintf(stdout, "| %s", rs->infostr); + fprintf(stdout, "%s", rs->infostr); } else { if (rs->tothalo) @@ -180,6 +187,9 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs) fprintf(stdout, IFACE_("Sce: %s Ve:%d Fa:%d La:%d"), rs->scene_name, rs->totvert, rs->totface, rs->totlamp); } + /* Flush stdout to be sure python callbacks are printing stuff after blender. */ + fflush(stdout); + BLI_callback_exec(G.main, NULL, BLI_CB_EVT_RENDER_STATS); fputc('\n', stdout); @@ -191,14 +201,10 @@ void RE_FreeRenderResult(RenderResult *res) render_result_free(res); } -float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype) +float *RE_RenderLayerGetPass(volatile RenderLayer *rl, int passtype, const char *viewname) { - RenderPass *rpass; - - for (rpass = rl->passes.first; rpass; rpass = rpass->next) - if (rpass->passtype == passtype) - return rpass->rect; - return NULL; + RenderPass *rpass = RE_pass_find_by_type(rl, passtype, viewname); + return rpass ? rpass->rect : NULL; } RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) @@ -257,7 +263,7 @@ Render *RE_GetRender(const char *name) /* search for existing renders */ for (re = RenderGlobal.renderlist.first; re; re = re->next) - if (strncmp(re->name, name, RE_MAXNAME) == 0) + if (STREQLEN(re->name, name, RE_MAXNAME)) break; return re; @@ -308,8 +314,71 @@ Scene *RE_GetScene(Render *re) return NULL; } +/** + * Same as #RE_AcquireResultImage but creating the necessary views to store the result + * fill provided result struct with a copy of thew views of what is done so far the + * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews +*/ +void RE_AcquireResultImageViews(Render *re, RenderResult *rr) +{ + memset(rr, 0, sizeof(RenderResult)); + + if (re) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_READ); + + if (re->result) { + RenderLayer *rl; + RenderView *rv, *rview; + + rr->rectx = re->result->rectx; + rr->recty = re->result->recty; + + /* creates a temporary duplication of views */ + render_result_views_shallowcopy(rr, re->result); + + rv = rr->views.first; + + /* active layer */ + rl = render_get_active_layer(re, re->result); + + if (rl) { + if (rv->rectf == NULL) { + for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) { + rview->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rview->name); + } + } + + if (rv->rectz == NULL) { + for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) { + rview->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rview->name); + } + } + } + + rr->have_combined = (rv->rectf != NULL); + rr->layers = re->result->layers; + rr->xof = re->disprect.xmin; + rr->yof = re->disprect.ymin; + rr->stamp_data = re->result->stamp_data; + } + } +} + +/* clear temporary renderresult struct */ +void RE_ReleaseResultImageViews(Render *re, RenderResult *rr) +{ + if (re) { + if (rr) { + render_result_views_shallowdelete(rr); + } + BLI_rw_mutex_unlock(&re->resultmutex); + } +} + /* fill provided result struct with what's currently active or done */ -void RE_AcquireResultImage(Render *re, RenderResult *rr) +/* this RenderResult struct is the only exception to the rule of a RenderResult */ +/* always having at least one RenderView */ +void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) { memset(rr, 0, sizeof(RenderResult)); @@ -318,27 +387,33 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr) if (re->result) { RenderLayer *rl; + RenderView *rv; rr->rectx = re->result->rectx; rr->recty = re->result->recty; - rr->rectf = re->result->rectf; - rr->rectz = re->result->rectz; - rr->rect32 = re->result->rect32; - + /* actview view */ + rv = RE_RenderViewGetById(re->result, view_id); + + rr->rectf = rv->rectf; + rr->rectz = rv->rectz; + rr->rect32 = rv->rect32; + /* active layer */ rl = render_get_active_layer(re, re->result); if (rl) { - if (rr->rectf == NULL) - rr->rectf = rl->rectf; - if (rr->rectz == NULL) - rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z); + if (rv->rectf == NULL) + rr->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rv->name); + + if (rv->rectz == NULL) + rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rv->name); } - rr->have_combined = (re->result->rectf != NULL); + rr->have_combined = (rv->rectf != NULL); rr->layers = re->result->layers; - + rr->views = re->result->views; + rr->xof = re->disprect.xmin; rr->yof = re->disprect.ymin; } @@ -355,17 +430,18 @@ void RE_ReleaseResultImage(Render *re) void RE_ResultGet32(Render *re, unsigned int *rect) { RenderResult rres; - - RE_AcquireResultImage(re, &rres); - render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings); - RE_ReleaseResultImage(re); + const size_t view_id = BKE_scene_multiview_view_id_get(&re->r, re->viewname); + + RE_AcquireResultImageViews(re, &rres); + render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, view_id); + RE_ReleaseResultImageViews(re, &rres); } /* caller is responsible for allocating rect in correct size! */ /* Only for acquired results, for lock */ -void RE_AcquiredResultGet32(Render *re, RenderResult *result, unsigned int *rect) +void RE_AcquiredResultGet32(Render *re, RenderResult *result, unsigned int *rect, const int view_id) { - render_result_rect_get_pixels(result, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings); + render_result_rect_get_pixels(result, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, view_id); } RenderStats *RE_GetStats(Render *re) @@ -386,8 +462,8 @@ Render *RE_NewRender(const char *name) BLI_addtail(&RenderGlobal.renderlist, re); BLI_strncpy(re->name, name, RE_MAXNAME); BLI_rw_mutex_init(&re->resultmutex); - re->eval_ctx = MEM_callocN(sizeof(EvaluationContext), "re->eval_ctx"); - re->eval_ctx->mode = DAG_EVAL_RENDER; + BLI_rw_mutex_init(&re->partsmutex); + re->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER); } RE_InitRenderCB(re); @@ -424,9 +500,11 @@ void RE_FreeRender(Render *re) RE_engine_free(re->engine); BLI_rw_mutex_end(&re->resultmutex); + BLI_rw_mutex_end(&re->partsmutex); BLI_freelistN(&re->r.layers); - + BLI_freelistN(&re->r.views); + /* main dbase can already be invalid now, some database-free code checks it */ re->main = NULL; re->scene = NULL; @@ -455,6 +533,17 @@ void RE_FreeAllRender(void) #endif } +void RE_FreeAllPersistentData(void) +{ + Render *re; + for (re = RenderGlobal.renderlist.first; re != NULL; re = re->next) { + if ((re->r.mode & R_PERSISTENT_DATA) != 0 && re->engine != NULL) { + RE_engine_free(re->engine); + re->engine = NULL; + } + } +} + /* on file load, free all re */ void RE_FreeAllRenderResults(void) { @@ -492,6 +581,12 @@ static int check_mode_full_sample(RenderData *rd) { int scemode = rd->scemode; + if (!STREQ(rd->engine, RE_engine_id_BLENDER_RENDER) && + !STREQ(rd->engine, RE_engine_id_BLENDER_GAME)) + { + scemode &= ~R_FULL_SAMPLE; + } + if ((rd->mode & R_OSA) == 0) scemode &= ~R_FULL_SAMPLE; @@ -567,8 +662,10 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, /* copy render data and render layers for thread safety */ BLI_freelistN(&re->r.layers); + BLI_freelistN(&re->r.views); re->r = *rd; BLI_duplicatelist(&re->r.layers, &rd->layers); + BLI_duplicatelist(&re->r.views, &rd->views); if (source) { /* reuse border flags from source renderer */ @@ -659,6 +756,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, re->result = MEM_callocN(sizeof(RenderResult), "new render result"); re->result->rectx = re->rectx; re->result->recty = re->recty; + render_result_view_new(re->result, "new temporary view"); } if (re->r.scemode & R_VIEWPORT_PREVIEW) @@ -676,18 +774,23 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, RE_init_threadcount(re); } +/* This function is only called by view3d rendering, which doesn't support + * multiview at the moment. so handle only one view here */ static void render_result_rescale(Render *re) { RenderResult *result = re->result; + RenderView *rv; int x, y; float scale_x, scale_y; float *src_rectf; - src_rectf = result->rectf; + rv = RE_RenderViewGetById(result, 0); + src_rectf = rv->rectf; + if (src_rectf == NULL) { RenderLayer *rl = render_get_active_layer(re, re->result); if (rl != NULL) { - src_rectf = rl->rectf; + src_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL); } } @@ -697,32 +800,34 @@ static void render_result_rescale(Render *re) &re->disprect, 0, RR_USE_MEM, - RR_ALL_LAYERS); - - dst_rectf = re->result->rectf; - if (dst_rectf == NULL) { - RenderLayer *rl; - rl = render_get_active_layer(re, re->result); - if (rl != NULL) { - dst_rectf = rl->rectf; + RR_ALL_LAYERS, + ""); + + if (re->result != NULL) { + dst_rectf = RE_RenderViewGetById(re->result, 0)->rectf; + if (dst_rectf == NULL) { + RenderLayer *rl; + rl = render_get_active_layer(re, re->result); + if (rl != NULL) { + dst_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL); + } } - } - scale_x = (float) result->rectx / re->result->rectx; - scale_y = (float) result->recty / re->result->recty; - for (x = 0; x < re->result->rectx; ++x) { - for (y = 0; y < re->result->recty; ++y) { - int src_x = x * scale_x, - src_y = y * scale_y; - int dst_index = y * re->result->rectx + x, - src_index = src_y * result->rectx + src_x; - copy_v4_v4(dst_rectf + dst_index * 4, - src_rectf + src_index * 4); + scale_x = (float) result->rectx / re->result->rectx; + scale_y = (float) result->recty / re->result->recty; + for (x = 0; x < re->result->rectx; ++x) { + for (y = 0; y < re->result->recty; ++y) { + int src_x = x * scale_x; + int src_y = y * scale_y; + int dst_index = y * re->result->rectx + x; + int src_index = src_y * result->rectx + src_x; + copy_v4_v4(dst_rectf + dst_index * 4, + src_rectf + src_index * 4); + } } } + render_result_free(result); } - - render_result_free(result); } void RE_ChangeResolution(Render *re, int winx, int winy, rcti *disprect) @@ -769,6 +874,10 @@ void render_update_anim_renderdata(Render *re, RenderData *rd) /* render layers */ BLI_freelistN(&re->r.layers); BLI_duplicatelist(&re->r.layers, &rd->layers); + + /* render views */ + BLI_freelistN(&re->r.views); + BLI_duplicatelist(&re->r.views, &rd->views); } void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend) @@ -901,9 +1010,9 @@ static void *do_part_thread(void *pa_v) if (R.test_break(R.tbh) == 0) { if (!R.sss_points && (R.r.scemode & R_FULL_SAMPLE)) - pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM); + pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM, R.viewname); else - pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS); + pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS, R.viewname); /* Copy EXR tile settings, so pipeline knows whether this is a result * for Save Buffers enabled rendering. @@ -926,7 +1035,7 @@ static void *do_part_thread(void *pa_v) /* merge too on break! */ if (R.result->do_exr_tile) { - render_result_exr_file_merge(R.result, pa->result); + render_result_exr_file_merge(R.result, pa->result, R.viewname); } else if (render_display_update_enabled(&R)) { /* on break, don't merge in result for preview renders, looks nicer */ @@ -1022,13 +1131,28 @@ static bool find_next_pano_slice(Render *re, int *slice, int *minx, rctf *viewpl return found; } -static RenderPart *find_next_part(Render *re, int minx) +typedef struct SortRenderPart { + RenderPart *pa; + long long int dist; +} SortRenderPart; + +static int sort_render_part(const void *pa1, const void *pa2) { + const SortRenderPart *rpa1 = pa1; + const SortRenderPart *rpa2 = pa2; + + if (rpa1->dist > rpa2->dist) return 1; + else if (rpa1->dist < rpa2->dist) return -1; + + return 0; +} + +static int sort_and_queue_parts(Render *re, int minx, ThreadQueue *workqueue) { - RenderPart *pa, *best = NULL; + RenderPart *pa; /* long long int's needed because of overflow [#24414] */ long long int centx = re->winx / 2, centy = re->winy / 2, tot = 1; - long long int mindist = (long long int)re->winx * (long long int)re->winy; + int totsort = 0; /* find center of rendered parts, image center counts for 1 too */ for (pa = re->parts.first; pa; pa = pa->next) { @@ -1037,31 +1161,48 @@ static RenderPart *find_next_part(Render *re, int minx) centy += BLI_rcti_cent_y(&pa->disprect); tot++; } + else if (pa->status == PART_STATUS_NONE && pa->nr == 0) { + if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) { + totsort++; + } + } } centx /= tot; centy /= tot; - /* closest of the non-rendering parts */ - for (pa = re->parts.first; pa; pa = pa->next) { - if (pa->status == PART_STATUS_NONE && pa->nr == 0) { - long long int distx = centx - BLI_rcti_cent_x(&pa->disprect); - long long int disty = centy - BLI_rcti_cent_y(&pa->disprect); - distx = (long long int)sqrt(distx * distx + disty * disty); - if (distx < mindist) { - if (re->r.mode & R_PANORAMA) { - if (pa->disprect.xmin == minx) { - best = pa; - mindist = distx; - } - } - else { - best = pa; - mindist = distx; + if (totsort > 0) { + SortRenderPart *sortlist = MEM_mallocN(sizeof(*sortlist) * totsort, "renderpartsort"); + long int i = 0; + + /* prepare the list */ + for (pa = re->parts.first; pa; pa = pa->next) { + if (pa->status == PART_STATUS_NONE && pa->nr == 0) { + if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) { + long long int distx = centx - BLI_rcti_cent_x(&pa->disprect); + long long int disty = centy - BLI_rcti_cent_y(&pa->disprect); + sortlist[i].dist = (long long int)sqrt(distx * distx + disty * disty); + sortlist[i].pa = pa; + i++; } } } + + /* Now sort it */ + qsort(sortlist, totsort, sizeof(*sortlist), sort_render_part); + + /* Finally flush it to the workqueue */ + for (i = 0; i < totsort; i++) { + pa = sortlist[i].pa; + pa->nr = i + 1; /* for nicest part, and for stats */ + BLI_thread_queue_push(workqueue, pa); + } + + MEM_freeN(sortlist); + + return totsort; } - return best; + + return 0; } static void print_part_stats(Render *re, RenderPart *pa) @@ -1106,16 +1247,23 @@ static void *do_render_thread(void *thread_v) return NULL; } -static void threaded_tile_processor(Render *re) +static void main_render_result_end(Render *re) +{ + if (re->result->do_exr_tile) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_exr_file_end(re); + BLI_rw_mutex_unlock(&re->resultmutex); + } + + if (re->r.scemode & R_EXR_CACHE_FILE) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_exr_file_cache_write(re); + BLI_rw_mutex_unlock(&re->resultmutex); + } +} + +static void main_render_result_new(Render *re) { - RenderThread thread[BLENDER_MAX_THREADS]; - ThreadQueue *workqueue, *donequeue; - ListBase threads; - RenderPart *pa; - rctf viewplane = re->viewplane; - double lastdraw, elapsed, redrawtime = 1.0f; - int totpart = 0, minx = 0, slice = 0, a, wait; - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); /* first step; free the entire render result, make new, and/or prepare exr buffer saving */ @@ -1123,25 +1271,38 @@ static void threaded_tile_processor(Render *re) render_result_free(re->result); if (re->sss_points && render_display_update_enabled(re)) - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); else if (re->r.scemode & R_FULL_SAMPLE) - re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR); + re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR, RR_ALL_VIEWS); else re->result = render_result_new(re, &re->disprect, 0, - (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS); + (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); } BLI_rw_mutex_unlock(&re->resultmutex); + + if (re->result) { + if (re->result->do_exr_tile) { + render_result_exr_file_begin(re); + } + } +} + +static void threaded_tile_processor(Render *re) +{ + RenderThread thread[BLENDER_MAX_THREADS]; + ThreadQueue *workqueue, *donequeue; + ListBase threads; + RenderPart *pa; + rctf viewplane = re->viewplane; + double lastdraw, elapsed, redrawtime = 1.0f; + int totpart = 0, minx = 0, slice = 0, a, wait; if (re->result == NULL) return; /* warning; no return here without closing exr file */ - RE_parts_init(re, true); - - if (re->result->do_exr_tile) - render_result_exr_file_begin(re); /* assuming no new data gets added to dbase... */ R = *re; @@ -1156,11 +1317,7 @@ static void threaded_tile_processor(Render *re) /* for panorama we loop over slices */ while (find_next_pano_slice(re, &slice, &minx, &viewplane)) { /* gather parts into queue */ - while ((pa = find_next_part(re, minx))) { - pa->nr = totpart + 1; /* for nicest part, and for stats */ - totpart++; - BLI_thread_queue_push(workqueue, pa); - } + totpart = sort_and_queue_parts(re, minx, workqueue); BLI_thread_queue_nowait(workqueue); @@ -1246,27 +1403,23 @@ static void threaded_tile_processor(Render *re) BLI_thread_queue_free(donequeue); BLI_thread_queue_free(workqueue); - - if (re->result->do_exr_tile) { - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - render_result_exr_file_end(re); - BLI_rw_mutex_unlock(&re->resultmutex); - } - if (re->r.scemode & R_EXR_CACHE_FILE) { + if (re->result->do_exr_tile) { BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - render_result_exr_file_cache_write(re); + render_result_save_empty_result_tiles(re); BLI_rw_mutex_unlock(&re->resultmutex); } /* unset threadsafety */ g_break = 0; - + BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE); RE_parts_free(re); + BLI_rw_mutex_unlock(&re->partsmutex); re->viewplane = viewplane; /* restore viewplane, modified by pano render */ } #ifdef WITH_FREESTYLE +static void init_freestyle(Render *re); static void add_freestyle(Render *re, int render); static void free_all_freestyle_renders(void); #endif @@ -1274,6 +1427,7 @@ static void free_all_freestyle_renders(void); /* currently only called by preview renders and envmap */ void RE_TileProcessor(Render *re) { + main_render_result_new(re); threaded_tile_processor(re); re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime; @@ -1283,8 +1437,8 @@ void RE_TileProcessor(Render *re) /* Freestyle */ if (re->r.mode & R_EDGE_FRS) { if (!re->test_break(re->tbh)) { + init_freestyle(re); add_freestyle(re, 1); - free_all_freestyle_renders(); re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime; @@ -1299,6 +1453,7 @@ void RE_TileProcessor(Render *re) static void do_render_3d(Render *re) { + RenderView *rv; int cfra_backup; re->current_scene_update(re->suh, re->scene); @@ -1315,40 +1470,55 @@ static void do_render_3d(Render *re) BKE_scene_frame_set(re->scene, (double)re->scene->r.cfra + (double)re->mblur_offs + (double)re->field_offs); - /* lock drawing in UI during data phase */ - if (re->draw_lock) - re->draw_lock(re->dlh, 1); - - /* make render verts/faces/halos/lamps */ - if (render_scene_needs_vector(re)) { - RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay); - } - else { - RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); - RE_Database_Preprocess(re); + /* init main render result */ + main_render_result_new(re); + +#ifdef WITH_FREESTYLE + if (re->r.mode & R_EDGE_FRS) { + init_freestyle(re); } +#endif + + /* we need a new database for each view */ + for (rv = re->result->views.first; rv; rv = rv->next) { + RE_SetActiveRenderView(re, rv->name); + + /* lock drawing in UI during data phase */ + if (re->draw_lock) + re->draw_lock(re->dlh, 1); + + /* make render verts/faces/halos/lamps */ + if (render_scene_needs_vector(re)) + RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay); + else { + RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); + RE_Database_Preprocess(re); + } - /* clear UI drawing locks */ - if (re->draw_lock) - re->draw_lock(re->dlh, 0); + /* clear UI drawing locks */ + if (re->draw_lock) + re->draw_lock(re->dlh, 0); - threaded_tile_processor(re); + threaded_tile_processor(re); #ifdef WITH_FREESTYLE - /* Freestyle */ - if (re->r.mode & R_EDGE_FRS) - if (!re->test_break(re->tbh)) - add_freestyle(re, 1); + /* Freestyle */ + if (re->r.mode & R_EDGE_FRS) + if (!re->test_break(re->tbh)) + add_freestyle(re, 1); #endif - /* do left-over 3d post effects (flares) */ - if (re->flag & R_HALO) - if (!re->test_break(re->tbh)) - add_halo_flare(re); - - /* free all render verts etc */ - RE_Database_Free(re); - + /* do left-over 3d post effects (flares) */ + if (re->flag & R_HALO) + if (!re->test_break(re->tbh)) + add_halo_flare(re); + + /* free all render verts etc */ + RE_Database_Free(re); + } + + main_render_result_end(re); + re->scene->r.cfra = cfra_backup; re->scene->r.subframe = 0.f; } @@ -1421,19 +1591,13 @@ static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float b rl1 = brr->layers.first; for (rl = rr->layers.first; rl && rl1; rl = rl->next, rl1 = rl1->next) { - - /* combined */ - if (rl->rectf && rl1->rectf) { - if (key_alpha) - addblur_rect_key(rr, rl->rectf, rl1->rectf, blurfac); - else - addblur_rect(rr, rl->rectf, rl1->rectf, blurfac, 4); - } - /* passes are allocated in sync */ rpass1 = rl1->passes.first; for (rpass = rl->passes.first; rpass && rpass1; rpass = rpass->next, rpass1 = rpass1->next) { - addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels); + if ((rpass->passtype & SCE_PASS_COMBINED) && key_alpha) + addblur_rect_key(rr, rpass->rect, rpass1->rect, blurfac); + else + addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels); } } } @@ -1446,7 +1610,7 @@ static void do_render_blur_3d(Render *re) int blur = re->r.mblur_samples; /* create accumulation render result */ - rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); /* do the blur steps */ while (blur--) { @@ -1508,10 +1672,6 @@ static void merge_renderresult_fields(RenderResult *rr, RenderResult *rr1, Rende rl2 = rr2->layers.first; for (rl = rr->layers.first; rl && rl1 && rl2; rl = rl->next, rl1 = rl1->next, rl2 = rl2->next) { - /* combined */ - if (rl->rectf && rl1->rectf && rl2->rectf) - interleave_rect(rr, rl->rectf, rl1->rectf, rl2->rectf, 4); - /* passes are allocated in sync */ rpass1 = rl1->passes.first; rpass2 = rl2->passes.first; @@ -1579,7 +1739,7 @@ static void do_render_fields_3d(Render *re) re->disprect.ymax *= 2; BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); if (rr2) { if (re->r.mode & R_ODDFIELD) @@ -1651,7 +1811,7 @@ static void do_render_fields_blur_3d(Render *re) /* weak is: it chances disprect from border */ render_result_disprect_to_full_resolution(re); - rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); render_result_merge(rres, re->result); render_result_free(re->result); @@ -1946,7 +2106,7 @@ static void ntree_render_scenes(Render *re) } /* bad call... need to think over proper method still */ -static void render_composit_stats(void *UNUSED(arg), char *str) +static void render_composit_stats(void *UNUSED(arg), const char *str) { R.i.infostr = str; R.stats_draw(R.sdh, &R.i); @@ -1954,6 +2114,23 @@ static void render_composit_stats(void *UNUSED(arg), char *str) } #ifdef WITH_FREESTYLE +/* init Freestyle renderer */ +static void init_freestyle(Render *re) +{ + re->freestyle_bmain = BKE_main_new(); + + /* We use the same window manager for freestyle bmain as + * real bmain uses. This is needed because freestyle's + * bmain could be used to tag scenes for update, which + * implies call of ED_render_scene_update in some cases + * and that function requires proper window manager + * to present (sergey) + */ + re->freestyle_bmain->wm = re->main->wm; + + FRS_init_stroke_renderer(re); +} + /* invokes Freestyle stroke rendering */ static void add_freestyle(Render *re, int render) { @@ -1964,18 +2141,7 @@ static void add_freestyle(Render *re, int render) actsrl = BLI_findlink(&re->r.layers, re->r.actlay); - re->freestyle_bmain = BKE_main_new(); - - /* We use the same window manager for freestyle bmain as - * real bmain uses. This is needed because freestyle's - * bmain could be used to tag scenes for update, which - * implies call of ED_render_scene_update in some cases - * and that function requires proper window manager - * to present (sergey) - */ - re->freestyle_bmain->wm = re->main->wm; - - FRS_init_stroke_rendering(re); + FRS_begin_stroke_rendering(re); for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) { if (do_link) { @@ -1991,7 +2157,7 @@ static void add_freestyle(Render *re, int render) } } - FRS_finish_stroke_rendering(re); + FRS_end_stroke_rendering(re); /* restore the global R value (invalidated by nested execution of the internal renderer) */ R = *re; @@ -2001,28 +2167,32 @@ static void add_freestyle(Render *re, int render) static void composite_freestyle_renders(Render *re, int sample) { Render *freestyle_render; + RenderView *rv; SceneRenderLayer *srl, *actsrl; LinkData *link; actsrl = BLI_findlink(&re->r.layers, re->r.actlay); link = (LinkData *)re->freestyle_renders.first; - for (srl= (SceneRenderLayer *)re->r.layers.first; srl; srl= srl->next) { - if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl) - continue; - if (FRS_is_freestyle_enabled(srl)) { - freestyle_render = (Render *)link->data; + for (rv = re->result->views.first; rv; rv = rv->next) { + for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) { + if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl) + continue; - /* may be NULL in case of empty render layer */ - if (freestyle_render) { - render_result_exr_file_read_sample(freestyle_render, sample); - FRS_composite_result(re, srl, freestyle_render); - RE_FreeRenderResult(freestyle_render->result); - freestyle_render->result = NULL; + if (FRS_is_freestyle_enabled(srl)) { + freestyle_render = (Render *)link->data; + + /* may be NULL in case of empty render layer */ + if (freestyle_render) { + render_result_exr_file_read_sample(freestyle_render, sample); + FRS_composite_result(re, srl, freestyle_render); + RE_FreeRenderResult(freestyle_render->result); + freestyle_render->result = NULL; + } } + link = link->next; } - link = link->next; } } @@ -2049,7 +2219,7 @@ static void free_all_freestyle_renders(void) /* detach the window manager from freestyle bmain (see comments * in add_freestyle() for more detail) */ - re1->freestyle_bmain->wm.first = re1->freestyle_bmain->wm.last = NULL; + BLI_listbase_clear(&re1->freestyle_bmain->wm); BKE_main_free(re1->freestyle_bmain); re1->freestyle_bmain = NULL; @@ -2058,11 +2228,14 @@ static void free_all_freestyle_renders(void) } #endif -/* reads all buffers, calls optional composite, merges in first result->rectf */ +/* reads all buffers, calls optional composite, merges in first result->views rectf */ static void do_merge_fullsample(Render *re, bNodeTree *ntree) { + ListBase *rectfs; + RenderView *rv; float *rectf, filt[3][3]; int x, y, sample; + int nr, numviews; /* interaction callbacks */ if (ntree) { @@ -2077,9 +2250,18 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) /* filtmask needs it */ R = *re; - /* we accumulate in here */ - rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba"); - + /* temporary storage of the acccumulation buffers */ + rectfs = MEM_callocN(sizeof(ListBase), "fullsample accumulation buffers"); + + numviews = BLI_listbase_count(&re->result->views); + for (nr = 0; nr < numviews; nr++) { + rv = MEM_callocN(sizeof(RenderView), "fullsample renderview"); + + /* we accumulate in here */ + rv->rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba"); + BLI_addtail(rectfs, rv); + } + for (sample = 0; sample < re->r.osa; sample++) { Scene *sce; Render *re1; @@ -2116,54 +2298,70 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) if (ntree) { ntreeCompositTagRender(re->scene); ntreeCompositTagAnimated(ntree); - - ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings); + + for (rv = re->result->views.first; rv; rv = rv->next) { + ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name); + } } - - /* ensure we get either composited result or the active layer */ - RE_AcquireResultImage(re, &rres); - - /* accumulate with filter, and clip */ - mask = (1 << sample); - mask_array(mask, filt); - for (y = 0; y < re->recty; y++) { - float *rf = rectf + 4 * y * re->rectx; - float *col = rres.rectf + 4 * y * re->rectx; - - for (x = 0; x < re->rectx; x++, rf += 4, col += 4) { - /* clamping to 1.0 is needed for correct AA */ - if (col[0] < 0.0f) col[0] = 0.0f; else if (col[0] > 1.0f) col[0] = 1.0f; - if (col[1] < 0.0f) col[1] = 0.0f; else if (col[1] > 1.0f) col[1] = 1.0f; - if (col[2] < 0.0f) col[2] = 0.0f; else if (col[2] > 1.0f) col[2] = 1.0f; + for (nr = 0, rv = rectfs->first; rv; rv = rv->next, nr++) { + rectf = rv->rectf; + + /* ensure we get either composited result or the active layer */ + RE_AcquireResultImage(re, &rres, nr); + + /* accumulate with filter, and clip */ + mask = (1 << sample); + mask_array(mask, filt); + + for (y = 0; y < re->recty; y++) { + float *rf = rectf + 4 * y * re->rectx; + float *col = rres.rectf + 4 * y * re->rectx; - add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y); + for (x = 0; x < re->rectx; x++, rf += 4, col += 4) { + /* clamping to 1.0 is needed for correct AA */ + CLAMP(col[0], 0.0f, 1.0f); + CLAMP(col[1], 0.0f, 1.0f); + CLAMP(col[2], 0.0f, 1.0f); + + add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y); + } } - } - RE_ReleaseResultImage(re); + RE_ReleaseResultImage(re); - /* show stuff */ - if (sample != re->osa - 1) { - /* weak... the display callback wants an active renderlayer pointer... */ - re->result->renlay = render_get_active_layer(re, re->result); - re->display_update(re->duh, re->result, NULL); + /* show stuff */ + if (sample != re->osa - 1) { + /* weak... the display callback wants an active renderlayer pointer... */ + re->result->renlay = render_get_active_layer(re, re->result); + RE_SetActiveRenderView(re, rv->name); + re->display_update(re->duh, re->result, NULL); + } } - - if (re->test_break(re->tbh)) - break; } - /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */ - for (y = 0; y < re->recty; y++) { - float *rf = rectf + 4 * y * re->rectx; + for (nr = 0; nr < numviews; nr++) { + rectf = ((RenderView *)BLI_findlink(rectfs, nr))->rectf; + + /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */ + for (y = 0; y < re->recty; y++) { + float *rf = rectf + 4 * y * re->rectx; - for (x = 0; x < re->rectx; x++, rf += 4) { - rf[0] = MAX2(rf[0], 0.0f); - rf[1] = MAX2(rf[1], 0.0f); - rf[2] = MAX2(rf[2], 0.0f); - CLAMP(rf[3], 0.0f, 1.0f); + for (x = 0; x < re->rectx; x++, rf += 4) { + rf[0] = MAX2(rf[0], 0.0f); + rf[1] = MAX2(rf[1], 0.0f); + rf[2] = MAX2(rf[2], 0.0f); + CLAMP(rf[3], 0.0f, 1.0f); + } } + + /* store the final result */ + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + rv = RE_RenderViewGetById(re->result, nr); + if (rv->rectf) + MEM_freeN(rv->rectf); + rv->rectf = rectf; + BLI_rw_mutex_unlock(&re->resultmutex); } /* clear interaction callbacks */ @@ -2176,12 +2374,14 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) /* disable full sample print */ R.i.curfsa = 0; - - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - if (re->result->rectf) - MEM_freeN(re->result->rectf); - re->result->rectf = rectf; - BLI_rw_mutex_unlock(&re->resultmutex); + + /* garbage collection */ + while (rectfs->first) { + RenderView *rv = rectfs->first; + BLI_remlink(rectfs, rv); + MEM_freeN(rv); + } + MEM_freeN(rectfs); } /* called externally, via compositor */ @@ -2234,8 +2434,10 @@ void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree) re->display_clear(re->dch, re->result); #ifdef WITH_FREESTYLE - if (re->r.mode & R_EDGE_FRS) + if (re->r.mode & R_EDGE_FRS) { + init_freestyle(re); add_freestyle(re, 0); + } #endif do_merge_fullsample(re, ntree); @@ -2257,7 +2459,11 @@ static void do_render_composite_fields_blur_3d(Render *re) if (composite_needs_render(re->scene, 1)) { /* save memory... free all cached images */ ntreeFreeCache(ntree); - + + /* render the frames + * it could be optimized to render only the needed view + * but what if a scene has a different number of views + * than the main scene? */ do_render_fields_blur_3d(re); } else { @@ -2270,7 +2476,7 @@ static void do_render_composite_fields_blur_3d(Render *re) if ((re->r.mode & R_CROP) == 0) { render_result_disprect_to_full_resolution(re); } - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); BLI_rw_mutex_unlock(&re->resultmutex); @@ -2308,6 +2514,8 @@ static void do_render_composite_fields_blur_3d(Render *re) /* in case it was never initialized */ R.sdh = re->sdh; R.stats_draw = re->stats_draw; + R.i.starttime = re->i.starttime; + R.i.cfra = re->i.cfra; if (update_newframe) BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, re->lay); @@ -2315,7 +2523,10 @@ static void do_render_composite_fields_blur_3d(Render *re) if (re->r.scemode & R_FULL_SAMPLE) do_merge_fullsample(re, ntree); else { - ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings); + RenderView *rv; + for (rv = re->result->views.first; rv; rv = rv->next) { + ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name); + } } ntree->stats_draw = NULL; @@ -2340,11 +2551,17 @@ static void do_render_composite_fields_blur_3d(Render *re) static void renderresult_stampinfo(Render *re) { RenderResult rres; + RenderView *rv; + int nr; /* this is the basic trick to get the displayed float or char rect from render result */ - RE_AcquireResultImage(re, &rres); - BKE_stamp_buf(re->scene, RE_GetCamera(re), (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4); - RE_ReleaseResultImage(re); + nr = 0; + for (rv = re->result->views.first;rv;rv = rv->next, nr++) { + RE_SetActiveRenderView(re, rv->name); + RE_AcquireResultImage(re, &rres, nr); + BKE_image_stamp_buf(re->scene, RE_GetCamera(re), (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4); + RE_ReleaseResultImage(re); + } } int RE_seq_render_active(Scene *scene, RenderData *rd) @@ -2368,10 +2585,13 @@ int RE_seq_render_active(Scene *scene, RenderData *rd) static void do_render_seq(Render *re) { static int recurs_depth = 0; - struct ImBuf *ibuf, *out; + struct ImBuf *out; RenderResult *rr; /* don't assign re->result here as it might change during give_ibuf_seq */ int cfra = re->r.cfra; SeqRenderData context; + size_t view_id, tot_views; + struct ImBuf **ibuf_arr; + int re_x, re_y; re->i.cfra = cfra; @@ -2385,48 +2605,82 @@ static void do_render_seq(Render *re) if ((re->r.mode & R_BORDER) && (re->r.mode & R_CROP) == 0) { /* if border rendering is used and cropping is disabled, final buffer should * be as large as the whole frame */ - context = BKE_sequencer_new_render_data(re->eval_ctx, re->main, re->scene, - re->winx, re->winy, 100); + re_x = re->winx; + re_y = re->winy; } else { - context = BKE_sequencer_new_render_data(re->eval_ctx, re->main, re->scene, - re->result->rectx, re->result->recty, 100); + re_x = re->result->rectx; + re_y = re->result->recty; } - out = BKE_sequencer_give_ibuf(&context, cfra, 0); + tot_views = BKE_scene_multiview_num_views_get(&re->r); + ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * tot_views, "Sequencer Views ImBufs"); - if (out) { - ibuf = IMB_dupImBuf(out); - IMB_freeImBuf(out); - BKE_sequencer_imbuf_from_sequencer_space(re->scene, ibuf); - } - else { - ibuf = NULL; - } + BKE_sequencer_new_render_data( + re->eval_ctx, re->main, re->scene, + re_x, re_y, 100, + &context); - recurs_depth--; + /* the renderresult gets destroyed during the rendering, so we first collect all ibufs + * and then we populate the final renderesult */ + + for (view_id = 0; view_id < tot_views; view_id++) { + context.view_id = view_id; + out = BKE_sequencer_give_ibuf(&context, cfra, 0); + + if (out) { + ibuf_arr[view_id] = IMB_dupImBuf(out); + IMB_metadata_copy(ibuf_arr[view_id], out); + IMB_freeImBuf(out); + BKE_sequencer_imbuf_from_sequencer_space(re->scene, ibuf_arr[view_id]); + } + else { + ibuf_arr[view_id] = NULL; + } + } rr = re->result; - + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_views_new(rr, &re->r); + BLI_rw_mutex_unlock(&re->resultmutex); - if (ibuf) { - /* copy ibuf into combined pixel rect */ - render_result_rect_from_ibuf(rr, &re->r, ibuf); - - if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */ - Editing *ed = re->scene->ed; - if (ed) - BKE_sequencer_free_imbuf(re->scene, &ed->seqbase, true); + for (view_id = 0; view_id < tot_views; view_id++) { + RenderView *rv = RE_RenderViewGetById(rr, view_id); + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + + if (ibuf_arr[view_id]) { + /* copy ibuf into combined pixel rect */ + render_result_rect_from_ibuf(rr, &re->r, ibuf_arr[view_id], view_id); + + if (ibuf_arr[view_id]->metadata && (re->r.stamp & R_STAMP_STRIPMETA)) { + /* ensure render stamp info first */ + BKE_render_result_stamp_info(NULL, NULL, rr, true); + BKE_stamp_info_from_imbuf(rr, ibuf_arr[view_id]); + } + + if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */ + Editing *ed = re->scene->ed; + if (ed) + BKE_sequencer_free_imbuf(re->scene, &ed->seqbase, true); + } + IMB_freeImBuf(ibuf_arr[view_id]); } - IMB_freeImBuf(ibuf); - } - else { - /* render result is delivered empty in most cases, nevertheless we handle all cases */ - render_result_rect_fill_zero(rr); + else { + /* render result is delivered empty in most cases, nevertheless we handle all cases */ + render_result_rect_fill_zero(rr, view_id); + } + + BLI_rw_mutex_unlock(&re->resultmutex); + + /* would mark display buffers as invalid */ + RE_SetActiveRenderView(re, rv->name); + re->display_update(re->duh, re->result, NULL); } - BLI_rw_mutex_unlock(&re->resultmutex); + MEM_freeN(ibuf_arr); + + recurs_depth--; /* just in case this flag went missing at some point */ re->r.scemode |= R_DOSEQ; @@ -2436,9 +2690,6 @@ static void do_render_seq(Render *re) re->progress(re->prh, (float)(cfra - re->r.sfra) / (re->r.efra - re->r.sfra)); else re->progress(re->prh, 1.0f); - - /* would mark display buffers as invalid */ - re->display_update(re->duh, re->result, NULL); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -2446,6 +2697,9 @@ static void do_render_seq(Render *re) /* main loop: doing sequence + fields + blur + 3d render + compositing */ static void do_render_all_options(Render *re) { + Object *camera; + bool render_seq = false; + re->current_scene_update(re->suh, re->scene); BKE_scene_camera_switch_update(re->scene); @@ -2460,8 +2714,10 @@ static void do_render_all_options(Render *re) } else if (RE_seq_render_active(re->scene, &re->r)) { /* note: do_render_seq() frees rect32 when sequencer returns float images */ - if (!re->test_break(re->tbh)) + if (!re->test_break(re->tbh)) { do_render_seq(re); + render_seq = true; + } re->stats_draw(re->sdh, &re->i); re->display_update(re->duh, re->result, NULL); @@ -2479,6 +2735,12 @@ static void do_render_all_options(Render *re) re->stats_draw(re->sdh, &re->i); + /* save render result stamp if needed */ + camera = RE_GetCamera(re); + /* sequence rendering should have taken care of that already */ + if (!(render_seq && (re->r.stamp & R_STAMP_STRIPMETA))) + BKE_render_result_stamp_info(re->scene, camera, re->result, false); + /* stamp image info here */ if ((re->r.stamp & R_STAMP_ALL) && (re->r.stamp & R_STAMP_DRAW)) { renderresult_stampinfo(re); @@ -2525,11 +2787,50 @@ static bool check_valid_compositing_camera(Scene *scene, Object *camera_override } } +static bool check_valid_camera_multiview(Scene *scene, Object *camera, ReportList *reports) +{ + SceneRenderView *srv; + bool active_view = false; + + if ((scene->r.scemode & R_MULTIVIEW) == 0) + return true; + + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) { + active_view = true; + + if (scene->r.views_format == SCE_VIEWS_FORMAT_MULTIVIEW) { + Object *view_camera; + view_camera = BKE_camera_multiview_render(scene, camera, srv->name); + + if (view_camera == camera) { + /* if the suffix is not in the camera, means we are using the fallback camera */ + if (!BLI_str_endswith(view_camera->id.name + 2, srv->suffix)) { + BKE_reportf(reports, RPT_ERROR, "Camera \"%s\" is not a multi-view camera", + camera->id.name + 2); + return false; + } + } + } + } + } + + if (!active_view) { + BKE_reportf(reports, RPT_ERROR, "No active view found in scene \"%s\"", scene->id.name + 2); + return false; + } + + return true; +} + static int check_valid_camera(Scene *scene, Object *camera_override, ReportList *reports) { if (camera_override == NULL && scene->camera == NULL) scene->camera = BKE_scene_camera_find(scene); + if (!check_valid_camera_multiview(scene, scene->camera, reports)) + return false; + if (RE_seq_render_active(scene, &scene->r)) { if (scene->ed) { Sequence *seq = scene->ed->seqbase.first; @@ -2547,6 +2848,8 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList } } } + else if (!check_valid_camera_multiview(seq->scene, seq->scene_camera, reports)) + return false; } seq = seq->next; @@ -2711,6 +3014,17 @@ static void update_physics_cache(Render *re, Scene *scene, int UNUSED(anim_init) BKE_ptcache_bake(&baker); } + +void RE_SetActiveRenderView(Render *re, const char *viewname) +{ + BLI_strncpy(re->viewname, viewname, sizeof(re->viewname)); +} + +const char *RE_GetActiveRenderView(Render *re) +{ + return re->viewname; +} + /* evaluating scene options for general Blender render */ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, Scene *scene, SceneRenderLayer *srl, Object *camera_override, unsigned int lay_override, int anim, int anim_init) @@ -2746,7 +3060,8 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, re->lay = lay_override ? lay_override : scene->lay; re->layer_override = lay_override; re->i.localview = (re->lay & 0xFF000000) != 0; - + re->viewname[0] = '\0'; + /* not too nice, but it survives anim-border render */ if (anim) { render_update_anim_renderdata(re, &scene->r); @@ -2818,15 +3133,19 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr } else { char name[FILE_MAX]; - BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false); + BKE_image_path_from_imformat( + name, scene->r.pic, bmain->name, scene->r.cfra, + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL); /* reports only used for Movie */ - do_write_image_or_movie(re, bmain, scene, NULL, name); + do_write_image_or_movie(re, bmain, scene, NULL, 0, name); } } BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */ + if (write_still) { + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE); + } } BLI_callback_exec(re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE); @@ -2851,111 +3170,287 @@ void RE_RenderFreestyleExternal(Render *re) if (!re->test_break(re->tbh)) { RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); RE_Database_Preprocess(re); + init_freestyle(re); add_freestyle(re, 1); RE_Database_Free(re); } } #endif -static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override) +bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scene, const bool stamp, char *name) { - char name[FILE_MAX]; - RenderResult rres; - Object *camera = RE_GetCamera(re); - double render_time; - int ok = 1; - - RE_AcquireResultImage(re, &rres); + bool is_mono; + bool ok = true; + RenderData *rd = &scene->r; - /* write movie or image */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { - bool do_free = false; - ImBuf *ibuf = render_result_rect_to_ibuf(&rres, &scene->r); + if (!rr) + return false; - /* note; the way it gets 32 bits rects is weak... */ - if (ibuf->rect == NULL) { - ibuf->rect = MEM_mapallocN(sizeof(int) * rres.rectx * rres.recty, "temp 32 bits rect"); - ibuf->mall |= IB_rect; - RE_AcquiredResultGet32(re, &rres, ibuf->rect); - do_free = true; - } + is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; + if (ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && + rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW) + { + RE_WriteRenderResult(reports, rr, name, &rd->im_format, true, NULL); + printf("Saved: %s\n", name); + } - IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, - &scene->display_settings, &scene->r.im_format); + /* mono, legacy code */ + else if (is_mono || (rd->im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) + { + RenderView *rv; + size_t view_id; + char filepath[FILE_MAX]; - ok = mh->append_movie(&re->r, scene->r.sfra, scene->r.cfra, (int *) ibuf->rect, - ibuf->x, ibuf->y, re->reports); - if (do_free) { - MEM_freeN(ibuf->rect); - ibuf->rect = NULL; - ibuf->mall &= ~IB_rect; - } + BLI_strncpy(filepath, name, sizeof(filepath)); - /* imbuf knows which rects are not part of ibuf */ - IMB_freeImBuf(ibuf); + for (view_id = 0, rv = rr->views.first; rv; rv = rv->next, view_id++) { + if (!is_mono) { + BKE_scene_multiview_view_filepath_get(&scene->r, filepath, rv->name, name); + } - printf("Append frame %d", scene->r.cfra); - } - else { - if (name_override) - BLI_strncpy(name, name_override, sizeof(name)); - else - BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true); - - if (re->r.im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { - if (re->result) { - RE_WriteRenderResult(re->reports, re->result, name, scene->r.im_format.exr_codec); - printf("Saved: %s", name); + if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { + RE_WriteRenderResult(reports, rr, name, &rd->im_format, false, rv->name); + printf("Saved: %s\n", name); + } + else { + ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id); + + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + &scene->display_settings, &rd->im_format); + + if (stamp) { + /* writes the name of the individual cameras */ + ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &rd->im_format); + } + else { + ok = BKE_imbuf_write(ibuf, name, &rd->im_format); + } + + if (ok == false) { + printf("Render error: cannot save %s\n", name); + } + else printf("Saved: %s\n", name); + + /* optional preview images for exr */ + if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { + ImageFormatData imf = rd->im_format; + imf.imtype = R_IMF_IMTYPE_JPEG90; + + if (BLI_testextensie(name, ".exr")) + name[strlen(name) - 4] = 0; + BKE_image_path_ensure_ext_from_imformat(name, &imf); + ibuf->planes = 24; + + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + &scene->display_settings, &imf); + + if (stamp) { + /* writes the name of the individual cameras */ + ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &imf); + } + else { + ok = BKE_imbuf_write(ibuf, name, &imf); + } + printf("Saved: %s\n", name); + } + + /* imbuf knows which rects are not part of ibuf */ + IMB_freeImBuf(ibuf); } } + } + else { /* R_IMF_VIEWS_STEREO_3D */ + BLI_assert(scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D); + + if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { + printf("Stereo 3D not support for MultiLayer image: %s\n", name); + } else { - ImBuf *ibuf = render_result_rect_to_ibuf(&rres, &scene->r); + ImBuf *ibuf_arr[3] = {NULL}; + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; + int i; + + for (i = 0; i < 2; i++) { + int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name)); + ibuf_arr[i] = render_result_rect_to_ibuf(rr, rd, view_id); + IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &scene->view_settings, + &scene->display_settings, &scene->r.im_format); + IMB_prepare_write_ImBuf(IMB_isfloat(ibuf_arr[i]), ibuf_arr[i]); + } - IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, - &scene->display_settings, &scene->r.im_format); + ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]); - ok = BKE_imbuf_write_stamp(scene, camera, ibuf, name, &scene->r.im_format); - - if (ok == 0) { + if (stamp) + ok = BKE_imbuf_write_stamp(scene, rr, ibuf_arr[2], name, &rd->im_format); + else + ok = BKE_imbuf_write(ibuf_arr[2], name, &rd->im_format); + + if (ok == false) printf("Render error: cannot save %s\n", name); - } - else printf("Saved: %s", name); - + else + printf("Saved: %s\n", name); + /* optional preview images for exr */ - if (ok && scene->r.im_format.imtype == R_IMF_IMTYPE_OPENEXR && (scene->r.im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { - ImageFormatData imf = scene->r.im_format; + if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR && + (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) + { + ImageFormatData imf = rd->im_format; imf.imtype = R_IMF_IMTYPE_JPEG90; if (BLI_testextensie(name, ".exr")) name[strlen(name) - 4] = 0; - BKE_add_image_extension(name, &imf); - ibuf->planes = 24; - IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + BKE_image_path_ensure_ext_from_imformat(name, &imf); + ibuf_arr[2]->planes = 24; + + IMB_colormanagement_imbuf_for_write(ibuf_arr[2], true, false, &scene->view_settings, &scene->display_settings, &imf); - BKE_imbuf_write_stamp(scene, camera, ibuf, name, &imf); - printf("\nSaved: %s", name); + if (stamp) + ok = BKE_imbuf_write_stamp(scene, rr, ibuf_arr[2], name, &rd->im_format); + else + ok = BKE_imbuf_write(ibuf_arr[2], name, &imf); + + printf("Saved: %s\n", name); } - + + /* imbuf knows which rects are not part of ibuf */ + for (i = 0; i < 3; i++) { + IMB_freeImBuf(ibuf_arr[i]); + } + } + } + + return ok; +} + +bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scene, RenderData *rd, bMovieHandle *mh, + const size_t width, const size_t height, void **movie_ctx_arr, const size_t totvideos, bool preview) +{ + bool is_mono; + bool ok = true; + + if (!rr) + return false; + + is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; + + if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { + size_t view_id; + for (view_id = 0; view_id < totvideos; view_id++) { + bool do_free = false; + const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id); + ImBuf *ibuf = render_result_rect_to_ibuf(rr, &scene->r, view_id); + + /* note; the way it gets 32 bits rects is weak... */ + if (ibuf->rect == NULL) { + ibuf->rect = MEM_mapallocN(sizeof(int) * rr->rectx * rr->recty, "temp 32 bits rect"); + ibuf->mall |= IB_rect; + render_result_rect_get_pixels(rr, ibuf->rect, width, height, &scene->view_settings, &scene->display_settings, view_id); + do_free = true; + } + + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + &scene->display_settings, &scene->r.im_format); + + ok &= mh->append_movie(movie_ctx_arr[view_id], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra, + (int *) ibuf->rect, ibuf->x, ibuf->y, suffix, reports); + + if (do_free) { + MEM_freeN(ibuf->rect); + ibuf->rect = NULL; + ibuf->mall &= ~IB_rect; + } + /* imbuf knows which rects are not part of ibuf */ IMB_freeImBuf(ibuf); } + printf("Append frame %d\n", scene->r.cfra); + } + else { /* R_IMF_VIEWS_STEREO_3D */ + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; + ImBuf *ibuf_arr[3] = {NULL}; + bool do_free[2] = {false, false}; + size_t i; + + BLI_assert((totvideos == 1) && (scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D)); + + for (i = 0; i < 2; i++) { + int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name)); + ibuf_arr[i] = render_result_rect_to_ibuf(rr, &scene->r, view_id); + + /* note; the way it gets 32 bits rects is weak... */ + if (ibuf_arr[i]->rect == NULL) { + ibuf_arr[i]->rect = MEM_mapallocN(sizeof(int) * width * height, "temp 32 bits rect"); + ibuf_arr[i]->mall |= IB_rect; + render_result_rect_get_pixels(rr, ibuf_arr[i]->rect, width, height, &scene->view_settings, &scene->display_settings, view_id); + do_free[i] = true; + } + + IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &scene->view_settings, + &scene->display_settings, &scene->r.im_format); + } + + ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]); + + ok = mh->append_movie(movie_ctx_arr[0], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra, (int *) ibuf_arr[2]->rect, + ibuf_arr[2]->x, ibuf_arr[2]->y, "", reports); + + for (i = 0; i < 2; i++) { + if (do_free[i]) { + MEM_freeN(ibuf_arr[i]->rect); + ibuf_arr[i]->rect = NULL; + ibuf_arr[i]->mall &= ~IB_rect; + } + + /* imbuf knows which rects are not part of ibuf */ + IMB_freeImBuf(ibuf_arr[i]); + } + } + + return ok; +} + +static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override) +{ + char name[FILE_MAX]; + RenderResult rres; + double render_time; + bool ok = true; + + RE_AcquireResultImageViews(re, &rres); + + /* write movie or image */ + if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { + RE_WriteRenderViewsMovie(re->reports, &rres, scene, &re->r, mh, re->rectx, re->recty, re->movie_ctx_arr, totvideos, false); + } + else { + if (name_override) + BLI_strncpy(name, name_override, sizeof(name)); + else + BKE_image_path_from_imformat( + name, scene->r.pic, bmain->name, scene->r.cfra, + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); + + /* write images as individual images or stereo */ + ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, true, name); } - RE_ReleaseResultImage(re); + RE_ReleaseResultImageViews(re, &rres); render_time = re->i.lastframetime; re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime; - BLI_timestr(re->i.lastframetime, name, sizeof(name)); + BLI_timecode_string_from_time_simple(name, sizeof(name), re->i.lastframetime); printf(" Time: %s", name); - + + /* Flush stdout to be sure python callbacks are printing stuff after blender. */ + fflush(stdout); + BLI_callback_exec(G.main, NULL, BLI_CB_EVT_RENDER_STATS); - BLI_timestr(re->i.lastframetime - render_time, name, sizeof(name)); + BLI_timecode_string_from_time_simple(name, sizeof(name), re->i.lastframetime - render_time); printf(" (Saving: %s)\n", name); fputc('\n', stdout); @@ -2964,20 +3459,51 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie return ok; } +static void get_videos_dimensions(Render *re, RenderData *rd, size_t *r_width, size_t *r_height) +{ + size_t width, height; + if (re->r.mode & R_BORDER) { + if ((re->r.mode & R_CROP) == 0) { + width = re->winx; + height = re->winy; + } + else { + width = re->rectx; + height = re->recty; + } + } + else { + width = re->rectx; + height = re->recty; + } + + BKE_scene_multiview_videos_dimensions_get(rd, width, height, r_width, r_height); +} + /* saves images to disk */ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_override, unsigned int lay_override, int sfra, int efra, int tfra) { RenderData rd = scene->r; - bMovieHandle *mh = BKE_movie_handle_get(scene->r.im_format.imtype); + bMovieHandle *mh = NULL; int cfrao = scene->r.cfra; int nfra, totrendered = 0, totskipped = 0; - + const size_t totvideos = BKE_scene_multiview_num_videos_get(&rd); + const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype); + const bool is_multiview_name = ((scene->r.scemode & R_MULTIVIEW) != 0 && + (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)); + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT); /* do not fully call for each frame, it initializes & pops output window */ if (!render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 0, 1)) return; + + /* we don't support Frame Server and streaming of individual views */ + if ((rd.im_format.imtype == R_IMF_IMTYPE_FRAMESERVER) && (totvideos > 1)) { + BKE_report(re->reports, RPT_ERROR, "Frame Server only support stereo output for multiview rendering"); + return; + } /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */ /* is also set by caller renderwin.c */ @@ -2985,30 +3511,38 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri re->flag |= R_ANIMATION; - if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { - int width, height; - if (re->r.mode & R_BORDER) { - if ((re->r.mode & R_CROP) == 0) { - width = re->winx; - height = re->winy; - } - else { - width = re->rectx; - height = re->recty; - } - } - else { - width = re->rectx; - height = re->recty; + if (is_movie) { + size_t i, width, height; + + get_videos_dimensions(re, &rd, &width, &height); + + mh = BKE_movie_handle_get(scene->r.im_format.imtype); + if (mh == NULL) { + BKE_report(re->reports, RPT_ERROR, "Movie format unsupported"); + return; } - if (!mh->start_movie(scene, &re->r, width, height, re->reports)) - G.is_break = true; + re->movie_ctx_arr = MEM_mallocN(sizeof(void *) * totvideos, "Movies' Context"); + + for (i = 0; i < totvideos; i++) { + const char *suffix = BKE_scene_multiview_view_id_suffix_get(&re->r, i); + + re->movie_ctx_arr[i] = mh->context_create(); + + if (!mh->start_movie(re->movie_ctx_arr[i], scene, &re->r, width, height, re->reports, false, suffix)) + G.is_break = true; + } } - if (mh->get_next_frame) { + if (mh && mh->get_next_frame) { + /* MULTIVIEW_TODO: + * in case a new video format is added that implements get_next_frame multiview has to be addressed + * or the error throwing for R_IMF_IMTYPE_FRAMESERVER has to be extended for those cases as well + */ + BLI_assert(totvideos < 2); + while (!(G.is_break == 1)) { - int nf = mh->get_next_frame(&re->r, re->reports); + int nf = mh->get_next_frame(re->movie_ctx_arr[0], &re->r, re->reports); if (nf >= 0 && nf >= scene->r.sfra && nf <= scene->r.efra) { scene->r.cfra = re->r.cfra = nf; @@ -3018,12 +3552,13 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri totrendered++; if (re->test_break(re->tbh) == 0) { - if (!do_write_image_or_movie(re, bmain, scene, mh, NULL)) + if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL)) G.is_break = true; } if (G.is_break == false) { BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */ + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE); } } else { @@ -3060,19 +3595,67 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri nfra += tfra; /* Touch/NoOverwrite options are only valid for image's */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) { + if (is_movie == false) { if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH)) - BKE_makepicstring(name, scene->r.pic, 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, bmain->name, scene->r.cfra, + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); + + if (scene->r.mode & R_NO_OVERWRITE) { + if (!is_multiview_name) { + if (BLI_exists(name)) { + printf("skipping existing frame \"%s\"\n", name); + totskipped++; + continue; + } + } + else { + SceneRenderView *srv; + bool is_skip = false; + char filepath[FILE_MAX]; - if (scene->r.mode & R_NO_OVERWRITE && BLI_exists(name)) { - printf("skipping existing frame \"%s\"\n", name); - totskipped++; - continue; + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) + continue; + + BKE_scene_multiview_filepath_get(srv, name, filepath); + + if (BLI_exists(filepath)) { + is_skip = true; + printf("skipping existing frame \"%s\" for view \"%s\"\n", filepath, srv->name); + } + } + + if (is_skip) { + totskipped++; + continue; + } + } } - if (scene->r.mode & R_TOUCH && !BLI_exists(name)) { - BLI_make_existing_file(name); /* makes the dir if its not there */ - BLI_file_touch(name); + + if (scene->r.mode & R_TOUCH) { + if (!is_multiview_name) { + if (!BLI_exists(name)) { + BLI_make_existing_file(name); /* makes the dir if its not there */ + BLI_file_touch(name); + } + } + else { + SceneRenderView *srv; + char filepath[FILE_MAX]; + + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) + continue; + + BKE_scene_multiview_filepath_get(srv, name, filepath); + + if (!BLI_exists(filepath)) { + BLI_make_existing_file(filepath); /* makes the dir if its not there */ + BLI_file_touch(filepath); + } + } + } } } @@ -3087,7 +3670,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri if (re->test_break(re->tbh) == 0) { if (!G.is_break) - if (!do_write_image_or_movie(re, bmain, scene, mh, NULL)) + if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL)) G.is_break = true; } else @@ -3095,9 +3678,30 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri if (G.is_break == true) { /* remove touched file */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) { - if (scene->r.mode & R_TOUCH && BLI_exists(name) && BLI_file_size(name) == 0) { - BLI_delete(name, false, false); + if (is_movie == false) { + if ((scene->r.mode & R_TOUCH)) { + if (!is_multiview_name) { + if ((BLI_file_size(name) == 0)) { + /* BLI_exists(name) is implicit */ + BLI_delete(name, false, false); + } + } + else { + SceneRenderView *srv; + char filepath[FILE_MAX]; + + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) + continue; + + BKE_scene_multiview_filepath_get(srv, name, filepath); + + if ((BLI_file_size(filepath) == 0)) { + /* BLI_exists(filepath) is implicit */ + BLI_delete(filepath, false, false); + } + } + } } } @@ -3106,13 +3710,23 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri if (G.is_break == false) { BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */ + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE); } } } /* end movie */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype)) - mh->end_movie(); + if (is_movie) { + size_t i; + for (i = 0; i < totvideos; i++) { + mh->end_movie(re->movie_ctx_arr[i]); + mh->context_free(re->movie_ctx_arr[i]); + } + + if (re->movie_ctx_arr) { + MEM_freeN(re->movie_ctx_arr); + } + } if (totskipped && totrendered == 0) BKE_report(re->reports, RPT_INFO, "No frames rendered, skipped to not overwrite"); @@ -3210,13 +3824,22 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char { /* OCIO_TODO: assume layer was saved in defaule color space */ ImBuf *ibuf = IMB_loadiffname(filename, IB_rect, NULL); + RenderPass *rpass = NULL; + + /* multiview: since the API takes no 'view', we use the first combined pass found */ + for (rpass = layer->passes.first; rpass; rpass = rpass->next) + if (rpass->passtype == SCE_PASS_COMBINED) + break; + + if (rpass == NULL) + BKE_reportf(reports, RPT_ERROR, "%s: no Combined pass found in the render layer '%s'", __func__, filename); if (ibuf && (ibuf->rect || ibuf->rect_float)) { if (ibuf->x == layer->rectx && ibuf->y == layer->recty) { if (ibuf->rect_float == NULL) IMB_float_from_rect(ibuf); - memcpy(layer->rectf, ibuf->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); + memcpy(rpass->rect, ibuf->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); } else { if ((ibuf->x - x >= layer->rectx) && (ibuf->y - y >= layer->recty)) { @@ -3229,29 +3852,29 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char if (ibuf_clip) { IMB_rectcpy(ibuf_clip, ibuf, 0, 0, x, y, layer->rectx, layer->recty); - memcpy(layer->rectf, ibuf_clip->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); + memcpy(rpass->rect, ibuf_clip->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); IMB_freeImBuf(ibuf_clip); } else { - BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to allocate clip buffer '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "%s: failed to allocate clip buffer '%s'", __func__, filename); } } else { - BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: incorrect dimensions for partial copy '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "%s: incorrect dimensions for partial copy '%s'", __func__, filename); } } IMB_freeImBuf(ibuf); } else { - BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filename); } } void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filename) { if (!render_result_exr_file_read_path(result, NULL, filename)) { - BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filename); return; } } @@ -3317,3 +3940,35 @@ bool RE_WriteEnvmapResult(struct ReportList *reports, Scene *scene, EnvMap *env, } } +/* used in the interface to decide whether to show layers */ +bool RE_layers_have_name(struct RenderResult *rr) +{ + switch (BLI_listbase_count_ex(&rr->layers, 2)) { + case 0: + return false; + break; + case 1: + return (((RenderLayer *)rr->layers.first)->name[0] != '\0'); + break; + default: + return true; + break; + } + return false; +} + +RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname) +{ + RenderPass *rp = NULL; + + for (rp = rl->passes.last; rp; rp = rp->prev) { + if (rp->passtype == passtype) { + + if (viewname == NULL || viewname[0] == '\0') + break; + else if (STREQ(rp->view, viewname)) + break; + } + } + return rp; +} diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c index 460a6814f07..32fb196e1f3 100644 --- a/source/blender/render/intern/source/pixelblending.c +++ b/source/blender/render/intern/source/pixelblending.c @@ -38,7 +38,6 @@ /* own includes */ #include "render_types.h" -#include "renderpipeline.h" #include "pixelblending.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c index 014df802a78..104cde0a0b5 100644 --- a/source/blender/render/intern/source/pixelshading.c +++ b/source/blender/render/intern/source/pixelshading.c @@ -36,8 +36,6 @@ #include "BLI_utildefines.h" /* External modules: */ -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" #include "DNA_group_types.h" #include "DNA_material_types.h" @@ -51,14 +49,11 @@ /* own module */ #include "render_types.h" -#include "renderpipeline.h" #include "renderdatabase.h" #include "texture.h" -#include "pixelblending.h" #include "rendercore.h" #include "shadbuf.h" #include "pixelshading.h" -#include "shading.h" #include "sunsky.h" /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -160,7 +155,7 @@ static void render_lighting_halo(HaloRen *har, float col_r[3]) x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2])); /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */ - inpr = 1.0 / (sqrtf(1.0f + x * x)); + inpr = 1.0f / (sqrtf(1.0f + x * x)); } else inpr= 0.0; } @@ -206,7 +201,7 @@ static void render_lighting_halo(HaloRen *har, float col_r[3]) /* dot product and reflectivity*/ - inp = 1.0 - fabsf(dot_v3v3(vn, lv)); + inp = 1.0f - fabsf(dot_v3v3(vn, lv)); /* inp= cos(0.5*M_PI-acos(inp)); */ @@ -366,7 +361,7 @@ int shadeHaloFloat(HaloRen *har, float col[4], int zz, else dist= dist/har->radsq; if (har->type & HA_FLARECIRC) { - dist = 0.5 + fabsf(dist - 0.5f); + dist = 0.5f + fabsf(dist - 0.5f); } if (har->hard>=30) { diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index ac2e85a33b3..b8d8cc37ae3 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -1,4 +1,4 @@ -/* +/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -40,11 +40,12 @@ #include "BLI_kdopbvh.h" #include "BLI_utildefines.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "BKE_DerivedMesh.h" #include "BKE_lattice.h" #include "BKE_main.h" +#include "BKE_object.h" #include "BKE_particle.h" #include "BKE_scene.h" #include "BKE_texture.h" @@ -55,39 +56,50 @@ #include "DNA_particle_types.h" #include "render_types.h" -#include "renderdatabase.h" #include "texture.h" #include "pointdensity.h" +#include "RE_render_ext.h" + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ /* only to be used here in this file, it's for speed */ extern struct Render R; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +static ThreadMutex sample_mutex = PTHREAD_MUTEX_INITIALIZER; static int point_data_used(PointDensity *pd) { int pd_bitflag = 0; - + if (pd->source == TEX_PD_PSYS) { - if ((pd->noise_influence == TEX_PD_NOISE_VEL) || (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) || (pd->color_source == TEX_PD_COLOR_PARTVEL) || (pd->color_source == TEX_PD_COLOR_PARTSPEED)) + if ((pd->noise_influence == TEX_PD_NOISE_VEL) || + (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) || + (pd->color_source == TEX_PD_COLOR_PARTVEL) || + (pd->color_source == TEX_PD_COLOR_PARTSPEED)) + { pd_bitflag |= POINT_DATA_VEL; - if ((pd->noise_influence == TEX_PD_NOISE_AGE) || (pd->color_source == TEX_PD_COLOR_PARTAGE) || (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE)) + } + if ((pd->noise_influence == TEX_PD_NOISE_AGE) || + (pd->color_source == TEX_PD_COLOR_PARTAGE) || + (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE)) + { pd_bitflag |= POINT_DATA_LIFE; + } } - + return pd_bitflag; } -/* additional data stored alongside the point density BVH, - * accessible by point index number to retrieve other information +/* additional data stored alongside the point density BVH, + * accessible by point index number to retrieve other information * such as particle velocity or lifetime */ static void alloc_point_data(PointDensity *pd, int total_particles, int point_data_used) { int data_size = 0; - + if (point_data_used & POINT_DATA_VEL) { /* store 3 channels of velocity data */ data_size += 3; @@ -97,60 +109,70 @@ static void alloc_point_data(PointDensity *pd, int total_particles, int point_da data_size += 1; } - if (data_size) - pd->point_data = MEM_mallocN(sizeof(float)*data_size*total_particles, "particle point data"); + if (data_size) { + pd->point_data = MEM_mallocN(sizeof(float) * data_size * total_particles, + "particle point data"); + } } -static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys) +static void pointdensity_cache_psys(Scene *scene, + PointDensity *pd, + Object *ob, + ParticleSystem *psys, + float viewmat[4][4], + float winmat[4][4], + int winx, int winy) { - DerivedMesh* dm; + DerivedMesh *dm; ParticleKey state; ParticleCacheKey *cache; - ParticleSimulationData sim= {NULL}; - ParticleData *pa=NULL; - float cfra = BKE_scene_frame_get(re->scene); + ParticleSimulationData sim = {NULL}; + ParticleData *pa = NULL; + float cfra = BKE_scene_frame_get(scene); int i /*, childexists*/ /* UNUSED */; - int total_particles, offset=0; + int total_particles, offset = 0; int data_used = point_data_used(pd); float partco[3]; - float obview[4][4]; - + /* init everything */ - if (!psys || !ob || !pd) return; + if (!psys || !ob || !pd) { + return; + } - mul_m4_m4m4(obview, ob->obmat, re->viewinv); - /* Just to create a valid rendering context for particles */ - psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0); - - dm = mesh_create_derived_render(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); - + psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0); + + dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + if ( !psys_check_enabled(ob, psys)) { psys_render_restore(ob, psys); return; } - - sim.scene= re->scene; - sim.ob= ob; - sim.psys= psys; + + sim.scene = scene; + sim.ob = ob; + sim.psys = psys; + sim.psmd = psys_get_modifier(ob, psys); /* in case ob->imat isn't up-to-date */ invert_m4_m4(ob->imat, ob->obmat); - - total_particles = psys->totpart+psys->totchild; + + total_particles = psys->totpart + psys->totchild; psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); - + pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); alloc_point_data(pd, total_particles, data_used); pd->totpoints = total_particles; - if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3; - + if (data_used & POINT_DATA_VEL) { + offset = pd->totpoints * 3; + } + #if 0 /* UNUSED */ if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) childexists = 1; #endif - for (i=0, pa=psys->particles; i < total_particles; i++, pa++) { + for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) { if (psys->part->type == PART_HAIR) { /* hair particles */ @@ -161,7 +183,7 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa else continue; - cache += cache->steps; /* use endpoint */ + cache += cache->segments; /* use endpoint */ copy_v3_v3(state.co, cache->co); zero_v3(state.vel); @@ -176,19 +198,19 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa if (data_used & POINT_DATA_LIFE) { if (i < psys->totpart) { - state.time = (cfra - pa->time)/pa->lifetime; + state.time = (cfra - pa->time) / pa->lifetime; } else { - ChildParticle *cpa= (psys->child + i) - psys->totpart; + ChildParticle *cpa = (psys->child + i) - psys->totpart; float pa_birthtime, pa_dietime; - + state.time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); } } } copy_v3_v3(partco, state.co); - + if (pd->psys_cache_space == TEX_PD_OBJECTSPACE) mul_m4_v3(ob->imat, partco); else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) { @@ -197,48 +219,50 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa else { /* TEX_PD_WORLDSPACE */ } - + BLI_bvhtree_insert(pd->point_tree, i, partco, 1); - + if (data_used & POINT_DATA_VEL) { - pd->point_data[i*3 + 0] = state.vel[0]; - pd->point_data[i*3 + 1] = state.vel[1]; - pd->point_data[i*3 + 2] = state.vel[2]; + pd->point_data[i * 3 + 0] = state.vel[0]; + pd->point_data[i * 3 + 1] = state.vel[1]; + pd->point_data[i * 3 + 2] = state.vel[2]; } if (data_used & POINT_DATA_LIFE) { pd->point_data[offset + i] = state.time; } } - + BLI_bvhtree_balance(pd->point_tree); dm->release(dm); - + if (psys->lattice_deform_data) { end_latt_deform(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } - + psys_render_restore(ob, psys); } -static void pointdensity_cache_object(Render *re, PointDensity *pd, Object *ob) +static void pointdensity_cache_object(Scene *scene, PointDensity *pd, Object *ob) { int i; DerivedMesh *dm; MVert *mvert = NULL; - - dm = mesh_create_derived_render(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); - mvert= dm->getVertArray(dm); /* local object space */ - - pd->totpoints= dm->getNumVerts(dm); - if (pd->totpoints == 0) return; + + dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); + mvert = dm->getVertArray(dm); /* local object space */ + + pd->totpoints = dm->getNumVerts(dm); + if (pd->totpoints == 0) { + return; + } pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6); - - for (i=0; i < pd->totpoints; i++, mvert++) { + + for (i = 0; i < pd->totpoints; i++, mvert++) { float co[3]; - + copy_v3_v3(co, mvert->co); switch (pd->ob_cache_space) { @@ -256,47 +280,60 @@ static void pointdensity_cache_object(Render *re, PointDensity *pd, Object *ob) BLI_bvhtree_insert(pd->point_tree, i, co, 1); } - + BLI_bvhtree_balance(pd->point_tree); dm->release(dm); } -void cache_pointdensity(Render *re, Tex *tex) + +static void cache_pointdensity_ex(Scene *scene, + PointDensity *pd, + float viewmat[4][4], + float winmat[4][4], + int winx, int winy) { - PointDensity *pd = tex->pd; - - if (!pd) + if (pd == NULL) { return; + } if (pd->point_tree) { BLI_bvhtree_free(pd->point_tree); pd->point_tree = NULL; } - + if (pd->source == TEX_PD_PSYS) { Object *ob = pd->object; ParticleSystem *psys; - if (!ob || !pd->psys) return; + if (!ob || !pd->psys) { + return; + } + + psys = BLI_findlink(&ob->particlesystem, pd->psys - 1); + if (!psys) { + return; + } - psys= BLI_findlink(&ob->particlesystem, pd->psys-1); - if (!psys) return; - - pointdensity_cache_psys(re, pd, ob, psys); + pointdensity_cache_psys(scene, pd, ob, psys, viewmat, winmat, winx, winy); } else if (pd->source == TEX_PD_OBJECT) { Object *ob = pd->object; if (ob && ob->type == OB_MESH) - pointdensity_cache_object(re, pd, ob); + pointdensity_cache_object(scene, pd, ob); } } -static void free_pointdensity(Render *UNUSED(re), Tex *tex) +void cache_pointdensity(Render *re, PointDensity *pd) { - PointDensity *pd = tex->pd; + cache_pointdensity_ex(re->scene, pd, re->viewmat, re->winmat, re->winx, re->winy); +} + +void free_pointdensity(PointDensity *pd) +{ + if (pd == NULL) { + return; + } - if (!pd) return; - if (pd->point_tree) { BLI_bvhtree_free(pd->point_tree); pd->point_tree = NULL; @@ -309,24 +346,23 @@ static void free_pointdensity(Render *UNUSED(re), Tex *tex) pd->totpoints = 0; } - - void make_pointdensities(Render *re) { Tex *tex; - - if (re->scene->r.scemode & R_BUTS_PREVIEW) + + if (re->scene->r.scemode & R_BUTS_PREVIEW) { return; - + } + re->i.infostr = IFACE_("Caching Point Densities"); re->stats_draw(re->sdh, &re->i); - for (tex= re->main->tex.first; tex; tex= tex->id.next) { - if (tex->id.us && tex->type==TEX_POINTDENSITY) { - cache_pointdensity(re, tex); + for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) { + if (tex->id.us && tex->type == TEX_POINTDENSITY) { + cache_pointdensity(re, tex->pd); } } - + re->i.infostr = NULL; re->stats_draw(re->sdh, &re->i); } @@ -334,13 +370,13 @@ void make_pointdensities(Render *re) void free_pointdensities(Render *re) { Tex *tex; - + if (re->scene->r.scemode & R_BUTS_PREVIEW) return; - - for (tex= re->main->tex.first; tex; tex= tex->id.next) { - if (tex->id.us && tex->type==TEX_POINTDENSITY) { - free_pointdensity(re, tex); + + for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) { + if (tex->id.us && tex->type == TEX_POINTDENSITY) { + free_pointdensity(tex->pd); } } } @@ -365,20 +401,20 @@ static void accum_density(void *userdata, int index, float squared_dist) PointDensityRangeData *pdr = (PointDensityRangeData *)userdata; const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f; float density = 0.0f; - + if (pdr->point_data_used & POINT_DATA_VEL) { - pdr->vec[0] += pdr->point_data[index*3 + 0]; // * density; - pdr->vec[1] += pdr->point_data[index*3 + 1]; // * density; - pdr->vec[2] += pdr->point_data[index*3 + 2]; // * density; + pdr->vec[0] += pdr->point_data[index * 3 + 0]; // * density; + pdr->vec[1] += pdr->point_data[index * 3 + 1]; // * density; + pdr->vec[2] += pdr->point_data[index * 3 + 2]; // * density; } if (pdr->point_data_used & POINT_DATA_LIFE) { *pdr->age += pdr->point_data[pdr->offset + index]; // * density; } - + if (pdr->falloff_type == TEX_PD_FALLOFF_STD) density = dist; else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH) - density = 3.0f*dist*dist - 2.0f*dist*dist*dist; + density = 3.0f * dist * dist - 2.0f * dist * dist * dist; else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT) density = pow(dist, pdr->softness); else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT) @@ -387,30 +423,30 @@ static void accum_density(void *userdata, int index, float squared_dist) density = sqrtf(dist); else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE) { if (pdr->point_data_used & POINT_DATA_LIFE) - density = dist*MIN2(pdr->point_data[pdr->offset + index], 1.0f); + density = dist * MIN2(pdr->point_data[pdr->offset + index], 1.0f); else density = dist; } else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) { if (pdr->point_data_used & POINT_DATA_VEL) - density = dist*len_v3(pdr->point_data + index*3)*pdr->velscale; + density = dist * len_v3(pdr->point_data + index * 3) * pdr->velscale; else density = dist; } - + if (pdr->density_curve && dist != 0.0f) { curvemapping_initialize(pdr->density_curve); - density = curvemapping_evaluateF(pdr->density_curve, 0, density/dist)*dist; + density = curvemapping_evaluateF(pdr->density_curve, 0, density / dist) * dist; } - + *pdr->density += density; } -static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr, +static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr, float *density, float *vec, float *age, struct CurveMapping *density_curve, float velscale) { - pdr->squared_radius = pd->radius*pd->radius; + pdr->squared_radius = pd->radius * pd->radius; pdr->density = density; pdr->point_data = pd->point_data; pdr->falloff_type = pd->falloff_type; @@ -419,63 +455,69 @@ static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData * pdr->softness = pd->falloff_softness; pdr->noise_influence = pd->noise_influence; pdr->point_data_used = point_data_used(pd); - pdr->offset = (pdr->point_data_used & POINT_DATA_VEL)?pd->totpoints*3:0; + pdr->offset = (pdr->point_data_used & POINT_DATA_VEL) ? pd->totpoints * 3 : 0; pdr->density_curve = density_curve; pdr->velscale = velscale; } -int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres) +static int pointdensity(PointDensity *pd, + const float texvec[3], + TexResult *texres, + float *r_age, + float r_vec[3]) { int retval = TEX_INT; - PointDensity *pd = tex->pd; PointDensityRangeData pdr; - float density=0.0f, age=0.0f, time=0.0f; + float density = 0.0f, age = 0.0f, time = 0.0f; float vec[3] = {0.0f, 0.0f, 0.0f}, co[3]; - float col[4]; float turb, noise_fac; - int num=0; - + int num = 0; + texres->tin = 0.0f; - + if ((!pd) || (!pd->point_tree)) return 0; - - init_pointdensityrangedata(pd, &pdr, &density, vec, &age, - (pd->flag&TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL), pd->falloff_speed_scale*0.001f); + + init_pointdensityrangedata(pd, &pdr, &density, vec, &age, + (pd->flag & TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL), + pd->falloff_speed_scale * 0.001f); noise_fac = pd->noise_fac * 0.5f; /* better default */ - + copy_v3_v3(co, texvec); - + if (point_data_used(pd)) { /* does a BVH lookup to find accumulated density and additional point data * * stores particle velocity vector in 'vec', and particle lifetime in 'time' */ num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); if (num > 0) { age /= num; - mul_v3_fl(vec, 1.0f/num); + mul_v3_fl(vec, 1.0f / num); } - + /* reset */ density = vec[0] = vec[1] = vec[2] = 0.0f; } - + if (pd->flag & TEX_PD_TURBULENCE) { - + if (pd->noise_influence == TEX_PD_NOISE_AGE) { - turb = BLI_gTurbulence(pd->noise_size, texvec[0]+age, texvec[1]+age, texvec[2]+age, pd->noise_depth, 0, pd->noise_basis); + turb = BLI_gTurbulence(pd->noise_size, texvec[0] + age, texvec[1] + age, texvec[2] + age, + pd->noise_depth, 0, pd->noise_basis); } else if (pd->noise_influence == TEX_PD_NOISE_TIME) { time = R.r.cfra / (float)R.r.efra; - turb = BLI_gTurbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth, 0, pd->noise_basis); + turb = BLI_gTurbulence(pd->noise_size, texvec[0] + time, texvec[1] + time, texvec[2] + time, + pd->noise_depth, 0, pd->noise_basis); //turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth); } else { - turb = BLI_gTurbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth, 0, pd->noise_basis); + turb = BLI_gTurbulence(pd->noise_size, texvec[0] + vec[0], texvec[1] + vec[1], texvec[2] + vec[2], + pd->noise_depth, 0, pd->noise_basis); } turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */ - + /* now we have an offset coordinate to use for the density lookup */ co[0] = texvec[0] + noise_fac * turb; co[1] = texvec[1] + noise_fac * turb; @@ -486,17 +528,27 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres) num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); if (num > 0) { age /= num; - mul_v3_fl(vec, 1.0f/num); + mul_v3_fl(vec, 1.0f / num); } - + texres->tin = density; - BRICONT; - - if (pd->color_source == TEX_PD_COLOR_CONSTANT) - return retval; - + if (r_age != NULL) { + *r_age = age; + } + if (r_vec != NULL) { + copy_v3_v3(r_vec, vec); + } + + return retval; +} + +static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3]) +{ + int retval = 0; + float col[4]; + retval |= TEX_RGB; - + switch (pd->color_source) { case TEX_PD_COLOR_PARTAGE: if (pd->coba) { @@ -511,7 +563,7 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres) case TEX_PD_COLOR_PARTSPEED: { float speed = len_v3(vec) * pd->speed_scale; - + if (pd->coba) { if (do_colorband(pd->coba, speed, col)) { texres->talpha = true; @@ -524,8 +576,7 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres) } case TEX_PD_COLOR_PARTVEL: texres->talpha = true; - mul_v3_fl(vec, pd->speed_scale); - copy_v3_v3(&texres->tr, vec); + mul_v3_v3fl(&texres->tr, vec, pd->speed_scale); texres->ta = texres->tin; break; case TEX_PD_COLOR_CONSTANT: @@ -533,13 +584,130 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres) texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; break; } - BRICONTRGB; return retval; - +} + +int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres) +{ + PointDensity *pd = tex->pd; + float age = 0.0f; + float vec[3] = {0.0f, 0.0f, 0.0f}; + int retval = pointdensity(pd, texvec, texres, &age, vec); + + BRICONT; + + retval |= pointdensity_color(pd, texres, age, vec); + BRICONTRGB; + + return retval; + #if 0 if (texres->nor!=NULL) { texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f; } #endif } + +static void sample_dummy_point_density(int resolution, float *values) +{ + memset(values, 0, sizeof(float) * 4 * resolution * resolution * resolution); +} + +static void particle_system_minmax(Object *object, + ParticleSystem *psys, + float radius, + float min[3], float max[3]) +{ + ParticleSettings *part = psys->part; + float imat[4][4]; + float size[3] = {radius, radius, radius}; + PARTICLE_P; + INIT_MINMAX(min, max); + if (part->type == PART_HAIR) { + /* TOOD(sergey): Not supported currently. */ + return; + } + invert_m4_m4(imat, object->obmat); + LOOP_PARTICLES { + float co_object[3], co_min[3], co_max[3]; + mul_v3_m4v3(co_object, imat, pa->state.co); + sub_v3_v3v3(co_min, co_object, size); + add_v3_v3v3(co_max, co_object, size); + minmax_v3v3_v3(min, max, co_min); + minmax_v3v3_v3(min, max, co_max); + } +} + +void RE_sample_point_density(Scene *scene, PointDensity *pd, + int resolution, float *values) +{ + const size_t resolution2 = resolution * resolution; + Object *object = pd->object; + size_t x, y, z; + float min[3], max[3], dim[3], mat[4][4]; + + if (object == NULL) { + sample_dummy_point_density(resolution, values); + return; + } + + if (pd->source == TEX_PD_PSYS) { + ParticleSystem *psys; + if (pd->psys == 0) { + sample_dummy_point_density(resolution, values); + return; + } + psys = BLI_findlink(&object->particlesystem, pd->psys - 1); + if (psys == NULL) { + sample_dummy_point_density(resolution, values); + return; + } + particle_system_minmax(object, psys, pd->radius, min, max); + } + else { + float radius[3] = {pd->radius, pd->radius, pd->radius}; + float *loc, *size; + BKE_object_obdata_texspace_get(pd->object, NULL, &loc, &size, NULL); + sub_v3_v3v3(min, loc, size); + add_v3_v3v3(max, loc, size); + /* Adjust texture space to include density points on the boundaries. */ + sub_v3_v3(min, radius); + add_v3_v3(max, radius); + } + + sub_v3_v3v3(dim, max, min); + if (dim[0] <= 0.0f || dim[1] <= 0.0f || dim[2] <= 0.0f) { + sample_dummy_point_density(resolution, values); + return; + } + + /* Same matricies/resolution as dupli_render_particle_set(). */ + unit_m4(mat); + + BLI_mutex_lock(&sample_mutex); + cache_pointdensity_ex(scene, pd, mat, mat, 1, 1); + for (z = 0; z < resolution; ++z) { + for (y = 0; y < resolution; ++y) { + for (x = 0; x < resolution; ++x) { + size_t index = z * resolution2 + y * resolution + x; + float texvec[3]; + float age, vec[3]; + TexResult texres; + + copy_v3_v3(texvec, min); + texvec[0] += dim[0] * (float)x / (float)resolution; + texvec[1] += dim[1] * (float)y / (float)resolution; + texvec[2] += dim[2] * (float)z / (float)resolution; + + pointdensity(pd, texvec, &texres, &age, vec); + pointdensity_color(pd, &texres, age, vec); + + copy_v3_v3(&values[index*4 + 0], &texres.tr); + values[index*4 + 3] = texres.tin; + } + } + } + free_pointdensity(pd); + BLI_mutex_unlock(&sample_mutex); +} diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 05e83f35179..900312ee984 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -27,7 +27,6 @@ * \ingroup render */ - #include <stdio.h> #include <math.h> #include <string.h> @@ -46,29 +45,22 @@ #include "BLI_rand.h" #include "BLI_utildefines.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "BKE_node.h" - -#include "PIL_time.h" - #include "render_result.h" #include "render_types.h" -#include "renderpipeline.h" #include "rendercore.h" #include "renderdatabase.h" -#include "pixelblending.h" #include "pixelshading.h" #include "shading.h" -#include "texture.h" #include "volumetric.h" #include "rayintersection.h" #include "rayobject.h" #include "raycounter.h" - #define RAY_TRA 1 #define RAY_INSIDE 2 @@ -314,22 +306,23 @@ static void makeraytree_single(Render *re) RayObject *raytree; RayFace *face = NULL; VlakPrimitive *vlakprimitive = NULL; - int faces = 0, obs = 0, special = 0; + int faces = 0, special = 0; - for (obi=re->instancetable.first; obi; obi=obi->next) - if (is_raytraceable(re, obi)) { - ObjectRen *obr = obi->obr; - obs++; - - if (has_special_rayobject(re, obi)) { - special++; - } - else { - int v; - for (v=0;v<obr->totvlak;v++) { - VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255); - if (is_raytraceable_vlr(re, vlr)) - faces++; + for (obi = re->instancetable.first; obi; obi = obi->next) { + if (is_raytraceable(re, obi)) { + ObjectRen *obr = obi->obr; + + if (has_special_rayobject(re, obi)) { + special++; + } + else { + int v; + for (v = 0;v < obr->totvlak; v++) { + VlakRen *vlr = obr->vlaknodes[v >> 8].vlak + (v&255); + if (is_raytraceable_vlr(re, vlr)) { + faces++; + } + } } } } @@ -743,6 +736,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, con //shi.sample= 0; // memset above, so don't need this shi.xs= origshi->xs; shi.ys= origshi->ys; + shi.do_manage= origshi->do_manage; shi.lay= origshi->lay; shi.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */ shi.combinedflag= 0xFFFFFF; /* ray trace does all options */ @@ -802,7 +796,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, con traceray(origshi, origshr, depth-1, shi.co, shi.view, tracol, shi.obi, shi.vlr, 0); f= shr.alpha; f1= 1.0f-f; - nf= d * shi.mat->filter; + nf= (shi.mat->mode & MA_RAYTRANSP) ? d * shi.mat->filter : 0.0f; fr= 1.0f+ nf*(shi.r-1.0f); fg= 1.0f+ nf*(shi.g-1.0f); fb= 1.0f+ nf*(shi.b-1.0f); @@ -1281,7 +1275,7 @@ static float get_avg_speed(ShadeInput *shi) post_x = (shi->winspeed[2] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[2]; post_y = (shi->winspeed[3] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[3]; - speedavg = (sqrtf(pre_x * pre_x + pre_y * pre_y) + sqrtf(post_x * post_x + post_y * post_y)) / 2.0; + speedavg = (sqrtf(pre_x * pre_x + pre_y * pre_y) + sqrtf(post_x * post_x + post_y * post_y)) / 2.0f; return speedavg; } @@ -1299,7 +1293,7 @@ static void trace_refract(float col[4], ShadeInput *shi, ShadeResult *shr) float v_refract[3], v_refract_new[3]; float sampcol[4], colsq[4]; - float blur = powf(1.0f - shi->mat->gloss_tra, 3); + float blur = pow3f(1.0f - shi->mat->gloss_tra); short max_samples = shi->mat->samp_gloss_tra; float adapt_thresh = shi->mat->adapt_thresh_tra; @@ -1400,7 +1394,7 @@ static void trace_reflect(float col[3], ShadeInput *shi, ShadeResult *shr, float float v_nor_new[3], v_reflect[3]; float sampcol[4], colsq[4]; - float blur = powf(1.0f - shi->mat->gloss_mir, 3); + float blur = pow3f(1.0f - shi->mat->gloss_mir); short max_samples = shi->mat->samp_gloss_mir; float adapt_thresh = shi->mat->adapt_thresh_mir; float aniso = 1.0f - shi->mat->aniso_gloss_mir; @@ -1562,7 +1556,7 @@ void ray_trace(ShadeInput *shi, ShadeResult *shr) } if (shi->combinedflag & SCE_PASS_REFLECT) { - /* values in shr->spec can be greater then 1.0. + /* values in shr->spec can be greater than 1.0. * In this case the mircol uses a zero blending factor, so ignoring it is ok. * Fixes bug #18837 - when the spec is higher then 1.0, * diff can become a negative color - Campbell */ @@ -1629,6 +1623,7 @@ static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int shi.xs= origshi->xs; shi.ys= origshi->ys; + shi.do_manage= origshi->do_manage; shi.lay= origshi->lay; shi.nodes= origshi->nodes; @@ -1636,9 +1631,9 @@ static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int shade_ray(is, &shi, &shr); if (shi.mat->material_type == MA_TYPE_SURFACE) { - const float d= (traflag & RAY_TRA) ? - shade_by_transmission(is, &shi, &shr) : - 1.0f; + const float d = (shi.mat->mode & MA_RAYTRANSP) ? + ((traflag & RAY_TRA) ? shade_by_transmission(is, &shi, &shr) : 1.0f) : + 0.0f; /* mix colors based on shadfac (rgb + amount of light factor) */ addAlphaLight(col, shr.diff, shr.alpha, d*shi.mat->filter); } @@ -2371,9 +2366,9 @@ static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, const float lampco[ mul_m3_v3(lar->mat, vec); /* set start and vec */ - isec->dir[0] = vec[0]+lampco[0]-isec->start[0]; - isec->dir[1] = vec[1]+lampco[1]-isec->start[1]; - isec->dir[2] = vec[2]+lampco[2]-isec->start[2]; + isec->dir[0] = vec[0]+lampco[0]-shi->co[0]; + isec->dir[1] = vec[1]+lampco[1]-shi->co[1]; + isec->dir[2] = vec[2]+lampco[2]-shi->co[2]; RE_instance_rotate_ray_dir(shi->obi, isec); diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index d8410fbe257..27fc412e1cd 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -35,19 +35,21 @@ #include "MEM_guardedalloc.h" +#include "BKE_appdir.h" #include "BLI_utildefines.h" #include "BLI_listbase.h" -#include "BLI_md5.h" +#include "BLI_hash_md5.h" #include "BLI_path_util.h" #include "BLI_rect.h" #include "BLI_string.h" -#include "BLI_system.h" #include "BLI_threads.h" #include "BKE_image.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_report.h" +#include "BKE_camera.h" +#include "BKE_scene.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -60,14 +62,32 @@ /********************************** Free *************************************/ +static void render_result_views_free(RenderResult *res) +{ + while (res->views.first) { + RenderView *rv = res->views.first; + BLI_remlink(&res->views, rv); + + if (rv->rect32) + MEM_freeN(rv->rect32); + + if (rv->rectz) + MEM_freeN(rv->rectz); + + if (rv->rectf) + MEM_freeN(rv->rectf); + + MEM_freeN(rv); + } +} + void render_result_free(RenderResult *res) { if (res == NULL) return; while (res->layers.first) { RenderLayer *rl = res->layers.first; - - if (rl->rectf) MEM_freeN(rl->rectf); + /* acolrect and scolrect are optionally allocated in shade_tile, only free here since it can be used for drawing */ if (rl->acolrect) MEM_freeN(rl->acolrect); if (rl->scolrect) MEM_freeN(rl->scolrect); @@ -82,7 +102,9 @@ void render_result_free(RenderResult *res) BLI_remlink(&res->layers, rl); MEM_freeN(rl); } - + + render_result_views_free(res); + if (res->rect32) MEM_freeN(res->rect32); if (res->rectz) @@ -91,7 +113,11 @@ void render_result_free(RenderResult *res) MEM_freeN(res->rectf); if (res->text) MEM_freeN(res->text); - + if (res->error) + MEM_freeN(res->error); + if (res->stamp_data) + MEM_freeN(res->stamp_data); + MEM_freeN(res); } @@ -110,13 +136,44 @@ void render_result_free_list(ListBase *lb, RenderResult *rr) } } -/********************************* Names *************************************/ +/********************************* multiview *************************************/ -/* NOTE: OpenEXR only supports 32 chars for layer+pass names - * In blender we now use max 10 chars for pass, max 20 for layer */ -static const char *get_pass_name(int passtype, int channel) +/* create a new views Listbase in rr without duplicating the memory pointers */ +void render_result_views_shallowcopy(RenderResult *dst, RenderResult *src) +{ + RenderView *rview; + + if (dst == NULL || src == NULL) + return; + + for (rview = src->views.first; rview; rview = rview->next) { + RenderView *rv; + + rv = MEM_mallocN(sizeof(RenderView), "new render view"); + BLI_addtail(&dst->views, rv); + + BLI_strncpy(rv->name, rview->name, sizeof(rv->name)); + rv->rectf = rview->rectf; + rv->rectz = rview->rectz; + rv->rect32 = rview->rect32; + } +} + +/* free the views created temporarily */ +void render_result_views_shallowdelete(RenderResult *rr) +{ + if (rr == NULL) + return; + + while (rr->views.first) { + RenderView *rv = rr->views.first; + BLI_remlink(&rr->views, rv); + MEM_freeN(rv); + } +} + +static const char *name_from_passtype(int passtype, int channel) { - if (passtype == SCE_PASS_COMBINED) { if (channel == -1) return "Combined"; if (channel == 0) return "Combined.R"; @@ -303,122 +360,151 @@ static const char *get_pass_name(int passtype, int channel) static int passtype_from_name(const char *str) { - - if (strcmp(str, "Combined") == 0) + if (STRPREFIX(str, "Combined")) return SCE_PASS_COMBINED; - if (strcmp(str, "Depth") == 0) + if (STRPREFIX(str, "Depth")) return SCE_PASS_Z; - if (strcmp(str, "Vector") == 0) + if (STRPREFIX(str, "Vector")) return SCE_PASS_VECTOR; - if (strcmp(str, "Normal") == 0) + if (STRPREFIX(str, "Normal")) return SCE_PASS_NORMAL; - if (strcmp(str, "UV") == 0) + if (STRPREFIX(str, "UV")) return SCE_PASS_UV; - if (strcmp(str, "Color") == 0) + if (STRPREFIX(str, "Color")) return SCE_PASS_RGBA; - if (strcmp(str, "Emit") == 0) + if (STRPREFIX(str, "Emit")) return SCE_PASS_EMIT; - if (strcmp(str, "Diffuse") == 0) + if (STRPREFIX(str, "Diffuse")) return SCE_PASS_DIFFUSE; - if (strcmp(str, "Spec") == 0) + if (STRPREFIX(str, "Spec")) return SCE_PASS_SPEC; - if (strcmp(str, "Shadow") == 0) + if (STRPREFIX(str, "Shadow")) return SCE_PASS_SHADOW; - if (strcmp(str, "AO") == 0) + if (STRPREFIX(str, "AO")) return SCE_PASS_AO; - if (strcmp(str, "Env") == 0) + if (STRPREFIX(str, "Env")) return SCE_PASS_ENVIRONMENT; - if (strcmp(str, "Indirect") == 0) + if (STRPREFIX(str, "Indirect")) return SCE_PASS_INDIRECT; - if (strcmp(str, "Reflect") == 0) + if (STRPREFIX(str, "Reflect")) return SCE_PASS_REFLECT; - if (strcmp(str, "Refract") == 0) + if (STRPREFIX(str, "Refract")) return SCE_PASS_REFRACT; - if (strcmp(str, "IndexOB") == 0) + if (STRPREFIX(str, "IndexOB")) return SCE_PASS_INDEXOB; - if (strcmp(str, "IndexMA") == 0) + if (STRPREFIX(str, "IndexMA")) return SCE_PASS_INDEXMA; - if (strcmp(str, "Mist") == 0) + if (STRPREFIX(str, "Mist")) return SCE_PASS_MIST; - if (strcmp(str, "RayHits") == 0) + if (STRPREFIX(str, "RayHits")) return SCE_PASS_RAYHITS; - if (strcmp(str, "DiffDir") == 0) + if (STRPREFIX(str, "DiffDir")) return SCE_PASS_DIFFUSE_DIRECT; - if (strcmp(str, "DiffInd") == 0) + if (STRPREFIX(str, "DiffInd")) return SCE_PASS_DIFFUSE_INDIRECT; - if (strcmp(str, "DiffCol") == 0) + if (STRPREFIX(str, "DiffCol")) return SCE_PASS_DIFFUSE_COLOR; - if (strcmp(str, "GlossDir") == 0) + if (STRPREFIX(str, "GlossDir")) return SCE_PASS_GLOSSY_DIRECT; - if (strcmp(str, "GlossInd") == 0) + if (STRPREFIX(str, "GlossInd")) return SCE_PASS_GLOSSY_INDIRECT; - if (strcmp(str, "GlossCol") == 0) + if (STRPREFIX(str, "GlossCol")) return SCE_PASS_GLOSSY_COLOR; - if (strcmp(str, "TransDir") == 0) + if (STRPREFIX(str, "TransDir")) return SCE_PASS_TRANSM_DIRECT; - if (strcmp(str, "TransInd") == 0) + if (STRPREFIX(str, "TransInd")) return SCE_PASS_TRANSM_INDIRECT; - if (strcmp(str, "TransCol") == 0) + if (STRPREFIX(str, "TransCol")) return SCE_PASS_TRANSM_COLOR; - if (strcmp(str, "SubsurfaceDir") == 0) + if (STRPREFIX(str, "SubsurfaceDir")) return SCE_PASS_SUBSURFACE_DIRECT; - if (strcmp(str, "SubsurfaceInd") == 0) + if (STRPREFIX(str, "SubsurfaceInd")) return SCE_PASS_SUBSURFACE_INDIRECT; - if (strcmp(str, "SubsurfaceCol") == 0) + if (STRPREFIX(str, "SubsurfaceCol")) return SCE_PASS_SUBSURFACE_COLOR; return 0; } + +static void set_pass_name(char *passname, int passtype, int channel, const char *view) +{ + const char delims[] = {'.', '\0'}; + const char *sep; + const char *token; + size_t len; + + const char *passtype_name = name_from_passtype(passtype, channel); + + if (view == NULL || view[0] == '\0') { + BLI_strncpy(passname, passtype_name, EXR_PASS_MAXNAME); + return; + } + + len = BLI_str_rpartition(passtype_name, delims, &sep, &token); + + if (sep) { + BLI_snprintf(passname, EXR_PASS_MAXNAME, "%.*s.%s.%s", (int)len, passtype_name, view, token); + } + else { + BLI_snprintf(passname, EXR_PASS_MAXNAME, "%s.%s", passtype_name, view); + } +} + /********************************** New **************************************/ -static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype) +static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname) { - const char *typestr = get_pass_name(passtype, 0); + const size_t view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name)); + const char *typestr = name_from_passtype(passtype, -1); RenderPass *rpass = MEM_callocN(sizeof(RenderPass), typestr); - int rectsize = rr->rectx * rr->recty * channels; + size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels; BLI_addtail(&rl->passes, rpass); rpass->passtype = passtype; rpass->channels = channels; rpass->rectx = rl->rectx; rpass->recty = rl->recty; - BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name)); + rpass->view_id = view_id; + + set_pass_name(rpass->name, rpass->passtype, -1, viewname); + BLI_strncpy(rpass->internal_name, typestr, sizeof(rpass->internal_name)); + BLI_strncpy(rpass->view, viewname, sizeof(rpass->view)); if (rl->exrhandle) { int a; for (a = 0; a < channels; a++) - IMB_exr_add_channel(rl->exrhandle, rl->name, get_pass_name(passtype, a), 0, 0, NULL); + IMB_exr_add_channel(rl->exrhandle, rl->name, name_from_passtype(passtype, a), viewname, 0, 0, NULL, false); } else { float *rect; @@ -438,18 +524,64 @@ static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channel rect[x] = 10e10; } } + return rpass; } +#ifdef WITH_CYCLES_DEBUG +const char *RE_debug_pass_name_get(int debug_type) +{ + switch (debug_type) { + case RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS: + return "BVH Traversal Steps"; + case RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES: + return "BVH Traversed Instances"; + case RENDER_PASS_DEBUG_RAY_BOUNCES: + return "Ray Bounces"; + } + return "Unknown"; +} + +int RE_debug_pass_num_channels_get(int UNUSED(debug_type)) +{ + /* Only single case currently, might be handy for further debug passes. */ + return 1; +} + +static RenderPass *render_layer_add_debug_pass(RenderResult *rr, + RenderLayer *rl, + int pass_type, + int debug_type, + const char *view) +{ + const char *name = RE_debug_pass_name_get(debug_type); + int channels = RE_debug_pass_num_channels_get(debug_type); + RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type, view); + rpass->debug_type = debug_type; + BLI_strncpy(rpass->name, + name, + sizeof(rpass->name)); + BLI_strncpy(rpass->internal_name, rpass->name, sizeof(rpass->internal_name)); + return rpass; +} + +int RE_debug_pass_type_get(Render *re) +{ + return re->r.debug_pass_type; +} +#endif + /* called by main render as well for parts */ /* will read info from Render *re to define layers */ /* called in threads */ /* re->winx,winy is coordinate space of entire image, partrct the part within */ -RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers, const char *layername) +RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers, const char *layername, const char *viewname) { RenderResult *rr; RenderLayer *rl; + RenderView *rv; SceneRenderLayer *srl; - int rectx, recty, nr; + int rectx, recty; + int nr; rectx = BLI_rcti_size_x(partrct); recty = BLI_rcti_size_y(partrct); @@ -474,11 +606,13 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf rr->do_exr_tile = true; } + render_result_views_new(rr, &re->r); + /* check renderdata for amount of layers */ for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) { if (layername && layername[0]) - if (strcmp(srl->name, layername) != 0) + if (!STREQ(srl->name, layername)) continue; if (re->r.scemode & R_SINGLE_LAYER) { @@ -507,77 +641,90 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf if (rr->do_exr_tile) { rl->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba"); - rl->exrhandle = IMB_exr_get_handle(); + } - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL); + for (rv = rr->views.first; rv; rv = rv->next) { + const char *view = rv->name; + + if (viewname && viewname[0]) + if (!STREQ(view, viewname)) + continue; + + if (rr->do_exr_tile) + IMB_exr_add_view(rl->exrhandle, view); + + /* a renderlayer should always have a Combined pass*/ + render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view); + + if (srl->passflag & SCE_PASS_Z) + render_layer_add_pass(rr, rl, 1, SCE_PASS_Z, view); + if (srl->passflag & SCE_PASS_VECTOR) + render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR, view); + if (srl->passflag & SCE_PASS_NORMAL) + render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL, view); + if (srl->passflag & SCE_PASS_UV) + render_layer_add_pass(rr, rl, 3, SCE_PASS_UV, view); + if (srl->passflag & SCE_PASS_RGBA) + render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA, view); + if (srl->passflag & SCE_PASS_EMIT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT, view); + if (srl->passflag & SCE_PASS_DIFFUSE) + render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE, view); + if (srl->passflag & SCE_PASS_SPEC) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC, view); + if (srl->passflag & SCE_PASS_AO) + render_layer_add_pass(rr, rl, 3, SCE_PASS_AO, view); + if (srl->passflag & SCE_PASS_ENVIRONMENT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT, view); + if (srl->passflag & SCE_PASS_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT, view); + if (srl->passflag & SCE_PASS_SHADOW) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW, view); + if (srl->passflag & SCE_PASS_REFLECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT, view); + if (srl->passflag & SCE_PASS_REFRACT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT, view); + if (srl->passflag & SCE_PASS_INDEXOB) + render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB, view); + if (srl->passflag & SCE_PASS_INDEXMA) + render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA, view); + if (srl->passflag & SCE_PASS_MIST) + render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST, view); + if (rl->passflag & SCE_PASS_RAYHITS) + render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS, view); + if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT, view); + if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT, view); + if (srl->passflag & SCE_PASS_DIFFUSE_COLOR) + render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR, view); + if (srl->passflag & SCE_PASS_GLOSSY_DIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT, view); + if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT, view); + if (srl->passflag & SCE_PASS_GLOSSY_COLOR) + render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_COLOR, view); + if (srl->passflag & SCE_PASS_TRANSM_DIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_DIRECT, view); + if (srl->passflag & SCE_PASS_TRANSM_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT, view); + if (srl->passflag & SCE_PASS_TRANSM_COLOR) + render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_COLOR, view); + if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT, view); + if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT, view); + if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR, view); + +#ifdef WITH_CYCLES_DEBUG + if (BKE_scene_use_new_shading_nodes(re->scene)) { + render_layer_add_debug_pass(rr, rl, SCE_PASS_DEBUG, + re->r.debug_pass_type, view); + } +#endif } - else - rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba"); - - if (srl->passflag & SCE_PASS_Z) - render_layer_add_pass(rr, rl, 1, SCE_PASS_Z); - if (srl->passflag & SCE_PASS_VECTOR) - render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR); - if (srl->passflag & SCE_PASS_NORMAL) - render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL); - if (srl->passflag & SCE_PASS_UV) - render_layer_add_pass(rr, rl, 3, SCE_PASS_UV); - if (srl->passflag & SCE_PASS_RGBA) - render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA); - if (srl->passflag & SCE_PASS_EMIT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT); - if (srl->passflag & SCE_PASS_DIFFUSE) - render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE); - if (srl->passflag & SCE_PASS_SPEC) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC); - if (srl->passflag & SCE_PASS_AO) - render_layer_add_pass(rr, rl, 3, SCE_PASS_AO); - if (srl->passflag & SCE_PASS_ENVIRONMENT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT); - if (srl->passflag & SCE_PASS_INDIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT); - if (srl->passflag & SCE_PASS_SHADOW) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW); - if (srl->passflag & SCE_PASS_REFLECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT); - if (srl->passflag & SCE_PASS_REFRACT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT); - if (srl->passflag & SCE_PASS_INDEXOB) - render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB); - if (srl->passflag & SCE_PASS_INDEXMA) - render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA); - if (srl->passflag & SCE_PASS_MIST) - render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST); - if (rl->passflag & SCE_PASS_RAYHITS) - render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS); - if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT); - if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT); - if (srl->passflag & SCE_PASS_DIFFUSE_COLOR) - render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR); - if (srl->passflag & SCE_PASS_GLOSSY_DIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT); - if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT); - if (srl->passflag & SCE_PASS_GLOSSY_COLOR) - render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_COLOR); - if (srl->passflag & SCE_PASS_TRANSM_DIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_DIRECT); - if (srl->passflag & SCE_PASS_TRANSM_INDIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT); - if (srl->passflag & SCE_PASS_TRANSM_COLOR) - render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_COLOR); - if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT); - if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT); - if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR); } /* sss, previewrender and envmap don't do layers, so we make a default one */ if (BLI_listbase_is_empty(&rr->layers) && !(layername && layername[0])) { @@ -590,18 +737,23 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf /* duplicate code... */ if (rr->do_exr_tile) { rl->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba"); - rl->exrhandle = IMB_exr_get_handle(); - - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.R", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.G", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.B", 0, 0, NULL); - IMB_exr_add_channel(rl->exrhandle, rl->name, "Combined.A", 0, 0, NULL); } - else { - rl->rectf = MEM_mapallocN(rectx * recty * sizeof(float) * 4, "Combined rgba"); + + for (rv = rr->views.first; rv; rv = rv->next) { + const char *view = rv->name; + + if (viewname && viewname[0]) + if (strcmp(view, viewname) != 0) + continue; + + if (rr->do_exr_tile) + IMB_exr_add_view(rl->exrhandle, view); + + /* a renderlayer should always have a Combined pass */ + render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view); } - + /* note, this has to be in sync with scene.c */ rl->lay = (1 << 20) - 1; rl->layflag = 0x7FFF; /* solid ztra halo strand */ @@ -619,15 +771,15 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf } /* allocate osa new results for samples */ -RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers) +RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers, const char *viewname) { int a; if (re->osa == 0) - return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS); + return render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname); for (a = 0; a < re->osa; a++) { - RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS); + RenderResult *rr = render_result_new(re, partrct, crop, savebuffers, RR_ALL_LAYERS, viewname); BLI_addtail(lb, rr); rr->sample_nr = a; } @@ -648,28 +800,98 @@ static void *ml_addlayer_cb(void *base, const char *str) return rl; } -static void ml_addpass_cb(void *UNUSED(base), void *lay, const char *str, float *rect, int totchan, const char *chan_id) +static void ml_addpass_cb(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id, const char *view) { + RenderResult *rr = base; RenderLayer *rl = lay; RenderPass *rpass = MEM_callocN(sizeof(RenderPass), "loaded pass"); int a; BLI_addtail(&rl->passes, rpass); rpass->channels = totchan; - rpass->passtype = passtype_from_name(str); if (rpass->passtype == 0) printf("unknown pass %s\n", str); rl->passflag |= rpass->passtype; - BLI_strncpy(rpass->name, str, EXR_PASS_MAXNAME); /* channel id chars */ for (a = 0; a < totchan; a++) rpass->chan_id[a] = chan_id[a]; - + rpass->rect = rect; + if (view[0] != '\0') { + BLI_snprintf(rpass->name, sizeof(rpass->name), "%s.%s", str, view); + rpass->view_id = BLI_findstringindex(&rr->views, view, offsetof(RenderView, name)); + } + else { + BLI_strncpy(rpass->name, str, sizeof(rpass->name)); + rpass->view_id = 0; + } + + BLI_strncpy(rpass->view, view, sizeof(rpass->view)); + BLI_strncpy(rpass->internal_name, str, sizeof(rpass->internal_name)); +} + +static void *ml_addview_cb(void *base, const char *str) +{ + RenderResult *rr = base; + RenderView *rv; + + rv = MEM_callocN(sizeof(RenderView), "new render view"); + BLI_strncpy(rv->name, str, EXR_VIEW_MAXNAME); + + /* For stereo drawing we need to ensure: + * STEREO_LEFT_NAME == STEREO_LEFT_ID and + * STEREO_RIGHT_NAME == STEREO_RIGHT_ID */ + + if (STREQ(str, STEREO_LEFT_NAME)) { + BLI_addhead(&rr->views, rv); + } + else if (STREQ(str, STEREO_RIGHT_NAME)) { + RenderView *left_rv = BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)); + + if (left_rv == NULL) { + BLI_addhead(&rr->views, rv); + } + else { + BLI_insertlinkafter(&rr->views, left_rv, rv); + } + } + else { + BLI_addtail(&rr->views, rv); + } + + return rv; } -/* from imbuf, if a handle was returned we convert this to render result */ +static int order_render_passes(const void *a, const void *b) +{ + // 1 if a is after b + RenderPass *rpa = (RenderPass *) a; + RenderPass *rpb = (RenderPass *) b; + + if (rpa->passtype > rpb->passtype) + return 1; + else if (rpa->passtype < rpb->passtype) + return 0; + + /* they have the same type */ + /* left first */ + if (STREQ(rpa->view, STEREO_LEFT_NAME)) + return 0; + else if (STREQ(rpb->view, STEREO_LEFT_NAME)) + return 1; + + /* right second */ + if (STREQ(rpa->view, STEREO_RIGHT_NAME)) + return 0; + else if (STREQ(rpb->view, STEREO_RIGHT_NAME)) + return 1; + + /* remaining in ascending id order */ + return (rpa->view_id < rpb->view_id); +} + +/* from imbuf, if a handle was returned and it's not a singlelayer multiview we convert this to render result */ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty) { RenderResult *rr = MEM_callocN(sizeof(RenderResult), __func__); @@ -680,12 +902,14 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace rr->rectx = rectx; rr->recty = recty; - IMB_exr_multilayer_convert(exrhandle, rr, ml_addlayer_cb, ml_addpass_cb); + IMB_exr_multilayer_convert(exrhandle, rr, ml_addview_cb, ml_addlayer_cb, ml_addpass_cb); for (rl = rr->layers.first; rl; rl = rl->next) { rl->rectx = rectx; rl->recty = recty; + BLI_listbase_sort(&rl->passes, order_render_passes); + for (rpass = rl->passes.first; rpass; rpass = rpass->next) { rpass->rectx = rectx; rpass->recty = recty; @@ -700,26 +924,56 @@ RenderResult *render_result_new_from_exr(void *exrhandle, const char *colorspace return rr; } +void render_result_view_new(RenderResult *rr, const char *viewname) +{ + RenderView *rv = MEM_callocN(sizeof(RenderView), "new render view"); + BLI_addtail(&rr->views, rv); + BLI_strncpy(rv->name, viewname, sizeof(rv->name)); +} + +void render_result_views_new(RenderResult *rr, RenderData *rd) +{ + SceneRenderView *srv; + + /* clear previously existing views - for sequencer */ + render_result_views_free(rr); + + /* check renderdata for amount of views */ + if ((rd->scemode & R_MULTIVIEW)) { + for (srv = rd->views.first; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) + continue; + render_result_view_new(rr, srv->name); + } + } + + /* we always need at least one view */ + if (BLI_listbase_count_ex(&rr->views, 1) == 0) { + render_result_view_new(rr, ""); + } +} + /*********************************** Merge ***********************************/ static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize) { - int y, ofs, copylen, tilex, tiley; + int y, tilex, tiley; + size_t ofs, copylen; copylen = tilex = rrpart->rectx; tiley = rrpart->recty; if (rrpart->crop) { /* filters add pixel extra */ - tile += pixsize * (rrpart->crop + rrpart->crop * tilex); + tile += pixsize * (rrpart->crop + ((size_t)rrpart->crop) * tilex); copylen = tilex - 2 * rrpart->crop; tiley -= 2 * rrpart->crop; - ofs = (rrpart->tilerect.ymin + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop); + ofs = (((size_t)rrpart->tilerect.ymin) + rrpart->crop) * rr->rectx + (rrpart->tilerect.xmin + rrpart->crop); target += pixsize * ofs; } else { - ofs = (rrpart->tilerect.ymin * rr->rectx + rrpart->tilerect.xmin); + ofs = (((size_t)rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin); target += pixsize * ofs; } @@ -745,16 +999,19 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart) for (rl = rr->layers.first; rl; rl = rl->next) { rlp = RE_GetRenderLayer(rrpart, rl->name); if (rlp) { - /* combined */ - if (rl->rectf && rlp->rectf) - do_merge_tile(rr, rrpart, rl->rectf, rlp->rectf, 4); - /* passes are allocated in sync */ for (rpass = rl->passes.first, rpassp = rlp->passes.first; rpass && rpassp; - rpass = rpass->next, rpassp = rpassp->next) + rpass = rpass->next) { + /* renderresult have all passes, renderpart only the active view's passes */ + if (strcmp(rpassp->name, rpass->name) != 0) + continue; + do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels); + + /* manually get next render pass */ + rpassp = rpassp->next; } } } @@ -763,7 +1020,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart) /* for passes read from files, these have names stored */ static char *make_pass_name(RenderPass *rpass, int chan) { - static char name[16]; + static char name[EXR_PASS_MAXNAME]; int len; BLI_strncpy(name, rpass->name, EXR_PASS_MAXNAME); @@ -775,55 +1032,111 @@ static char *make_pass_name(RenderPass *rpass, int chan) return name; } -/* filename already made absolute */ -/* called from within UI, saves both rendered result as a file-read result */ -bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, int compress) +/* called from within UI and render pipeline, saves both rendered result as a file-read result + * if multiview is true saves all views in a multiview exr + * else if view is not NULL saves single view + * else saves stereo3d + */ +bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, ImageFormatData *imf, const bool multiview, const char *view) { RenderLayer *rl; RenderPass *rpass; + RenderView *rview; void *exrhandle = IMB_exr_get_handle(); bool success; - - BLI_make_existing_file(filename); - - /* composite result */ - if (rr->rectf) { - IMB_exr_add_channel(exrhandle, "Composite", "Combined.R", 4, 4 * rr->rectx, rr->rectf); - IMB_exr_add_channel(exrhandle, "Composite", "Combined.G", 4, 4 * rr->rectx, rr->rectf + 1); - IMB_exr_add_channel(exrhandle, "Composite", "Combined.B", 4, 4 * rr->rectx, rr->rectf + 2); - IMB_exr_add_channel(exrhandle, "Composite", "Combined.A", 4, 4 * rr->rectx, rr->rectf + 3); + int a, nr; + const char *chan_view = NULL; + int compress = (imf ? imf->exr_codec : 0); + size_t width, height; + + const bool is_mono = view && !multiview; + const bool use_half_float = (imf != NULL) ? (imf->depth == R_IMF_CHAN_DEPTH_16) : false; + + width = rr->rectx; + height = rr->recty; + + if (imf && imf->imtype == R_IMF_IMTYPE_OPENEXR && multiview) { + /* single layer OpenEXR */ + const char *RGBAZ[] = {"R", "G", "B", "A", "Z"}; + for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) { + IMB_exr_add_view(exrhandle, rview->name); + + if (rview->rectf) { + for (a = 0; a < 4; a++) { + IMB_exr_add_channel(exrhandle, "", RGBAZ[a], + rview->name, 4, 4 * width, rview->rectf + a, + use_half_float); + } + if (rview->rectz) { + /* Z pass is always stored as float. */ + IMB_exr_add_channel(exrhandle, "", RGBAZ[4], + rview->name, 1, width, rview->rectz, + false); + } + } + } } - - /* add layers/passes and assign channels */ - for (rl = rr->layers.first; rl; rl = rl->next) { - - /* combined */ - if (rl->rectf) { - int a, xstride = 4; - for (a = 0; a < xstride; a++) { - IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a), - xstride, xstride * rr->rectx, rl->rectf + a); + else { + for (nr = 0, rview = rr->views.first; rview; rview = rview->next, nr++) { + if (is_mono) { + if (!STREQ(view, rview->name)) { + continue; + } + chan_view = ""; + } + else { + /* if rendered only one view, we treat as a a non-view render */ + chan_view = rview->name; + } + + IMB_exr_add_view(exrhandle, rview->name); + + if (rview->rectf) { + for (a = 0; a < 4; a++) { + IMB_exr_add_channel(exrhandle, "Composite", name_from_passtype(SCE_PASS_COMBINED, a), + chan_view, 4, 4 * width, rview->rectf + a, + use_half_float); + } } } - - /* passes are allocated in sync */ - for (rpass = rl->passes.first; rpass; rpass = rpass->next) { - int a, xstride = rpass->channels; - for (a = 0; a < xstride; a++) { - if (rpass->passtype) { - IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a), - xstride, xstride * rr->rectx, rpass->rect + a); + + /* add layers/passes and assign channels */ + for (rl = rr->layers.first; rl; rl = rl->next) { + + /* passes are allocated in sync */ + for (rpass = rl->passes.first; rpass; rpass = rpass->next) { + const int xstride = rpass->channels; + + if (is_mono) { + if (!STREQ(view, rpass->view)) { + continue; + } + chan_view = ""; } else { - IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), - xstride, xstride * rr->rectx, rpass->rect + a); + /* if rendered only one view, we treat as a a non-view render */ + chan_view = (nr > 1 ? rpass->view :""); + } + + for (a = 0; a < xstride; a++) { + if (rpass->passtype) { + IMB_exr_add_channel(exrhandle, rl->name, name_from_passtype(rpass->passtype, a), chan_view, + xstride, xstride * width, rpass->rect + a, + rpass->passtype == SCE_PASS_Z ? false : use_half_float); + } + else { + IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), chan_view, + xstride, xstride * width, rpass->rect + a, + use_half_float); + } } } } } - /* when the filename has no permissions, this can fail */ - if (IMB_exr_begin_write(exrhandle, filename, rr->rectx, rr->recty, compress)) { + BLI_make_existing_file(filename); + + if (IMB_exr_begin_write(exrhandle, filename, width, height, compress, rr->stamp_data)) { IMB_exr_write_channels(exrhandle); success = true; } @@ -832,8 +1145,8 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil BKE_report(reports, RPT_ERROR, "Error writing render result (see console)"); success = false; } - IMB_exr_close(exrhandle); + IMB_exr_close(exrhandle); return success; } @@ -894,7 +1207,7 @@ void render_result_single_layer_end(Render *re) /************************* EXR Tile File Rendering ***************************/ -static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart) +static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, const char *viewname) { RenderLayer *rlp, *rl; RenderPass *rpassp; @@ -917,21 +1230,17 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart) else { offs = 0; } - - /* combined */ - if (rlp->rectf) { - int a, xstride = 4; - for (a = 0; a < xstride; a++) { - IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a), - xstride, xstride * rrpart->rectx, rlp->rectf + a + xstride * offs); - } - } - + /* passes are allocated in sync */ for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) { - int a, xstride = rpassp->channels; + const int xstride = rpassp->channels; + int a; + char passname[EXR_PASS_MAXNAME]; + for (a = 0; a < xstride; a++) { - IMB_exr_set_channel(rl->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a), + set_pass_name(passname, rpassp->passtype, a, rpassp->view); + + IMB_exr_set_channel(rl->exrhandle, rlp->name, passname, xstride, xstride * rrpart->rectx, rpassp->rect + a + xstride * offs); } } @@ -950,13 +1259,13 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart) continue; } - IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0); + IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, viewname); } BLI_unlock_thread(LOCK_IMAGE); } -static void save_empty_result_tiles(Render *re) +void render_result_save_empty_result_tiles(Render *re) { RenderPart *pa; RenderResult *rr; @@ -964,13 +1273,13 @@ static void save_empty_result_tiles(Render *re) for (rr = re->result; rr; rr = rr->next) { for (rl = rr->layers.first; rl; rl = rl->next) { - IMB_exrtile_clear_channels(rl->exrhandle); + IMB_exr_clear_channels(rl->exrhandle); for (pa = re->parts.first; pa; pa = pa->next) { if (pa->status != PART_STATUS_READY) { int party = pa->disprect.ymin - re->disprect.ymin + pa->crop; int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop; - IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0); + IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0, re->viewname); } } } @@ -999,8 +1308,6 @@ void render_result_exr_file_end(Render *re) RenderResult *rr; RenderLayer *rl; - save_empty_result_tiles(re); - for (rr = re->result; rr; rr = rr->next) { for (rl = rr->layers.first; rl; rl = rl->next) { IMB_exr_close(rl->exrhandle); @@ -1017,18 +1324,18 @@ void render_result_exr_file_end(Render *re) } /* save part into exr file */ -void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart) +void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart, const char *viewname) { for (; rr && rrpart; rr = rr->next, rrpart = rrpart->next) - save_render_result_tile(rr, rrpart); + save_render_result_tile(rr, rrpart, viewname); } /* path to temporary exr file */ void render_result_exr_file_path(Scene *scene, const char *layname, int sample, char *filepath) { - char name[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100], fi[FILE_MAXFILE]; + char name[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100]; + const char *fi = BLI_path_basename(G.main->name); - BLI_split_file_part(G.main->name, fi, sizeof(fi)); if (sample == 0) { BLI_snprintf(name, sizeof(name), "%s_%s_%s.exr", fi, scene->id.name + 2, layname); } @@ -1036,7 +1343,10 @@ void render_result_exr_file_path(Scene *scene, const char *layname, int sample, BLI_snprintf(name, sizeof(name), "%s_%s_%s%d.exr", fi, scene->id.name + 2, layname, sample); } - BLI_make_file_string("/", filepath, BLI_temp_dir_session(), name); + /* Make name safe for paths, see T43275. */ + BLI_filename_make_safe(name); + + BLI_make_file_string("/", filepath, BKE_tempdir_session(), name); } /* only for temp buffer, makes exact copy of render result */ @@ -1047,7 +1357,7 @@ int render_result_exr_file_read_sample(Render *re, int sample) bool success = true; RE_FreeRenderResult(re->result); - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); for (rl = re->result->layers.first; rl; rl = rl->next) { render_result_exr_file_path(re->scene, rl->name, sample, str); @@ -1088,23 +1398,20 @@ int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, c for (rl = rr->layers.first; rl; rl = rl->next) { if (rl_single && rl_single != rl) continue; - - /* combined */ - if (rl->rectf) { - int a, xstride = 4; - for (a = 0; a < xstride; a++) - IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a), - xstride, xstride * rectx, rl->rectf + a); - } /* passes are allocated in sync */ for (rpass = rl->passes.first; rpass; rpass = rpass->next) { - int a, xstride = rpass->channels; - for (a = 0; a < xstride; a++) - IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a), + const int xstride = rpass->channels; + int a; + char passname[EXR_PASS_MAXNAME]; + + for (a = 0; a < xstride; a++) { + set_pass_name(passname, rpass->passtype, a, rpass->view); + IMB_exr_set_channel(exrhandle, rl->name, passname, xstride, xstride * rectx, rpass->rect + a); + } - BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name)); + set_pass_name(rpass->name, rpass->passtype, -1, rpass->view); } } @@ -1124,17 +1431,17 @@ static void render_result_exr_file_cache_path(Scene *sce, const char *root, char if (G.main->name[0]) { BLI_split_dirfile(G.main->name, dirname, filename, sizeof(dirname), sizeof(filename)); BLI_replace_extension(filename, sizeof(filename), ""); /* strip '.blend' */ - md5_buffer(G.main->name, strlen(G.main->name), path_digest); + BLI_hash_md5_buffer(G.main->name, strlen(G.main->name), path_digest); } else { - BLI_strncpy(dirname, BLI_temp_dir_base(), sizeof(dirname)); + BLI_strncpy(dirname, BKE_tempdir_base(), sizeof(dirname)); BLI_strncpy(filename, "UNSAVED", sizeof(filename)); } - md5_to_hexdigest(path_digest, path_hexdigest); + BLI_hash_md5_to_hexdigest(path_digest, path_hexdigest); /* Default to *non-volatile* tmp dir. */ if (*root == '\0') { - root = BLI_temp_dir_base(); + root = BKE_tempdir_base(); } BLI_snprintf(filename_full, sizeof(filename_full), "cached_RR_%s_%s_%s.exr", @@ -1150,7 +1457,8 @@ void render_result_exr_file_cache_write(Render *re) render_result_exr_file_cache_path(re->scene, root, str); printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str); - RE_WriteRenderResult(NULL, rr, str, 0); + + RE_WriteRenderResult(NULL, rr, str, NULL, true, NULL); } /* For cache, makes exact copy of render result */ @@ -1160,7 +1468,7 @@ bool render_result_exr_file_cache_read(Render *re) char *root = U.render_cachedir; RE_FreeRenderResult(re->result); - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); /* First try cache. */ render_result_exr_file_cache_path(re->scene, root, str); @@ -1175,15 +1483,16 @@ bool render_result_exr_file_cache_read(Render *re) /*************************** Combined Pixel Rect *****************************/ -ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd) +ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd, const int view_id) { ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, 0); - + RenderView *rv = RE_RenderViewGetById(rr, view_id); + /* if not exists, BKE_imbuf_write makes one */ - ibuf->rect = (unsigned int *)rr->rect32; - ibuf->rect_float = rr->rectf; - ibuf->zbuf_float = rr->rectz; - + ibuf->rect = (unsigned int *) rv->rect32; + ibuf->rect_float = rv->rectf; + ibuf->zbuf_float = rv->rectz; + /* float factor for random dither, imbuf takes care of it */ ibuf->dither = rd->dither_intensity; @@ -1218,57 +1527,97 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd) return ibuf; } -void render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf) +void render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf, const int view_id) { + RenderView *rv = RE_RenderViewGetById(rr, view_id); + if (ibuf->rect_float) { - if (!rr->rectf) - rr->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf"); + if (!rv->rectf) + rv->rectf = MEM_mallocN(4 * sizeof(float) * rr->rectx * rr->recty, "render_seq rectf"); - memcpy(rr->rectf, ibuf->rect_float, 4 * sizeof(float) * rr->rectx * rr->recty); + memcpy(rv->rectf, ibuf->rect_float, 4 * sizeof(float) * rr->rectx * rr->recty); /* TSK! Since sequence render doesn't free the *rr render result, the old rect32 * can hang around when sequence render has rendered a 32 bits one before */ - if (rr->rect32) { - MEM_freeN(rr->rect32); - rr->rect32 = NULL; - } + MEM_SAFE_FREE(rv->rect32); } else if (ibuf->rect) { - if (!rr->rect32) - rr->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect"); + if (!rv->rect32) + rv->rect32 = MEM_mallocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect"); - memcpy(rr->rect32, ibuf->rect, 4 * rr->rectx * rr->recty); + memcpy(rv->rect32, ibuf->rect, 4 * rr->rectx * rr->recty); /* Same things as above, old rectf can hang around from previous render. */ - if (rr->rectf) { - MEM_freeN(rr->rectf); - rr->rectf = NULL; - } + MEM_SAFE_FREE(rv->rectf); } } -void render_result_rect_fill_zero(RenderResult *rr) +void render_result_rect_fill_zero(RenderResult *rr, const int view_id) { - if (rr->rectf) - memset(rr->rectf, 0, 4 * sizeof(float) * rr->rectx * rr->recty); - else if (rr->rect32) - memset(rr->rect32, 0, 4 * rr->rectx * rr->recty); + RenderView *rv = RE_RenderViewGetById(rr, view_id); + + if (rv->rectf) + memset(rv->rectf, 0, 4 * sizeof(float) * rr->rectx * rr->recty); + else if (rv->rect32) + memset(rv->rect32, 0, 4 * rr->rectx * rr->recty); else - rr->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect"); + rv->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect"); } void render_result_rect_get_pixels(RenderResult *rr, unsigned int *rect, int rectx, int recty, - const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings) + const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, + const int view_id) { - if (rr->rect32) { - memcpy(rect, rr->rect32, sizeof(int) * rr->rectx * rr->recty); - } - else if (rr->rectf) { - IMB_display_buffer_transform_apply((unsigned char *) rect, rr->rectf, rr->rectx, rr->recty, 4, + RenderView *rv = RE_RenderViewGetById(rr, view_id); + + if (rv->rect32) + memcpy(rect, rv->rect32, sizeof(int) * rr->rectx * rr->recty); + else if (rv->rectf) + IMB_display_buffer_transform_apply((unsigned char *) rect, rv->rectf, rr->rectx, rr->recty, 4, view_settings, display_settings, true); - } else /* else fill with black */ memset(rect, 0, sizeof(int) * rectx * recty); } + +/*************************** multiview functions *****************************/ + +bool RE_HasFakeLayer(RenderResult *res) +{ + RenderView *rv; + + if (res == NULL) + return false; + + rv = res->views.first; + if (rv == NULL) + return false; + + return (rv->rect32 || rv->rectf); +} + +bool RE_RenderResult_is_stereo(RenderResult *res) +{ + if (! BLI_findstring(&res->views, STEREO_LEFT_NAME, offsetof(RenderView, name))) + return false; + + if (! BLI_findstring(&res->views, STEREO_RIGHT_NAME, offsetof(RenderView, name))) + return false; + + return true; +} + +RenderView *RE_RenderViewGetById(RenderResult *res, const int view_id) +{ + RenderView *rv = BLI_findlink(&res->views, view_id); + BLI_assert(res->views.first); + return rv ? rv : res->views.first; +} + +RenderView *RE_RenderViewGetByName(RenderResult *res, const char *viewname) +{ + RenderView *rv = BLI_findstring(&res->views, viewname, offsetof(RenderView, name)); + BLI_assert(res->views.first); + return rv ? rv : res->views.first; +} diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index ae01779e814..b282ec0593e 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -48,7 +48,6 @@ #include "DNA_node_types.h" #include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" #include "IMB_colormanagement.h" #include "BKE_image.h" @@ -68,9 +67,7 @@ #include "envmap.h" #include "pointdensity.h" #include "voxeldata.h" -#include "renderpipeline.h" #include "render_types.h" -#include "rendercore.h" #include "shading.h" #include "texture.h" #include "texture_ocean.h" @@ -85,8 +82,19 @@ extern struct Render R; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +static RNG_THREAD_ARRAY *random_tex_array; +void RE_init_texture_rng(void) +{ + random_tex_array = BLI_rng_threaded_new(); +} + +void RE_exit_texture_rng(void) +{ + BLI_rng_threaded_free(random_tex_array); +} + static void init_render_texture(Render *re, Tex *tex) { @@ -108,7 +116,7 @@ static void init_render_texture(Render *re, Tex *tex) if (G.is_rendering && re) { if (re->r.mode & R_ENVMAP) if (tex->env->stype==ENV_ANIM) - BKE_free_envmapdata(tex->env); + BKE_texture_envmap_free_data(tex->env); } } } @@ -212,10 +220,10 @@ static int blend(Tex *tex, const float texvec[3], TexResult *texres) texres->tin= (2.0f+x+y)/4.0f; } else if (tex->stype==TEX_RAD) { /* radial */ - texres->tin = (atan2f(y, x) / (2 * M_PI) + 0.5f); + texres->tin = (atan2f(y, x) / (float)(2 * M_PI) + 0.5f); } else { /* sphere TEX_SPHERE */ - texres->tin = 1.0 - sqrtf(x * x + y * y + texvec[2] * texvec[2]); + texres->tin = 1.0f - sqrtf(x * x + y * y + texvec[2] * texvec[2]); if (texres->tin<0.0f) texres->tin= 0.0f; if (tex->stype==TEX_HALO) texres->tin*= texres->tin; /* halo */ } @@ -266,7 +274,7 @@ static int clouds(Tex *tex, const float texvec[3], TexResult *texres) /* creates a sine wave */ static float tex_sin(float a) { - a = 0.5 + 0.5 * sinf(a); + a = 0.5f + 0.5f * sinf(a); return a; } @@ -709,19 +717,22 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres) /* ------------------------------------------------------------------------- */ -static int texnoise(Tex *tex, TexResult *texres) +static int texnoise(Tex *tex, TexResult *texres, int thread) { float div=3.0; - int val, ran, loop; + int val, ran, loop, shift = 29; - ran= BLI_rand(); - val= (ran & 3); + ran= BLI_rng_thread_rand(random_tex_array, thread); loop= tex->noisedepth; + + /* start from top bits since they have more variance */ + val= ((ran >> shift) & 3); + while (loop--) { - ran= (ran>>2); - val*= (ran & 3); - div*= 3.0f; + shift -= 2; + val *= ((ran >> shift) & 3); + div *= 3.0f; } texres->tin= ((float)val)/div; @@ -1092,7 +1103,7 @@ static void do_2d_mapping(MTex *mtex, float texvec[3], VlakRen *vlr, const float /* ************************************** */ -static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, const short thread, short which_output, struct ImagePool *pool) +static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, const short thread, short which_output, struct ImagePool *pool, const bool skip_load_image) { float tmpvec[3]; int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */ @@ -1127,17 +1138,17 @@ static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int o retval = stucci(tex, texvec, texres); break; case TEX_NOISE: - retval = texnoise(tex, texres); + retval = texnoise(tex, texres, thread); break; case TEX_IMAGE: - if (osatex) retval = imagewraposa(tex, tex->ima, NULL, texvec, dxt, dyt, texres, pool); - else retval = imagewrap(tex, tex->ima, NULL, texvec, texres, pool); + if (osatex) retval = imagewraposa(tex, tex->ima, NULL, texvec, dxt, dyt, texres, pool, skip_load_image); + else retval = imagewrap(tex, tex->ima, NULL, texvec, texres, pool, skip_load_image); if (tex->ima) { BKE_image_tag_time(tex->ima); } break; case TEX_ENVMAP: - retval = envmaptex(tex, texvec, dxt, dyt, osatex, texres, pool); + retval = envmaptex(tex, texvec, dxt, dyt, osatex, texres, pool, skip_load_image); break; case TEX_MUSGRAVE: /* newnoise: musgrave types */ @@ -1209,7 +1220,7 @@ static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int o static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, const short thread, short which_output, ShadeInput *shi, MTex *mtex, struct ImagePool *pool, - bool scene_color_manage) + bool scene_color_manage, const bool skip_load_image) { if (tex==NULL) { memset(texres, 0, sizeof(TexResult)); @@ -1225,7 +1236,7 @@ static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float if (mtex) { /* we have mtex, use it for 2d mapping images only */ do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt); - rgbnor = multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool); + rgbnor = multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool, skip_load_image); if (mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) { ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); @@ -1258,7 +1269,7 @@ static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float } do_2d_mapping(&localmtex, texvec_l, NULL, NULL, dxt_l, dyt_l); - rgbnor = multitex(tex, texvec_l, dxt_l, dyt_l, osatex, texres, thread, which_output, pool); + rgbnor = multitex(tex, texvec_l, dxt_l, dyt_l, osatex, texres, thread, which_output, pool, skip_load_image); { ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool); @@ -1274,7 +1285,7 @@ static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float return rgbnor; } else { - return multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool); + return multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool, skip_load_image); } } @@ -1285,11 +1296,12 @@ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int os const short thread, short which_output, ShadeInput *shi, MTex *mtex, struct ImagePool *pool) { return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres, - thread, which_output, shi, mtex, pool, R.scene_color_manage); + thread, which_output, shi, mtex, pool, R.scene_color_manage, + (R.r.scemode & R_NO_IMAGE_LOAD) != 0); } /* this is called for surface shading */ -static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt[3], float dyt[3], TexResult *texres, struct ImagePool *pool) +static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt[3], float dyt[3], TexResult *texres, struct ImagePool *pool, const bool skip_load_image) { Tex *tex = mtex->tex; @@ -1300,7 +1312,7 @@ static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt tex, mtex->which_output, R.r.cfra, (R.r.scemode & R_TEXNODE_PREVIEW) != 0, shi, mtex); } else { - return multitex(mtex->tex, texvec, dxt, dyt, shi->osatex, texres, shi->thread, mtex->which_output, pool); + return multitex(mtex->tex, texvec, dxt, dyt, shi->osatex, texres, shi->thread, mtex->which_output, pool, skip_load_image); } } @@ -1309,21 +1321,21 @@ static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt * * Use it for stuff which is out of render pipeline. */ -int multitex_ext(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool, bool scene_color_manage) +int multitex_ext(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image) { - return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres, 0, 0, NULL, NULL, pool, scene_color_manage); + return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres, 0, 0, NULL, NULL, pool, scene_color_manage, skip_load_image); } /* extern-tex doesn't support nodes (ntreeBeginExec() can't be called when rendering is going on)\ * * Use it for stuff which is out of render pipeline. */ -int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct ImagePool *pool, bool scene_color_manage) +int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image) { int use_nodes= tex->use_nodes, retval; tex->use_nodes = false; - retval= multitex_nodes_intern(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL, pool, scene_color_manage); + retval= multitex_nodes_intern(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL, pool, scene_color_manage, skip_load_image); tex->use_nodes= use_nodes; return retval; @@ -1336,7 +1348,7 @@ int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct Image /* fact = texture strength, facg = button strength value */ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype) { - float facm, col; + float facm; switch (blendtype) { case MTEX_BLEND: @@ -1423,13 +1435,10 @@ void texture_rgb_blend(float in[3], const float tex[3], const float out[3], floa case MTEX_LIGHT: fact*= facg; - - col= fact*tex[0]; - if (col > out[0]) in[0]= col; else in[0]= out[0]; - col= fact*tex[1]; - if (col > out[1]) in[1]= col; else in[1]= out[1]; - col= fact*tex[2]; - if (col > out[2]) in[2]= col; else in[2]= out[2]; + + in[0] = max_ff(fact * tex[0], out[0]); + in[1] = max_ff(fact * tex[1], out[1]); + in[2] = max_ff(fact * tex[2], out[2]); break; case MTEX_BLEND_HUE: @@ -1707,7 +1716,7 @@ static void compatible_bump_uv_derivs(CompatibleBump *compat_bump, ShadeInput *s static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres, float Tnor, const float co[3], const float dx[3], const float dy[3], float texvec[3], float dxt[3], float dyt[3], - struct ImagePool *pool) + struct ImagePool *pool, const bool skip_load_image) { TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; /* temp TexResult */ float tco[3], texv[3], cd, ud, vd, du, dv, idu, idv; @@ -1760,7 +1769,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, /* center, main return value */ texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); - rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool); + rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool, skip_load_image); cd = fromrgb ? (texres->tr + texres->tg + texres->tb) / 3.0f : texres->tin; if (mtex->texco == TEXCO_UV) { @@ -1774,7 +1783,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, tco[1] = co[1] + compat_bump->dvdnu*du; tco[2] = 0.f; texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt); - multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool); + multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image); ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin)); /* +v val */ @@ -1782,7 +1791,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, tco[1] = co[1] + compat_bump->dvdnv*du; tco[2] = 0.f; texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt); - multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool); + multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image); vd = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin)); } else { @@ -1816,7 +1825,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, tco[1] = co[1] + tu[1]*du; tco[2] = co[2] + tu[2]*du; texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt); - multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool); + multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image); ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin)); /* +v val */ @@ -1824,7 +1833,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, tco[1] = co[1] + tv[1]*dv; tco[2] = co[2] + tv[2]*dv; texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt); - multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool); + multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image); vd = idv*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin)); } @@ -1866,7 +1875,8 @@ static void ntap_bump_init(NTapBump *ntap_bump) static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres, float Tnor, const float co[3], const float dx[3], const float dy[3], - float texvec[3], float dxt[3], float dyt[3], struct ImagePool *pool) + float texvec[3], float dxt[3], float dyt[3], struct ImagePool *pool, + const bool skip_load_image) { TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; /* temp TexResult */ @@ -1926,7 +1936,7 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T float dBdu, dBdv, auto_bump = 1.0f; float s = 1; /* negate this if flipped texture coordinate */ texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); - rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool); + rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool, skip_load_image); if (shi->obr->ob->derivedFinal) { auto_bump = shi->obr->ob->derivedFinal->auto_bump_scale; @@ -1968,15 +1978,15 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T } /* use texres for the center sample, set rgbnor */ - rgbnor = multitex_mtex(shi, mtex, STll, dxt, dyt, texres, pool); - Hll = (fromrgb) ? rgb_to_grayscale(&texres->tr) : texres->tin; + rgbnor = multitex_mtex(shi, mtex, STll, dxt, dyt, texres, pool, skip_load_image); + Hll = (fromrgb) ? IMB_colormanagement_get_luminance(&texres->tr) : texres->tin; /* use ttexr for the other 2 taps */ - multitex_mtex(shi, mtex, STlr, dxt, dyt, &ttexr, pool); - Hlr = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; + multitex_mtex(shi, mtex, STlr, dxt, dyt, &ttexr, pool, skip_load_image); + Hlr = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin; - multitex_mtex(shi, mtex, STul, dxt, dyt, &ttexr, pool); - Hul = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; + multitex_mtex(shi, mtex, STul, dxt, dyt, &ttexr, pool, skip_load_image); + Hul = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin; dHdx = Hscale*(Hlr - Hll); dHdy = Hscale*(Hul - Hll); @@ -2006,18 +2016,18 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T } /* use texres for the center sample, set rgbnor */ - rgbnor = multitex_mtex(shi, mtex, STc, dxt, dyt, texres, pool); - /* Hc = (fromrgb) ? rgb_to_grayscale(&texres->tr) : texres->tin; */ /* UNUSED */ + rgbnor = multitex_mtex(shi, mtex, STc, dxt, dyt, texres, pool, skip_load_image); + /* Hc = (fromrgb) ? IMB_colormanagement_get_luminance(&texres->tr) : texres->tin; */ /* UNUSED */ /* use ttexr for the other taps */ - multitex_mtex(shi, mtex, STl, dxt, dyt, &ttexr, pool); - Hl = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; - multitex_mtex(shi, mtex, STr, dxt, dyt, &ttexr, pool); - Hr = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; - multitex_mtex(shi, mtex, STd, dxt, dyt, &ttexr, pool); - Hd = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; - multitex_mtex(shi, mtex, STu, dxt, dyt, &ttexr, pool); - Hu = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin; + multitex_mtex(shi, mtex, STl, dxt, dyt, &ttexr, pool, skip_load_image); + Hl = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin; + multitex_mtex(shi, mtex, STr, dxt, dyt, &ttexr, pool, skip_load_image); + Hr = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin; + multitex_mtex(shi, mtex, STd, dxt, dyt, &ttexr, pool, skip_load_image); + Hd = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin; + multitex_mtex(shi, mtex, STu, dxt, dyt, &ttexr, pool, skip_load_image); + Hu = (fromrgb) ? IMB_colormanagement_get_luminance(&ttexr.tr) : ttexr.tin; dHdx = Hscale*(Hr - Hl); dHdy = Hscale*(Hu - Hd); @@ -2126,6 +2136,7 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T void do_material_tex(ShadeInput *shi, Render *re) { + const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0; CompatibleBump compat_bump; NTapBump ntap_bump; MTex *mtex; @@ -2238,7 +2249,7 @@ void do_material_tex(ShadeInput *shi, Render *re) if (mtex->uvname[0] != 0) { for (i = 0; i < shi->totuv; i++) { - if (strcmp(shi->uv[i].name, mtex->uvname)==0) { + if (STREQ(shi->uv[i].name, mtex->uvname)) { suv= &shi->uv[i]; break; } @@ -2294,27 +2305,27 @@ void do_material_tex(ShadeInput *shi, Render *re) if (use_compat_bump) { rgbnor = compatible_bump_compute(&compat_bump, shi, mtex, tex, &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt, - re->pool); + re->pool, skip_load_image); } else if (use_ntap_bump) { rgbnor = ntap_bump_compute(&ntap_bump, shi, mtex, tex, &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt, - re->pool); + re->pool, skip_load_image); } else { texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); - rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool); + rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool, skip_load_image); } } else { texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); - rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool); + rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool, skip_load_image); } /* texture output */ if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) { - texres.tin = rgb_to_grayscale(&texres.tr); + texres.tin = IMB_colormanagement_get_luminance(&texres.tr); rgbnor -= TEX_RGB; } if (mtex->texflag & MTEX_NEGATIVE) { @@ -2420,7 +2431,7 @@ void do_material_tex(ShadeInput *shi, Render *re) BKE_image_pool_release_ibuf(ima, ibuf, re->pool); } - + if (mtex->mapto & MAP_COL) { float colfac= mtex->colfac*stencilTin; texture_rgb_blend(&shi->r, tcol, &shi->r, texres.tin, colfac, mtex->blendtype); @@ -2554,7 +2565,7 @@ void do_material_tex(ShadeInput *shi, Render *re) } if (rgbnor & TEX_RGB) { - texres.tin = rgb_to_grayscale(&texres.tr); + texres.tin = IMB_colormanagement_get_luminance(&texres.tr); } factt= (0.5f-texres.tin)*mtex->dispfac*stencilTin; facmm= 1.0f-factt; @@ -2582,7 +2593,7 @@ void do_material_tex(ShadeInput *shi, Render *re) if (rgbnor & TEX_RGB) { if (texres.talpha) texres.tin = texres.ta; - else texres.tin = rgb_to_grayscale(&texres.tr); + else texres.tin = IMB_colormanagement_get_luminance(&texres.tr); } if (mtex->mapto & MAP_REF) { @@ -2660,6 +2671,7 @@ void do_material_tex(ShadeInput *shi, Render *re) void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_r[3], float *val, Render *re) { + const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0; MTex *mtex; Tex *tex; TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL}; @@ -2747,12 +2759,12 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_ else texvec[2]= mtex->size[2]*(mtex->ofs[2]); } - rgbnor = multitex(tex, texvec, NULL, NULL, 0, &texres, shi->thread, mtex->which_output, re->pool); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */ + rgbnor = multitex(tex, texvec, NULL, NULL, 0, &texres, shi->thread, mtex->which_output, re->pool, skip_load_image); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */ /* texture output */ if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) { - texres.tin = rgb_to_grayscale(&texres.tr); + texres.tin = IMB_colormanagement_get_luminance(&texres.tr); rgbnor -= TEX_RGB; } if (mtex->texflag & MTEX_NEGATIVE) { @@ -2821,7 +2833,7 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_ /* convert RGB to intensity if intensity info isn't provided */ if (rgbnor & TEX_RGB) { if (texres.talpha) texres.tin = texres.ta; - else texres.tin = rgb_to_grayscale(&texres.tr); + else texres.tin = IMB_colormanagement_get_luminance(&texres.tr); } if ((mapto_flag & MAP_EMISSION) && (mtex->mapto & MAP_EMISSION)) { @@ -2858,6 +2870,7 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4]) { + const bool skip_load_image = har->skip_load_image; MTex *mtex; TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL}; float texvec[3], dxt[3], dyt[3], fact, facm, dx; @@ -2914,11 +2927,11 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4]) if (mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt); - rgb = multitex(mtex->tex, texvec, dxt, dyt, osatex, &texres, 0, mtex->which_output, har->pool); + rgb = multitex(mtex->tex, texvec, dxt, dyt, osatex, &texres, 0, mtex->which_output, har->pool, skip_load_image); /* texture output */ if (rgb && (mtex->texflag & MTEX_RGBTOINT)) { - texres.tin = rgb_to_bw(&texres.tr); + texres.tin = IMB_colormanagement_get_luminance(&texres.tr); rgb= 0; } if (mtex->texflag & MTEX_NEGATIVE) { @@ -2990,7 +3003,7 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4]) texres.tin = texres.ta; } else { - texres.tin = rgb_to_bw(&texres.tr); + texres.tin = IMB_colormanagement_get_luminance(&texres.tr); } } @@ -3003,6 +3016,7 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4]) /* hor and zen are RGB vectors, blend is 1 float, should all be initialized */ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float hor[3], float zen[3], float *blend, int skyflag, short thread) { + const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0; MTex *mtex; Tex *tex; TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL}; @@ -3039,7 +3053,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h switch (mtex->texco) { case TEXCO_ANGMAP: /* only works with texture being "real" */ - /* use saacos(), fixes bug [#22398], float precision caused lo[2] to be slightly less then -1.0 */ + /* use saacos(), fixes bug [#22398], float precision caused lo[2] to be slightly less than -1.0 */ if (lo[0] || lo[1]) { /* check for zero case [#24807] */ fact= (1.0f/(float)M_PI)*saacos(lo[2])/(sqrtf(lo[0]*lo[0] + lo[1]*lo[1])); tempvec[0]= lo[0]*fact; @@ -3119,11 +3133,11 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h /* texture */ if (tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt); - rgb = multitex(mtex->tex, texvec, dxt, dyt, R.osa, &texres, thread, mtex->which_output, R.pool); + rgb = multitex(mtex->tex, texvec, dxt, dyt, R.osa, &texres, thread, mtex->which_output, R.pool, skip_load_image); /* texture output */ if (rgb && (mtex->texflag & MTEX_RGBTOINT)) { - texres.tin = rgb_to_bw(&texres.tr); + texres.tin = IMB_colormanagement_get_luminance(&texres.tr); rgb= 0; } if (mtex->texflag & MTEX_NEGATIVE) { @@ -3198,7 +3212,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h } } if (mtex->mapto & WOMAP_BLEND) { - if (rgb) texres.tin = rgb_to_bw(&texres.tr); + if (rgb) texres.tin = IMB_colormanagement_get_luminance(&texres.tr); *blend= texture_value_blend(mtex->def_var, *blend, texres.tin, mtex->blendfac, mtex->blendtype); } @@ -3211,6 +3225,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r[3], int effect) { + const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0; Object *ob; MTex *mtex; Tex *tex; @@ -3334,11 +3349,11 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt); } - rgb = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output, R.pool); + rgb = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output, R.pool, skip_load_image); /* texture output */ if (rgb && (mtex->texflag & MTEX_RGBTOINT)) { - texres.tin = rgb_to_bw(&texres.tr); + texres.tin = IMB_colormanagement_get_luminance(&texres.tr); rgb= 0; } if (mtex->texflag & MTEX_NEGATIVE) { @@ -3396,8 +3411,11 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r col[0]= texres.tr*la->energy; col[1]= texres.tg*la->energy; col[2]= texres.tb*la->energy; - - texture_rgb_blend(col_r, col, col_r, texres.tin, mtex->colfac, mtex->blendtype); + + if (effect & LA_SHAD_TEX) + texture_rgb_blend(col_r, col, col_r, texres.tin, mtex->shadowfac, mtex->blendtype); + else + texture_rgb_blend(col_r, col, col_r, texres.tin, mtex->colfac, mtex->blendtype); } } } @@ -3405,7 +3423,7 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r /* ------------------------------------------------------------------------- */ -int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool) +int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool, const bool skip_load_image) { Tex *tex; TexResult texr; @@ -3431,10 +3449,10 @@ int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt); } - rgb = multitex(tex, texvec, dxt, dyt, 0, &texr, thread, mtex->which_output, pool); + rgb = multitex(tex, texvec, dxt, dyt, 0, &texr, thread, mtex->which_output, pool, skip_load_image); if (rgb) { - texr.tin = rgb_to_bw(&texr.tr); + texr.tin = IMB_colormanagement_get_luminance(&texr.tr); } else { texr.tr= mtex->r; @@ -3456,6 +3474,7 @@ int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, void render_realtime_texture(ShadeInput *shi, Image *ima) { + const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0; TexResult texr; static Tex imatex[BLENDER_MAX_THREADS]; /* threadsafe */ static int firsttime= 1; @@ -3471,7 +3490,7 @@ void render_realtime_texture(ShadeInput *shi, Image *ima) if (firsttime) { for (a=0; a<BLENDER_MAX_THREADS; a++) { memset(&imatex[a], 0, sizeof(Tex)); - default_tex(&imatex[a]); + BKE_texture_default(&imatex[a]); imatex[a].type= TEX_IMAGE; } @@ -3496,8 +3515,8 @@ void render_realtime_texture(ShadeInput *shi, Image *ima) texr.nor= NULL; - if (shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr, R.pool); - else imagewrap(tex, ima, NULL, texvec, &texr, R.pool); + if (shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr, R.pool, skip_load_image); + else imagewrap(tex, ima, NULL, texvec, &texr, R.pool, skip_load_image); shi->vcol[0]*= texr.tr; shi->vcol[1]*= texr.tg; @@ -3507,7 +3526,10 @@ void render_realtime_texture(ShadeInput *shi, Image *ima) /* A modified part of shadeinput.c -> shade_input_set_uv() * Used for sampling UV mapped texture color */ -static void textured_face_generate_uv(float *uv, const float normal[3], float *hit, float *v1, float *v2, float *v3) +static void textured_face_generate_uv( + const float normal[3], const float hit[3], + const float v1[3], const float v2[3], const float v3[3], + float r_uv[2]) { float detsh, t00, t10, t01, t11; @@ -3524,12 +3546,12 @@ static void textured_face_generate_uv(float *uv, const float normal[3], float *h t00*= detsh; t01*=detsh; t10*=detsh; t11*=detsh; - uv[0] = (hit[axis1]-v3[axis1])*t11-(hit[axis2]-v3[axis2])*t10; - uv[1] = (hit[axis2]-v3[axis2])*t00-(hit[axis1]-v3[axis1])*t01; + r_uv[0] = (hit[axis1] - v3[axis1]) * t11 - (hit[axis2] - v3[axis2]) * t10; + r_uv[1] = (hit[axis2] - v3[axis2]) * t00 - (hit[axis1] - v3[axis1]) * t01; /* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */ - CLAMP(uv[0], -2.0f, 1.0f); - CLAMP(uv[1], -2.0f, 1.0f); + CLAMP(r_uv[0], -2.0f, 1.0f); + CLAMP(r_uv[1], -2.0f, 1.0f); } /* Generate an updated copy of material to use for color sampling. */ @@ -3592,7 +3614,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene) } /* copy texture */ - tex= mtex->tex = localize_texture(cur_tex); + tex= mtex->tex = BKE_texture_localize(cur_tex); /* update texture anims */ BKE_animsys_evaluate_animdata(scene, &tex->id, tex->adt, BKE_scene_frame_get(scene), ADT_RECALC_ANIM); @@ -3609,7 +3631,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene) unit_m4(dummy_re.viewmat); unit_m4(dummy_re.winmat); dummy_re.winx = dummy_re.winy = 128; - cache_pointdensity(&dummy_re, tex); + cache_pointdensity(&dummy_re, tex->pd); } /* update image sequences and movies */ @@ -3645,34 +3667,37 @@ void RE_free_sample_material(Material *mat) MEM_freeN(mat); } - - /* * Get material diffuse color and alpha (including linked textures) in given coordinates * * color,alpha : input/output color values * volume_co : sample coordinate in global space. used by volumetric materials * surface_co : sample surface coordinate in global space. used by "surface" materials - * face_index : surface face index - * hit_quad : whether point is on second "half" of a quad + * tri_index : surface tri index * orcoDm : orco state derived mesh */ -void RE_sample_material_color(Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3], int face_index, short hit_quad, DerivedMesh *orcoDm, Object *ob) +void RE_sample_material_color( + Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3], + int tri_index, DerivedMesh *orcoDm, Object *ob) { - MFace *mface; int v1, v2, v3; MVert *mvert; + MLoop *mloop; + const MLoopTri *mlooptri; float uv[3], normal[3]; ShadeInput shi = {NULL}; Render re = {NULL}; /* Get face data */ mvert = orcoDm->getVertArray(orcoDm); - mface = orcoDm->getTessFaceArray(orcoDm); + mloop = orcoDm->getLoopArray(orcoDm); + mlooptri = orcoDm->getLoopTriArray(orcoDm); - if (!mvert || !mface || !mat) return; - v1=mface[face_index].v1, v2=mface[face_index].v2, v3=mface[face_index].v3; - if (hit_quad) { v2 = mface[face_index].v3; v3 = mface[face_index].v4; } + if (!mvert || !mlooptri || !mat) { + return; + } + + v1=mloop[mlooptri[tri_index].tri[0]].v, v2=mloop[mlooptri[tri_index].tri[1]].v, v3=mloop[mlooptri[tri_index].tri[2]].v; normal_tri_v3(normal, mvert[v1].co, mvert[v2].co, mvert[v3].co); /* generate shadeinput with data required */ @@ -3689,7 +3714,7 @@ void RE_sample_material_color(Material *mat, float color[3], float *alpha, const { float l; /* Get generated UV */ - textured_face_generate_uv(uv, normal, shi.co, mvert[v1].co, mvert[v2].co, mvert[v3].co); + textured_face_generate_uv(normal, shi.co, mvert[v1].co, mvert[v2].co, mvert[v3].co, uv); l= 1.0f+uv[0]+uv[1]; /* calculate generated coordinate */ @@ -3699,35 +3724,37 @@ void RE_sample_material_color(Material *mat, float color[3], float *alpha, const } /* uv coordinates */ { - int i, layers = CustomData_number_of_layers(&orcoDm->faceData, CD_MTFACE); - int layer_index = CustomData_get_layer_index(&orcoDm->faceData, CD_MTFACE); + const int layers = CustomData_number_of_layers(&orcoDm->loopData, CD_MLOOPUV); + const int layer_index = CustomData_get_layer_index(&orcoDm->loopData, CD_MLOOPUV); + int i; /* for every uv map set coords and name */ for (i=0; i<layers; i++) { if (layer_index >= 0) { const float *uv1, *uv2, *uv3; + const CustomData *data = &orcoDm->loopData; + const MLoopUV *mloopuv = data->layers[layer_index + i].data; + float uv[2]; float l; - CustomData *data = &orcoDm->faceData; - MTFace *tface = (MTFace *) data->layers[layer_index+i].data; - float uv[3]; + /* point layer name from actual layer data */ shi.uv[i].name = data->layers[i].name; /* Get generated coordinates to calculate UV from */ - textured_face_generate_uv(uv, normal, shi.co, mvert[v1].co, mvert[v2].co, mvert[v3].co); + textured_face_generate_uv(normal, shi.co, mvert[v1].co, mvert[v2].co, mvert[v3].co, uv); /* Get UV mapping coordinate */ l= 1.0f+uv[0]+uv[1]; - - uv1= tface[face_index].uv[0]; - uv2= (hit_quad) ? tface[face_index].uv[2] : tface[face_index].uv[1]; - uv3= (hit_quad) ? tface[face_index].uv[3] : tface[face_index].uv[2]; - + + uv1 = mloopuv[mlooptri[tri_index].tri[0]].uv; + uv2 = mloopuv[mlooptri[tri_index].tri[1]].uv; + uv3 = mloopuv[mlooptri[tri_index].tri[2]].uv; + shi.uv[i].uv[0]= -1.0f + 2.0f*(l*uv3[0]-uv[0]*uv1[0]-uv[1]*uv2[0]); shi.uv[i].uv[1]= -1.0f + 2.0f*(l*uv3[1]-uv[0]*uv1[1]-uv[1]*uv2[1]); shi.uv[i].uv[2]= 0.0f; /* texture.c assumes there are 3 coords */ } } /* active uv map */ - shi.actuv = CustomData_get_active_layer_index(&orcoDm->faceData, CD_MTFACE) - layer_index; + shi.actuv = CustomData_get_active_layer_index(&orcoDm->loopData, CD_MLOOPUV) - layer_index; shi.totuv = layers; } diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index a67140c6334..910ea16607e 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -50,15 +50,7 @@ #include "DNA_material_types.h" #include "DNA_group_types.h" -#include "BKE_main.h" - -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" -#include "IMB_colormanagement.h" - /* local include */ -#include "rayintersection.h" -#include "rayobject.h" #include "renderpipeline.h" #include "render_result.h" #include "render_types.h" @@ -71,8 +63,6 @@ #include "sss.h" #include "zbuf.h" -#include "PIL_time.h" - /* own include */ #include "rendercore.h" @@ -191,8 +181,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in if (fullsample) { for (sample=0; sample<totsample; sample++) - if (ps->mask & (1 << sample)) - addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add); + if (ps->mask & (1 << sample)) { + float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + addalphaAddfacFloat(pass + od*4, col, har->add); + } } else { fac= ((float)amountm)/(float)R.osa; @@ -224,8 +216,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in if (fullsample) { for (sample=0; sample<totsample; sample++) - if (!(mask & (1 << sample))) - addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add); + if (!(mask & (1 << sample))) { + float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + addalphaAddfacFloat(pass + od*4, col, har->add); + } } else { col[0]= accol[0]; @@ -233,8 +227,10 @@ static void halo_pixelstruct(HaloRen *har, RenderLayer **rlpp, int totsample, in col[2]= accol[2]; col[3]= accol[3]; - for (sample=0; sample<totsample; sample++) - addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add); + for (sample=0; sample<totsample; sample++) { + float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + addalphaAddfacFloat(pass + od*4, col, har->add); + } } } @@ -315,8 +311,10 @@ static void halo_tile(RenderPart *pa, RenderLayer *rl) zz= calchalo_z(har, *rz); if ((zz> har->zs) || (har->mat && (har->mat->mode & MA_HALO_SOFT))) { if (shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec)) { - for (sample=0; sample<totsample; sample++) - addalphaAddfacFloat(rlpp[sample]->rectf + od*4, col, har->add); + for (sample=0; sample<totsample; sample++) { + float * rect= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + addalphaAddfacFloat(rect + od*4, col, har->add); + } } } } @@ -369,7 +367,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) if (fullsample) { for (sample=0; sample<totsample; sample++) { if (ps->mask & (1 << sample)) { - pass= rlpp[sample]->rectf + od*4; + pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + pass += od * 4; pass[0]+= col[0]; pass[1]+= col[1]; pass[2]+= col[2]; @@ -380,7 +379,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) } else { fac= ((float)count)/(float)R.osa; - pass= rl->rectf + od*4; + pass = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); + pass += od * 4; pass[0]+= fac*col[0]; pass[1]+= fac*col[1]; pass[2]+= fac*col[2]; @@ -400,7 +400,9 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) if (fullsample) { for (sample=0; sample<totsample; sample++) { if (!(mask & (1 << sample))) { - pass= rlpp[sample]->rectf + od*4; + + pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + pass += od * 4; pass[0]+= col[0]; pass[1]+= col[1]; pass[2]+= col[2]; @@ -411,7 +413,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) } else { fac= ((float)R.osa-totsamp)/(float)R.osa; - pass= rl->rectf + od*4; + pass = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); + pass += od * 4; pass[0]+= fac*col[0]; pass[1]+= fac*col[1]; pass[2]+= fac*col[2]; @@ -430,7 +433,8 @@ static void lamphalo_tile(RenderPart *pa, RenderLayer *rl) renderspothalo(&shi, col, 1.0f); for (sample=0; sample<totsample; sample++) { - pass= rlpp[sample]->rectf + od*4; + pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + pass += od * 4; pass[0]+= col[0]; pass[1]+= col[1]; pass[2]+= col[2]; @@ -454,14 +458,14 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, { RenderPass *rpass; - /* combined rgb */ - add_filt_fmask(curmask, shr->combined, rl->rectf + 4*offset, rectx); - for (rpass= rl->passes.first; rpass; rpass= rpass->next) { float *fp, *col= NULL; int pixsize= 3; switch (rpass->passtype) { + case SCE_PASS_COMBINED: + add_filt_fmask(curmask, shr->combined, rpass->rect + 4*offset, rectx); + break; case SCE_PASS_Z: fp= rpass->rect + offset; *fp= shr->z; @@ -544,9 +548,9 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, fp[2]= shr->winspeed[2]; fp[3]= shr->winspeed[3]; } - } - break; + break; + } case SCE_PASS_RAYHITS: /* */ col= shr->rayhits; @@ -565,15 +569,16 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult { RenderPass *rpass; float *fp; - - fp= rl->rectf + 4*offset; - copy_v4_v4(fp, shr->combined); - + for (rpass= rl->passes.first; rpass; rpass= rpass->next) { float *col= NULL, uvcol[3]; int a, pixsize= 3; switch (rpass->passtype) { + case SCE_PASS_COMBINED: + /* copy combined to use for preview */ + copy_v4_v4(rpass->rect + 4*offset, shr->combined); + break; case SCE_PASS_Z: fp= rpass->rect + offset; *fp= shr->z; @@ -691,7 +696,8 @@ static void sky_tile(RenderPart *pa, RenderLayer *rl) bool done = false; for (sample= 0; sample<totsample; sample++) { - float *pass= rlpp[sample]->rectf + od; + float *pass = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + pass += od; if (pass[3]<1.0f) { @@ -752,8 +758,8 @@ static void atm_tile(RenderPart *pa, RenderLayer *rl) int sample; for (sample=0; sample<totsample; sample++) { - const float *zrect= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_Z) + od; - float *rgbrect = rlpp[sample]->rectf + 4*od; + const float *zrect = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_Z, R.viewname) + od; + float *rgbrect = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname) + 4*od; float rgb[3] = {0}; bool done = false; @@ -988,8 +994,8 @@ static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl) return; for (sample= 0; sample<totsample; sample++) { - float *rectf= rlpp[sample]->rectf; - + float *rectf = RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_COMBINED, R.viewname); + for (y= pa->rectx*pa->recty; y>0; y--, rectf+=4) { rectf[0] = MAX2(rectf[0], 0.0f); rectf[1] = MAX2(rectf[1], 0.0f); @@ -1070,7 +1076,7 @@ static void reset_sky_speed(RenderPart *pa, RenderLayer *rl) totsample= get_sample_layers(pa, rl, rlpp); for (sample= 0; sample<totsample; sample++) { - fp= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_VECTOR); + fp= RE_RenderLayerGetPass(rlpp[sample], SCE_PASS_VECTOR, R.viewname); if (fp==NULL) break; for (a= 4*pa->rectx*pa->recty - 1; a>=0; a--) @@ -1181,6 +1187,8 @@ void zbufshadeDA_tile(RenderPart *pa) pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp"); pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz"); for (rl= rr->layers.first; rl; rl= rl->next) { + float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); + if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK)) pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask"); @@ -1221,7 +1229,7 @@ void zbufshadeDA_tile(RenderPart *pa) if (R.flag & R_ZTRA || R.totstrand) { if (rl->layflag & (SCE_LAY_ZTRA|SCE_LAY_STRAND)) { if (pa->fullresult.first) { - zbuffer_transp_shade(pa, rl, rl->rectf, &psmlist); + zbuffer_transp_shade(pa, rl, rect, &psmlist); } else { unsigned short *ztramask, *solidmask= NULL; /* 16 bits, MAX_OSA */ @@ -1230,9 +1238,9 @@ void zbufshadeDA_tile(RenderPart *pa) rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer"); /* swap for live updates, and it is used in zbuf.c!!! */ - SWAP(float *, rl->acolrect, rl->rectf); - ztramask= zbuffer_transp_shade(pa, rl, rl->rectf, &psmlist); - SWAP(float *, rl->acolrect, rl->rectf); + SWAP(float *, rl->acolrect, rect); + ztramask = zbuffer_transp_shade(pa, rl, rect, &psmlist); + SWAP(float *, rl->acolrect, rect); /* zbuffer transp only returns ztramask if there's solid rendered */ if (ztramask) @@ -1241,7 +1249,8 @@ void zbufshadeDA_tile(RenderPart *pa) if (ztramask && solidmask) { unsigned short *sps= solidmask, *spz= ztramask; unsigned short fullmask= (1<<R.osa)-1; - float *fcol= rl->rectf; float *acol= rl->acolrect; + float *fcol= rect; + float *acol= rl->acolrect; int x; for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4, sps++, spz++) { @@ -1252,7 +1261,8 @@ void zbufshadeDA_tile(RenderPart *pa) } } else { - float *fcol= rl->rectf; float *acol= rl->acolrect; + float *fcol= rect; + float *acol= rl->acolrect; int x; for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) { addAlphaOverFloat(fcol, acol); @@ -1275,7 +1285,7 @@ void zbufshadeDA_tile(RenderPart *pa) /* extra layers */ if (rl->layflag & SCE_LAY_EDGE) if (R.r.mode & R_EDGE) - edge_enhance_add(pa, rl->rectf, edgerect); + edge_enhance_add(pa, rect, edgerect); if (rl->passflag & SCE_PASS_VECTOR) reset_sky_speed(pa, rl); @@ -1329,6 +1339,7 @@ void zbufshade_tile(RenderPart *pa) pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz"); for (rl= rr->layers.first; rl; rl= rl->next) { + float *rect= RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); if ((rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK)) pa->rectmask= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectmask"); @@ -1352,7 +1363,7 @@ void zbufshade_tile(RenderPart *pa) rr->renlay= rl; if (rl->layflag & SCE_LAY_SOLID) { - const float *fcol= rl->rectf; + const float *fcol = rect; const int *ro= pa->recto, *rp= pa->rectp, *rz= pa->rectz; int x, y, offs=0, seed; @@ -1415,11 +1426,11 @@ void zbufshade_tile(RenderPart *pa) rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer"); /* swap for live updates */ - SWAP(float *, rl->acolrect, rl->rectf); - zbuffer_transp_shade(pa, rl, rl->rectf, NULL); - SWAP(float *, rl->acolrect, rl->rectf); + SWAP(float *, rl->acolrect, rect); + zbuffer_transp_shade(pa, rl, rect, NULL); + SWAP(float *, rl->acolrect, rect); - fcol= rl->rectf; acol= rl->acolrect; + fcol= rect; acol= rl->acolrect; for (x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) { addAlphaOverFloat(fcol, acol); } @@ -1437,7 +1448,7 @@ void zbufshade_tile(RenderPart *pa) if (!R.test_break(R.tbh)) { if (rl->layflag & SCE_LAY_EDGE) if (R.r.mode & R_EDGE) - edge_enhance_add(pa, rl->rectf, edgerect); + edge_enhance_add(pa, rect, edgerect); } if (rl->passflag & SCE_PASS_VECTOR) @@ -1611,7 +1622,8 @@ void zbufshade_sss_tile(RenderPart *pa) VlakRen *vlr; Material *mat= re->sss_mat; float (*co)[3], (*color)[3], *area, *fcol; - int x, y, seed, quad, totpoint, display = !(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW)); + int x, y, seed, quad, totpoint; + const bool display = (re->r.scemode & (R_BUTS_PREVIEW | R_VIEWPORT_PREVIEW)) == 0; int *ro, *rz, *rp, *rbo, *rbz, *rbp, lay; #if 0 PixStr *ps; @@ -1664,7 +1676,7 @@ void zbufshade_sss_tile(RenderPart *pa) return; } - fcol= rl->rectf; + fcol= RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); co= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSCo"); color= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSColor"); @@ -1948,6 +1960,7 @@ void add_halo_flare(Render *re) RenderLayer *rl; HaloRen *har; int a, mode; + float *rect; /* for now, we get the first renderlayer in list with halos set */ for (rl= rr->layers.first; rl; rl= rl->next) { @@ -1955,9 +1968,12 @@ void add_halo_flare(Render *re) if ((rl->layflag & SCE_LAY_HALO) == 0) continue; - if (rl->rectf==NULL) + + rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname); + + if (rect==NULL) continue; - + mode= R.r.mode; R.r.mode &= ~R_PANORAMA; @@ -1968,7 +1984,7 @@ void add_halo_flare(Render *re) if (har->flarec && (har->lay & rl->lay)) { do_draw = true; - renderflare(rr, rl->rectf, har); + renderflare(rr, rect, har); } } diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index 46c504aaabf..7a9b2d0903e 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -69,7 +69,8 @@ #include "DNA_material_types.h" #include "DNA_meshdata_types.h" -#include "DNA_texture_types.h" +#include "DNA_texture_types.h" +#include "DNA_particle_types.h" #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" @@ -78,11 +79,8 @@ #include "rayintersection.h" #include "rayobject.h" -#include "renderpipeline.h" #include "render_types.h" #include "renderdatabase.h" -#include "texture.h" -#include "strand.h" #include "zbuf.h" /* ------------------------------------------------------------------------- */ @@ -957,6 +955,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma, const float vec[3], const float vec1[3], const float *orco, float hasize, float vectsize, int seed) { + const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0; HaloRen *har; MTex *mtex; float tin, tr, tg, tb, ta; @@ -1048,7 +1047,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma, } } - externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool); + externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool, skip_load_image); yn= tin*mtex->colfac; //zn= tin*mtex->alphafac; @@ -1068,6 +1067,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma, } har->pool = re->pool; + har->skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0; return har; } @@ -1076,6 +1076,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater const float vec[3], const float vec1[3], const float *orco, const float *uvco, float hasize, float vectsize, int seed, const float pa_co[3]) { + const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0; HaloRen *har; MTex *mtex; float tin, tr, tg, tb, ta; @@ -1179,7 +1180,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater copy_v3_v3(texvec, orco); } - hasrgb = externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool); + hasrgb = externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool, skip_load_image); //yn= tin*mtex->colfac; //zn= tin*mtex->alphafac; @@ -1223,6 +1224,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater } har->pool = re->pool; + har->skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0; return har; } @@ -1374,6 +1376,38 @@ ObjectInstanceRen *RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob, obi->psysindex= psysindex; obi->lay= lay; + /* Fill particle info */ + if (obi->psysindex > 0) { + int psysindex = 1; + int index; + ParticleSystem *psys; + if (obi->par) { + for (psys = obi->par->particlesystem.first; psys; psys = psys->next) { + if (psysindex == obi->psysindex) + break; + ++psysindex; + } + if (psys) { + if (obi->index < psys->totpart) + index = obi->index; + else { + index = psys->child[obi->index - psys->totpart].parent; + } + if (index >= 0) { + ParticleData* p = &psys->particles[index]; + obi->part_index = index; + obi->part_size = p->size; + obi->part_age = RE_GetStats(re)->cfra - p->time; + obi->part_lifetime = p->lifetime; + + copy_v3_v3(obi->part_co, p->state.co); + copy_v3_v3(obi->part_vel, p->state.vel); + copy_v3_v3(obi->part_avel, p->state.ave); + } + } + } + } + if (mat) { copy_m4_m4(obi->mat, mat); copy_m3_m4(mat3, mat); @@ -1387,6 +1421,18 @@ ObjectInstanceRen *RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob, return obi; } +void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) +{ + *index = obi->part_index; + *age = obi->part_age; + *lifetime = obi->part_lifetime; + copy_v3_v3(co, obi->part_co); + *size = obi->part_size; + copy_v3_v3(vel, obi->part_vel); + copy_v3_v3(angvel, obi->part_avel); +} + + void RE_makeRenderInstances(Render *re) { ObjectInstanceRen *obi, *oldobi; @@ -1394,7 +1440,7 @@ void RE_makeRenderInstances(Render *re) int tot; /* convert list of object instances to an array for index based lookup */ - tot= BLI_countlist(&re->instancetable); + tot= BLI_listbase_count(&re->instancetable); re->objectinstance= MEM_callocN(sizeof(ObjectInstanceRen)*tot, "ObjectInstance"); re->totinstance= tot; newlist.first= newlist.last= NULL; diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c index 9d83ff1d7e8..0bd4815fb73 100644 --- a/source/blender/render/intern/source/shadbuf.c +++ b/source/blender/render/intern/source/shadbuf.c @@ -50,7 +50,6 @@ #include "PIL_time.h" -#include "renderpipeline.h" #include "render_types.h" #include "renderdatabase.h" #include "rendercore.h" diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index 7aca6b9ac87..08304533b95 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -39,6 +39,7 @@ #include "DNA_lamp_types.h" #include "DNA_meshdata_types.h" #include "DNA_material_types.h" +#include "DNA_particle_types.h" #include "BKE_scene.h" @@ -46,11 +47,9 @@ /* local include */ #include "raycounter.h" -#include "renderpipeline.h" #include "render_types.h" #include "renderdatabase.h" #include "rendercore.h" -#include "shadbuf.h" #include "shading.h" #include "strand.h" #include "texture.h" @@ -157,9 +156,10 @@ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr) memset(&shi->raycounter, 0, sizeof(shi->raycounter)); #endif - if (shi->mat->nodetree && shi->mat->use_nodes) + if (shi->mat->nodetree && shi->mat->use_nodes) { compat = ntreeShaderExecTree(shi->mat->nodetree, shi, shr); - + } + /* also run this when node shaders fail, due to incompatible shader nodes */ if (compat == false) { /* copy all relevant material vars, note, keep this synced with render_types.h */ @@ -425,14 +425,11 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert } if (texco & TEXCO_GLOB) { - copy_v3_v3(shi->gl, shi->co); - mul_m4_v3(R.viewinv, shi->gl); + mul_v3_m4v3(shi->gl, R.viewinv, shi->co); if (shi->osatex) { - copy_v3_v3(shi->dxgl, shi->dxco); - mul_mat3_m4_v3(R.viewinv, shi->dxgl); - copy_v3_v3(shi->dygl, shi->dyco); - mul_mat3_m4_v3(R.viewinv, shi->dygl); + mul_v3_mat3_m4v3(shi->dxgl, R.viewinv, shi->dxco); + mul_v3_mat3_m4v3(shi->dygl, R.viewinv, shi->dyco); } } @@ -635,7 +632,7 @@ void shade_input_calc_viewco(ShadeInput *shi, float x, float y, float z, float v dyco[2] = 0.0f; if (dxyview) { - if (co[2] != 0.0f) fac = 1.0f / co[2]; else fac = 0.0f; + fac = (co[2] != 0.0f) ? (1.0f / co[2]) : 0.0f; dxyview[0] = -R.viewdx * fac; dxyview[1] = -R.viewdy * fac; } diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index 6d6bba834ba..39dfa48d3f1 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -47,9 +47,7 @@ /* local include */ #include "occlusion.h" -#include "renderpipeline.h" #include "render_types.h" -#include "pixelblending.h" #include "rendercore.h" #include "shadbuf.h" #include "sss.h" @@ -57,6 +55,8 @@ #include "shading.h" /* own include */ +#include "IMB_colormanagement.h" + /* could enable at some point but for now there are far too many conversions */ #ifdef __GNUC__ # pragma GCC diagnostic ignored "-Wdouble-promotion" @@ -950,7 +950,7 @@ static void ramp_diffuse_result(float *diff, ShadeInput *shi) if (ma->ramp_col) { if (ma->rampin_col==MA_RAMP_IN_RESULT) { - float fac = rgb_to_grayscale(diff); + float fac = IMB_colormanagement_get_luminance(diff); do_colorband(ma->ramp_col, fac, col); /* blending method */ @@ -962,7 +962,7 @@ static void ramp_diffuse_result(float *diff, ShadeInput *shi) } /* r,g,b denote energy, ramp is used with different values to make new material color */ -static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, float g, float b) +static void add_to_diffuse(float diff[3], const ShadeInput *shi, const float is, const float rgb[3]) { Material *ma= shi->mat; @@ -971,9 +971,9 @@ static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, floa /* MA_RAMP_IN_RESULT is exceptional */ if (ma->rampin_col==MA_RAMP_IN_RESULT) { /* normal add */ - diff[0] += r * shi->r; - diff[1] += g * shi->g; - diff[2] += b * shi->b; + diff[0] += rgb[0] * shi->r; + diff[1] += rgb[1] * shi->g; + diff[2] += rgb[2] * shi->b; } else { float colt[3], col[4]; @@ -982,40 +982,37 @@ static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, floa /* input */ switch (ma->rampin_col) { case MA_RAMP_IN_ENERGY: - /* should use 'rgb_to_grayscale' but we only have a vector version */ - fac= 0.3f*r + 0.58f*g + 0.12f*b; + fac = IMB_colormanagement_get_luminance(rgb); break; case MA_RAMP_IN_SHADER: - fac= is; + fac = is; break; case MA_RAMP_IN_NOR: - fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2]; + fac = dot_v3v3(shi->view, shi->vn); break; default: - fac= 0.0f; + fac = 0.0f; break; } do_colorband(ma->ramp_col, fac, col); /* blending method */ - fac= col[3]*ma->rampfac_col; - colt[0]= shi->r; - colt[1]= shi->g; - colt[2]= shi->b; + fac = col[3] * ma->rampfac_col; + copy_v3_v3(colt, &shi->r); ramp_blend(ma->rampblend_col, colt, fac, col); /* output to */ - diff[0] += r * colt[0]; - diff[1] += g * colt[1]; - diff[2] += b * colt[2]; + diff[0] += rgb[0] * colt[0]; + diff[1] += rgb[1] * colt[1]; + diff[2] += rgb[2] * colt[2]; } } else { - diff[0] += r * shi->r; - diff[1] += g * shi->g; - diff[2] += b * shi->b; + diff[0] += rgb[0] * shi->r; + diff[1] += rgb[1] * shi->g; + diff[2] += rgb[2] * shi->b; } } @@ -1025,7 +1022,7 @@ static void ramp_spec_result(float spec_col[3], ShadeInput *shi) if (ma->ramp_spec && (ma->rampin_spec==MA_RAMP_IN_RESULT)) { float col[4]; - float fac = rgb_to_grayscale(spec_col); + float fac = IMB_colormanagement_get_luminance(spec_col); do_colorband(ma->ramp_spec, fac, col); @@ -1478,27 +1475,55 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int i*= shadfac[3]; shr->shad[3] = shadfac[3]; /* store this for possible check in troublesome cases */ } + else { + shr->shad[3] = 1.0f; /* No shadow at all! */ + } } } /* in case 'no diffuse' we still do most calculus, spec can be in shadow.*/ if (!(lar->mode & LA_NO_DIFF)) { if (i>0.0f) { - if (ma->mode & MA_SHADOW_TRA) - add_to_diffuse(shr->shad, shi, is, i*shadfac[0]*lacol[0], i*shadfac[1]*lacol[1], i*shadfac[2]*lacol[2]); - else - add_to_diffuse(shr->shad, shi, is, i*lacol[0], i*lacol[1], i*lacol[2]); + if (ma->mode & MA_SHADOW_TRA) { + const float tcol[3] = { + i * shadfac[0] * lacol[0], + i * shadfac[1] * lacol[1], + i * shadfac[2] * lacol[2], + }; + add_to_diffuse(shr->shad, shi, is, tcol); + } + else { + const float tcol[3] = { + i * lacol[0], + i * lacol[1], + i * lacol[2], + }; + add_to_diffuse(shr->shad, shi, is, tcol); + } } /* add light for colored shadow */ if (i_noshad>i && !(lashdw[0]==0 && lashdw[1]==0 && lashdw[2]==0)) { - add_to_diffuse(shr->shad, shi, is, lashdw[0]*(i_noshad-i)*lacol[0], lashdw[1]*(i_noshad-i)*lacol[1], lashdw[2]*(i_noshad-i)*lacol[2]); + const float tcol[3] = { + lashdw[0] * (i_noshad - i) * lacol[0], + lashdw[1] * (i_noshad - i) * lacol[1], + lashdw[2] * (i_noshad - i) * lacol[2], + }; + add_to_diffuse(shr->shad, shi, is, tcol); } if (i_noshad>0.0f) { - if (passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW)) { - add_to_diffuse(shr->diff, shi, is, i_noshad*lacol[0], i_noshad*lacol[1], i_noshad*lacol[2]); + if (passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW) || + ((passflag & SCE_PASS_COMBINED) && !(shi->combinedflag & SCE_PASS_SHADOW))) + { + const float tcol[3] = { + i_noshad * lacol[0], + i_noshad * lacol[1], + i_noshad * lacol[2] + }; + add_to_diffuse(shr->diff, shi, is, tcol); } - else + else { copy_v3_v3(shr->diff, shr->shad); + } } } @@ -1618,10 +1643,10 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr) if (shi->mat->shadowonly_flag == MA_SO_OLD) { /* Old "Shadows Only" */ - accum+= (1.0f-visifac) + (visifac)*rgb_to_grayscale(shadfac)*shadfac[3]; + accum+= (1.0f-visifac) + (visifac)*IMB_colormanagement_get_luminance(shadfac)*shadfac[3]; } else { - shaded += rgb_to_grayscale(shadfac)*shadfac[3] * visifac * lar->energy; + shaded += IMB_colormanagement_get_luminance(shadfac)*shadfac[3] * visifac * lar->energy; if (shi->mat->shadowonly_flag == MA_SO_SHADOW) { lightness += visifac * lar->energy; @@ -1648,7 +1673,8 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr) else { /* shadowonly_flag == MA_SO_SHADED */ /* Use shaded value */ accum = 1.0f - shaded; - }} + } + } shr->alpha= (shi->alpha)*(accum); if (shr->alpha<0.0f) shr->alpha=0.0f; @@ -1669,26 +1695,26 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr) if (R.wrld.aomix==WO_AOADD) { if (shi->mat->shadowonly_flag == MA_SO_OLD) { - f= f*(1.0f - rgb_to_grayscale(shi->ao)); + f= f*(1.0f - IMB_colormanagement_get_luminance(shi->ao)); shr->alpha= (shr->alpha + f)*f; } else { - shr->alpha -= f*rgb_to_grayscale(shi->ao); + shr->alpha -= f*IMB_colormanagement_get_luminance(shi->ao); if (shr->alpha<0.0f) shr->alpha=0.0f; } } else /* AO Multiply */ - shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*rgb_to_grayscale(shi->ao)); + shr->alpha= (1.0f - f)*shr->alpha + f*(1.0f - (1.0f - shr->alpha)*IMB_colormanagement_get_luminance(shi->ao)); } if (R.wrld.mode & WO_ENV_LIGHT) { if (shi->mat->shadowonly_flag == MA_SO_OLD) { - f= R.wrld.ao_env_energy*shi->amb*(1.0f - rgb_to_grayscale(shi->env)); + f= R.wrld.ao_env_energy*shi->amb*(1.0f - IMB_colormanagement_get_luminance(shi->env)); shr->alpha= (shr->alpha + f)*f; } else { f= R.wrld.ao_env_energy*shi->amb; - shr->alpha -= f*rgb_to_grayscale(shi->env); + shr->alpha -= f*IMB_colormanagement_get_luminance(shi->env); if (shr->alpha<0.0f) shr->alpha=0.0f; } } @@ -1714,7 +1740,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) */ const int color_passes = SCE_PASS_COMBINED | SCE_PASS_RGBA | SCE_PASS_DIFFUSE | SCE_PASS_SPEC | - SCE_PASS_REFLECT | SCE_PASS_NORMAL | SCE_PASS_REFRACT | SCE_PASS_EMIT; + SCE_PASS_REFLECT | SCE_PASS_NORMAL | SCE_PASS_REFRACT | SCE_PASS_EMIT | SCE_PASS_SHADOW; Material *ma= shi->mat; int passflag= shi->passflag; @@ -1889,7 +1915,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) } if (shi->combinedflag & SCE_PASS_SHADOW) - copy_v3_v3(shr->diffshad, shr->shad); /* note, no ';' ! */ + copy_v3_v3(shr->diffshad, shr->shad); else copy_v3_v3(shr->diffshad, shr->diff); @@ -2062,7 +2088,7 @@ float RE_lamp_get_data(ShadeInput *shi, Object *lamp_obj, float col[4], float lv if (R.r.scemode & R_BUTS_PREVIEW) { for (go = R.lights.first; go; go = go->next) { /* "Lamp.002" is main key light of material preview */ - if (strcmp(go->ob->id.name + 2, "Lamp.002") == 0) + if (STREQ(go->ob->id.name + 2, "Lamp.002")) return lamp_get_data_internal(shi, go, col, lv, dist, shadow); } return 0.0f; diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c index 7e9003aaee7..553710b4367 100644 --- a/source/blender/render/intern/source/sss.c +++ b/source/blender/render/intern/source/sss.c @@ -55,9 +55,8 @@ #include "BLI_ghash.h" #include "BLI_memarena.h" -#include "BLF_translation.h" +#include "BLT_translation.h" -#include "PIL_time.h" #include "DNA_material_types.h" @@ -68,11 +67,7 @@ /* this module */ #include "render_types.h" -#include "rendercore.h" -#include "renderdatabase.h" -#include "shading.h" #include "sss.h" -#include "zbuf.h" /* Generic Multiple Scattering API */ @@ -1036,14 +1031,12 @@ void make_sss_tree(Render *re) void free_sss(Render *re) { if (re->sss_hash) { - GHashIterator *it= BLI_ghashIterator_new(re->sss_hash); + GHashIterator gh_iter; - while (!BLI_ghashIterator_done(it)) { - sss_free_tree(BLI_ghashIterator_getValue(it)); - BLI_ghashIterator_step(it); + GHASH_ITER (gh_iter, re->sss_hash) { + sss_free_tree(BLI_ghashIterator_getValue(&gh_iter)); } - BLI_ghashIterator_free(it); BLI_ghash_free(re->sss_hash, NULL, NULL); re->sss_hash= NULL; } diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c index 485680da76f..6b52d4aa419 100644 --- a/source/blender/render/intern/source/strand.c +++ b/source/blender/render/intern/source/strand.c @@ -47,11 +47,8 @@ #include "render_types.h" -#include "initrender.h" #include "rendercore.h" #include "renderdatabase.h" -#include "renderpipeline.h" -#include "pixelblending.h" #include "shading.h" #include "strand.h" #include "zbuf.h" diff --git a/source/blender/render/intern/source/sunsky.c b/source/blender/render/intern/source/sunsky.c index 1836b3f48a7..d4e53eb7305 100644 --- a/source/blender/render/intern/source/sunsky.c +++ b/source/blender/render/intern/source/sunsky.c @@ -254,14 +254,14 @@ void GetSkyXYZRadiance(struct SunSky *sunsky, float theta, float phi, float colo float hfade = 1, nfade = 1; - if (theta > (0.5f * (float)M_PI)) { + if (theta > (float)M_PI_2) { hfade = 1.0f - (theta * (float)M_1_PI - 0.5f) * 2.0f; hfade = hfade * hfade * (3.0f - 2.0f * hfade); - theta = 0.5 * M_PI; + theta = M_PI_2; } - if (sunsky->theta > (0.5f * (float)M_PI)) { - if (theta <= 0.5f * (float)M_PI) { + if (sunsky->theta > (float)M_PI_2) { + if (theta <= (float)M_PI_2) { nfade = 1.0f - (0.5f - theta * (float)M_1_PI) * 2.0f; nfade *= 1.0f - (sunsky->theta * (float)M_1_PI - 0.5f) * 2.0f; nfade = nfade * nfade * (3.0f - 2.0f * nfade); @@ -299,8 +299,7 @@ void GetSkyXYZRadiancef(struct SunSky *sunsky, const float varg[3], float color_ float theta, phi; float v[3]; - copy_v3_v3(v, (float *)varg); - normalize_v3(v); + normalize_v3_v3(v, varg); if (v[2] < 0.001f) { v[2] = 0.001f; diff --git a/source/blender/render/intern/source/texture_ocean.c b/source/blender/render/intern/source/texture_ocean.c index 55f4bf3794d..a932123243d 100644 --- a/source/blender/render/intern/source/texture_ocean.c +++ b/source/blender/render/intern/source/texture_ocean.c @@ -56,8 +56,6 @@ extern struct Render R; /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - - /* ***** actual texture sampling ***** */ int ocean_texture(Tex *tex, const float texvec[2], TexResult *texres) { @@ -75,7 +73,7 @@ int ocean_texture(Tex *tex, const float texvec[2], TexResult *texres) return 0; } else { - const int do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS); + const bool do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS) != 0; int cfra = R.r.cfra; int retval = TEX_INT; diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 6135a8761bb..78ede01d6c1 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -44,7 +44,7 @@ #include "BLI_voxel.h" #include "BLI_utildefines.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "PIL_time.h" diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index d5c4c407bf6..2c0917243a3 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -41,6 +41,8 @@ #include "RE_shader_ext.h" +#include "IMB_colormanagement.h" + #include "DNA_material_types.h" #include "DNA_group_types.h" #include "DNA_lamp_types.h" @@ -504,7 +506,7 @@ static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) { mul_v3_fl(lacol, vol_get_shadow(shi, lar, co)); - if (rgb_to_luma_y(lacol) < 0.001f) return; + if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return; } /* find minimum of volume bounds, or lamp coord */ @@ -538,7 +540,7 @@ static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const } } - if (rgb_to_luma_y(lacol) < 0.001f) return; + if (IMB_colormanagement_get_luminance(lacol) < 0.001f) return; normalize_v3(lv); p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, view, lv); @@ -620,7 +622,7 @@ static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co if (t0 > t1 * 0.25f) { /* only use depth cutoff after we've traced a little way into the volume */ - if (rgb_to_luma_y(tr) < shi->mat->vol.depth_cutoff) break; + if (IMB_colormanagement_get_luminance(tr) < shi->mat->vol.depth_cutoff) break; } vol_get_emission(shi, emit_col, p); @@ -649,7 +651,7 @@ static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co add_v3_v3(col, radiance); /* alpha <-- transmission luminance */ - col[3] = 1.0f - rgb_to_luma_y(tr); + col[3] = 1.0f - IMB_colormanagement_get_luminance(tr); } /* the main entry point for volume shading */ @@ -790,7 +792,7 @@ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct copy_v3_v3(shr->combined, tr); - shr->combined[3] = 1.0f - rgb_to_luma_y(tr); + shr->combined[3] = 1.0f - IMB_colormanagement_get_luminance(tr); shr->alpha = shr->combined[3]; } diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index 50b5e392b3f..bb92a8f7e8a 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -46,27 +46,29 @@ #include "BLI_voxel.h" #include "BLI_utildefines.h" -#include "BLF_translation.h" +#include "BLT_translation.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "BKE_cloth.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "smoke_API.h" +#include "BPH_mass_spring.h" #include "DNA_texture_types.h" #include "DNA_object_force.h" #include "DNA_object_types.h" +#include "DNA_particle_types.h" #include "DNA_modifier_types.h" #include "DNA_smoke_types.h" #include "render_types.h" -#include "renderdatabase.h" #include "texture.h" #include "voxeldata.h" @@ -365,6 +367,27 @@ static void init_frame_smoke(VoxelData *vd, int cfra) #endif } +static void init_frame_hair(VoxelData *vd, int UNUSED(cfra)) +{ + Object *ob; + ModifierData *md; + bool found = false; + + vd->dataset = NULL; + if (vd->object == NULL) return; + ob = vd->object; + + if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_ParticleSystem))) { + ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md; + + if (pmd->psys && pmd->psys->clmd) { + found |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd); + } + } + + vd->ok = found; +} + void cache_voxeldata(Tex *tex, int scene_frame) { VoxelData *vd = tex->vd; @@ -398,6 +421,9 @@ void cache_voxeldata(Tex *tex, int scene_frame) case TEX_VD_SMOKE: init_frame_smoke(vd, scene_frame); return; + case TEX_VD_HAIR: + init_frame_hair(vd, scene_frame); + return; case TEX_VD_BLENDERVOXEL: BLI_path_abs(path, G.main->name); if (!BLI_exists(path)) return; diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index 87e546ef24e..58ac34080b9 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -63,12 +63,10 @@ #include "pixelblending.h" #include "render_result.h" #include "render_types.h" -#include "renderpipeline.h" #include "renderdatabase.h" #include "rendercore.h" #include "shadbuf.h" #include "shading.h" -#include "sss.h" #include "strand.h" /* own includes */ @@ -332,8 +330,8 @@ static void zbuffillAc4(ZSpan *zspan, int obi, int zvlnr, /* clipped */ if (zspan->minp2==NULL || zspan->maxp2==NULL) return; - if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1; - if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1; + my0 = max_ii(zspan->miny1, zspan->miny2); + my2 = min_ii(zspan->maxy1, zspan->maxy2); if (my2<my0) return; @@ -1075,8 +1073,8 @@ static void zbuffillGLinv4(ZSpan *zspan, int obi, int zvlnr, /* clipped */ if (zspan->minp2==NULL || zspan->maxp2==NULL) return; - if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1; - if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1; + my0 = max_ii(zspan->miny1, zspan->miny2); + my2 = min_ii(zspan->maxy1, zspan->maxy2); // printf("my %d %d\n", my0, my2); if (my2<my0) return; @@ -1198,8 +1196,8 @@ static void zbuffillGL4(ZSpan *zspan, int obi, int zvlnr, /* clipped */ if (zspan->minp2==NULL || zspan->maxp2==NULL) return; - if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1; - if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1; + my0 = max_ii(zspan->miny1, zspan->miny2); + my2 = min_ii(zspan->maxy1, zspan->maxy2); // printf("my %d %d\n", my0, my2); if (my2<my0) return; @@ -1326,8 +1324,8 @@ static void zbuffillGL_onlyZ(ZSpan *zspan, int UNUSED(obi), int UNUSED(zvlnr), /* clipped */ if (zspan->minp2==NULL || zspan->maxp2==NULL) return; - if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1; - if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1; + my0 = max_ii(zspan->miny1, zspan->miny2); + my2 = min_ii(zspan->maxy1, zspan->maxy2); // printf("my %d %d\n", my0, my2); if (my2<my0) return; @@ -1428,8 +1426,8 @@ void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2, /* clipped */ if (zspan->minp2==NULL || zspan->maxp2==NULL) return; - if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1; - if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1; + my0 = max_ii(zspan->miny1, zspan->miny2); + my2 = min_ii(zspan->maxy1, zspan->maxy2); // printf("my %d %d\n", my0, my2); if (my2<my0) return; @@ -1515,7 +1513,7 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float * float x0, y0, x1, y1, x2, y2, z0, z1, z2; float u, v, uxd, uyd, vxd, vyd, uy0, vy0, xx1; const float *span1, *span2; - int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2; + int i, j, x, y, sn1, sn2, rectx = zspan->rectx, my0, my2; /* init */ zbuf_init_span(zspan); @@ -1528,8 +1526,8 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float * /* clipped */ if (zspan->minp2==NULL || zspan->maxp2==NULL) return; - if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1; - if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1; + my0 = max_ii(zspan->miny1, zspan->miny2); + my2 = min_ii(zspan->maxy1, zspan->maxy2); // printf("my %d %d\n", my0, my2); if (my2<my0) return; @@ -1576,7 +1574,7 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float * span2= zspan->span1+my2; } - for (y=my2; y>=my0; y--, span1--, span2--) { + for (i = 0, y = my2; y >= my0; i++, y--, span1--, span2--) { sn1= floor(*span1); sn2= floor(*span2); @@ -1585,14 +1583,12 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float * if (sn2>=rectx) sn2= rectx-1; if (sn1<0) sn1= 0; - u= (double)sn1*uxd + uy0; - v= (double)sn1*vxd + vy0; + u = (((double)sn1 * uxd) + uy0) - (i * uyd); + v = (((double)sn1 * vxd) + vy0) - (i * vyd); - for (x= sn1; x<=sn2; x++, u+=uxd, v+=vxd) - func(handle, x, y, u, v); - - uy0 -= uyd; - vy0 -= vyd; + for (j = 0, x = sn1; x <= sn2; j++, x++) { + func(handle, x, y, u + (j * uxd), v + (j * vxd)); + } } } @@ -2065,8 +2061,6 @@ static void zmask_rect(int *rectz, int *rectp, int xs, int ys, int neg) } - - /* ***************** ZBUFFER MAIN ROUTINES **************** */ void zbuffer_solid(RenderPart *pa, RenderLayer *rl, void(*fillfunc)(RenderPart *, ZSpan *, int, void *), void *data) @@ -2083,8 +2077,8 @@ void zbuffer_solid(RenderPart *pa, RenderLayer *rl, void(*fillfunc)(RenderPart * unsigned int lay= rl->lay, lay_zmask= rl->lay_zmask; int i, v, zvlnr, zsample, samples, c1, c2, c3, c4=0; short nofill=0, env=0, wire=0, zmaskpass=0; - short all_z= (rl->layflag & SCE_LAY_ALL_Z) && !(rl->layflag & SCE_LAY_ZMASK); - short neg_zmask= (rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK); + const bool all_z = (rl->layflag & SCE_LAY_ALL_Z) && !(rl->layflag & SCE_LAY_ZMASK); + const bool neg_zmask = (rl->layflag & SCE_LAY_ZMASK) && (rl->layflag & SCE_LAY_NEG_ZMASK); zbuf_make_winmat(&R, winmat); @@ -2486,8 +2480,8 @@ static void zbuffill_sss(ZSpan *zspan, int obi, int zvlnr, /* clipped */ if (zspan->minp2==NULL || zspan->maxp2==NULL) return; - if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1; - if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1; + my0 = max_ii(zspan->miny1, zspan->miny2); + my2 = min_ii(zspan->maxy1, zspan->maxy2); if (my2<my0) return; @@ -2687,8 +2681,8 @@ static void zbuf_fill_in_rgba(ZSpan *zspan, DrawBufPixel *col, float *v1, float /* clipped */ if (zspan->minp2==NULL || zspan->maxp2==NULL) return; - if (zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1; - if (zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1; + my0 = max_ii(zspan->miny1, zspan->miny2); + my2 = min_ii(zspan->maxy1, zspan->maxy2); // printf("my %d %d\n", my0, my2); if (my2<my0) return; @@ -3965,7 +3959,7 @@ static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl, float *rectf float *fp, *col; int a; - fp= RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR); + fp = RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR, R.viewname); if (fp==NULL) return; col= rectf+3; @@ -4058,9 +4052,10 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas /* zero alpha pixels get speed vector max again */ if (addpassflag & SCE_PASS_VECTOR) - if (rl->layflag & SCE_LAY_SOLID) - reset_sky_speedvectors(pa, rl, rl->acolrect?rl->acolrect:rl->rectf); /* if acolrect is set we use it */ - + if (rl->layflag & SCE_LAY_SOLID) { + float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); + reset_sky_speedvectors(pa, rl, rl->acolrect ? rl->acolrect : rect); /* if acolrect is set we use it */ + } /* filtered render, for now we assume only 1 filter size */ if (pa->crop) { crop= 1; @@ -4245,8 +4240,9 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas alpha= samp_shr[a].combined[3]; if (alpha!=0.0f) { RenderLayer *rl= ssamp.rlpp[a]; - - addAlphaOverFloat(rl->rectf + 4*od, samp_shr[a].combined); + + float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname); + addAlphaOverFloat(rect + 4 * od, samp_shr[a].combined); add_transp_passes(rl, od, &samp_shr[a], alpha); if (addpassflag & SCE_PASS_VECTOR) |