diff options
Diffstat (limited to 'intern/cycles/blender')
21 files changed, 8668 insertions, 8726 deletions
diff --git a/intern/cycles/blender/CCL_api.h b/intern/cycles/blender/CCL_api.h index b9750ad0c53..233ffc8802c 100644 --- a/intern/cycles/blender/CCL_api.h +++ b/intern/cycles/blender/CCL_api.h @@ -33,4 +33,4 @@ void CCL_logging_verbosity_set(int verbosity); } #endif -#endif /* __CCL_API_H__ */ +#endif /* __CCL_API_H__ */ diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index fc265a47a01..7354b1e615e 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -1,68 +1,68 @@ set(INC - .. - ../../glew-mx - ../../guardedalloc - ../../mikktspace - ../../../source/blender/makesdna - ../../../source/blender/makesrna - ../../../source/blender/blenlib - ${CMAKE_BINARY_DIR}/source/blender/makesrna/intern + .. + ../../glew-mx + ../../guardedalloc + ../../mikktspace + ../../../source/blender/makesdna + ../../../source/blender/makesrna + ../../../source/blender/blenlib + ${CMAKE_BINARY_DIR}/source/blender/makesrna/intern ) set(INC_SYS - ${PYTHON_INCLUDE_DIRS} - ${GLEW_INCLUDE_DIR} + ${PYTHON_INCLUDE_DIRS} + ${GLEW_INCLUDE_DIR} ) set(SRC - blender_camera.cpp - blender_device.cpp - blender_mesh.cpp - blender_object.cpp - blender_object_cull.cpp - blender_particles.cpp - blender_curves.cpp - blender_logging.cpp - blender_python.cpp - blender_session.cpp - blender_shader.cpp - blender_sync.cpp - blender_texture.cpp + blender_camera.cpp + blender_device.cpp + blender_mesh.cpp + blender_object.cpp + blender_object_cull.cpp + blender_particles.cpp + blender_curves.cpp + blender_logging.cpp + blender_python.cpp + blender_session.cpp + blender_shader.cpp + blender_sync.cpp + blender_texture.cpp - CCL_api.h - blender_object_cull.h - blender_sync.h - blender_session.h - blender_texture.h - blender_util.h + CCL_api.h + blender_object_cull.h + blender_sync.h + blender_session.h + blender_texture.h + blender_util.h ) set(LIB - cycles_bvh - cycles_device - cycles_graph - cycles_kernel - cycles_render - cycles_subd - cycles_util + cycles_bvh + cycles_device + cycles_graph + cycles_kernel + cycles_render + cycles_subd + cycles_util ) if(WITH_CYCLES_LOGGING) - list(APPEND LIB - extern_glog - ) + list(APPEND LIB + extern_glog + ) endif() set(ADDON_FILES - addon/__init__.py - addon/engine.py - addon/operators.py - addon/osl.py - addon/presets.py - addon/properties.py - addon/ui.py - addon/version_update.py + addon/__init__.py + addon/engine.py + addon/operators.py + addon/osl.py + addon/presets.py + addon/properties.py + addon/ui.py + addon/version_update.py ) add_definitions(${GL_DEFINITIONS}) @@ -72,14 +72,14 @@ if(WITH_CYCLES_DEVICE_OPENCL) endif() if(WITH_CYCLES_NETWORK) - add_definitions(-DWITH_NETWORK) + add_definitions(-DWITH_NETWORK) endif() blender_add_lib(bf_intern_cycles "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") # avoid link failure with clang 3.4 debug if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT ${CMAKE_C_COMPILER_VERSION} VERSION_LESS '3.4') - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -gline-tables-only") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -gline-tables-only") endif() add_dependencies(bf_intern_cycles bf_rna) diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index 21efba4cdf0..b3bfaa992a9 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -28,875 +28,858 @@ CCL_NAMESPACE_BEGIN * render camera to this, and from there convert to our native camera format. */ struct BlenderCamera { - float nearclip; - float farclip; + float nearclip; + float farclip; - CameraType type; - float ortho_scale; + CameraType type; + float ortho_scale; - float lens; - float shuttertime; - Camera::MotionPosition motion_position; - array<float> shutter_curve; + float lens; + float shuttertime; + Camera::MotionPosition motion_position; + array<float> shutter_curve; - Camera::RollingShutterType rolling_shutter_type; - float rolling_shutter_duration; + Camera::RollingShutterType rolling_shutter_type; + float rolling_shutter_duration; - float aperturesize; - uint apertureblades; - float aperturerotation; - float focaldistance; + float aperturesize; + uint apertureblades; + float aperturerotation; + float focaldistance; - float2 shift; - float2 offset; - float zoom; + float2 shift; + float2 offset; + float zoom; - float2 pixelaspect; + float2 pixelaspect; - float aperture_ratio; + float aperture_ratio; - PanoramaType panorama_type; - float fisheye_fov; - float fisheye_lens; - float latitude_min; - float latitude_max; - float longitude_min; - float longitude_max; - bool use_spherical_stereo; - float interocular_distance; - float convergence_distance; - bool use_pole_merge; - float pole_merge_angle_from; - float pole_merge_angle_to; + PanoramaType panorama_type; + float fisheye_fov; + float fisheye_lens; + float latitude_min; + float latitude_max; + float longitude_min; + float longitude_max; + bool use_spherical_stereo; + float interocular_distance; + float convergence_distance; + bool use_pole_merge; + float pole_merge_angle_from; + float pole_merge_angle_to; - enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit; - float sensor_width; - float sensor_height; + enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit; + float sensor_width; + float sensor_height; - int full_width; - int full_height; + int full_width; + int full_height; - BoundBox2D border; - BoundBox2D pano_viewplane; - BoundBox2D viewport_camera_border; + BoundBox2D border; + BoundBox2D pano_viewplane; + BoundBox2D viewport_camera_border; - Transform matrix; + Transform matrix; - float offscreen_dicing_scale; + float offscreen_dicing_scale; - int motion_steps; + int motion_steps; }; -static void blender_camera_init(BlenderCamera *bcam, - BL::RenderSettings& b_render) +static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings &b_render) { - memset((void *)bcam, 0, sizeof(BlenderCamera)); - - bcam->type = CAMERA_PERSPECTIVE; - bcam->zoom = 1.0f; - bcam->pixelaspect = make_float2(1.0f, 1.0f); - bcam->sensor_width = 36.0f; - bcam->sensor_height = 24.0f; - bcam->sensor_fit = BlenderCamera::AUTO; - bcam->shuttertime = 1.0f; - bcam->motion_position = Camera::MOTION_POSITION_CENTER; - bcam->rolling_shutter_type = Camera::ROLLING_SHUTTER_NONE; - bcam->rolling_shutter_duration = 0.1f; - bcam->border.right = 1.0f; - bcam->border.top = 1.0f; - bcam->pano_viewplane.right = 1.0f; - bcam->pano_viewplane.top = 1.0f; - bcam->viewport_camera_border.right = 1.0f; - bcam->viewport_camera_border.top = 1.0f; - bcam->offscreen_dicing_scale = 1.0f; - - /* render resolution */ - bcam->full_width = render_resolution_x(b_render); - bcam->full_height = render_resolution_y(b_render); + memset((void *)bcam, 0, sizeof(BlenderCamera)); + + bcam->type = CAMERA_PERSPECTIVE; + bcam->zoom = 1.0f; + bcam->pixelaspect = make_float2(1.0f, 1.0f); + bcam->sensor_width = 36.0f; + bcam->sensor_height = 24.0f; + bcam->sensor_fit = BlenderCamera::AUTO; + bcam->shuttertime = 1.0f; + bcam->motion_position = Camera::MOTION_POSITION_CENTER; + bcam->rolling_shutter_type = Camera::ROLLING_SHUTTER_NONE; + bcam->rolling_shutter_duration = 0.1f; + bcam->border.right = 1.0f; + bcam->border.top = 1.0f; + bcam->pano_viewplane.right = 1.0f; + bcam->pano_viewplane.top = 1.0f; + bcam->viewport_camera_border.right = 1.0f; + bcam->viewport_camera_border.top = 1.0f; + bcam->offscreen_dicing_scale = 1.0f; + + /* render resolution */ + bcam->full_width = render_resolution_x(b_render); + bcam->full_height = render_resolution_y(b_render); } -static float blender_camera_focal_distance(BL::RenderEngine& b_engine, - BL::Object& b_ob, - BL::Camera& b_camera, +static float blender_camera_focal_distance(BL::RenderEngine &b_engine, + BL::Object &b_ob, + BL::Camera &b_camera, BlenderCamera *bcam) { - BL::Object b_dof_object = b_camera.dof_object(); - - if(!b_dof_object) - return b_camera.dof_distance(); - - /* for dof object, return distance along camera Z direction */ - BL::Array<float, 16> b_ob_matrix; - b_engine.camera_model_matrix(b_ob, bcam->use_spherical_stereo, b_ob_matrix); - Transform obmat = transform_clear_scale(get_transform(b_ob_matrix)); - Transform dofmat = get_transform(b_dof_object.matrix_world()); - float3 view_dir = normalize(transform_get_column(&obmat, 2)); - float3 dof_dir = transform_get_column(&obmat, 3) - transform_get_column(&dofmat, 3); - return fabsf(dot(view_dir, dof_dir)); + BL::Object b_dof_object = b_camera.dof_object(); + + if (!b_dof_object) + return b_camera.dof_distance(); + + /* for dof object, return distance along camera Z direction */ + BL::Array<float, 16> b_ob_matrix; + b_engine.camera_model_matrix(b_ob, bcam->use_spherical_stereo, b_ob_matrix); + Transform obmat = transform_clear_scale(get_transform(b_ob_matrix)); + Transform dofmat = get_transform(b_dof_object.matrix_world()); + float3 view_dir = normalize(transform_get_column(&obmat, 2)); + float3 dof_dir = transform_get_column(&obmat, 3) - transform_get_column(&dofmat, 3); + return fabsf(dot(view_dir, dof_dir)); } static void blender_camera_from_object(BlenderCamera *bcam, - BL::RenderEngine& b_engine, - BL::Object& b_ob, + BL::RenderEngine &b_engine, + BL::Object &b_ob, bool skip_panorama = false) { - BL::ID b_ob_data = b_ob.data(); - - if(b_ob_data.is_a(&RNA_Camera)) { - BL::Camera b_camera(b_ob_data); - PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles"); - - bcam->nearclip = b_camera.clip_start(); - bcam->farclip = b_camera.clip_end(); - - switch(b_camera.type()) - { - case BL::Camera::type_ORTHO: - bcam->type = CAMERA_ORTHOGRAPHIC; - break; - case BL::Camera::type_PANO: - if(!skip_panorama) - bcam->type = CAMERA_PANORAMA; - else - bcam->type = CAMERA_PERSPECTIVE; - break; - case BL::Camera::type_PERSP: - default: - bcam->type = CAMERA_PERSPECTIVE; - break; - } - - bcam->panorama_type = (PanoramaType)get_enum(ccamera, - "panorama_type", - PANORAMA_NUM_TYPES, - PANORAMA_EQUIRECTANGULAR); - - bcam->fisheye_fov = RNA_float_get(&ccamera, "fisheye_fov"); - bcam->fisheye_lens = RNA_float_get(&ccamera, "fisheye_lens"); - bcam->latitude_min = RNA_float_get(&ccamera, "latitude_min"); - bcam->latitude_max = RNA_float_get(&ccamera, "latitude_max"); - bcam->longitude_min = RNA_float_get(&ccamera, "longitude_min"); - bcam->longitude_max = RNA_float_get(&ccamera, "longitude_max"); - - bcam->interocular_distance = b_camera.stereo().interocular_distance(); - if(b_camera.stereo().convergence_mode() == BL::CameraStereoData::convergence_mode_PARALLEL) { - bcam->convergence_distance = FLT_MAX; - } - else { - bcam->convergence_distance = b_camera.stereo().convergence_distance(); - } - bcam->use_spherical_stereo = b_engine.use_spherical_stereo(b_ob); - - bcam->use_pole_merge = b_camera.stereo().use_pole_merge(); - bcam->pole_merge_angle_from = b_camera.stereo().pole_merge_angle_from(); - bcam->pole_merge_angle_to = b_camera.stereo().pole_merge_angle_to(); - - bcam->ortho_scale = b_camera.ortho_scale(); - - bcam->lens = b_camera.lens(); - - /* allow f/stop number to change aperture_size but still - * give manual control over aperture radius */ - int aperture_type = get_enum(ccamera, "aperture_type"); - - if(aperture_type == 1) { - float fstop = RNA_float_get(&ccamera, "aperture_fstop"); - fstop = max(fstop, 1e-5f); - - if(bcam->type == CAMERA_ORTHOGRAPHIC) - bcam->aperturesize = 1.0f/(2.0f*fstop); - else - bcam->aperturesize = (bcam->lens*1e-3f)/(2.0f*fstop); - } - else - bcam->aperturesize = RNA_float_get(&ccamera, "aperture_size"); - - bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades"); - bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation"); - bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera, bcam); - bcam->aperture_ratio = RNA_float_get(&ccamera, "aperture_ratio"); - - bcam->shift.x = b_engine.camera_shift_x(b_ob, bcam->use_spherical_stereo); - bcam->shift.y = b_camera.shift_y(); - - bcam->sensor_width = b_camera.sensor_width(); - bcam->sensor_height = b_camera.sensor_height(); - - if(b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO) - bcam->sensor_fit = BlenderCamera::AUTO; - else if(b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL) - bcam->sensor_fit = BlenderCamera::HORIZONTAL; - else - bcam->sensor_fit = BlenderCamera::VERTICAL; - } - else if(b_ob_data.is_a(&RNA_Light)) { - /* Can also look through spot light. */ - BL::SpotLight b_light(b_ob_data); - float lens = 16.0f / tanf(b_light.spot_size() * 0.5f); - if (lens > 0.0f) { - bcam->lens = lens; - } - } - - bcam->motion_steps = object_motion_steps(b_ob, b_ob); + BL::ID b_ob_data = b_ob.data(); + + if (b_ob_data.is_a(&RNA_Camera)) { + BL::Camera b_camera(b_ob_data); + PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles"); + + bcam->nearclip = b_camera.clip_start(); + bcam->farclip = b_camera.clip_end(); + + switch (b_camera.type()) { + case BL::Camera::type_ORTHO: + bcam->type = CAMERA_ORTHOGRAPHIC; + break; + case BL::Camera::type_PANO: + if (!skip_panorama) + bcam->type = CAMERA_PANORAMA; + else + bcam->type = CAMERA_PERSPECTIVE; + break; + case BL::Camera::type_PERSP: + default: + bcam->type = CAMERA_PERSPECTIVE; + break; + } + + bcam->panorama_type = (PanoramaType)get_enum( + ccamera, "panorama_type", PANORAMA_NUM_TYPES, PANORAMA_EQUIRECTANGULAR); + + bcam->fisheye_fov = RNA_float_get(&ccamera, "fisheye_fov"); + bcam->fisheye_lens = RNA_float_get(&ccamera, "fisheye_lens"); + bcam->latitude_min = RNA_float_get(&ccamera, "latitude_min"); + bcam->latitude_max = RNA_float_get(&ccamera, "latitude_max"); + bcam->longitude_min = RNA_float_get(&ccamera, "longitude_min"); + bcam->longitude_max = RNA_float_get(&ccamera, "longitude_max"); + + bcam->interocular_distance = b_camera.stereo().interocular_distance(); + if (b_camera.stereo().convergence_mode() == BL::CameraStereoData::convergence_mode_PARALLEL) { + bcam->convergence_distance = FLT_MAX; + } + else { + bcam->convergence_distance = b_camera.stereo().convergence_distance(); + } + bcam->use_spherical_stereo = b_engine.use_spherical_stereo(b_ob); + + bcam->use_pole_merge = b_camera.stereo().use_pole_merge(); + bcam->pole_merge_angle_from = b_camera.stereo().pole_merge_angle_from(); + bcam->pole_merge_angle_to = b_camera.stereo().pole_merge_angle_to(); + + bcam->ortho_scale = b_camera.ortho_scale(); + + bcam->lens = b_camera.lens(); + + /* allow f/stop number to change aperture_size but still + * give manual control over aperture radius */ + int aperture_type = get_enum(ccamera, "aperture_type"); + + if (aperture_type == 1) { + float fstop = RNA_float_get(&ccamera, "aperture_fstop"); + fstop = max(fstop, 1e-5f); + + if (bcam->type == CAMERA_ORTHOGRAPHIC) + bcam->aperturesize = 1.0f / (2.0f * fstop); + else + bcam->aperturesize = (bcam->lens * 1e-3f) / (2.0f * fstop); + } + else + bcam->aperturesize = RNA_float_get(&ccamera, "aperture_size"); + + bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades"); + bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation"); + bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera, bcam); + bcam->aperture_ratio = RNA_float_get(&ccamera, "aperture_ratio"); + + bcam->shift.x = b_engine.camera_shift_x(b_ob, bcam->use_spherical_stereo); + bcam->shift.y = b_camera.shift_y(); + + bcam->sensor_width = b_camera.sensor_width(); + bcam->sensor_height = b_camera.sensor_height(); + + if (b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO) + bcam->sensor_fit = BlenderCamera::AUTO; + else if (b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL) + bcam->sensor_fit = BlenderCamera::HORIZONTAL; + else + bcam->sensor_fit = BlenderCamera::VERTICAL; + } + else if (b_ob_data.is_a(&RNA_Light)) { + /* Can also look through spot light. */ + BL::SpotLight b_light(b_ob_data); + float lens = 16.0f / tanf(b_light.spot_size() * 0.5f); + if (lens > 0.0f) { + bcam->lens = lens; + } + } + + bcam->motion_steps = object_motion_steps(b_ob, b_ob); } -static Transform blender_camera_matrix(const Transform& tfm, +static Transform blender_camera_matrix(const Transform &tfm, const CameraType type, const PanoramaType panorama_type) { - Transform result; - - if(type == CAMERA_PANORAMA) { - if(panorama_type == PANORAMA_MIRRORBALL) { - /* Mirror ball camera is looking into the negative Y direction - * which matches texture mirror ball mapping. - */ - result = tfm * - make_transform(1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f); - } - else { - /* Make it so environment camera needs to be pointed in the direction - * of the positive x-axis to match an environment texture, this way - * it is looking at the center of the texture - */ - result = tfm * - make_transform( 0.0f, -1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - -1.0f, 0.0f, 0.0f, 0.0f); - } - } - else { - /* note the blender camera points along the negative z-axis */ - result = tfm * transform_scale(1.0f, 1.0f, -1.0f); - } - - return transform_clear_scale(result); + Transform result; + + if (type == CAMERA_PANORAMA) { + if (panorama_type == PANORAMA_MIRRORBALL) { + /* Mirror ball camera is looking into the negative Y direction + * which matches texture mirror ball mapping. + */ + result = tfm * make_transform( + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f); + } + else { + /* Make it so environment camera needs to be pointed in the direction + * of the positive x-axis to match an environment texture, this way + * it is looking at the center of the texture + */ + result = tfm * make_transform( + 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f); + } + } + else { + /* note the blender camera points along the negative z-axis */ + result = tfm * transform_scale(1.0f, 1.0f, -1.0f); + } + + return transform_clear_scale(result); } static void blender_camera_viewplane(BlenderCamera *bcam, - int width, int height, + int width, + int height, BoundBox2D *viewplane, float *aspectratio, float *sensor_size) { - /* dimensions */ - float xratio = (float)width*bcam->pixelaspect.x; - float yratio = (float)height*bcam->pixelaspect.y; - - /* compute x/y aspect and ratio */ - float xaspect, yaspect; - bool horizontal_fit; - - /* sensor fitting */ - if(bcam->sensor_fit == BlenderCamera::AUTO) { - horizontal_fit = (xratio > yratio); - if(sensor_size != NULL) { - *sensor_size = bcam->sensor_width; - } - } - else if(bcam->sensor_fit == BlenderCamera::HORIZONTAL) { - horizontal_fit = true; - if(sensor_size != NULL) { - *sensor_size = bcam->sensor_width; - } - } - else { - horizontal_fit = false; - if(sensor_size != NULL) { - *sensor_size = bcam->sensor_height; - } - } - - if(horizontal_fit) { - if(aspectratio != NULL) { - *aspectratio = xratio/yratio; - } - xaspect = *aspectratio; - yaspect = 1.0f; - } - else { - if(aspectratio != NULL) { - *aspectratio = yratio/xratio; - } - xaspect = 1.0f; - yaspect = *aspectratio; - } - - /* modify aspect for orthographic scale */ - if(bcam->type == CAMERA_ORTHOGRAPHIC) { - xaspect = xaspect*bcam->ortho_scale/(*aspectratio*2.0f); - yaspect = yaspect*bcam->ortho_scale/(*aspectratio*2.0f); - if(aspectratio != NULL) { - *aspectratio = bcam->ortho_scale/2.0f; - } - } - - if(bcam->type == CAMERA_PANORAMA) { - /* set viewplane */ - if(viewplane != NULL) { - *viewplane = bcam->pano_viewplane; - } - } - else { - /* set viewplane */ - if(viewplane != NULL) { - viewplane->left = -xaspect; - viewplane->right = xaspect; - viewplane->bottom = -yaspect; - viewplane->top = yaspect; - - /* zoom for 3d camera view */ - *viewplane = (*viewplane) * bcam->zoom; - - /* modify viewplane with camera shift and 3d camera view offset */ - float dx = 2.0f*(*aspectratio*bcam->shift.x + bcam->offset.x*xaspect*2.0f); - float dy = 2.0f*(*aspectratio*bcam->shift.y + bcam->offset.y*yaspect*2.0f); - - viewplane->left += dx; - viewplane->right += dx; - viewplane->bottom += dy; - viewplane->top += dy; - } - } + /* dimensions */ + float xratio = (float)width * bcam->pixelaspect.x; + float yratio = (float)height * bcam->pixelaspect.y; + + /* compute x/y aspect and ratio */ + float xaspect, yaspect; + bool horizontal_fit; + + /* sensor fitting */ + if (bcam->sensor_fit == BlenderCamera::AUTO) { + horizontal_fit = (xratio > yratio); + if (sensor_size != NULL) { + *sensor_size = bcam->sensor_width; + } + } + else if (bcam->sensor_fit == BlenderCamera::HORIZONTAL) { + horizontal_fit = true; + if (sensor_size != NULL) { + *sensor_size = bcam->sensor_width; + } + } + else { + horizontal_fit = false; + if (sensor_size != NULL) { + *sensor_size = bcam->sensor_height; + } + } + + if (horizontal_fit) { + if (aspectratio != NULL) { + *aspectratio = xratio / yratio; + } + xaspect = *aspectratio; + yaspect = 1.0f; + } + else { + if (aspectratio != NULL) { + *aspectratio = yratio / xratio; + } + xaspect = 1.0f; + yaspect = *aspectratio; + } + + /* modify aspect for orthographic scale */ + if (bcam->type == CAMERA_ORTHOGRAPHIC) { + xaspect = xaspect * bcam->ortho_scale / (*aspectratio * 2.0f); + yaspect = yaspect * bcam->ortho_scale / (*aspectratio * 2.0f); + if (aspectratio != NULL) { + *aspectratio = bcam->ortho_scale / 2.0f; + } + } + + if (bcam->type == CAMERA_PANORAMA) { + /* set viewplane */ + if (viewplane != NULL) { + *viewplane = bcam->pano_viewplane; + } + } + else { + /* set viewplane */ + if (viewplane != NULL) { + viewplane->left = -xaspect; + viewplane->right = xaspect; + viewplane->bottom = -yaspect; + viewplane->top = yaspect; + + /* zoom for 3d camera view */ + *viewplane = (*viewplane) * bcam->zoom; + + /* modify viewplane with camera shift and 3d camera view offset */ + float dx = 2.0f * (*aspectratio * bcam->shift.x + bcam->offset.x * xaspect * 2.0f); + float dy = 2.0f * (*aspectratio * bcam->shift.y + bcam->offset.y * yaspect * 2.0f); + + viewplane->left += dx; + viewplane->right += dx; + viewplane->bottom += dy; + viewplane->top += dy; + } + } } static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, - int width, int height, + int width, + int height, const char *viewname, PointerRNA *cscene) { - /* copy camera to compare later */ - Camera prevcam = *cam; - float aspectratio, sensor_size; - - /* viewplane */ - blender_camera_viewplane(bcam, width, height, - &cam->viewplane, &aspectratio, &sensor_size); - - cam->width = bcam->full_width; - cam->height = bcam->full_height; - - cam->full_width = width; - cam->full_height = height; - - /* panorama sensor */ - if(bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) { - float fit_xratio = (float)bcam->full_width*bcam->pixelaspect.x; - float fit_yratio = (float)bcam->full_height*bcam->pixelaspect.y; - bool horizontal_fit; - float sensor_size; - - if(bcam->sensor_fit == BlenderCamera::AUTO) { - horizontal_fit = (fit_xratio > fit_yratio); - sensor_size = bcam->sensor_width; - } - else if(bcam->sensor_fit == BlenderCamera::HORIZONTAL) { - horizontal_fit = true; - sensor_size = bcam->sensor_width; - } - else { /* vertical */ - horizontal_fit = false; - sensor_size = bcam->sensor_height; - } - - if(horizontal_fit) { - cam->sensorwidth = sensor_size; - cam->sensorheight = sensor_size * fit_yratio / fit_xratio; - } - else { - cam->sensorwidth = sensor_size * fit_xratio / fit_yratio; - cam->sensorheight = sensor_size; - } - } - - /* clipping distances */ - cam->nearclip = bcam->nearclip; - cam->farclip = bcam->farclip; - - /* type */ - cam->type = bcam->type; - - /* panorama */ - cam->panorama_type = bcam->panorama_type; - cam->fisheye_fov = bcam->fisheye_fov; - cam->fisheye_lens = bcam->fisheye_lens; - cam->latitude_min = bcam->latitude_min; - cam->latitude_max = bcam->latitude_max; - - cam->longitude_min = bcam->longitude_min; - cam->longitude_max = bcam->longitude_max; - - /* panorama stereo */ - cam->interocular_distance = bcam->interocular_distance; - cam->convergence_distance = bcam->convergence_distance; - cam->use_spherical_stereo = bcam->use_spherical_stereo; - - if(cam->use_spherical_stereo) { - if(strcmp(viewname, "left") == 0) - cam->stereo_eye = Camera::STEREO_LEFT; - else if(strcmp(viewname, "right") == 0) - cam->stereo_eye = Camera::STEREO_RIGHT; - else - cam->stereo_eye = Camera::STEREO_NONE; - } - - cam->use_pole_merge = bcam->use_pole_merge; - cam->pole_merge_angle_from = bcam->pole_merge_angle_from; - cam->pole_merge_angle_to = bcam->pole_merge_angle_to; - - /* anamorphic lens bokeh */ - cam->aperture_ratio = bcam->aperture_ratio; - - /* perspective */ - cam->fov = 2.0f * atanf((0.5f * sensor_size) / bcam->lens / aspectratio); - cam->focaldistance = bcam->focaldistance; - cam->aperturesize = bcam->aperturesize; - cam->blades = bcam->apertureblades; - cam->bladesrotation = bcam->aperturerotation; - - /* transform */ - cam->matrix = blender_camera_matrix(bcam->matrix, - bcam->type, - bcam->panorama_type); - cam->motion.clear(); - cam->motion.resize(bcam->motion_steps, cam->matrix); - cam->use_perspective_motion = false; - cam->shuttertime = bcam->shuttertime; - cam->fov_pre = cam->fov; - cam->fov_post = cam->fov; - cam->motion_position = bcam->motion_position; - - cam->rolling_shutter_type = bcam->rolling_shutter_type; - cam->rolling_shutter_duration = bcam->rolling_shutter_duration; - - cam->shutter_curve = bcam->shutter_curve; - - /* border */ - cam->border = bcam->border; - cam->viewport_camera_border = bcam->viewport_camera_border; - - bcam->offscreen_dicing_scale = RNA_float_get(cscene, "offscreen_dicing_scale"); - cam->offscreen_dicing_scale = bcam->offscreen_dicing_scale; - - /* set update flag */ - if(cam->modified(prevcam)) - cam->tag_update(); + /* copy camera to compare later */ + Camera prevcam = *cam; + float aspectratio, sensor_size; + + /* viewplane */ + blender_camera_viewplane(bcam, width, height, &cam->viewplane, &aspectratio, &sensor_size); + + cam->width = bcam->full_width; + cam->height = bcam->full_height; + + cam->full_width = width; + cam->full_height = height; + + /* panorama sensor */ + if (bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) { + float fit_xratio = (float)bcam->full_width * bcam->pixelaspect.x; + float fit_yratio = (float)bcam->full_height * bcam->pixelaspect.y; + bool horizontal_fit; + float sensor_size; + + if (bcam->sensor_fit == BlenderCamera::AUTO) { + horizontal_fit = (fit_xratio > fit_yratio); + sensor_size = bcam->sensor_width; + } + else if (bcam->sensor_fit == BlenderCamera::HORIZONTAL) { + horizontal_fit = true; + sensor_size = bcam->sensor_width; + } + else { /* vertical */ + horizontal_fit = false; + sensor_size = bcam->sensor_height; + } + + if (horizontal_fit) { + cam->sensorwidth = sensor_size; + cam->sensorheight = sensor_size * fit_yratio / fit_xratio; + } + else { + cam->sensorwidth = sensor_size * fit_xratio / fit_yratio; + cam->sensorheight = sensor_size; + } + } + + /* clipping distances */ + cam->nearclip = bcam->nearclip; + cam->farclip = bcam->farclip; + + /* type */ + cam->type = bcam->type; + + /* panorama */ + cam->panorama_type = bcam->panorama_type; + cam->fisheye_fov = bcam->fisheye_fov; + cam->fisheye_lens = bcam->fisheye_lens; + cam->latitude_min = bcam->latitude_min; + cam->latitude_max = bcam->latitude_max; + + cam->longitude_min = bcam->longitude_min; + cam->longitude_max = bcam->longitude_max; + + /* panorama stereo */ + cam->interocular_distance = bcam->interocular_distance; + cam->convergence_distance = bcam->convergence_distance; + cam->use_spherical_stereo = bcam->use_spherical_stereo; + + if (cam->use_spherical_stereo) { + if (strcmp(viewname, "left") == 0) + cam->stereo_eye = Camera::STEREO_LEFT; + else if (strcmp(viewname, "right") == 0) + cam->stereo_eye = Camera::STEREO_RIGHT; + else + cam->stereo_eye = Camera::STEREO_NONE; + } + + cam->use_pole_merge = bcam->use_pole_merge; + cam->pole_merge_angle_from = bcam->pole_merge_angle_from; + cam->pole_merge_angle_to = bcam->pole_merge_angle_to; + + /* anamorphic lens bokeh */ + cam->aperture_ratio = bcam->aperture_ratio; + + /* perspective */ + cam->fov = 2.0f * atanf((0.5f * sensor_size) / bcam->lens / aspectratio); + cam->focaldistance = bcam->focaldistance; + cam->aperturesize = bcam->aperturesize; + cam->blades = bcam->apertureblades; + cam->bladesrotation = bcam->aperturerotation; + + /* transform */ + cam->matrix = blender_camera_matrix(bcam->matrix, bcam->type, bcam->panorama_type); + cam->motion.clear(); + cam->motion.resize(bcam->motion_steps, cam->matrix); + cam->use_perspective_motion = false; + cam->shuttertime = bcam->shuttertime; + cam->fov_pre = cam->fov; + cam->fov_post = cam->fov; + cam->motion_position = bcam->motion_position; + + cam->rolling_shutter_type = bcam->rolling_shutter_type; + cam->rolling_shutter_duration = bcam->rolling_shutter_duration; + + cam->shutter_curve = bcam->shutter_curve; + + /* border */ + cam->border = bcam->border; + cam->viewport_camera_border = bcam->viewport_camera_border; + + bcam->offscreen_dicing_scale = RNA_float_get(cscene, "offscreen_dicing_scale"); + cam->offscreen_dicing_scale = bcam->offscreen_dicing_scale; + + /* set update flag */ + if (cam->modified(prevcam)) + cam->tag_update(); } /* Sync Render Camera */ -void BlenderSync::sync_camera(BL::RenderSettings& b_render, - BL::Object& b_override, - int width, int height, +void BlenderSync::sync_camera(BL::RenderSettings &b_render, + BL::Object &b_override, + int width, + int height, const char *viewname) { - BlenderCamera bcam; - blender_camera_init(&bcam, b_render); - - /* pixel aspect */ - bcam.pixelaspect.x = b_render.pixel_aspect_x(); - bcam.pixelaspect.y = b_render.pixel_aspect_y(); - bcam.shuttertime = b_render.motion_blur_shutter(); - - BL::CurveMapping b_shutter_curve(b_render.motion_blur_shutter_curve()); - curvemapping_to_array(b_shutter_curve, bcam.shutter_curve, RAMP_TABLE_SIZE); - - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - bcam.motion_position = - (Camera::MotionPosition)get_enum(cscene, - "motion_blur_position", - Camera::MOTION_NUM_POSITIONS, - Camera::MOTION_POSITION_CENTER); - bcam.rolling_shutter_type = - (Camera::RollingShutterType)get_enum(cscene, - "rolling_shutter_type", - Camera::ROLLING_SHUTTER_NUM_TYPES, - Camera::ROLLING_SHUTTER_NONE); - bcam.rolling_shutter_duration = RNA_float_get(&cscene, "rolling_shutter_duration"); - - /* border */ - if(b_render.use_border()) { - bcam.border.left = b_render.border_min_x(); - bcam.border.right = b_render.border_max_x(); - bcam.border.bottom = b_render.border_min_y(); - bcam.border.top = b_render.border_max_y(); - } - - /* camera object */ - BL::Object b_ob = b_scene.camera(); - - if(b_override) - b_ob = b_override; - - if(b_ob) { - BL::Array<float, 16> b_ob_matrix; - blender_camera_from_object(&bcam, b_engine, b_ob); - b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix); - bcam.matrix = get_transform(b_ob_matrix); - } - - /* sync */ - Camera *cam = scene->camera; - blender_camera_sync(cam, &bcam, width, height, viewname, &cscene); - - /* dicing camera */ - b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera")); - if(b_ob) { - BL::Array<float, 16> b_ob_matrix; - blender_camera_from_object(&bcam, b_engine, b_ob); - b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix); - bcam.matrix = get_transform(b_ob_matrix); - - blender_camera_sync(scene->dicing_camera, &bcam, width, height, viewname, &cscene); - } - else { - *scene->dicing_camera = *cam; - } + BlenderCamera bcam; + blender_camera_init(&bcam, b_render); + + /* pixel aspect */ + bcam.pixelaspect.x = b_render.pixel_aspect_x(); + bcam.pixelaspect.y = b_render.pixel_aspect_y(); + bcam.shuttertime = b_render.motion_blur_shutter(); + + BL::CurveMapping b_shutter_curve(b_render.motion_blur_shutter_curve()); + curvemapping_to_array(b_shutter_curve, bcam.shutter_curve, RAMP_TABLE_SIZE); + + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + bcam.motion_position = (Camera::MotionPosition)get_enum(cscene, + "motion_blur_position", + Camera::MOTION_NUM_POSITIONS, + Camera::MOTION_POSITION_CENTER); + bcam.rolling_shutter_type = (Camera::RollingShutterType)get_enum( + cscene, + "rolling_shutter_type", + Camera::ROLLING_SHUTTER_NUM_TYPES, + Camera::ROLLING_SHUTTER_NONE); + bcam.rolling_shutter_duration = RNA_float_get(&cscene, "rolling_shutter_duration"); + + /* border */ + if (b_render.use_border()) { + bcam.border.left = b_render.border_min_x(); + bcam.border.right = b_render.border_max_x(); + bcam.border.bottom = b_render.border_min_y(); + bcam.border.top = b_render.border_max_y(); + } + + /* camera object */ + BL::Object b_ob = b_scene.camera(); + + if (b_override) + b_ob = b_override; + + if (b_ob) { + BL::Array<float, 16> b_ob_matrix; + blender_camera_from_object(&bcam, b_engine, b_ob); + b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix); + bcam.matrix = get_transform(b_ob_matrix); + } + + /* sync */ + Camera *cam = scene->camera; + blender_camera_sync(cam, &bcam, width, height, viewname, &cscene); + + /* dicing camera */ + b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera")); + if (b_ob) { + BL::Array<float, 16> b_ob_matrix; + blender_camera_from_object(&bcam, b_engine, b_ob); + b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix); + bcam.matrix = get_transform(b_ob_matrix); + + blender_camera_sync(scene->dicing_camera, &bcam, width, height, viewname, &cscene); + } + else { + *scene->dicing_camera = *cam; + } } -void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render, - BL::Object& b_ob, - int width, int height, - float motion_time) +void BlenderSync::sync_camera_motion( + BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time) { - if(!b_ob) - return; - - Camera *cam = scene->camera; - BL::Array<float, 16> b_ob_matrix; - b_engine.camera_model_matrix(b_ob, cam->use_spherical_stereo, b_ob_matrix); - Transform tfm = get_transform(b_ob_matrix); - tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type); - - if(motion_time == 0.0f) { - /* When motion blur is not centered in frame, cam->matrix gets reset. */ - cam->matrix = tfm; - } - - /* Set transform in motion array. */ - int motion_step = cam->motion_step(motion_time); - if(motion_step >= 0) { - cam->motion[motion_step] = tfm; - } - - if(cam->type == CAMERA_PERSPECTIVE) { - BlenderCamera bcam; - float aspectratio, sensor_size; - blender_camera_init(&bcam, b_render); - - /* TODO(sergey): Consider making it a part of blender_camera_init(). */ - bcam.pixelaspect.x = b_render.pixel_aspect_x(); - bcam.pixelaspect.y = b_render.pixel_aspect_y(); - - blender_camera_from_object(&bcam, b_engine, b_ob); - blender_camera_viewplane(&bcam, - width, height, - NULL, - &aspectratio, - &sensor_size); - /* TODO(sergey): De-duplicate calculation with camera sync. */ - float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio); - if(fov != cam->fov) { - VLOG(1) << "Camera " << b_ob.name() << " FOV change detected."; - if(motion_time == 0.0f) { - cam->fov = fov; - } - else if(motion_time == -1.0f) { - cam->fov_pre = fov; - cam->use_perspective_motion = true; - } - else if(motion_time == 1.0f) { - cam->fov_post = fov; - cam->use_perspective_motion = true; - } - } - } + if (!b_ob) + return; + + Camera *cam = scene->camera; + BL::Array<float, 16> b_ob_matrix; + b_engine.camera_model_matrix(b_ob, cam->use_spherical_stereo, b_ob_matrix); + Transform tfm = get_transform(b_ob_matrix); + tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type); + + if (motion_time == 0.0f) { + /* When motion blur is not centered in frame, cam->matrix gets reset. */ + cam->matrix = tfm; + } + + /* Set transform in motion array. */ + int motion_step = cam->motion_step(motion_time); + if (motion_step >= 0) { + cam->motion[motion_step] = tfm; + } + + if (cam->type == CAMERA_PERSPECTIVE) { + BlenderCamera bcam; + float aspectratio, sensor_size; + blender_camera_init(&bcam, b_render); + + /* TODO(sergey): Consider making it a part of blender_camera_init(). */ + bcam.pixelaspect.x = b_render.pixel_aspect_x(); + bcam.pixelaspect.y = b_render.pixel_aspect_y(); + + blender_camera_from_object(&bcam, b_engine, b_ob); + blender_camera_viewplane(&bcam, width, height, NULL, &aspectratio, &sensor_size); + /* TODO(sergey): De-duplicate calculation with camera sync. */ + float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio); + if (fov != cam->fov) { + VLOG(1) << "Camera " << b_ob.name() << " FOV change detected."; + if (motion_time == 0.0f) { + cam->fov = fov; + } + else if (motion_time == -1.0f) { + cam->fov_pre = fov; + cam->use_perspective_motion = true; + } + else if (motion_time == 1.0f) { + cam->fov_post = fov; + cam->use_perspective_motion = true; + } + } + } } /* Sync 3D View Camera */ -static void blender_camera_view_subset(BL::RenderEngine& b_engine, - BL::RenderSettings& b_render, - BL::Scene& b_scene, - BL::Object& b_ob, - BL::SpaceView3D& b_v3d, - BL::RegionView3D& b_rv3d, - int width, int height, +static void blender_camera_view_subset(BL::RenderEngine &b_engine, + BL::RenderSettings &b_render, + BL::Scene &b_scene, + BL::Object &b_ob, + BL::SpaceView3D &b_v3d, + BL::RegionView3D &b_rv3d, + int width, + int height, BoundBox2D *view_box, BoundBox2D *cam_box); static void blender_camera_from_view(BlenderCamera *bcam, - BL::RenderEngine& b_engine, - BL::Scene& b_scene, - BL::SpaceView3D& b_v3d, - BL::RegionView3D& b_rv3d, - int width, int height, + BL::RenderEngine &b_engine, + BL::Scene &b_scene, + BL::SpaceView3D &b_v3d, + BL::RegionView3D &b_rv3d, + int width, + int height, bool skip_panorama = false) { - /* 3d view parameters */ - bcam->nearclip = b_v3d.clip_start(); - bcam->farclip = b_v3d.clip_end(); - bcam->lens = b_v3d.lens(); - bcam->shuttertime = b_scene.render().motion_blur_shutter(); - - BL::CurveMapping b_shutter_curve(b_scene.render().motion_blur_shutter_curve()); - curvemapping_to_array(b_shutter_curve, bcam->shutter_curve, RAMP_TABLE_SIZE); - - if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) { - /* camera view */ - BL::Object b_ob = (b_v3d.use_local_camera())? b_v3d.camera(): b_scene.camera(); - - if(b_ob) { - blender_camera_from_object(bcam, b_engine, b_ob, skip_panorama); - - if(!skip_panorama && bcam->type == CAMERA_PANORAMA) { - /* in panorama camera view, we map viewplane to camera border */ - BoundBox2D view_box, cam_box; - - BL::RenderSettings b_render_settings(b_scene.render()); - blender_camera_view_subset(b_engine, - b_render_settings, - b_scene, - b_ob, - b_v3d, - b_rv3d, - width, height, - &view_box, - &cam_box); - - bcam->pano_viewplane = view_box.make_relative_to(cam_box); - } - else { - /* magic zoom formula */ - bcam->zoom = (float)b_rv3d.view_camera_zoom(); - bcam->zoom = (1.41421f + bcam->zoom/50.0f); - bcam->zoom *= bcam->zoom; - bcam->zoom = 2.0f/bcam->zoom; - - /* offset */ - bcam->offset = get_float2(b_rv3d.view_camera_offset()); - } - } - } - else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) { - /* orthographic view */ - bcam->farclip *= 0.5f; - bcam->nearclip = -bcam->farclip; - - float sensor_size; - if(bcam->sensor_fit == BlenderCamera::VERTICAL) - sensor_size = bcam->sensor_height; - else - sensor_size = bcam->sensor_width; - - bcam->type = CAMERA_ORTHOGRAPHIC; - bcam->ortho_scale = b_rv3d.view_distance() * sensor_size / b_v3d.lens(); - } - - bcam->zoom *= 2.0f; - - /* 3d view transform */ - bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix())); + /* 3d view parameters */ + bcam->nearclip = b_v3d.clip_start(); + bcam->farclip = b_v3d.clip_end(); + bcam->lens = b_v3d.lens(); + bcam->shuttertime = b_scene.render().motion_blur_shutter(); + + BL::CurveMapping b_shutter_curve(b_scene.render().motion_blur_shutter_curve()); + curvemapping_to_array(b_shutter_curve, bcam->shutter_curve, RAMP_TABLE_SIZE); + + if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) { + /* camera view */ + BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera(); + + if (b_ob) { + blender_camera_from_object(bcam, b_engine, b_ob, skip_panorama); + + if (!skip_panorama && bcam->type == CAMERA_PANORAMA) { + /* in panorama camera view, we map viewplane to camera border */ + BoundBox2D view_box, cam_box; + + BL::RenderSettings b_render_settings(b_scene.render()); + blender_camera_view_subset(b_engine, + b_render_settings, + b_scene, + b_ob, + b_v3d, + b_rv3d, + width, + height, + &view_box, + &cam_box); + + bcam->pano_viewplane = view_box.make_relative_to(cam_box); + } + else { + /* magic zoom formula */ + bcam->zoom = (float)b_rv3d.view_camera_zoom(); + bcam->zoom = (1.41421f + bcam->zoom / 50.0f); + bcam->zoom *= bcam->zoom; + bcam->zoom = 2.0f / bcam->zoom; + + /* offset */ + bcam->offset = get_float2(b_rv3d.view_camera_offset()); + } + } + } + else if (b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) { + /* orthographic view */ + bcam->farclip *= 0.5f; + bcam->nearclip = -bcam->farclip; + + float sensor_size; + if (bcam->sensor_fit == BlenderCamera::VERTICAL) + sensor_size = bcam->sensor_height; + else + sensor_size = bcam->sensor_width; + + bcam->type = CAMERA_ORTHOGRAPHIC; + bcam->ortho_scale = b_rv3d.view_distance() * sensor_size / b_v3d.lens(); + } + + bcam->zoom *= 2.0f; + + /* 3d view transform */ + bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix())); } -static void blender_camera_view_subset(BL::RenderEngine& b_engine, - BL::RenderSettings& b_render, - BL::Scene& b_scene, - BL::Object& b_ob, - BL::SpaceView3D& b_v3d, - BL::RegionView3D& b_rv3d, - int width, int height, +static void blender_camera_view_subset(BL::RenderEngine &b_engine, + BL::RenderSettings &b_render, + BL::Scene &b_scene, + BL::Object &b_ob, + BL::SpaceView3D &b_v3d, + BL::RegionView3D &b_rv3d, + int width, + int height, BoundBox2D *view_box, BoundBox2D *cam_box) { - BoundBox2D cam, view; - float view_aspect, cam_aspect, sensor_size; + BoundBox2D cam, view; + float view_aspect, cam_aspect, sensor_size; - /* get viewport viewplane */ - BlenderCamera view_bcam; - blender_camera_init(&view_bcam, b_render); - blender_camera_from_view(&view_bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height, true); + /* get viewport viewplane */ + BlenderCamera view_bcam; + blender_camera_init(&view_bcam, b_render); + blender_camera_from_view(&view_bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height, true); - blender_camera_viewplane(&view_bcam, width, height, - &view, &view_aspect, &sensor_size); + blender_camera_viewplane(&view_bcam, width, height, &view, &view_aspect, &sensor_size); - /* get camera viewplane */ - BlenderCamera cam_bcam; - blender_camera_init(&cam_bcam, b_render); - blender_camera_from_object(&cam_bcam, b_engine, b_ob, true); + /* get camera viewplane */ + BlenderCamera cam_bcam; + blender_camera_init(&cam_bcam, b_render); + blender_camera_from_object(&cam_bcam, b_engine, b_ob, true); - blender_camera_viewplane(&cam_bcam, cam_bcam.full_width, cam_bcam.full_height, - &cam, &cam_aspect, &sensor_size); + blender_camera_viewplane( + &cam_bcam, cam_bcam.full_width, cam_bcam.full_height, &cam, &cam_aspect, &sensor_size); - /* return */ - *view_box = view * (1.0f/view_aspect); - *cam_box = cam * (1.0f/cam_aspect); + /* return */ + *view_box = view * (1.0f / view_aspect); + *cam_box = cam * (1.0f / cam_aspect); } -static void blender_camera_border_subset(BL::RenderEngine& b_engine, - BL::RenderSettings& b_render, - BL::Scene& b_scene, - BL::SpaceView3D& b_v3d, - BL::RegionView3D& b_rv3d, - BL::Object& b_ob, - int width, int height, +static void blender_camera_border_subset(BL::RenderEngine &b_engine, + BL::RenderSettings &b_render, + BL::Scene &b_scene, + BL::SpaceView3D &b_v3d, + BL::RegionView3D &b_rv3d, + BL::Object &b_ob, + int width, + int height, const BoundBox2D &border, BoundBox2D *result) { - /* Determine camera viewport subset. */ - BoundBox2D view_box, cam_box; - blender_camera_view_subset(b_engine, b_render, b_scene, b_ob, b_v3d, b_rv3d, width, height, - &view_box, &cam_box); - - /* Determine viewport subset matching given border. */ - cam_box = cam_box.make_relative_to(view_box); - *result = cam_box.subset(border); + /* Determine camera viewport subset. */ + BoundBox2D view_box, cam_box; + blender_camera_view_subset( + b_engine, b_render, b_scene, b_ob, b_v3d, b_rv3d, width, height, &view_box, &cam_box); + + /* Determine viewport subset matching given border. */ + cam_box = cam_box.make_relative_to(view_box); + *result = cam_box.subset(border); } static void blender_camera_border(BlenderCamera *bcam, - BL::RenderEngine& b_engine, - BL::RenderSettings& b_render, - BL::Scene& b_scene, - BL::SpaceView3D& b_v3d, - BL::RegionView3D& b_rv3d, - int width, int height) + BL::RenderEngine &b_engine, + BL::RenderSettings &b_render, + BL::Scene &b_scene, + BL::SpaceView3D &b_v3d, + BL::RegionView3D &b_rv3d, + int width, + int height) { - bool is_camera_view; - - /* camera view? */ - is_camera_view = b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA; - - if(!is_camera_view) { - /* for non-camera view check whether render border is enabled for viewport - * and if so use border from 3d viewport - * assume viewport has got correctly clamped border already - */ - if(b_v3d.use_render_border()) { - bcam->border.left = b_v3d.render_border_min_x(); - bcam->border.right = b_v3d.render_border_max_x(); - bcam->border.bottom = b_v3d.render_border_min_y(); - bcam->border.top = b_v3d.render_border_max_y(); - } - return; - } - - BL::Object b_ob = (b_v3d.use_local_camera())? b_v3d.camera(): b_scene.camera(); - - if(!b_ob) - return; - - /* Determine camera border inside the viewport. */ - BoundBox2D full_border; - blender_camera_border_subset(b_engine, - b_render, - b_scene, - b_v3d, - b_rv3d, - b_ob, - width, height, - full_border, - &bcam->viewport_camera_border); - - if(!b_render.use_border()) { - return; - } - - bcam->border.left = b_render.border_min_x(); - bcam->border.right = b_render.border_max_x(); - bcam->border.bottom = b_render.border_min_y(); - bcam->border.top = b_render.border_max_y(); - - /* Determine viewport subset matching camera border. */ - blender_camera_border_subset(b_engine, - b_render, - b_scene, - b_v3d, - b_rv3d, - b_ob, - width, height, - bcam->border, - &bcam->border); - bcam->border = bcam->border.clamp(); + bool is_camera_view; + + /* camera view? */ + is_camera_view = b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA; + + if (!is_camera_view) { + /* for non-camera view check whether render border is enabled for viewport + * and if so use border from 3d viewport + * assume viewport has got correctly clamped border already + */ + if (b_v3d.use_render_border()) { + bcam->border.left = b_v3d.render_border_min_x(); + bcam->border.right = b_v3d.render_border_max_x(); + bcam->border.bottom = b_v3d.render_border_min_y(); + bcam->border.top = b_v3d.render_border_max_y(); + } + return; + } + + BL::Object b_ob = (b_v3d.use_local_camera()) ? b_v3d.camera() : b_scene.camera(); + + if (!b_ob) + return; + + /* Determine camera border inside the viewport. */ + BoundBox2D full_border; + blender_camera_border_subset(b_engine, + b_render, + b_scene, + b_v3d, + b_rv3d, + b_ob, + width, + height, + full_border, + &bcam->viewport_camera_border); + + if (!b_render.use_border()) { + return; + } + + bcam->border.left = b_render.border_min_x(); + bcam->border.right = b_render.border_max_x(); + bcam->border.bottom = b_render.border_min_y(); + bcam->border.top = b_render.border_max_y(); + + /* Determine viewport subset matching camera border. */ + blender_camera_border_subset(b_engine, + b_render, + b_scene, + b_v3d, + b_rv3d, + b_ob, + width, + height, + bcam->border, + &bcam->border); + bcam->border = bcam->border.clamp(); } -void BlenderSync::sync_view(BL::SpaceView3D& b_v3d, - BL::RegionView3D& b_rv3d, - int width, int height) +void BlenderSync::sync_view(BL::SpaceView3D &b_v3d, + BL::RegionView3D &b_rv3d, + int width, + int height) { - BlenderCamera bcam; - BL::RenderSettings b_render_settings(b_scene.render()); - blender_camera_init(&bcam, b_render_settings); - blender_camera_from_view(&bcam, - b_engine, - b_scene, - b_v3d, - b_rv3d, - width, height); - blender_camera_border(&bcam, - b_engine, - b_render_settings, - b_scene, - b_v3d, - b_rv3d, - width, height); - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - blender_camera_sync(scene->camera, &bcam, width, height, "", &cscene); - - /* dicing camera */ - BL::Object b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera")); - if(b_ob) { - BL::Array<float, 16> b_ob_matrix; - blender_camera_from_object(&bcam, b_engine, b_ob); - b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix); - bcam.matrix = get_transform(b_ob_matrix); - - blender_camera_sync(scene->dicing_camera, &bcam, width, height, "", &cscene); - } - else { - *scene->dicing_camera = *scene->camera; - } + BlenderCamera bcam; + BL::RenderSettings b_render_settings(b_scene.render()); + blender_camera_init(&bcam, b_render_settings); + blender_camera_from_view(&bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height); + blender_camera_border(&bcam, b_engine, b_render_settings, b_scene, b_v3d, b_rv3d, width, height); + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + blender_camera_sync(scene->camera, &bcam, width, height, "", &cscene); + + /* dicing camera */ + BL::Object b_ob = BL::Object(RNA_pointer_get(&cscene, "dicing_camera")); + if (b_ob) { + BL::Array<float, 16> b_ob_matrix; + blender_camera_from_object(&bcam, b_engine, b_ob); + b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix); + bcam.matrix = get_transform(b_ob_matrix); + + blender_camera_sync(scene->dicing_camera, &bcam, width, height, "", &cscene); + } + else { + *scene->dicing_camera = *scene->camera; + } } -BufferParams BlenderSync::get_buffer_params(BL::RenderSettings& b_render, - BL::SpaceView3D& b_v3d, - BL::RegionView3D& b_rv3d, +BufferParams BlenderSync::get_buffer_params(BL::RenderSettings &b_render, + BL::SpaceView3D &b_v3d, + BL::RegionView3D &b_rv3d, Camera *cam, - int width, int height) + int width, + int height) { - BufferParams params; - bool use_border = false; - - params.full_width = width; - params.full_height = height; - - if(b_v3d && b_rv3d && b_rv3d.view_perspective() != BL::RegionView3D::view_perspective_CAMERA) - use_border = b_v3d.use_render_border(); - else - use_border = b_render.use_border(); - - if(use_border) { - /* border render */ - /* the viewport may offset the border outside the view */ - BoundBox2D border = cam->border.clamp(); - params.full_x = (int)(border.left * (float)width); - params.full_y = (int)(border.bottom * (float)height); - params.width = (int)(border.right * (float)width) - params.full_x; - params.height = (int)(border.top * (float)height) - params.full_y; - - /* survive in case border goes out of view or becomes too small */ - params.width = max(params.width, 1); - params.height = max(params.height, 1); - } - else { - params.width = width; - params.height = height; - } - - return params; + BufferParams params; + bool use_border = false; + + params.full_width = width; + params.full_height = height; + + if (b_v3d && b_rv3d && b_rv3d.view_perspective() != BL::RegionView3D::view_perspective_CAMERA) + use_border = b_v3d.use_render_border(); + else + use_border = b_render.use_border(); + + if (use_border) { + /* border render */ + /* the viewport may offset the border outside the view */ + BoundBox2D border = cam->border.clamp(); + params.full_x = (int)(border.left * (float)width); + params.full_y = (int)(border.bottom * (float)height); + params.width = (int)(border.right * (float)width) - params.full_x; + params.height = (int)(border.top * (float)height) - params.full_y; + + /* survive in case border goes out of view or becomes too small */ + params.width = max(params.width, 1); + params.height = max(params.height, 1); + } + else { + params.width = width; + params.height = height; + } + + return params; } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 602e63a3e47..d0375ceb79c 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -40,170 +40,165 @@ ParticleCurveData::~ParticleCurveData() static void interp_weights(float t, float data[4]) { - /* Cardinal curve interpolation */ - float t2 = t * t; - float t3 = t2 * t; - float fc = 0.71f; - - data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t; - data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f; - data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t; - data[3] = fc * t3 - fc * t2; + /* Cardinal curve interpolation */ + float t2 = t * t; + float t3 = t2 * t; + float fc = 0.71f; + + data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t; + data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f; + data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t; + data[3] = fc * t3 - fc * t2; } -static void curveinterp_v3_v3v3v3v3(float3 *p, - float3 *v1, float3 *v2, float3 *v3, float3 *v4, - const float w[4]) +static void curveinterp_v3_v3v3v3v3( + float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]) { - p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3]; - p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3]; - p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3]; + p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3]; + p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3]; + p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3]; } static float shaperadius(float shape, float root, float tip, float time) { - assert(time >= 0.0f); - assert(time <= 1.0f); - float radius = 1.0f - time; - - if(shape != 0.0f) { - if(shape < 0.0f) - radius = powf(radius, 1.0f + shape); - else - radius = powf(radius, 1.0f / (1.0f - shape)); - } - return (radius * (root - tip)) + tip; + assert(time >= 0.0f); + assert(time <= 1.0f); + float radius = 1.0f - time; + + if (shape != 0.0f) { + if (shape < 0.0f) + radius = powf(radius, 1.0f + shape); + else + radius = powf(radius, 1.0f / (1.0f - shape)); + } + return (radius * (root - tip)) + tip; } /* curve functions */ -static void InterpolateKeySegments(int seg, - int segno, - int key, - int curve, - float3 *keyloc, - float *time, - ParticleCurveData *CData) +static void InterpolateKeySegments( + int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData) { - float3 ckey_loc1 = CData->curvekey_co[key]; - float3 ckey_loc2 = ckey_loc1; - float3 ckey_loc3 = CData->curvekey_co[key+1]; - float3 ckey_loc4 = ckey_loc3; + float3 ckey_loc1 = CData->curvekey_co[key]; + float3 ckey_loc2 = ckey_loc1; + float3 ckey_loc3 = CData->curvekey_co[key + 1]; + float3 ckey_loc4 = ckey_loc3; - if(key > CData->curve_firstkey[curve]) - ckey_loc1 = CData->curvekey_co[key - 1]; + if (key > CData->curve_firstkey[curve]) + ckey_loc1 = CData->curvekey_co[key - 1]; - if(key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) - ckey_loc4 = CData->curvekey_co[key + 2]; + if (key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) + ckey_loc4 = CData->curvekey_co[key + 2]; - float time1 = CData->curvekey_time[key]/CData->curve_length[curve]; - float time2 = CData->curvekey_time[key + 1]/CData->curve_length[curve]; + float time1 = CData->curvekey_time[key] / CData->curve_length[curve]; + float time2 = CData->curvekey_time[key + 1] / CData->curve_length[curve]; - float dfra = (time2 - time1) / (float)segno; + float dfra = (time2 - time1) / (float)segno; - if(time) - *time = (dfra * seg) + time1; + if (time) + *time = (dfra * seg) + time1; - float t[4]; + float t[4]; - interp_weights((float)seg / (float)segno, t); + interp_weights((float)seg / (float)segno, t); - if(keyloc) - curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t); + if (keyloc) + curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t); } -static bool ObtainCacheParticleData(Mesh *mesh, - BL::Mesh *b_mesh, - BL::Object *b_ob, - ParticleCurveData *CData, - bool background) +static bool ObtainCacheParticleData( + Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background) { - int curvenum = 0; - int keyno = 0; - - if(!(mesh && b_mesh && b_ob && CData)) - return false; - - Transform tfm = get_transform(b_ob->matrix_world()); - Transform itfm = transform_quick_inverse(tfm); - - BL::Object::modifiers_iterator b_mod; - for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { - if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) { - BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); - BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); - BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr); - - if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) { - int shader = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1); - int display_step = background ? b_part.render_step() : b_part.display_step(); - int totparts = b_psys.particles.length(); - int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.display_percentage() / 100.0f); - int totcurves = totchild; - - if(b_part.child_type() == 0 || totchild == 0) - totcurves += totparts; - - if(totcurves == 0) - continue; - - int ren_step = (1 << display_step) + 1; - if(b_part.kink() == BL::ParticleSettings::kink_SPIRAL) - ren_step += b_part.kink_extra_steps(); - - CData->psys_firstcurve.push_back_slow(curvenum); - CData->psys_curvenum.push_back_slow(totcurves); - CData->psys_shader.push_back_slow(shader); - - float radius = b_part.radius_scale() * 0.5f; - - CData->psys_rootradius.push_back_slow(radius * b_part.root_radius()); - CData->psys_tipradius.push_back_slow(radius * b_part.tip_radius()); - CData->psys_shape.push_back_slow(b_part.shape()); - CData->psys_closetip.push_back_slow(b_part.use_close_tip()); - - int pa_no = 0; - if(!(b_part.child_type() == 0) && totchild != 0) - pa_no = totparts; - - int num_add = (totparts+totchild - pa_no); - CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add); - CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add); - CData->curve_length.reserve(CData->curve_length.size() + num_add); - CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add*ren_step); - CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add*ren_step); - - for(; pa_no < totparts+totchild; pa_no++) { - int keynum = 0; - CData->curve_firstkey.push_back_slow(keyno); - - float curve_length = 0.0f; - float3 pcKey; - for(int step_no = 0; step_no < ren_step; step_no++) { - float nco[3]; - b_psys.co_hair(*b_ob, pa_no, step_no, nco); - float3 cKey = make_float3(nco[0], nco[1], nco[2]); - cKey = transform_point(&itfm, cKey); - if(step_no > 0) { - const float step_length = len(cKey - pcKey); - curve_length += step_length; - } - CData->curvekey_co.push_back_slow(cKey); - CData->curvekey_time.push_back_slow(curve_length); - pcKey = cKey; - keynum++; - } - keyno += keynum; - - CData->curve_keynum.push_back_slow(keynum); - CData->curve_length.push_back_slow(curve_length); - curvenum++; - } - } - } - } - - return true; + int curvenum = 0; + int keyno = 0; + + if (!(mesh && b_mesh && b_ob && CData)) + return false; + + Transform tfm = get_transform(b_ob->matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + + BL::Object::modifiers_iterator b_mod; + for (b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { + if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && + (background ? b_mod->show_render() : b_mod->show_viewport())) { + BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); + BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); + BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr); + + if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && + (b_part.type() == BL::ParticleSettings::type_HAIR)) { + int shader = clamp(b_part.material() - 1, 0, mesh->used_shaders.size() - 1); + int display_step = background ? b_part.render_step() : b_part.display_step(); + int totparts = b_psys.particles.length(); + int totchild = background ? b_psys.child_particles.length() : + (int)((float)b_psys.child_particles.length() * + (float)b_part.display_percentage() / 100.0f); + int totcurves = totchild; + + if (b_part.child_type() == 0 || totchild == 0) + totcurves += totparts; + + if (totcurves == 0) + continue; + + int ren_step = (1 << display_step) + 1; + if (b_part.kink() == BL::ParticleSettings::kink_SPIRAL) + ren_step += b_part.kink_extra_steps(); + + CData->psys_firstcurve.push_back_slow(curvenum); + CData->psys_curvenum.push_back_slow(totcurves); + CData->psys_shader.push_back_slow(shader); + + float radius = b_part.radius_scale() * 0.5f; + + CData->psys_rootradius.push_back_slow(radius * b_part.root_radius()); + CData->psys_tipradius.push_back_slow(radius * b_part.tip_radius()); + CData->psys_shape.push_back_slow(b_part.shape()); + CData->psys_closetip.push_back_slow(b_part.use_close_tip()); + + int pa_no = 0; + if (!(b_part.child_type() == 0) && totchild != 0) + pa_no = totparts; + + int num_add = (totparts + totchild - pa_no); + CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add); + CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add); + CData->curve_length.reserve(CData->curve_length.size() + num_add); + CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add * ren_step); + CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add * ren_step); + + for (; pa_no < totparts + totchild; pa_no++) { + int keynum = 0; + CData->curve_firstkey.push_back_slow(keyno); + + float curve_length = 0.0f; + float3 pcKey; + for (int step_no = 0; step_no < ren_step; step_no++) { + float nco[3]; + b_psys.co_hair(*b_ob, pa_no, step_no, nco); + float3 cKey = make_float3(nco[0], nco[1], nco[2]); + cKey = transform_point(&itfm, cKey); + if (step_no > 0) { + const float step_length = len(cKey - pcKey); + curve_length += step_length; + } + CData->curvekey_co.push_back_slow(cKey); + CData->curvekey_time.push_back_slow(curve_length); + pcKey = cKey; + keynum++; + } + keyno += keynum; + + CData->curve_keynum.push_back_slow(keynum); + CData->curve_length.push_back_slow(curve_length); + curvenum++; + } + } + } + } + + return true; } static bool ObtainCacheParticleUV(Mesh *mesh, @@ -213,56 +208,60 @@ static bool ObtainCacheParticleUV(Mesh *mesh, bool background, int uv_num) { - if(!(mesh && b_mesh && b_ob && CData)) - return false; - - CData->curve_uv.clear(); - - BL::Object::modifiers_iterator b_mod; - for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { - if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) { - BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); - BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); - BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr); - - if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) { - int totparts = b_psys.particles.length(); - int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.display_percentage() / 100.0f); - int totcurves = totchild; - - if(b_part.child_type() == 0 || totchild == 0) - totcurves += totparts; - - if(totcurves == 0) - continue; - - int pa_no = 0; - if(!(b_part.child_type() == 0) && totchild != 0) - pa_no = totparts; - - int num_add = (totparts+totchild - pa_no); - CData->curve_uv.reserve(CData->curve_uv.size() + num_add); - - BL::ParticleSystem::particles_iterator b_pa; - b_psys.particles.begin(b_pa); - for(; pa_no < totparts+totchild; pa_no++) { - /* Add UVs */ - BL::Mesh::uv_layers_iterator l; - b_mesh->uv_layers.begin(l); - - float2 uv = make_float2(0.0f, 0.0f); - if(b_mesh->uv_layers.length()) - b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x); - CData->curve_uv.push_back_slow(uv); - - if(pa_no < totparts && b_pa != b_psys.particles.end()) - ++b_pa; - } - } - } - } - - return true; + if (!(mesh && b_mesh && b_ob && CData)) + return false; + + CData->curve_uv.clear(); + + BL::Object::modifiers_iterator b_mod; + for (b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { + if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && + (background ? b_mod->show_render() : b_mod->show_viewport())) { + BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); + BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); + BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr); + + if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && + (b_part.type() == BL::ParticleSettings::type_HAIR)) { + int totparts = b_psys.particles.length(); + int totchild = background ? b_psys.child_particles.length() : + (int)((float)b_psys.child_particles.length() * + (float)b_part.display_percentage() / 100.0f); + int totcurves = totchild; + + if (b_part.child_type() == 0 || totchild == 0) + totcurves += totparts; + + if (totcurves == 0) + continue; + + int pa_no = 0; + if (!(b_part.child_type() == 0) && totchild != 0) + pa_no = totparts; + + int num_add = (totparts + totchild - pa_no); + CData->curve_uv.reserve(CData->curve_uv.size() + num_add); + + BL::ParticleSystem::particles_iterator b_pa; + b_psys.particles.begin(b_pa); + for (; pa_no < totparts + totchild; pa_no++) { + /* Add UVs */ + BL::Mesh::uv_layers_iterator l; + b_mesh->uv_layers.begin(l); + + float2 uv = make_float2(0.0f, 0.0f); + if (b_mesh->uv_layers.length()) + b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x); + CData->curve_uv.push_back_slow(uv); + + if (pa_no < totparts && b_pa != b_psys.particles.end()) + ++b_pa; + } + } + } + } + + return true; } static bool ObtainCacheParticleVcol(Mesh *mesh, @@ -272,481 +271,542 @@ static bool ObtainCacheParticleVcol(Mesh *mesh, bool background, int vcol_num) { - if(!(mesh && b_mesh && b_ob && CData)) - return false; - - CData->curve_vcol.clear(); - - BL::Object::modifiers_iterator b_mod; - for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { - if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) { - BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); - BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); - BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr); - - if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) { - int totparts = b_psys.particles.length(); - int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.display_percentage() / 100.0f); - int totcurves = totchild; - - if(b_part.child_type() == 0 || totchild == 0) - totcurves += totparts; - - if(totcurves == 0) - continue; - - int pa_no = 0; - if(!(b_part.child_type() == 0) && totchild != 0) - pa_no = totparts; - - int num_add = (totparts+totchild - pa_no); - CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add); - - BL::ParticleSystem::particles_iterator b_pa; - b_psys.particles.begin(b_pa); - for(; pa_no < totparts+totchild; pa_no++) { - /* Add vertex colors */ - BL::Mesh::vertex_colors_iterator l; - b_mesh->vertex_colors.begin(l); - - float3 vcol = make_float3(0.0f, 0.0f, 0.0f); - if(b_mesh->vertex_colors.length()) - b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x); - CData->curve_vcol.push_back_slow(vcol); - - if(pa_no < totparts && b_pa != b_psys.particles.end()) - ++b_pa; - } - } - } - } - - return true; + if (!(mesh && b_mesh && b_ob && CData)) + return false; + + CData->curve_vcol.clear(); + + BL::Object::modifiers_iterator b_mod; + for (b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { + if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && + (background ? b_mod->show_render() : b_mod->show_viewport())) { + BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); + BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); + BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr); + + if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && + (b_part.type() == BL::ParticleSettings::type_HAIR)) { + int totparts = b_psys.particles.length(); + int totchild = background ? b_psys.child_particles.length() : + (int)((float)b_psys.child_particles.length() * + (float)b_part.display_percentage() / 100.0f); + int totcurves = totchild; + + if (b_part.child_type() == 0 || totchild == 0) + totcurves += totparts; + + if (totcurves == 0) + continue; + + int pa_no = 0; + if (!(b_part.child_type() == 0) && totchild != 0) + pa_no = totparts; + + int num_add = (totparts + totchild - pa_no); + CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add); + + BL::ParticleSystem::particles_iterator b_pa; + b_psys.particles.begin(b_pa); + for (; pa_no < totparts + totchild; pa_no++) { + /* Add vertex colors */ + BL::Mesh::vertex_colors_iterator l; + b_mesh->vertex_colors.begin(l); + + float3 vcol = make_float3(0.0f, 0.0f, 0.0f); + if (b_mesh->vertex_colors.length()) + b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x); + CData->curve_vcol.push_back_slow(vcol); + + if (pa_no < totparts && b_pa != b_psys.particles.end()) + ++b_pa; + } + } + } + } + + return true; } -static void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, - float3 RotCam, bool is_ortho) +static void ExportCurveTrianglePlanes(Mesh *mesh, + ParticleCurveData *CData, + float3 RotCam, + bool is_ortho) { - int vertexno = mesh->verts.size(); - int vertexindex = vertexno; - int numverts = 0, numtris = 0; - - /* compute and reserve size of arrays */ - for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { - numverts += 2 + (CData->curve_keynum[curve] - 1)*2; - numtris += (CData->curve_keynum[curve] - 1)*2; - } - } - - mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); - - /* actually export */ - for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { - float3 xbasis; - float3 v1; - float time = 0.0f; - float3 ickey_loc = CData->curvekey_co[CData->curve_firstkey[curve]]; - float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.0f); - v1 = CData->curvekey_co[CData->curve_firstkey[curve] + 1] - CData->curvekey_co[CData->curve_firstkey[curve]]; - if(is_ortho) - xbasis = normalize(cross(RotCam, v1)); - else - xbasis = normalize(cross(RotCam - ickey_loc, v1)); - float3 ickey_loc_shfl = ickey_loc - radius * xbasis; - float3 ickey_loc_shfr = ickey_loc + radius * xbasis; - mesh->add_vertex(ickey_loc_shfl); - mesh->add_vertex(ickey_loc_shfr); - vertexindex += 2; - - for(int curvekey = CData->curve_firstkey[curve] + 1; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) { - ickey_loc = CData->curvekey_co[curvekey]; - - if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) - v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 1, CData->curve_firstkey[curve])]; - else - v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1]; - - time = CData->curvekey_time[curvekey]/CData->curve_length[curve]; - radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); - - if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) - radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f); - - if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) - radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); - - if(is_ortho) - xbasis = normalize(cross(RotCam, v1)); - else - xbasis = normalize(cross(RotCam - ickey_loc, v1)); - float3 ickey_loc_shfl = ickey_loc - radius * xbasis; - float3 ickey_loc_shfr = ickey_loc + radius * xbasis; - mesh->add_vertex(ickey_loc_shfl); - mesh->add_vertex(ickey_loc_shfr); - mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], true); - mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], true); - vertexindex += 2; - } - } - } - - mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles()); - mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); - mesh->attributes.remove(ATTR_STD_FACE_NORMAL); - mesh->add_face_normals(); - mesh->add_vertex_normals(); - mesh->attributes.remove(ATTR_STD_FACE_NORMAL); - - /* texture coords still needed */ + int vertexno = mesh->verts.size(); + int vertexindex = vertexno; + int numverts = 0, numtris = 0; + + /* compute and reserve size of arrays */ + for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for (int curve = CData->psys_firstcurve[sys]; + curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; + curve++) { + numverts += 2 + (CData->curve_keynum[curve] - 1) * 2; + numtris += (CData->curve_keynum[curve] - 1) * 2; + } + } + + mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); + + /* actually export */ + for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for (int curve = CData->psys_firstcurve[sys]; + curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; + curve++) { + float3 xbasis; + float3 v1; + float time = 0.0f; + float3 ickey_loc = CData->curvekey_co[CData->curve_firstkey[curve]]; + float radius = shaperadius( + CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.0f); + v1 = CData->curvekey_co[CData->curve_firstkey[curve] + 1] - + CData->curvekey_co[CData->curve_firstkey[curve]]; + if (is_ortho) + xbasis = normalize(cross(RotCam, v1)); + else + xbasis = normalize(cross(RotCam - ickey_loc, v1)); + float3 ickey_loc_shfl = ickey_loc - radius * xbasis; + float3 ickey_loc_shfr = ickey_loc + radius * xbasis; + mesh->add_vertex(ickey_loc_shfl); + mesh->add_vertex(ickey_loc_shfr); + vertexindex += 2; + + for (int curvekey = CData->curve_firstkey[curve] + 1; + curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; + curvekey++) { + ickey_loc = CData->curvekey_co[curvekey]; + + if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) + v1 = CData->curvekey_co[curvekey] - + CData->curvekey_co[max(curvekey - 1, CData->curve_firstkey[curve])]; + else + v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1]; + + time = CData->curvekey_time[curvekey] / CData->curve_length[curve]; + radius = shaperadius( + CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); + + if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) + radius = shaperadius(CData->psys_shape[sys], + CData->psys_rootradius[sys], + CData->psys_tipradius[sys], + 0.95f); + + if (CData->psys_closetip[sys] && + (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); + + if (is_ortho) + xbasis = normalize(cross(RotCam, v1)); + else + xbasis = normalize(cross(RotCam - ickey_loc, v1)); + float3 ickey_loc_shfl = ickey_loc - radius * xbasis; + float3 ickey_loc_shfr = ickey_loc + radius * xbasis; + mesh->add_vertex(ickey_loc_shfl); + mesh->add_vertex(ickey_loc_shfr); + mesh->add_triangle( + vertexindex - 2, vertexindex, vertexindex - 1, CData->psys_shader[sys], true); + mesh->add_triangle( + vertexindex + 1, vertexindex - 1, vertexindex, CData->psys_shader[sys], true); + vertexindex += 2; + } + } + } + + mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles()); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + mesh->add_vertex_normals(); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + + /* texture coords still needed */ } -static void ExportCurveTriangleGeometry(Mesh *mesh, - ParticleCurveData *CData, - int resolution) +static void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution) { - int vertexno = mesh->verts.size(); - int vertexindex = vertexno; - int numverts = 0, numtris = 0; - - /* compute and reserve size of arrays */ - for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { - numverts += (CData->curve_keynum[curve] - 1)*resolution + resolution; - numtris += (CData->curve_keynum[curve] - 1)*2*resolution; - } - } - - mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); - - /* actually export */ - for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { - float3 firstxbasis = cross(make_float3(1.0f,0.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]); - if(!is_zero(firstxbasis)) - firstxbasis = normalize(firstxbasis); - else - firstxbasis = normalize(cross(make_float3(0.0f,1.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]])); - - for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { - float3 xbasis = firstxbasis; - float3 v1; - float3 v2; - - if(curvekey == CData->curve_firstkey[curve]) { - v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1]; - v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; - } - else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { - v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; - v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])]; - } - else { - v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; - v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; - } - - xbasis = cross(v1, v2); - - if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { - firstxbasis = normalize(xbasis); - break; - } - } - - for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { - int subv = 1; - float3 xbasis; - float3 ybasis; - float3 v1; - float3 v2; - - if(curvekey == CData->curve_firstkey[curve]) { - subv = 0; - v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1]; - v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; - } - else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { - v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; - v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])]; - } - else { - v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; - v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; - } - - xbasis = cross(v1, v2); - - if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { - xbasis = normalize(xbasis); - firstxbasis = xbasis; - } - else - xbasis = firstxbasis; - - ybasis = normalize(cross(xbasis, v2)); - - for(; subv <= 1; subv++) { - float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); - float time = 0.0f; - - InterpolateKeySegments(subv, 1, curvekey, curve, &ickey_loc, &time, CData); - - float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); - - if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && (subv == 1)) - radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f); - - if(CData->psys_closetip[sys] && (subv == 1) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)) - radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); - - float angle = M_2PI_F / (float)resolution; - for(int section = 0; section < resolution; section++) { - float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis); - mesh->add_vertex(ickey_loc_shf); - } - - if(subv != 0) { - for(int section = 0; section < resolution - 1; section++) { - mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], true); - mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], true); - } - mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], true); - mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], true); - } - vertexindex += resolution; - } - } - } - } - - mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles()); - mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); - mesh->attributes.remove(ATTR_STD_FACE_NORMAL); - mesh->add_face_normals(); - mesh->add_vertex_normals(); - mesh->attributes.remove(ATTR_STD_FACE_NORMAL); - - /* texture coords still needed */ + int vertexno = mesh->verts.size(); + int vertexindex = vertexno; + int numverts = 0, numtris = 0; + + /* compute and reserve size of arrays */ + for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for (int curve = CData->psys_firstcurve[sys]; + curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; + curve++) { + numverts += (CData->curve_keynum[curve] - 1) * resolution + resolution; + numtris += (CData->curve_keynum[curve] - 1) * 2 * resolution; + } + } + + mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); + + /* actually export */ + for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for (int curve = CData->psys_firstcurve[sys]; + curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; + curve++) { + float3 firstxbasis = cross(make_float3(1.0f, 0.0f, 0.0f), + CData->curvekey_co[CData->curve_firstkey[curve] + 1] - + CData->curvekey_co[CData->curve_firstkey[curve]]); + if (!is_zero(firstxbasis)) + firstxbasis = normalize(firstxbasis); + else + firstxbasis = normalize(cross(make_float3(0.0f, 1.0f, 0.0f), + CData->curvekey_co[CData->curve_firstkey[curve] + 1] - + CData->curvekey_co[CData->curve_firstkey[curve]])); + + for (int curvekey = CData->curve_firstkey[curve]; + curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; + curvekey++) { + float3 xbasis = firstxbasis; + float3 v1; + float3 v2; + + if (curvekey == CData->curve_firstkey[curve]) { + v1 = CData->curvekey_co[min( + curvekey + 2, CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - + CData->curvekey_co[curvekey + 1]; + v2 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; + } + else if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; + v2 = CData->curvekey_co[curvekey - 1] - + CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])]; + } + else { + v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; + v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; + } + + xbasis = cross(v1, v2); + + if (len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { + firstxbasis = normalize(xbasis); + break; + } + } + + for (int curvekey = CData->curve_firstkey[curve]; + curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; + curvekey++) { + int subv = 1; + float3 xbasis; + float3 ybasis; + float3 v1; + float3 v2; + + if (curvekey == CData->curve_firstkey[curve]) { + subv = 0; + v1 = CData->curvekey_co[min( + curvekey + 2, CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - + CData->curvekey_co[curvekey + 1]; + v2 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; + } + else if (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; + v2 = CData->curvekey_co[curvekey - 1] - + CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])]; + } + else { + v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey]; + v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey - 1]; + } + + xbasis = cross(v1, v2); + + if (len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { + xbasis = normalize(xbasis); + firstxbasis = xbasis; + } + else + xbasis = firstxbasis; + + ybasis = normalize(cross(xbasis, v2)); + + for (; subv <= 1; subv++) { + float3 ickey_loc = make_float3(0.0f, 0.0f, 0.0f); + float time = 0.0f; + + InterpolateKeySegments(subv, 1, curvekey, curve, &ickey_loc, &time, CData); + + float radius = shaperadius(CData->psys_shape[sys], + CData->psys_rootradius[sys], + CData->psys_tipradius[sys], + time); + + if ((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) && + (subv == 1)) + radius = shaperadius(CData->psys_shape[sys], + CData->psys_rootradius[sys], + CData->psys_tipradius[sys], + 0.95f); + + if (CData->psys_closetip[sys] && (subv == 1) && + (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); + + float angle = M_2PI_F / (float)resolution; + for (int section = 0; section < resolution; section++) { + float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + + sinf(angle * section) * ybasis); + mesh->add_vertex(ickey_loc_shf); + } + + if (subv != 0) { + for (int section = 0; section < resolution - 1; section++) { + mesh->add_triangle(vertexindex - resolution + section, + vertexindex + section, + vertexindex - resolution + section + 1, + CData->psys_shader[sys], + true); + mesh->add_triangle(vertexindex + section + 1, + vertexindex - resolution + section + 1, + vertexindex + section, + CData->psys_shader[sys], + true); + } + mesh->add_triangle(vertexindex - 1, + vertexindex + resolution - 1, + vertexindex - resolution, + CData->psys_shader[sys], + true); + mesh->add_triangle(vertexindex, + vertexindex - resolution, + vertexindex + resolution - 1, + CData->psys_shader[sys], + true); + } + vertexindex += resolution; + } + } + } + } + + mesh->resize_mesh(mesh->verts.size(), mesh->num_triangles()); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + mesh->add_vertex_normals(); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + + /* texture coords still needed */ } static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) { - int num_keys = 0; - int num_curves = 0; - - if(mesh->num_curves()) - return; - - Attribute *attr_intercept = NULL; - Attribute *attr_random = NULL; - - if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) - attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT); - if(mesh->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) - attr_random = mesh->curve_attributes.add(ATTR_STD_CURVE_RANDOM); - - /* compute and reserve size of arrays */ - for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { - num_keys += CData->curve_keynum[curve]; - num_curves++; - } - } - - if(num_curves > 0) { - VLOG(1) << "Exporting curve segments for mesh " << mesh->name; - } - - mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys); - - num_keys = 0; - num_curves = 0; - - /* actually export */ - for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { - size_t num_curve_keys = 0; - - for(int curvekey = CData->curve_firstkey[curve]; - curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; - curvekey++) - { - const float3 ickey_loc = CData->curvekey_co[curvekey]; - const float curve_time = CData->curvekey_time[curvekey]; - const float curve_length = CData->curve_length[curve]; - const float time = (curve_length > 0.0f) - ? curve_time / curve_length - : 0.0f; - float radius = shaperadius(CData->psys_shape[sys], - CData->psys_rootradius[sys], - CData->psys_tipradius[sys], - time); - if(CData->psys_closetip[sys] && - (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) - { - radius = 0.0f; - } - mesh->add_curve_key(ickey_loc, radius); - if(attr_intercept) - attr_intercept->add(time); - - num_curve_keys++; - } - - if(attr_random != NULL) { - attr_random->add(hash_int_01(num_curves)); - } - - mesh->add_curve(num_keys, CData->psys_shader[sys]); - num_keys += num_curve_keys; - num_curves++; - } - } - - /* check allocation */ - if((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) { - VLOG(1) << "Allocation failed, clearing data"; - mesh->clear(); - } + int num_keys = 0; + int num_curves = 0; + + if (mesh->num_curves()) + return; + + Attribute *attr_intercept = NULL; + Attribute *attr_random = NULL; + + if (mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) + attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT); + if (mesh->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) + attr_random = mesh->curve_attributes.add(ATTR_STD_CURVE_RANDOM); + + /* compute and reserve size of arrays */ + for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for (int curve = CData->psys_firstcurve[sys]; + curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; + curve++) { + num_keys += CData->curve_keynum[curve]; + num_curves++; + } + } + + if (num_curves > 0) { + VLOG(1) << "Exporting curve segments for mesh " << mesh->name; + } + + mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys); + + num_keys = 0; + num_curves = 0; + + /* actually export */ + for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for (int curve = CData->psys_firstcurve[sys]; + curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; + curve++) { + size_t num_curve_keys = 0; + + for (int curvekey = CData->curve_firstkey[curve]; + curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; + curvekey++) { + const float3 ickey_loc = CData->curvekey_co[curvekey]; + const float curve_time = CData->curvekey_time[curvekey]; + const float curve_length = CData->curve_length[curve]; + const float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f; + float radius = shaperadius( + CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); + if (CData->psys_closetip[sys] && + (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) { + radius = 0.0f; + } + mesh->add_curve_key(ickey_loc, radius); + if (attr_intercept) + attr_intercept->add(time); + + num_curve_keys++; + } + + if (attr_random != NULL) { + attr_random->add(hash_int_01(num_curves)); + } + + mesh->add_curve(num_keys, CData->psys_shader[sys]); + num_keys += num_curve_keys; + num_curves++; + } + } + + /* check allocation */ + if ((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) { + VLOG(1) << "Allocation failed, clearing data"; + mesh->clear(); + } } static float4 CurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, int curvekey) { - const float3 ickey_loc = CData->curvekey_co[curvekey]; - const float curve_time = CData->curvekey_time[curvekey]; - const float curve_length = CData->curve_length[curve]; - float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f; - float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); - - if(CData->psys_closetip[sys] && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) - radius = 0.0f; - - /* curve motion keys store both position and radius in float4 */ - float4 mP = float3_to_float4(ickey_loc); - mP.w = radius; - return mP; + const float3 ickey_loc = CData->curvekey_co[curvekey]; + const float curve_time = CData->curvekey_time[curvekey]; + const float curve_length = CData->curve_length[curve]; + float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f; + float radius = shaperadius( + CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); + + if (CData->psys_closetip[sys] && + (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) + radius = 0.0f; + + /* curve motion keys store both position and radius in float4 */ + float4 mP = float3_to_float4(ickey_loc); + mP.w = radius; + return mP; } static float4 LerpCurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, float step) { - assert(step >= 0.0f); - assert(step <= 1.0f); - const int first_curve_key = CData->curve_firstkey[curve]; - const float curve_key_f = step * (CData->curve_keynum[curve] - 1); - int curvekey = (int)floorf(curve_key_f); - const float remainder = curve_key_f - curvekey; - if(remainder == 0.0f) { - return CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey); - } - int curvekey2 = curvekey + 1; - if(curvekey2 >= (CData->curve_keynum[curve] - 1)) { - curvekey2 = (CData->curve_keynum[curve] - 1); - curvekey = curvekey2 - 1; - } - const float4 mP = CurveSegmentMotionCV( - CData, sys, curve, first_curve_key + curvekey); - const float4 mP2 = CurveSegmentMotionCV( - CData, sys, curve, first_curve_key + curvekey2); - return lerp(mP, mP2, remainder); + assert(step >= 0.0f); + assert(step <= 1.0f); + const int first_curve_key = CData->curve_firstkey[curve]; + const float curve_key_f = step * (CData->curve_keynum[curve] - 1); + int curvekey = (int)floorf(curve_key_f); + const float remainder = curve_key_f - curvekey; + if (remainder == 0.0f) { + return CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey); + } + int curvekey2 = curvekey + 1; + if (curvekey2 >= (CData->curve_keynum[curve] - 1)) { + curvekey2 = (CData->curve_keynum[curve] - 1); + curvekey = curvekey2 - 1; + } + const float4 mP = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey); + const float4 mP2 = CurveSegmentMotionCV(CData, sys, curve, first_curve_key + curvekey2); + return lerp(mP, mP2, remainder); } static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int motion_step) { - VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name - << ", motion step " << motion_step; - - /* find attribute */ - Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - bool new_attribute = false; - - /* add new attribute if it doesn't exist already */ - if(!attr_mP) { - VLOG(1) << "Creating new motion vertex position attribute"; - attr_mP = mesh->curve_attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); - new_attribute = true; - } - - /* export motion vectors for curve keys */ - size_t numkeys = mesh->curve_keys.size(); - float4 *mP = attr_mP->data_float4() + motion_step*numkeys; - bool have_motion = false; - int i = 0; - int num_curves = 0; - - for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { - /* Curve lengths may not match! Curves can be clipped. */ - int curve_key_end = (num_curves+1 < (int)mesh->curve_first_key.size() ? mesh->curve_first_key[num_curves+1] : (int)mesh->curve_keys.size()); - const int num_center_curve_keys = curve_key_end - mesh->curve_first_key[num_curves]; - const int is_num_keys_different = CData->curve_keynum[curve] - num_center_curve_keys; - - if(!is_num_keys_different) { - for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) { - if(i < mesh->curve_keys.size()) { - mP[i] = CurveSegmentMotionCV(CData, sys, curve, curvekey); - if(!have_motion) { - /* unlike mesh coordinates, these tend to be slightly different - * between frames due to particle transforms into/out of object - * space, so we use an epsilon to detect actual changes */ - float4 curve_key = float3_to_float4(mesh->curve_keys[i]); - curve_key.w = mesh->curve_radius[i]; - if(len_squared(mP[i] - curve_key) > 1e-5f*1e-5f) - have_motion = true; - } - } - i++; - } - } - else { - /* Number of keys has changed. Genereate an interpolated version - * to preserve motion blur. */ - const float step_size = - num_center_curve_keys > 1 - ? 1.0f / (num_center_curve_keys - 1) - : 0.0f; - for(int step_index = 0; - step_index < num_center_curve_keys; - ++step_index) - { - const float step = step_index * step_size; - mP[i] = LerpCurveSegmentMotionCV(CData, sys, curve, step); - i++; - } - have_motion = true; - } - num_curves++; - } - } - - /* in case of new attribute, we verify if there really was any motion */ - if(new_attribute) { - if(i != numkeys || !have_motion) { - /* No motion or hair "topology" changed, remove attributes again. */ - if(i != numkeys) { - VLOG(1) << "Hair topology changed, removing attribute."; - } - else { - VLOG(1) << "No motion, removing attribute."; - } - mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); - } - else if(motion_step > 0) { - VLOG(1) << "Filling in new motion vertex position for motion_step " - << motion_step; - /* motion, fill up previous steps that we might have skipped because - * they had no motion, but we need them anyway now */ - for(int step = 0; step < motion_step; step++) { - float4 *mP = attr_mP->data_float4() + step*numkeys; - - for(int key = 0; key < numkeys; key++) { - mP[key] = float3_to_float4(mesh->curve_keys[key]); - mP[key].w = mesh->curve_radius[key]; - } - } - } - } + VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name << ", motion step " + << motion_step; + + /* find attribute */ + Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + bool new_attribute = false; + + /* add new attribute if it doesn't exist already */ + if (!attr_mP) { + VLOG(1) << "Creating new motion vertex position attribute"; + attr_mP = mesh->curve_attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); + new_attribute = true; + } + + /* export motion vectors for curve keys */ + size_t numkeys = mesh->curve_keys.size(); + float4 *mP = attr_mP->data_float4() + motion_step * numkeys; + bool have_motion = false; + int i = 0; + int num_curves = 0; + + for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for (int curve = CData->psys_firstcurve[sys]; + curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; + curve++) { + /* Curve lengths may not match! Curves can be clipped. */ + int curve_key_end = (num_curves + 1 < (int)mesh->curve_first_key.size() ? + mesh->curve_first_key[num_curves + 1] : + (int)mesh->curve_keys.size()); + const int num_center_curve_keys = curve_key_end - mesh->curve_first_key[num_curves]; + const int is_num_keys_different = CData->curve_keynum[curve] - num_center_curve_keys; + + if (!is_num_keys_different) { + for (int curvekey = CData->curve_firstkey[curve]; + curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; + curvekey++) { + if (i < mesh->curve_keys.size()) { + mP[i] = CurveSegmentMotionCV(CData, sys, curve, curvekey); + if (!have_motion) { + /* unlike mesh coordinates, these tend to be slightly different + * between frames due to particle transforms into/out of object + * space, so we use an epsilon to detect actual changes */ + float4 curve_key = float3_to_float4(mesh->curve_keys[i]); + curve_key.w = mesh->curve_radius[i]; + if (len_squared(mP[i] - curve_key) > 1e-5f * 1e-5f) + have_motion = true; + } + } + i++; + } + } + else { + /* Number of keys has changed. Genereate an interpolated version + * to preserve motion blur. */ + const float step_size = num_center_curve_keys > 1 ? 1.0f / (num_center_curve_keys - 1) : + 0.0f; + for (int step_index = 0; step_index < num_center_curve_keys; ++step_index) { + const float step = step_index * step_size; + mP[i] = LerpCurveSegmentMotionCV(CData, sys, curve, step); + i++; + } + have_motion = true; + } + num_curves++; + } + } + + /* in case of new attribute, we verify if there really was any motion */ + if (new_attribute) { + if (i != numkeys || !have_motion) { + /* No motion or hair "topology" changed, remove attributes again. */ + if (i != numkeys) { + VLOG(1) << "Hair topology changed, removing attribute."; + } + else { + VLOG(1) << "No motion, removing attribute."; + } + mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); + } + else if (motion_step > 0) { + VLOG(1) << "Filling in new motion vertex position for motion_step " << motion_step; + /* motion, fill up previous steps that we might have skipped because + * they had no motion, but we need them anyway now */ + for (int step = 0; step < motion_step; step++) { + float4 *mP = attr_mP->data_float4() + step * numkeys; + + for (int key = 0; key < numkeys; key++) { + mP[key] = float3_to_float4(mesh->curve_keys[key]); + mP[key].w = mesh->curve_radius[key]; + } + } + } + } } static void ExportCurveTriangleUV(ParticleCurveData *CData, @@ -754,30 +814,34 @@ static void ExportCurveTriangleUV(ParticleCurveData *CData, int resol, float2 *uvdata) { - if(uvdata == NULL) - return; - int vertexindex = vert_offset; - - for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { - for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { - for(int section = 0; section < resol; section++) { - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - uvdata[vertexindex] = CData->curve_uv[curve]; - vertexindex++; - } - } - } - } + if (uvdata == NULL) + return; + int vertexindex = vert_offset; + + for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for (int curve = CData->psys_firstcurve[sys]; + curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; + curve++) { + for (int curvekey = CData->curve_firstkey[curve]; + curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; + curvekey++) { + for (int section = 0; section < resol; section++) { + uvdata[vertexindex] = CData->curve_uv[curve]; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + vertexindex++; + } + } + } + } } static void ExportCurveTriangleVcol(ParticleCurveData *CData, @@ -785,295 +849,296 @@ static void ExportCurveTriangleVcol(ParticleCurveData *CData, int resol, uchar4 *cdata) { - if(cdata == NULL) - return; - - int vertexindex = vert_offset; - - for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { - for(int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { - for(int section = 0; section < resol; section++) { - /* Encode vertex color using the sRGB curve. */ - cdata[vertexindex] = color_float_to_byte(color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - cdata[vertexindex] = color_float_to_byte(color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - cdata[vertexindex] = color_float_to_byte(color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - cdata[vertexindex] = color_float_to_byte(color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - cdata[vertexindex] = color_float_to_byte(color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - cdata[vertexindex] = color_float_to_byte(color_srgb_to_linear_v3(CData->curve_vcol[curve])); - vertexindex++; - } - } - } - } + if (cdata == NULL) + return; + + int vertexindex = vert_offset; + + for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for (int curve = CData->psys_firstcurve[sys]; + curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; + curve++) { + for (int curvekey = CData->curve_firstkey[curve]; + curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; + curvekey++) { + for (int section = 0; section < resol; section++) { + /* Encode vertex color using the sRGB curve. */ + cdata[vertexindex] = color_float_to_byte( + color_srgb_to_linear_v3(CData->curve_vcol[curve])); + vertexindex++; + cdata[vertexindex] = color_float_to_byte( + color_srgb_to_linear_v3(CData->curve_vcol[curve])); + vertexindex++; + cdata[vertexindex] = color_float_to_byte( + color_srgb_to_linear_v3(CData->curve_vcol[curve])); + vertexindex++; + cdata[vertexindex] = color_float_to_byte( + color_srgb_to_linear_v3(CData->curve_vcol[curve])); + vertexindex++; + cdata[vertexindex] = color_float_to_byte( + color_srgb_to_linear_v3(CData->curve_vcol[curve])); + vertexindex++; + cdata[vertexindex] = color_float_to_byte( + color_srgb_to_linear_v3(CData->curve_vcol[curve])); + vertexindex++; + } + } + } + } } /* Hair Curve Sync */ void BlenderSync::sync_curve_settings() { - PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves"); - - CurveSystemManager *curve_system_manager = scene->curve_system_manager; - CurveSystemManager prev_curve_system_manager = *curve_system_manager; - - curve_system_manager->use_curves = get_boolean(csscene, "use_curves"); - curve_system_manager->minimum_width = get_float(csscene, "minimum_width"); - curve_system_manager->maximum_width = get_float(csscene, "maximum_width"); - - curve_system_manager->primitive = - (CurvePrimitiveType)get_enum(csscene, - "primitive", - CURVE_NUM_PRIMITIVE_TYPES, - CURVE_LINE_SEGMENTS); - curve_system_manager->curve_shape = - (CurveShapeType)get_enum(csscene, - "shape", - CURVE_NUM_SHAPE_TYPES, - CURVE_THICK); - curve_system_manager->resolution = get_int(csscene, "resolution"); - curve_system_manager->subdivisions = get_int(csscene, "subdivisions"); - curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing"); - - /* Triangles */ - if(curve_system_manager->primitive == CURVE_TRIANGLES) { - /* camera facing planes */ - if(curve_system_manager->curve_shape == CURVE_RIBBON) { - curve_system_manager->triangle_method = CURVE_CAMERA_TRIANGLES; - curve_system_manager->resolution = 1; - } - else if(curve_system_manager->curve_shape == CURVE_THICK) { - curve_system_manager->triangle_method = CURVE_TESSELATED_TRIANGLES; - } - } - /* Line Segments */ - else if(curve_system_manager->primitive == CURVE_LINE_SEGMENTS) { - if(curve_system_manager->curve_shape == CURVE_RIBBON) { - /* tangent shading */ - curve_system_manager->line_method = CURVE_UNCORRECTED; - curve_system_manager->use_encasing = true; - curve_system_manager->use_backfacing = false; - curve_system_manager->use_tangent_normal_geometry = true; - } - else if(curve_system_manager->curve_shape == CURVE_THICK) { - curve_system_manager->line_method = CURVE_ACCURATE; - curve_system_manager->use_encasing = false; - curve_system_manager->use_tangent_normal_geometry = false; - } - } - /* Curve Segments */ - else if(curve_system_manager->primitive == CURVE_SEGMENTS) { - if(curve_system_manager->curve_shape == CURVE_RIBBON) { - curve_system_manager->primitive = CURVE_RIBBONS; - curve_system_manager->use_backfacing = false; - } - } - - if(curve_system_manager->modified_mesh(prev_curve_system_manager)) { - BL::BlendData::objects_iterator b_ob; - - for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) { - if(object_is_mesh(*b_ob)) { - BL::Object::particle_systems_iterator b_psys; - for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) { - if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) { - BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data(); - mesh_map.set_recalc(key); - object_map.set_recalc(*b_ob); - } - } - } - } - } - - if(curve_system_manager->modified(prev_curve_system_manager)) - curve_system_manager->tag_update(scene); + PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves"); + + CurveSystemManager *curve_system_manager = scene->curve_system_manager; + CurveSystemManager prev_curve_system_manager = *curve_system_manager; + + curve_system_manager->use_curves = get_boolean(csscene, "use_curves"); + curve_system_manager->minimum_width = get_float(csscene, "minimum_width"); + curve_system_manager->maximum_width = get_float(csscene, "maximum_width"); + + curve_system_manager->primitive = (CurvePrimitiveType)get_enum( + csscene, "primitive", CURVE_NUM_PRIMITIVE_TYPES, CURVE_LINE_SEGMENTS); + curve_system_manager->curve_shape = (CurveShapeType)get_enum( + csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK); + curve_system_manager->resolution = get_int(csscene, "resolution"); + curve_system_manager->subdivisions = get_int(csscene, "subdivisions"); + curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing"); + + /* Triangles */ + if (curve_system_manager->primitive == CURVE_TRIANGLES) { + /* camera facing planes */ + if (curve_system_manager->curve_shape == CURVE_RIBBON) { + curve_system_manager->triangle_method = CURVE_CAMERA_TRIANGLES; + curve_system_manager->resolution = 1; + } + else if (curve_system_manager->curve_shape == CURVE_THICK) { + curve_system_manager->triangle_method = CURVE_TESSELATED_TRIANGLES; + } + } + /* Line Segments */ + else if (curve_system_manager->primitive == CURVE_LINE_SEGMENTS) { + if (curve_system_manager->curve_shape == CURVE_RIBBON) { + /* tangent shading */ + curve_system_manager->line_method = CURVE_UNCORRECTED; + curve_system_manager->use_encasing = true; + curve_system_manager->use_backfacing = false; + curve_system_manager->use_tangent_normal_geometry = true; + } + else if (curve_system_manager->curve_shape == CURVE_THICK) { + curve_system_manager->line_method = CURVE_ACCURATE; + curve_system_manager->use_encasing = false; + curve_system_manager->use_tangent_normal_geometry = false; + } + } + /* Curve Segments */ + else if (curve_system_manager->primitive == CURVE_SEGMENTS) { + if (curve_system_manager->curve_shape == CURVE_RIBBON) { + curve_system_manager->primitive = CURVE_RIBBONS; + curve_system_manager->use_backfacing = false; + } + } + + if (curve_system_manager->modified_mesh(prev_curve_system_manager)) { + BL::BlendData::objects_iterator b_ob; + + for (b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) { + if (object_is_mesh(*b_ob)) { + BL::Object::particle_systems_iterator b_psys; + for (b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); + ++b_psys) { + if ((b_psys->settings().render_type() == BL::ParticleSettings::render_type_PATH) && + (b_psys->settings().type() == BL::ParticleSettings::type_HAIR)) { + BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data(); + mesh_map.set_recalc(key); + object_map.set_recalc(*b_ob); + } + } + } + } + } + + if (curve_system_manager->modified(prev_curve_system_manager)) + curve_system_manager->tag_update(scene); } -void BlenderSync::sync_curves(Mesh *mesh, - BL::Mesh& b_mesh, - BL::Object& b_ob, - bool motion, - int motion_step) +void BlenderSync::sync_curves( + Mesh *mesh, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step) { - if(!motion) { - /* Clear stored curve data */ - mesh->curve_keys.clear(); - mesh->curve_radius.clear(); - mesh->curve_first_key.clear(); - mesh->curve_shader.clear(); - mesh->curve_attributes.clear(); - } - - /* obtain general settings */ - const bool use_curves = scene->curve_system_manager->use_curves; - - if(!(use_curves && b_ob.mode() != b_ob.mode_PARTICLE_EDIT)) { - if(!motion) - mesh->compute_bounds(); - return; - } - - const int primitive = scene->curve_system_manager->primitive; - const int triangle_method = scene->curve_system_manager->triangle_method; - const int resolution = scene->curve_system_manager->resolution; - const size_t vert_num = mesh->verts.size(); - const size_t tri_num = mesh->num_triangles(); - int used_res = 1; - - /* extract particle hair data - should be combined with connecting to mesh later*/ - - ParticleCurveData CData; - - ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview); - - /* add hair geometry to mesh */ - if(primitive == CURVE_TRIANGLES) { - if(triangle_method == CURVE_CAMERA_TRIANGLES) { - /* obtain camera parameters */ - float3 RotCam; - Camera *camera = scene->camera; - Transform &ctfm = camera->matrix; - if(camera->type == CAMERA_ORTHOGRAPHIC) { - RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z); - } - else { - Transform tfm = get_transform(b_ob.matrix_world()); - Transform itfm = transform_quick_inverse(tfm); - RotCam = transform_point(&itfm, make_float3(ctfm.x.w, - ctfm.y.w, - ctfm.z.w)); - } - bool is_ortho = camera->type == CAMERA_ORTHOGRAPHIC; - ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho); - } - else { - ExportCurveTriangleGeometry(mesh, &CData, resolution); - used_res = resolution; - } - } - else { - if(motion) - ExportCurveSegmentsMotion(mesh, &CData, motion_step); - else - ExportCurveSegments(scene, mesh, &CData); - } - - /* generated coordinates from first key. we should ideally get this from - * blender to handle deforming objects */ - if(!motion) { - if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) { - float3 loc, size; - mesh_texture_space(b_mesh, loc, size); - - if(primitive == CURVE_TRIANGLES) { - Attribute *attr_generated = mesh->attributes.add(ATTR_STD_GENERATED); - float3 *generated = attr_generated->data_float3(); - - for(size_t i = vert_num; i < mesh->verts.size(); i++) - generated[i] = mesh->verts[i]*size - loc; - } - else { - Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED); - float3 *generated = attr_generated->data_float3(); - - for(size_t i = 0; i < mesh->num_curves(); i++) { - float3 co = mesh->curve_keys[mesh->get_curve(i).first_key]; - generated[i] = co*size - loc; - } - } - } - } - - /* create vertex color attributes */ - if(!motion) { - BL::Mesh::vertex_colors_iterator l; - int vcol_num = 0; - - for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l, vcol_num++) { - if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) - continue; - - ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num); - - if(primitive == CURVE_TRIANGLES) { - Attribute *attr_vcol = mesh->attributes.add( - ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); - - uchar4 *cdata = attr_vcol->data_uchar4(); - - ExportCurveTriangleVcol(&CData, tri_num * 3, used_res, cdata); - } - else { - Attribute *attr_vcol = mesh->curve_attributes.add( - ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE); - - float3 *fdata = attr_vcol->data_float3(); - - if(fdata) { - size_t i = 0; - - /* Encode vertex color using the sRGB curve. */ - for(size_t curve = 0; curve < CData.curve_vcol.size(); curve++) { - fdata[i++] = color_srgb_to_linear_v3(CData.curve_vcol[curve]); - } - } - } - } - } - - /* create UV attributes */ - if(!motion) { - BL::Mesh::uv_layers_iterator l; - int uv_num = 0; - - for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, uv_num++) { - bool active_render = l->active_render(); - AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; - ustring name = ustring(l->name().c_str()); - - /* UV map */ - if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) { - Attribute *attr_uv; - - ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, !preview, uv_num); - - if(primitive == CURVE_TRIANGLES) { - if(active_render) - attr_uv = mesh->attributes.add(std, name); - else - attr_uv = mesh->attributes.add(name, TypeFloat2, ATTR_ELEMENT_CORNER); - - float2 *uv = attr_uv->data_float2(); - - ExportCurveTriangleUV(&CData, tri_num * 3, used_res, uv); - } - else { - if(active_render) - attr_uv = mesh->curve_attributes.add(std, name); - else - attr_uv = mesh->curve_attributes.add(name, TypeFloat2, ATTR_ELEMENT_CURVE); - - float2 *uv = attr_uv->data_float2(); - - if(uv) { - size_t i = 0; - - for(size_t curve = 0; curve < CData.curve_uv.size(); curve++) { - uv[i++] = CData.curve_uv[curve]; - } - } - } - } - } - } - - mesh->compute_bounds(); + if (!motion) { + /* Clear stored curve data */ + mesh->curve_keys.clear(); + mesh->curve_radius.clear(); + mesh->curve_first_key.clear(); + mesh->curve_shader.clear(); + mesh->curve_attributes.clear(); + } + + /* obtain general settings */ + const bool use_curves = scene->curve_system_manager->use_curves; + + if (!(use_curves && b_ob.mode() != b_ob.mode_PARTICLE_EDIT)) { + if (!motion) + mesh->compute_bounds(); + return; + } + + const int primitive = scene->curve_system_manager->primitive; + const int triangle_method = scene->curve_system_manager->triangle_method; + const int resolution = scene->curve_system_manager->resolution; + const size_t vert_num = mesh->verts.size(); + const size_t tri_num = mesh->num_triangles(); + int used_res = 1; + + /* extract particle hair data - should be combined with connecting to mesh later*/ + + ParticleCurveData CData; + + ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview); + + /* add hair geometry to mesh */ + if (primitive == CURVE_TRIANGLES) { + if (triangle_method == CURVE_CAMERA_TRIANGLES) { + /* obtain camera parameters */ + float3 RotCam; + Camera *camera = scene->camera; + Transform &ctfm = camera->matrix; + if (camera->type == CAMERA_ORTHOGRAPHIC) { + RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z); + } + else { + Transform tfm = get_transform(b_ob.matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w)); + } + bool is_ortho = camera->type == CAMERA_ORTHOGRAPHIC; + ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho); + } + else { + ExportCurveTriangleGeometry(mesh, &CData, resolution); + used_res = resolution; + } + } + else { + if (motion) + ExportCurveSegmentsMotion(mesh, &CData, motion_step); + else + ExportCurveSegments(scene, mesh, &CData); + } + + /* generated coordinates from first key. we should ideally get this from + * blender to handle deforming objects */ + if (!motion) { + if (mesh->need_attribute(scene, ATTR_STD_GENERATED)) { + float3 loc, size; + mesh_texture_space(b_mesh, loc, size); + + if (primitive == CURVE_TRIANGLES) { + Attribute *attr_generated = mesh->attributes.add(ATTR_STD_GENERATED); + float3 *generated = attr_generated->data_float3(); + + for (size_t i = vert_num; i < mesh->verts.size(); i++) + generated[i] = mesh->verts[i] * size - loc; + } + else { + Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED); + float3 *generated = attr_generated->data_float3(); + + for (size_t i = 0; i < mesh->num_curves(); i++) { + float3 co = mesh->curve_keys[mesh->get_curve(i).first_key]; + generated[i] = co * size - loc; + } + } + } + } + + /* create vertex color attributes */ + if (!motion) { + BL::Mesh::vertex_colors_iterator l; + int vcol_num = 0; + + for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l, vcol_num++) { + if (!mesh->need_attribute(scene, ustring(l->name().c_str()))) + continue; + + ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num); + + if (primitive == CURVE_TRIANGLES) { + Attribute *attr_vcol = mesh->attributes.add( + ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); + + uchar4 *cdata = attr_vcol->data_uchar4(); + + ExportCurveTriangleVcol(&CData, tri_num * 3, used_res, cdata); + } + else { + Attribute *attr_vcol = mesh->curve_attributes.add( + ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE); + + float3 *fdata = attr_vcol->data_float3(); + + if (fdata) { + size_t i = 0; + + /* Encode vertex color using the sRGB curve. */ + for (size_t curve = 0; curve < CData.curve_vcol.size(); curve++) { + fdata[i++] = color_srgb_to_linear_v3(CData.curve_vcol[curve]); + } + } + } + } + } + + /* create UV attributes */ + if (!motion) { + BL::Mesh::uv_layers_iterator l; + int uv_num = 0; + + for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, uv_num++) { + bool active_render = l->active_render(); + AttributeStandard std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE; + ustring name = ustring(l->name().c_str()); + + /* UV map */ + if (mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) { + Attribute *attr_uv; + + ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, !preview, uv_num); + + if (primitive == CURVE_TRIANGLES) { + if (active_render) + attr_uv = mesh->attributes.add(std, name); + else + attr_uv = mesh->attributes.add(name, TypeFloat2, ATTR_ELEMENT_CORNER); + + float2 *uv = attr_uv->data_float2(); + + ExportCurveTriangleUV(&CData, tri_num * 3, used_res, uv); + } + else { + if (active_render) + attr_uv = mesh->curve_attributes.add(std, name); + else + attr_uv = mesh->curve_attributes.add(name, TypeFloat2, ATTR_ELEMENT_CURVE); + + float2 *uv = attr_uv->data_float2(); + + if (uv) { + size_t i = 0; + + for (size_t curve = 0; curve < CData.curve_uv.size(); curve++) { + uv[i++] = CData.curve_uv[curve]; + } + } + } + } + } + } + + mesh->compute_bounds(); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_device.cpp b/intern/cycles/blender/blender_device.cpp index 969601b1c37..98fc0c6dec4 100644 --- a/intern/cycles/blender/blender_device.cpp +++ b/intern/cycles/blender/blender_device.cpp @@ -19,91 +19,89 @@ CCL_NAMESPACE_BEGIN -int blender_device_threads(BL::Scene& b_scene) +int blender_device_threads(BL::Scene &b_scene) { - BL::RenderSettings b_r = b_scene.render(); + BL::RenderSettings b_r = b_scene.render(); - if(b_r.threads_mode() == BL::RenderSettings::threads_mode_FIXED) - return b_r.threads(); - else - return 0; + if (b_r.threads_mode() == BL::RenderSettings::threads_mode_FIXED) + return b_r.threads(); + else + return 0; } -DeviceInfo blender_device_info(BL::Preferences& b_preferences, BL::Scene& b_scene, bool background) +DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scene, bool background) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - /* Default to CPU device. */ - DeviceInfo device = Device::available_devices(DEVICE_MASK_CPU).front(); + /* Default to CPU device. */ + DeviceInfo device = Device::available_devices(DEVICE_MASK_CPU).front(); - if(get_enum(cscene, "device") == 2) { - /* Find network device. */ - vector<DeviceInfo> devices = Device::available_devices(DEVICE_MASK_NETWORK); - if(!devices.empty()) { - device = devices.front(); - } - } - else if(get_enum(cscene, "device") == 1) { - /* Find cycles preferences. */ - PointerRNA cpreferences; + if (get_enum(cscene, "device") == 2) { + /* Find network device. */ + vector<DeviceInfo> devices = Device::available_devices(DEVICE_MASK_NETWORK); + if (!devices.empty()) { + device = devices.front(); + } + } + else if (get_enum(cscene, "device") == 1) { + /* Find cycles preferences. */ + PointerRNA cpreferences; - BL::Preferences::addons_iterator b_addon_iter; - for(b_preferences.addons.begin(b_addon_iter); b_addon_iter != b_preferences.addons.end(); ++b_addon_iter) { - if(b_addon_iter->module() == "cycles") { - cpreferences = b_addon_iter->preferences().ptr; - break; - } - } + BL::Preferences::addons_iterator b_addon_iter; + for (b_preferences.addons.begin(b_addon_iter); b_addon_iter != b_preferences.addons.end(); + ++b_addon_iter) { + if (b_addon_iter->module() == "cycles") { + cpreferences = b_addon_iter->preferences().ptr; + break; + } + } - /* Test if we are using GPU devices. */ - enum ComputeDevice { - COMPUTE_DEVICE_CPU = 0, - COMPUTE_DEVICE_CUDA = 1, - COMPUTE_DEVICE_OPENCL = 2, - COMPUTE_DEVICE_NUM = 3, - }; + /* Test if we are using GPU devices. */ + enum ComputeDevice { + COMPUTE_DEVICE_CPU = 0, + COMPUTE_DEVICE_CUDA = 1, + COMPUTE_DEVICE_OPENCL = 2, + COMPUTE_DEVICE_NUM = 3, + }; - ComputeDevice compute_device = (ComputeDevice)get_enum(cpreferences, - "compute_device_type", - COMPUTE_DEVICE_NUM, - COMPUTE_DEVICE_CPU); + ComputeDevice compute_device = (ComputeDevice)get_enum( + cpreferences, "compute_device_type", COMPUTE_DEVICE_NUM, COMPUTE_DEVICE_CPU); - if(compute_device != COMPUTE_DEVICE_CPU) { - /* Query GPU devices with matching types. */ - uint mask = DEVICE_MASK_CPU; - if(compute_device == COMPUTE_DEVICE_CUDA) { - mask |= DEVICE_MASK_CUDA; - } - else if(compute_device == COMPUTE_DEVICE_OPENCL) { - mask |= DEVICE_MASK_OPENCL; - } - vector<DeviceInfo> devices = Device::available_devices(mask); + if (compute_device != COMPUTE_DEVICE_CPU) { + /* Query GPU devices with matching types. */ + uint mask = DEVICE_MASK_CPU; + if (compute_device == COMPUTE_DEVICE_CUDA) { + mask |= DEVICE_MASK_CUDA; + } + else if (compute_device == COMPUTE_DEVICE_OPENCL) { + mask |= DEVICE_MASK_OPENCL; + } + vector<DeviceInfo> devices = Device::available_devices(mask); - /* Match device preferences and available devices. */ - vector<DeviceInfo> used_devices; - RNA_BEGIN(&cpreferences, device, "devices") { - if(get_boolean(device, "use")) { - string id = get_string(device, "id"); - foreach(DeviceInfo& info, devices) { - if(info.id == id) { - used_devices.push_back(info); - break; - } - } - } - } RNA_END; + /* Match device preferences and available devices. */ + vector<DeviceInfo> used_devices; + RNA_BEGIN (&cpreferences, device, "devices") { + if (get_boolean(device, "use")) { + string id = get_string(device, "id"); + foreach (DeviceInfo &info, devices) { + if (info.id == id) { + used_devices.push_back(info); + break; + } + } + } + } + RNA_END; - if(!used_devices.empty()) { - int threads = blender_device_threads(b_scene); - device = Device::get_multi_device(used_devices, - threads, - background); - } - /* Else keep using the CPU device that was set before. */ - } - } + if (!used_devices.empty()) { + int threads = blender_device_threads(b_scene); + device = Device::get_multi_device(used_devices, threads, background); + } + /* Else keep using the CPU device that was set before. */ + } + } - return device; + return device; } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_device.h b/intern/cycles/blender/blender_device.h index 061020936e2..fd6c045c966 100644 --- a/intern/cycles/blender/blender_device.h +++ b/intern/cycles/blender/blender_device.h @@ -27,11 +27,13 @@ CCL_NAMESPACE_BEGIN /* Get number of threads to use for rendering. */ -int blender_device_threads(BL::Scene& b_scene); +int blender_device_threads(BL::Scene &b_scene); /* Convert Blender settings to device specification. */ -DeviceInfo blender_device_info(BL::Preferences& b_preferences, BL::Scene& b_scene, bool background); +DeviceInfo blender_device_info(BL::Preferences &b_preferences, + BL::Scene &b_scene, + bool background); CCL_NAMESPACE_END -#endif /* __BLENDER_DEVICE_H__ */ +#endif /* __BLENDER_DEVICE_H__ */ diff --git a/intern/cycles/blender/blender_logging.cpp b/intern/cycles/blender/blender_logging.cpp index 3fca4efd097..b42a1f47821 100644 --- a/intern/cycles/blender/blender_logging.cpp +++ b/intern/cycles/blender/blender_logging.cpp @@ -19,15 +19,15 @@ void CCL_init_logging(const char *argv0) { - ccl::util_logging_init(argv0); + ccl::util_logging_init(argv0); } void CCL_start_debug_logging() { - ccl::util_logging_start(); + ccl::util_logging_start(); } void CCL_logging_verbosity_set(int verbosity) { - ccl::util_logging_verbosity_set(verbosity); + ccl::util_logging_verbosity_set(verbosity); } diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 9b2c2c8e5d5..de594f4fb6c 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -38,1241 +38,1174 @@ CCL_NAMESPACE_BEGIN /* Tangent Space */ struct MikkUserData { - MikkUserData(const BL::Mesh& b_mesh, - const char *layer_name, - const Mesh *mesh, - float3 *tangent, - float *tangent_sign) - : mesh(mesh), - texface(NULL), - orco(NULL), - tangent(tangent), - tangent_sign(tangent_sign) - { - const AttributeSet& attributes = (mesh->subd_faces.size()) ? - mesh->subd_attributes : mesh->attributes; - - Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL); - vertex_normal = attr_vN->data_float3(); - - if(layer_name == NULL) { - Attribute *attr_orco = attributes.find(ATTR_STD_GENERATED); - - if(attr_orco) { - orco = attr_orco->data_float3(); - mesh_texture_space(*(BL::Mesh*)&b_mesh, orco_loc, orco_size); - } - } - else { - Attribute *attr_uv = attributes.find(ustring(layer_name)); - if(attr_uv != NULL) { - texface = attr_uv->data_float2(); - } - } - } - - const Mesh *mesh; - int num_faces; - - float3 *vertex_normal; - float2 *texface; - float3 *orco; - float3 orco_loc, orco_size; - - float3 *tangent; - float *tangent_sign; + MikkUserData(const BL::Mesh &b_mesh, + const char *layer_name, + const Mesh *mesh, + float3 *tangent, + float *tangent_sign) + : mesh(mesh), texface(NULL), orco(NULL), tangent(tangent), tangent_sign(tangent_sign) + { + const AttributeSet &attributes = (mesh->subd_faces.size()) ? mesh->subd_attributes : + mesh->attributes; + + Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL); + vertex_normal = attr_vN->data_float3(); + + if (layer_name == NULL) { + Attribute *attr_orco = attributes.find(ATTR_STD_GENERATED); + + if (attr_orco) { + orco = attr_orco->data_float3(); + mesh_texture_space(*(BL::Mesh *)&b_mesh, orco_loc, orco_size); + } + } + else { + Attribute *attr_uv = attributes.find(ustring(layer_name)); + if (attr_uv != NULL) { + texface = attr_uv->data_float2(); + } + } + } + + const Mesh *mesh; + int num_faces; + + float3 *vertex_normal; + float2 *texface; + float3 *orco; + float3 orco_loc, orco_size; + + float3 *tangent; + float *tangent_sign; }; static int mikk_get_num_faces(const SMikkTSpaceContext *context) { - const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; - if(userdata->mesh->subd_faces.size()) { - return userdata->mesh->subd_faces.size(); - } - else { - return userdata->mesh->num_triangles(); - } + const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; + if (userdata->mesh->subd_faces.size()) { + return userdata->mesh->subd_faces.size(); + } + else { + return userdata->mesh->num_triangles(); + } } -static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, - const int face_num) +static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context, const int face_num) { - const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; - if(userdata->mesh->subd_faces.size()) { - const Mesh *mesh = userdata->mesh; - return mesh->subd_faces[face_num].num_corners; - } - else { - return 3; - } + const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; + if (userdata->mesh->subd_faces.size()) { + const Mesh *mesh = userdata->mesh; + return mesh->subd_faces[face_num].num_corners; + } + else { + return 3; + } } static int mikk_vertex_index(const Mesh *mesh, const int face_num, const int vert_num) { - if(mesh->subd_faces.size()) { - const Mesh::SubdFace& face = mesh->subd_faces[face_num]; - return mesh->subd_face_corners[face.start_corner + vert_num]; - } - else { - return mesh->triangles[face_num * 3 + vert_num]; - } + if (mesh->subd_faces.size()) { + const Mesh::SubdFace &face = mesh->subd_faces[face_num]; + return mesh->subd_face_corners[face.start_corner + vert_num]; + } + else { + return mesh->triangles[face_num * 3 + vert_num]; + } } static int mikk_corner_index(const Mesh *mesh, const int face_num, const int vert_num) { - if(mesh->subd_faces.size()) { - const Mesh::SubdFace& face = mesh->subd_faces[face_num]; - return face.start_corner + vert_num; - } - else { - return face_num * 3 + vert_num; - } + if (mesh->subd_faces.size()) { + const Mesh::SubdFace &face = mesh->subd_faces[face_num]; + return face.start_corner + vert_num; + } + else { + return face_num * 3 + vert_num; + } } static void mikk_get_position(const SMikkTSpaceContext *context, float P[3], - const int face_num, const int vert_num) + const int face_num, + const int vert_num) { - const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; - const Mesh *mesh = userdata->mesh; - const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); - const float3 vP = mesh->verts[vertex_index]; - P[0] = vP.x; - P[1] = vP.y; - P[2] = vP.z; + const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; + const Mesh *mesh = userdata->mesh; + const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); + const float3 vP = mesh->verts[vertex_index]; + P[0] = vP.x; + P[1] = vP.y; + P[2] = vP.z; } static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, float uv[2], - const int face_num, const int vert_num) + const int face_num, + const int vert_num) { - const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; - const Mesh *mesh = userdata->mesh; - if(userdata->texface != NULL) { - const int corner_index = mikk_corner_index(mesh, face_num, vert_num); - float2 tfuv = userdata->texface[corner_index]; - uv[0] = tfuv.x; - uv[1] = tfuv.y; - } - else if(userdata->orco != NULL) { - const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); - const float3 orco_loc = userdata->orco_loc; - const float3 orco_size = userdata->orco_size; - const float3 orco = (userdata->orco[vertex_index] + orco_loc) / orco_size; - - const float2 tmp = map_to_sphere(orco); - uv[0] = tmp.x; - uv[1] = tmp.y; - } - else { - uv[0] = 0.0f; - uv[1] = 0.0f; - } + const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; + const Mesh *mesh = userdata->mesh; + if (userdata->texface != NULL) { + const int corner_index = mikk_corner_index(mesh, face_num, vert_num); + float2 tfuv = userdata->texface[corner_index]; + uv[0] = tfuv.x; + uv[1] = tfuv.y; + } + else if (userdata->orco != NULL) { + const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); + const float3 orco_loc = userdata->orco_loc; + const float3 orco_size = userdata->orco_size; + const float3 orco = (userdata->orco[vertex_index] + orco_loc) / orco_size; + + const float2 tmp = map_to_sphere(orco); + uv[0] = tmp.x; + uv[1] = tmp.y; + } + else { + uv[0] = 0.0f; + uv[1] = 0.0f; + } } -static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3], - const int face_num, const int vert_num) +static void mikk_get_normal(const SMikkTSpaceContext *context, + float N[3], + const int face_num, + const int vert_num) { - const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; - const Mesh *mesh = userdata->mesh; - float3 vN; - if(mesh->subd_faces.size()) { - const Mesh::SubdFace& face = mesh->subd_faces[face_num]; - if(face.smooth) { - const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); - vN = userdata->vertex_normal[vertex_index]; - } - else { - vN = face.normal(mesh); - } - } - else { - if(mesh->smooth[face_num]) { - const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); - vN = userdata->vertex_normal[vertex_index]; - } - else { - const Mesh::Triangle tri = mesh->get_triangle(face_num); - vN = tri.compute_normal(&mesh->verts[0]); - } - } - N[0] = vN.x; - N[1] = vN.y; - N[2] = vN.z; + const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData; + const Mesh *mesh = userdata->mesh; + float3 vN; + if (mesh->subd_faces.size()) { + const Mesh::SubdFace &face = mesh->subd_faces[face_num]; + if (face.smooth) { + const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); + vN = userdata->vertex_normal[vertex_index]; + } + else { + vN = face.normal(mesh); + } + } + else { + if (mesh->smooth[face_num]) { + const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num); + vN = userdata->vertex_normal[vertex_index]; + } + else { + const Mesh::Triangle tri = mesh->get_triangle(face_num); + vN = tri.compute_normal(&mesh->verts[0]); + } + } + N[0] = vN.x; + N[1] = vN.y; + N[2] = vN.z; } static void mikk_set_tangent_space(const SMikkTSpaceContext *context, const float T[], const float sign, - const int face_num, const int vert_num) + const int face_num, + const int vert_num) { - MikkUserData *userdata = (MikkUserData *)context->m_pUserData; - const Mesh *mesh = userdata->mesh; - const int corner_index = mikk_corner_index(mesh, face_num, vert_num); - userdata->tangent[corner_index] = make_float3(T[0], T[1], T[2]); - if(userdata->tangent_sign != NULL) { - userdata->tangent_sign[corner_index] = sign; - } + MikkUserData *userdata = (MikkUserData *)context->m_pUserData; + const Mesh *mesh = userdata->mesh; + const int corner_index = mikk_corner_index(mesh, face_num, vert_num); + userdata->tangent[corner_index] = make_float3(T[0], T[1], T[2]); + if (userdata->tangent_sign != NULL) { + userdata->tangent_sign[corner_index] = sign; + } } -static void mikk_compute_tangents(const BL::Mesh& b_mesh, - const char *layer_name, - Mesh *mesh, - bool need_sign, - bool active_render) +static void mikk_compute_tangents( + const BL::Mesh &b_mesh, const char *layer_name, Mesh *mesh, bool need_sign, bool active_render) { - /* Create tangent attributes. */ - AttributeSet& attributes = (mesh->subd_faces.size()) ? - mesh->subd_attributes : mesh->attributes; - Attribute *attr; - ustring name; - if(layer_name != NULL) { - name = ustring((string(layer_name) + ".tangent").c_str()); - } - else { - name = ustring("orco.tangent"); - } - if(active_render) { - attr = attributes.add(ATTR_STD_UV_TANGENT, name); - } - else { - attr = attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER); - } - float3 *tangent = attr->data_float3(); - /* Create bitangent sign attribute. */ - float *tangent_sign = NULL; - if(need_sign) { - Attribute *attr_sign; - ustring name_sign; - if(layer_name != NULL) { - name_sign = ustring((string(layer_name) + - ".tangent_sign").c_str()); - } - else { - name_sign = ustring("orco.tangent_sign"); - } - - if(active_render) { - attr_sign = attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign); - } - else { - attr_sign = attributes.add(name_sign, - TypeDesc::TypeFloat, - ATTR_ELEMENT_CORNER); - } - tangent_sign = attr_sign->data_float(); - } - /* Setup userdata. */ - MikkUserData userdata(b_mesh, layer_name, mesh, tangent, tangent_sign); - /* Setup interface. */ - SMikkTSpaceInterface sm_interface; - memset(&sm_interface, 0, sizeof(sm_interface)); - sm_interface.m_getNumFaces = mikk_get_num_faces; - sm_interface.m_getNumVerticesOfFace = mikk_get_num_verts_of_face; - sm_interface.m_getPosition = mikk_get_position; - sm_interface.m_getTexCoord = mikk_get_texture_coordinate; - sm_interface.m_getNormal = mikk_get_normal; - sm_interface.m_setTSpaceBasic = mikk_set_tangent_space; - /* Setup context. */ - SMikkTSpaceContext context; - memset(&context, 0, sizeof(context)); - context.m_pUserData = &userdata; - context.m_pInterface = &sm_interface; - /* Compute tangents. */ - genTangSpaceDefault(&context); + /* Create tangent attributes. */ + AttributeSet &attributes = (mesh->subd_faces.size()) ? mesh->subd_attributes : mesh->attributes; + Attribute *attr; + ustring name; + if (layer_name != NULL) { + name = ustring((string(layer_name) + ".tangent").c_str()); + } + else { + name = ustring("orco.tangent"); + } + if (active_render) { + attr = attributes.add(ATTR_STD_UV_TANGENT, name); + } + else { + attr = attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER); + } + float3 *tangent = attr->data_float3(); + /* Create bitangent sign attribute. */ + float *tangent_sign = NULL; + if (need_sign) { + Attribute *attr_sign; + ustring name_sign; + if (layer_name != NULL) { + name_sign = ustring((string(layer_name) + ".tangent_sign").c_str()); + } + else { + name_sign = ustring("orco.tangent_sign"); + } + + if (active_render) { + attr_sign = attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign); + } + else { + attr_sign = attributes.add(name_sign, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER); + } + tangent_sign = attr_sign->data_float(); + } + /* Setup userdata. */ + MikkUserData userdata(b_mesh, layer_name, mesh, tangent, tangent_sign); + /* Setup interface. */ + SMikkTSpaceInterface sm_interface; + memset(&sm_interface, 0, sizeof(sm_interface)); + sm_interface.m_getNumFaces = mikk_get_num_faces; + sm_interface.m_getNumVerticesOfFace = mikk_get_num_verts_of_face; + sm_interface.m_getPosition = mikk_get_position; + sm_interface.m_getTexCoord = mikk_get_texture_coordinate; + sm_interface.m_getNormal = mikk_get_normal; + sm_interface.m_setTSpaceBasic = mikk_set_tangent_space; + /* Setup context. */ + SMikkTSpaceContext context; + memset(&context, 0, sizeof(context)); + context.m_pUserData = &userdata; + context.m_pInterface = &sm_interface; + /* Compute tangents. */ + genTangSpaceDefault(&context); } /* Create Volume Attribute */ -static void create_mesh_volume_attribute(BL::Object& b_ob, - Mesh *mesh, - ImageManager *image_manager, - AttributeStandard std, - float frame) +static void create_mesh_volume_attribute( + BL::Object &b_ob, Mesh *mesh, ImageManager *image_manager, AttributeStandard std, float frame) { - BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob); - - if(!b_domain) - return; - - mesh->volume_isovalue = b_domain.clipping(); - - Attribute *attr = mesh->attributes.add(std); - VoxelAttribute *volume_data = attr->data_voxel(); - ImageMetaData metadata; - bool animated = false; - bool use_alpha = true; - - volume_data->manager = image_manager; - volume_data->slot = image_manager->add_image( - Attribute::standard_name(std), - b_ob.ptr.data, - animated, - frame, - INTERPOLATION_LINEAR, - EXTENSION_CLIP, - use_alpha, - metadata); + BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob); + + if (!b_domain) + return; + + mesh->volume_isovalue = b_domain.clipping(); + + Attribute *attr = mesh->attributes.add(std); + VoxelAttribute *volume_data = attr->data_voxel(); + ImageMetaData metadata; + bool animated = false; + bool use_alpha = true; + + volume_data->manager = image_manager; + volume_data->slot = image_manager->add_image(Attribute::standard_name(std), + b_ob.ptr.data, + animated, + frame, + INTERPOLATION_LINEAR, + EXTENSION_CLIP, + use_alpha, + metadata); } -static void create_mesh_volume_attributes(Scene *scene, - BL::Object& b_ob, - Mesh *mesh, - float frame) +static void create_mesh_volume_attributes(Scene *scene, BL::Object &b_ob, Mesh *mesh, float frame) { - /* for smoke volume rendering */ - if(mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY)) - create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_DENSITY, frame); - if(mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR)) - create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_COLOR, frame); - if(mesh->need_attribute(scene, ATTR_STD_VOLUME_FLAME)) - create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_FLAME, frame); - if(mesh->need_attribute(scene, ATTR_STD_VOLUME_HEAT)) - create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_HEAT, frame); - if(mesh->need_attribute(scene, ATTR_STD_VOLUME_TEMPERATURE)) - create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_TEMPERATURE, frame); - if(mesh->need_attribute(scene, ATTR_STD_VOLUME_VELOCITY)) - create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_VELOCITY, frame); + /* for smoke volume rendering */ + if (mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY)) + create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_DENSITY, frame); + if (mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR)) + create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_COLOR, frame); + if (mesh->need_attribute(scene, ATTR_STD_VOLUME_FLAME)) + create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_FLAME, frame); + if (mesh->need_attribute(scene, ATTR_STD_VOLUME_HEAT)) + create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_HEAT, frame); + if (mesh->need_attribute(scene, ATTR_STD_VOLUME_TEMPERATURE)) + create_mesh_volume_attribute( + b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_TEMPERATURE, frame); + if (mesh->need_attribute(scene, ATTR_STD_VOLUME_VELOCITY)) + create_mesh_volume_attribute( + b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_VELOCITY, frame); } /* Create vertex color attributes. */ -static void attr_create_vertex_color(Scene *scene, - Mesh *mesh, - BL::Mesh& b_mesh, - bool subdivision) +static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision) { - if(subdivision) { - BL::Mesh::vertex_colors_iterator l; - - for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { - if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) - continue; - - Attribute *attr = mesh->subd_attributes.add(ustring(l->name().c_str()), - TypeDesc::TypeColor, - ATTR_ELEMENT_CORNER_BYTE); - - BL::Mesh::polygons_iterator p; - uchar4 *cdata = attr->data_uchar4(); - - for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { - int n = p->loop_total(); - for(int i = 0; i < n; i++) { - float3 color = get_float3(l->data[p->loop_start() + i].color()); - /* Compress/encode vertex color using the sRGB curve. */ - *(cdata++) = color_float_to_byte(color_srgb_to_linear_v3(color)); - } - } - } - } - else { - BL::Mesh::vertex_colors_iterator l; - for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { - if(!mesh->need_attribute(scene, ustring(l->name().c_str()))) - continue; - - Attribute *attr = mesh->attributes.add(ustring(l->name().c_str()), - TypeDesc::TypeColor, - ATTR_ELEMENT_CORNER_BYTE); - - BL::Mesh::loop_triangles_iterator t; - uchar4 *cdata = attr->data_uchar4(); - - for(b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) { - int3 li = get_int3(t->loops()); - float3 c1 = get_float3(l->data[li[0]].color()); - float3 c2 = get_float3(l->data[li[1]].color()); - float3 c3 = get_float3(l->data[li[2]].color()); - - /* Compress/encode vertex color using the sRGB curve. */ - cdata[0] = color_float_to_byte(color_srgb_to_linear_v3(c1)); - cdata[1] = color_float_to_byte(color_srgb_to_linear_v3(c2)); - cdata[2] = color_float_to_byte(color_srgb_to_linear_v3(c3)); - cdata += 3; - } - } - } + if (subdivision) { + BL::Mesh::vertex_colors_iterator l; + + for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { + if (!mesh->need_attribute(scene, ustring(l->name().c_str()))) + continue; + + Attribute *attr = mesh->subd_attributes.add( + ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); + + BL::Mesh::polygons_iterator p; + uchar4 *cdata = attr->data_uchar4(); + + for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + int n = p->loop_total(); + for (int i = 0; i < n; i++) { + float3 color = get_float3(l->data[p->loop_start() + i].color()); + /* Compress/encode vertex color using the sRGB curve. */ + *(cdata++) = color_float_to_byte(color_srgb_to_linear_v3(color)); + } + } + } + } + else { + BL::Mesh::vertex_colors_iterator l; + for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) { + if (!mesh->need_attribute(scene, ustring(l->name().c_str()))) + continue; + + Attribute *attr = mesh->attributes.add( + ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); + + BL::Mesh::loop_triangles_iterator t; + uchar4 *cdata = attr->data_uchar4(); + + for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) { + int3 li = get_int3(t->loops()); + float3 c1 = get_float3(l->data[li[0]].color()); + float3 c2 = get_float3(l->data[li[1]].color()); + float3 c3 = get_float3(l->data[li[2]].color()); + + /* Compress/encode vertex color using the sRGB curve. */ + cdata[0] = color_float_to_byte(color_srgb_to_linear_v3(c1)); + cdata[1] = color_float_to_byte(color_srgb_to_linear_v3(c2)); + cdata[2] = color_float_to_byte(color_srgb_to_linear_v3(c3)); + cdata += 3; + } + } + } } /* Create uv map attributes. */ -static void attr_create_uv_map(Scene *scene, - Mesh *mesh, - BL::Mesh& b_mesh) +static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh) { - if(b_mesh.uv_layers.length() != 0) { - BL::Mesh::uv_layers_iterator l; - - for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l) { - const bool active_render = l->active_render(); - AttributeStandard uv_std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; - ustring uv_name = ustring(l->name().c_str()); - AttributeStandard tangent_std = (active_render)? ATTR_STD_UV_TANGENT - : ATTR_STD_NONE; - ustring tangent_name = ustring( - (string(l->name().c_str()) + ".tangent").c_str()); - - /* Denotes whether UV map was requested directly. */ - const bool need_uv = mesh->need_attribute(scene, uv_name) || - mesh->need_attribute(scene, uv_std); - /* Denotes whether tangent was requested directly. */ - const bool need_tangent = - mesh->need_attribute(scene, tangent_name) || - (active_render && mesh->need_attribute(scene, tangent_std)); - - /* UV map */ - /* NOTE: We create temporary UV layer if its needed for tangent but - * wasn't requested by other nodes in shaders. - */ - Attribute *uv_attr = NULL; - if(need_uv || need_tangent) { - if(active_render) { - uv_attr = mesh->attributes.add(uv_std, uv_name); - } - else { - uv_attr = mesh->attributes.add(uv_name, - TypeFloat2, - ATTR_ELEMENT_CORNER); - } - - BL::Mesh::loop_triangles_iterator t; - float2 *fdata = uv_attr->data_float2(); - - for(b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) { - int3 li = get_int3(t->loops()); - fdata[0] = get_float2(l->data[li[0]].uv()); - fdata[1] = get_float2(l->data[li[1]].uv()); - fdata[2] = get_float2(l->data[li[2]].uv()); - fdata += 3; - } - } - - /* UV tangent */ - if(need_tangent) { - AttributeStandard sign_std = - (active_render)? ATTR_STD_UV_TANGENT_SIGN - : ATTR_STD_NONE; - ustring sign_name = ustring( - (string(l->name().c_str()) + ".tangent_sign").c_str()); - bool need_sign = (mesh->need_attribute(scene, sign_name) || - mesh->need_attribute(scene, sign_std)); - mikk_compute_tangents(b_mesh, - l->name().c_str(), - mesh, - need_sign, - active_render); - } - /* Remove temporarily created UV attribute. */ - if(!need_uv && uv_attr != NULL) { - mesh->attributes.remove(uv_attr); - } - } - } - else if(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) { - bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN); - mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true); - if(!mesh->need_attribute(scene, ATTR_STD_GENERATED)) { - mesh->attributes.remove(ATTR_STD_GENERATED); - } - } + if (b_mesh.uv_layers.length() != 0) { + BL::Mesh::uv_layers_iterator l; + + for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l) { + const bool active_render = l->active_render(); + AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE; + ustring uv_name = ustring(l->name().c_str()); + AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE; + ustring tangent_name = ustring((string(l->name().c_str()) + ".tangent").c_str()); + + /* Denotes whether UV map was requested directly. */ + const bool need_uv = mesh->need_attribute(scene, uv_name) || + mesh->need_attribute(scene, uv_std); + /* Denotes whether tangent was requested directly. */ + const bool need_tangent = mesh->need_attribute(scene, tangent_name) || + (active_render && mesh->need_attribute(scene, tangent_std)); + + /* UV map */ + /* NOTE: We create temporary UV layer if its needed for tangent but + * wasn't requested by other nodes in shaders. + */ + Attribute *uv_attr = NULL; + if (need_uv || need_tangent) { + if (active_render) { + uv_attr = mesh->attributes.add(uv_std, uv_name); + } + else { + uv_attr = mesh->attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER); + } + + BL::Mesh::loop_triangles_iterator t; + float2 *fdata = uv_attr->data_float2(); + + for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) { + int3 li = get_int3(t->loops()); + fdata[0] = get_float2(l->data[li[0]].uv()); + fdata[1] = get_float2(l->data[li[1]].uv()); + fdata[2] = get_float2(l->data[li[2]].uv()); + fdata += 3; + } + } + + /* UV tangent */ + if (need_tangent) { + AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE; + ustring sign_name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str()); + bool need_sign = (mesh->need_attribute(scene, sign_name) || + mesh->need_attribute(scene, sign_std)); + mikk_compute_tangents(b_mesh, l->name().c_str(), mesh, need_sign, active_render); + } + /* Remove temporarily created UV attribute. */ + if (!need_uv && uv_attr != NULL) { + mesh->attributes.remove(uv_attr); + } + } + } + else if (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) { + bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN); + mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true); + if (!mesh->need_attribute(scene, ATTR_STD_GENERATED)) { + mesh->attributes.remove(ATTR_STD_GENERATED); + } + } } -static void attr_create_subd_uv_map(Scene *scene, - Mesh *mesh, - BL::Mesh& b_mesh, - bool subdivide_uvs) +static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivide_uvs) { - if(b_mesh.uv_layers.length() != 0) { - BL::Mesh::uv_layers_iterator l; - int i = 0; - - for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) { - bool active_render = l->active_render(); - AttributeStandard uv_std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; - ustring uv_name = ustring(l->name().c_str()); - AttributeStandard tangent_std = (active_render)? ATTR_STD_UV_TANGENT - : ATTR_STD_NONE; - ustring tangent_name = ustring( - (string(l->name().c_str()) + ".tangent").c_str()); - - /* Denotes whether UV map was requested directly. */ - const bool need_uv = mesh->need_attribute(scene, uv_name) || - mesh->need_attribute(scene, uv_std); - /* Denotes whether tangent was requested directly. */ - const bool need_tangent = - mesh->need_attribute(scene, tangent_name) || - (active_render && mesh->need_attribute(scene, tangent_std)); - - Attribute *uv_attr = NULL; - - /* UV map */ - if(need_uv || need_tangent) { - if(active_render) - uv_attr = mesh->subd_attributes.add(uv_std, uv_name); - else - uv_attr = mesh->subd_attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER); - - if(subdivide_uvs) { - uv_attr->flags |= ATTR_SUBDIVIDED; - } - - BL::Mesh::polygons_iterator p; - float2 *fdata = uv_attr->data_float2(); - - for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { - int n = p->loop_total(); - for(int j = 0; j < n; j++) { - *(fdata++) = get_float2(l->data[p->loop_start() + j].uv()); - } - } - } - - /* UV tangent */ - if(need_tangent) { - AttributeStandard sign_std = - (active_render)? ATTR_STD_UV_TANGENT_SIGN - : ATTR_STD_NONE; - ustring sign_name = ustring( - (string(l->name().c_str()) + ".tangent_sign").c_str()); - bool need_sign = (mesh->need_attribute(scene, sign_name) || - mesh->need_attribute(scene, sign_std)); - mikk_compute_tangents(b_mesh, - l->name().c_str(), - mesh, - need_sign, - active_render); - } - /* Remove temporarily created UV attribute. */ - if(!need_uv && uv_attr != NULL) { - mesh->subd_attributes.remove(uv_attr); - } - } - } - else if(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) { - bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN); - mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true); - if(!mesh->need_attribute(scene, ATTR_STD_GENERATED)) { - mesh->subd_attributes.remove(ATTR_STD_GENERATED); - } - } + if (b_mesh.uv_layers.length() != 0) { + BL::Mesh::uv_layers_iterator l; + int i = 0; + + for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) { + bool active_render = l->active_render(); + AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE; + ustring uv_name = ustring(l->name().c_str()); + AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE; + ustring tangent_name = ustring((string(l->name().c_str()) + ".tangent").c_str()); + + /* Denotes whether UV map was requested directly. */ + const bool need_uv = mesh->need_attribute(scene, uv_name) || + mesh->need_attribute(scene, uv_std); + /* Denotes whether tangent was requested directly. */ + const bool need_tangent = mesh->need_attribute(scene, tangent_name) || + (active_render && mesh->need_attribute(scene, tangent_std)); + + Attribute *uv_attr = NULL; + + /* UV map */ + if (need_uv || need_tangent) { + if (active_render) + uv_attr = mesh->subd_attributes.add(uv_std, uv_name); + else + uv_attr = mesh->subd_attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER); + + if (subdivide_uvs) { + uv_attr->flags |= ATTR_SUBDIVIDED; + } + + BL::Mesh::polygons_iterator p; + float2 *fdata = uv_attr->data_float2(); + + for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + int n = p->loop_total(); + for (int j = 0; j < n; j++) { + *(fdata++) = get_float2(l->data[p->loop_start() + j].uv()); + } + } + } + + /* UV tangent */ + if (need_tangent) { + AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE; + ustring sign_name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str()); + bool need_sign = (mesh->need_attribute(scene, sign_name) || + mesh->need_attribute(scene, sign_std)); + mikk_compute_tangents(b_mesh, l->name().c_str(), mesh, need_sign, active_render); + } + /* Remove temporarily created UV attribute. */ + if (!need_uv && uv_attr != NULL) { + mesh->subd_attributes.remove(uv_attr); + } + } + } + else if (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) { + bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN); + mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true); + if (!mesh->need_attribute(scene, ATTR_STD_GENERATED)) { + mesh->subd_attributes.remove(ATTR_STD_GENERATED); + } + } } /* Create vertex pointiness attributes. */ /* Compare vertices by sum of their coordinates. */ class VertexAverageComparator { -public: - VertexAverageComparator(const array<float3>& verts) - : verts_(verts) { - } - - bool operator()(const int& vert_idx_a, const int& vert_idx_b) - { - const float3 &vert_a = verts_[vert_idx_a]; - const float3 &vert_b = verts_[vert_idx_b]; - if(vert_a == vert_b) { - /* Special case for doubles, so we ensure ordering. */ - return vert_idx_a > vert_idx_b; - } - const float x1 = vert_a.x + vert_a.y + vert_a.z; - const float x2 = vert_b.x + vert_b.y + vert_b.z; - return x1 < x2; - } - -protected: - const array<float3>& verts_; + public: + VertexAverageComparator(const array<float3> &verts) : verts_(verts) + { + } + + bool operator()(const int &vert_idx_a, const int &vert_idx_b) + { + const float3 &vert_a = verts_[vert_idx_a]; + const float3 &vert_b = verts_[vert_idx_b]; + if (vert_a == vert_b) { + /* Special case for doubles, so we ensure ordering. */ + return vert_idx_a > vert_idx_b; + } + const float x1 = vert_a.x + vert_a.y + vert_a.z; + const float x2 = vert_b.x + vert_b.y + vert_b.z; + return x1 < x2; + } + + protected: + const array<float3> &verts_; }; -static void attr_create_pointiness(Scene *scene, - Mesh *mesh, - BL::Mesh& b_mesh, - bool subdivision) +static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision) { - if(!mesh->need_attribute(scene, ATTR_STD_POINTINESS)) { - return; - } - const int num_verts = b_mesh.vertices.length(); - if(num_verts == 0) { - return; - } - /* STEP 1: Find out duplicated vertices and point duplicates to a single - * original vertex. - */ - vector<int> sorted_vert_indeices(num_verts); - for(int vert_index = 0; vert_index < num_verts; ++vert_index) { - sorted_vert_indeices[vert_index] = vert_index; - } - VertexAverageComparator compare(mesh->verts); - sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare); - /* This array stores index of the original vertex for the given vertex - * index. - */ - vector<int> vert_orig_index(num_verts); - for(int sorted_vert_index = 0; - sorted_vert_index < num_verts; - ++sorted_vert_index) - { - const int vert_index = sorted_vert_indeices[sorted_vert_index]; - const float3 &vert_co = mesh->verts[vert_index]; - bool found = false; - for(int other_sorted_vert_index = sorted_vert_index + 1; - other_sorted_vert_index < num_verts; - ++other_sorted_vert_index) - { - const int other_vert_index = - sorted_vert_indeices[other_sorted_vert_index]; - const float3 &other_vert_co = mesh->verts[other_vert_index]; - /* We are too far away now, we wouldn't have duplicate. */ - if((other_vert_co.x + other_vert_co.y + other_vert_co.z) - - (vert_co.x + vert_co.y + vert_co.z) > 3 * FLT_EPSILON) - { - break; - } - /* Found duplicate. */ - if(len_squared(other_vert_co - vert_co) < FLT_EPSILON) { - found = true; - vert_orig_index[vert_index] = other_vert_index; - break; - } - } - if(!found) { - vert_orig_index[vert_index] = vert_index; - } - } - /* Make sure we always points to the very first orig vertex. */ - for(int vert_index = 0; vert_index < num_verts; ++vert_index) { - int orig_index = vert_orig_index[vert_index]; - while(orig_index != vert_orig_index[orig_index]) { - orig_index = vert_orig_index[orig_index]; - } - vert_orig_index[vert_index] = orig_index; - } - sorted_vert_indeices.free_memory(); - /* STEP 2: Calculate vertex normals taking into account their possible - * duplicates which gets "welded" together. - */ - vector<float3> vert_normal(num_verts, make_float3(0.0f, 0.0f, 0.0f)); - /* First we accumulate all vertex normals in the original index. */ - for(int vert_index = 0; vert_index < num_verts; ++vert_index) { - const float3 normal = get_float3(b_mesh.vertices[vert_index].normal()); - const int orig_index = vert_orig_index[vert_index]; - vert_normal[orig_index] += normal; - } - /* Then we normalize the accumulated result and flush it to all duplicates - * as well. - */ - for(int vert_index = 0; vert_index < num_verts; ++vert_index) { - const int orig_index = vert_orig_index[vert_index]; - vert_normal[vert_index] = normalize(vert_normal[orig_index]); - } - /* STEP 3: Calculate pointiness using single ring neighborhood. */ - vector<int> counter(num_verts, 0); - vector<float> raw_data(num_verts, 0.0f); - vector<float3> edge_accum(num_verts, make_float3(0.0f, 0.0f, 0.0f)); - BL::Mesh::edges_iterator e; - EdgeMap visited_edges; - int edge_index = 0; - memset(&counter[0], 0, sizeof(int) * counter.size()); - for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) { - const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]], - v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]]; - if(visited_edges.exists(v0, v1)) { - continue; - } - visited_edges.insert(v0, v1); - float3 co0 = get_float3(b_mesh.vertices[v0].co()), - co1 = get_float3(b_mesh.vertices[v1].co()); - float3 edge = normalize(co1 - co0); - edge_accum[v0] += edge; - edge_accum[v1] += -edge; - ++counter[v0]; - ++counter[v1]; - } - for(int vert_index = 0; vert_index < num_verts; ++vert_index) { - const int orig_index = vert_orig_index[vert_index]; - if(orig_index != vert_index) { - /* Skip duplicates, they'll be overwritten later on. */ - continue; - } - if(counter[vert_index] > 0) { - const float3 normal = vert_normal[vert_index]; - const float angle = - safe_acosf(dot(normal, - edge_accum[vert_index] / counter[vert_index])); - raw_data[vert_index] = angle * M_1_PI_F; - } - else { - raw_data[vert_index] = 0.0f; - } - } - /* STEP 3: Blur vertices to approximate 2 ring neighborhood. */ - AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; - Attribute *attr = attributes.add(ATTR_STD_POINTINESS); - float *data = attr->data_float(); - memcpy(data, &raw_data[0], sizeof(float) * raw_data.size()); - memset(&counter[0], 0, sizeof(int) * counter.size()); - edge_index = 0; - visited_edges.clear(); - for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) { - const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]], - v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]]; - if(visited_edges.exists(v0, v1)) { - continue; - } - visited_edges.insert(v0, v1); - data[v0] += raw_data[v1]; - data[v1] += raw_data[v0]; - ++counter[v0]; - ++counter[v1]; - } - for(int vert_index = 0; vert_index < num_verts; ++vert_index) { - data[vert_index] /= counter[vert_index] + 1; - } - /* STEP 4: Copy attribute to the duplicated vertices. */ - for(int vert_index = 0; vert_index < num_verts; ++vert_index) { - const int orig_index = vert_orig_index[vert_index]; - data[vert_index] = data[orig_index]; - } + if (!mesh->need_attribute(scene, ATTR_STD_POINTINESS)) { + return; + } + const int num_verts = b_mesh.vertices.length(); + if (num_verts == 0) { + return; + } + /* STEP 1: Find out duplicated vertices and point duplicates to a single + * original vertex. + */ + vector<int> sorted_vert_indeices(num_verts); + for (int vert_index = 0; vert_index < num_verts; ++vert_index) { + sorted_vert_indeices[vert_index] = vert_index; + } + VertexAverageComparator compare(mesh->verts); + sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare); + /* This array stores index of the original vertex for the given vertex + * index. + */ + vector<int> vert_orig_index(num_verts); + for (int sorted_vert_index = 0; sorted_vert_index < num_verts; ++sorted_vert_index) { + const int vert_index = sorted_vert_indeices[sorted_vert_index]; + const float3 &vert_co = mesh->verts[vert_index]; + bool found = false; + for (int other_sorted_vert_index = sorted_vert_index + 1; other_sorted_vert_index < num_verts; + ++other_sorted_vert_index) { + const int other_vert_index = sorted_vert_indeices[other_sorted_vert_index]; + const float3 &other_vert_co = mesh->verts[other_vert_index]; + /* We are too far away now, we wouldn't have duplicate. */ + if ((other_vert_co.x + other_vert_co.y + other_vert_co.z) - + (vert_co.x + vert_co.y + vert_co.z) > + 3 * FLT_EPSILON) { + break; + } + /* Found duplicate. */ + if (len_squared(other_vert_co - vert_co) < FLT_EPSILON) { + found = true; + vert_orig_index[vert_index] = other_vert_index; + break; + } + } + if (!found) { + vert_orig_index[vert_index] = vert_index; + } + } + /* Make sure we always points to the very first orig vertex. */ + for (int vert_index = 0; vert_index < num_verts; ++vert_index) { + int orig_index = vert_orig_index[vert_index]; + while (orig_index != vert_orig_index[orig_index]) { + orig_index = vert_orig_index[orig_index]; + } + vert_orig_index[vert_index] = orig_index; + } + sorted_vert_indeices.free_memory(); + /* STEP 2: Calculate vertex normals taking into account their possible + * duplicates which gets "welded" together. + */ + vector<float3> vert_normal(num_verts, make_float3(0.0f, 0.0f, 0.0f)); + /* First we accumulate all vertex normals in the original index. */ + for (int vert_index = 0; vert_index < num_verts; ++vert_index) { + const float3 normal = get_float3(b_mesh.vertices[vert_index].normal()); + const int orig_index = vert_orig_index[vert_index]; + vert_normal[orig_index] += normal; + } + /* Then we normalize the accumulated result and flush it to all duplicates + * as well. + */ + for (int vert_index = 0; vert_index < num_verts; ++vert_index) { + const int orig_index = vert_orig_index[vert_index]; + vert_normal[vert_index] = normalize(vert_normal[orig_index]); + } + /* STEP 3: Calculate pointiness using single ring neighborhood. */ + vector<int> counter(num_verts, 0); + vector<float> raw_data(num_verts, 0.0f); + vector<float3> edge_accum(num_verts, make_float3(0.0f, 0.0f, 0.0f)); + BL::Mesh::edges_iterator e; + EdgeMap visited_edges; + int edge_index = 0; + memset(&counter[0], 0, sizeof(int) * counter.size()); + for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) { + const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]], + v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]]; + if (visited_edges.exists(v0, v1)) { + continue; + } + visited_edges.insert(v0, v1); + float3 co0 = get_float3(b_mesh.vertices[v0].co()), co1 = get_float3(b_mesh.vertices[v1].co()); + float3 edge = normalize(co1 - co0); + edge_accum[v0] += edge; + edge_accum[v1] += -edge; + ++counter[v0]; + ++counter[v1]; + } + for (int vert_index = 0; vert_index < num_verts; ++vert_index) { + const int orig_index = vert_orig_index[vert_index]; + if (orig_index != vert_index) { + /* Skip duplicates, they'll be overwritten later on. */ + continue; + } + if (counter[vert_index] > 0) { + const float3 normal = vert_normal[vert_index]; + const float angle = safe_acosf(dot(normal, edge_accum[vert_index] / counter[vert_index])); + raw_data[vert_index] = angle * M_1_PI_F; + } + else { + raw_data[vert_index] = 0.0f; + } + } + /* STEP 3: Blur vertices to approximate 2 ring neighborhood. */ + AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes; + Attribute *attr = attributes.add(ATTR_STD_POINTINESS); + float *data = attr->data_float(); + memcpy(data, &raw_data[0], sizeof(float) * raw_data.size()); + memset(&counter[0], 0, sizeof(int) * counter.size()); + edge_index = 0; + visited_edges.clear(); + for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) { + const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]], + v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]]; + if (visited_edges.exists(v0, v1)) { + continue; + } + visited_edges.insert(v0, v1); + data[v0] += raw_data[v1]; + data[v1] += raw_data[v0]; + ++counter[v0]; + ++counter[v1]; + } + for (int vert_index = 0; vert_index < num_verts; ++vert_index) { + data[vert_index] /= counter[vert_index] + 1; + } + /* STEP 4: Copy attribute to the duplicated vertices. */ + for (int vert_index = 0; vert_index < num_verts; ++vert_index) { + const int orig_index = vert_orig_index[vert_index]; + data[vert_index] = data[orig_index]; + } } /* Create Mesh */ static void create_mesh(Scene *scene, Mesh *mesh, - BL::Mesh& b_mesh, - const vector<Shader*>& used_shaders, + BL::Mesh &b_mesh, + const vector<Shader *> &used_shaders, bool subdivision = false, bool subdivide_uvs = true) { - /* count vertices and faces */ - int numverts = b_mesh.vertices.length(); - int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length(); - int numtris = 0; - int numcorners = 0; - int numngons = 0; - bool use_loop_normals = b_mesh.use_auto_smooth() && (mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK); - - /* If no faces, create empty mesh. */ - if(numfaces == 0) { - return; - } - - if(!subdivision) { - numtris = numfaces; - } - else { - BL::Mesh::polygons_iterator p; - for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { - numngons += (p->loop_total() == 4)? 0: 1; - numcorners += p->loop_total(); - } - } - - /* allocate memory */ - mesh->reserve_mesh(numverts, numtris); - mesh->reserve_subd_faces(numfaces, numngons, numcorners); - - /* create vertex coordinates and normals */ - BL::Mesh::vertices_iterator v; - for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) - mesh->add_vertex(get_float3(v->co())); - - AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes; - Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL); - float3 *N = attr_N->data_float3(); - - for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N) - *N = get_float3(v->normal()); - N = attr_N->data_float3(); - - /* create generated coordinates from undeformed coordinates */ - const bool need_default_tangent = - (subdivision == false) && - (b_mesh.uv_layers.length() == 0) && - (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)); - if(mesh->need_attribute(scene, ATTR_STD_GENERATED) || - need_default_tangent) - { - Attribute *attr = attributes.add(ATTR_STD_GENERATED); - attr->flags |= ATTR_SUBDIVIDED; - - float3 loc, size; - mesh_texture_space(b_mesh, loc, size); - - float3 *generated = attr->data_float3(); - size_t i = 0; - - for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) { - generated[i++] = get_float3(v->undeformed_co())*size - loc; - } - } - - /* create faces */ - if(!subdivision) { - BL::Mesh::loop_triangles_iterator t; - - for(b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) { - BL::MeshPolygon p = b_mesh.polygons[t->polygon_index()]; - int3 vi = get_int3(t->vertices()); - - int shader = clamp(p.material_index(), 0, used_shaders.size()-1); - bool smooth = p.use_smooth() || use_loop_normals; - - if(use_loop_normals) { - BL::Array<float, 9> loop_normals = t->split_normals(); - for(int i = 0; i < 3; i++) { - N[vi[i]] = make_float3(loop_normals[i * 3], - loop_normals[i * 3 + 1], - loop_normals[i * 3 + 2]); - } - } - - /* Create triangles. - * - * NOTE: Autosmooth is already taken care about. - */ - mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); - } - } - else { - BL::Mesh::polygons_iterator p; - vector<int> vi; - - for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { - int n = p->loop_total(); - int shader = clamp(p->material_index(), 0, used_shaders.size()-1); - bool smooth = p->use_smooth() || use_loop_normals; - - vi.resize(n); - for(int i = 0; i < n; i++) { - /* NOTE: Autosmooth is already taken care about. */ - vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index(); - } - - /* create subd faces */ - mesh->add_subd_face(&vi[0], n, shader, smooth); - } - } - - /* Create all needed attributes. - * The calculate functions will check whether they're needed or not. - */ - attr_create_pointiness(scene, mesh, b_mesh, subdivision); - attr_create_vertex_color(scene, mesh, b_mesh, subdivision); - - if(subdivision) { - attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs); - } - else { - attr_create_uv_map(scene, mesh, b_mesh); - } - - /* for volume objects, create a matrix to transform from object space to - * mesh texture space. this does not work with deformations but that can - * probably only be done well with a volume grid mapping of coordinates */ - if(mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) { - Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM); - Transform *tfm = attr->data_transform(); - - float3 loc, size; - mesh_texture_space(b_mesh, loc, size); - - *tfm = transform_translate(-loc)*transform_scale(size); - } + /* count vertices and faces */ + int numverts = b_mesh.vertices.length(); + int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length(); + int numtris = 0; + int numcorners = 0; + int numngons = 0; + bool use_loop_normals = b_mesh.use_auto_smooth() && + (mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK); + + /* If no faces, create empty mesh. */ + if (numfaces == 0) { + return; + } + + if (!subdivision) { + numtris = numfaces; + } + else { + BL::Mesh::polygons_iterator p; + for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + numngons += (p->loop_total() == 4) ? 0 : 1; + numcorners += p->loop_total(); + } + } + + /* allocate memory */ + mesh->reserve_mesh(numverts, numtris); + mesh->reserve_subd_faces(numfaces, numngons, numcorners); + + /* create vertex coordinates and normals */ + BL::Mesh::vertices_iterator v; + for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) + mesh->add_vertex(get_float3(v->co())); + + AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes; + Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL); + float3 *N = attr_N->data_float3(); + + for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N) + *N = get_float3(v->normal()); + N = attr_N->data_float3(); + + /* create generated coordinates from undeformed coordinates */ + const bool need_default_tangent = (subdivision == false) && (b_mesh.uv_layers.length() == 0) && + (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)); + if (mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) { + Attribute *attr = attributes.add(ATTR_STD_GENERATED); + attr->flags |= ATTR_SUBDIVIDED; + + float3 loc, size; + mesh_texture_space(b_mesh, loc, size); + + float3 *generated = attr->data_float3(); + size_t i = 0; + + for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) { + generated[i++] = get_float3(v->undeformed_co()) * size - loc; + } + } + + /* create faces */ + if (!subdivision) { + BL::Mesh::loop_triangles_iterator t; + + for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) { + BL::MeshPolygon p = b_mesh.polygons[t->polygon_index()]; + int3 vi = get_int3(t->vertices()); + + int shader = clamp(p.material_index(), 0, used_shaders.size() - 1); + bool smooth = p.use_smooth() || use_loop_normals; + + if (use_loop_normals) { + BL::Array<float, 9> loop_normals = t->split_normals(); + for (int i = 0; i < 3; i++) { + N[vi[i]] = make_float3( + loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]); + } + } + + /* Create triangles. + * + * NOTE: Autosmooth is already taken care about. + */ + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); + } + } + else { + BL::Mesh::polygons_iterator p; + vector<int> vi; + + for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) { + int n = p->loop_total(); + int shader = clamp(p->material_index(), 0, used_shaders.size() - 1); + bool smooth = p->use_smooth() || use_loop_normals; + + vi.resize(n); + for (int i = 0; i < n; i++) { + /* NOTE: Autosmooth is already taken care about. */ + vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index(); + } + + /* create subd faces */ + mesh->add_subd_face(&vi[0], n, shader, smooth); + } + } + + /* Create all needed attributes. + * The calculate functions will check whether they're needed or not. + */ + attr_create_pointiness(scene, mesh, b_mesh, subdivision); + attr_create_vertex_color(scene, mesh, b_mesh, subdivision); + + if (subdivision) { + attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs); + } + else { + attr_create_uv_map(scene, mesh, b_mesh); + } + + /* for volume objects, create a matrix to transform from object space to + * mesh texture space. this does not work with deformations but that can + * probably only be done well with a volume grid mapping of coordinates */ + if (mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) { + Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM); + Transform *tfm = attr->data_transform(); + + float3 loc, size; + mesh_texture_space(b_mesh, loc, size); + + *tfm = transform_translate(-loc) * transform_scale(size); + } } static void create_subd_mesh(Scene *scene, Mesh *mesh, - BL::Object& b_ob, - BL::Mesh& b_mesh, - const vector<Shader*>& used_shaders, + BL::Object &b_ob, + BL::Mesh &b_mesh, + const vector<Shader *> &used_shaders, float dicing_rate, int max_subdivisions) { - BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length()-1]); - bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE; + BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]); + bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE; - create_mesh(scene, mesh, b_mesh, used_shaders, true, subdivide_uvs); + create_mesh(scene, mesh, b_mesh, used_shaders, true, subdivide_uvs); - /* export creases */ - size_t num_creases = 0; - BL::Mesh::edges_iterator e; + /* export creases */ + size_t num_creases = 0; + BL::Mesh::edges_iterator e; - for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) { - if(e->crease() != 0.0f) { - num_creases++; - } - } + for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) { + if (e->crease() != 0.0f) { + num_creases++; + } + } - mesh->subd_creases.resize(num_creases); + mesh->subd_creases.resize(num_creases); - Mesh::SubdEdgeCrease* crease = mesh->subd_creases.data(); - for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) { - if(e->crease() != 0.0f) { - crease->v[0] = e->vertices()[0]; - crease->v[1] = e->vertices()[1]; - crease->crease = e->crease(); + Mesh::SubdEdgeCrease *crease = mesh->subd_creases.data(); + for (b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) { + if (e->crease() != 0.0f) { + crease->v[0] = e->vertices()[0]; + crease->v[1] = e->vertices()[1]; + crease->crease = e->crease(); - crease++; - } - } + crease++; + } + } - /* set subd params */ - if(!mesh->subd_params) { - mesh->subd_params = new SubdParams(mesh); - } - SubdParams& sdparams = *mesh->subd_params; + /* set subd params */ + if (!mesh->subd_params) { + mesh->subd_params = new SubdParams(mesh); + } + SubdParams &sdparams = *mesh->subd_params; - PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles"); + PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles"); - sdparams.dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate); - sdparams.max_level = max_subdivisions; + sdparams.dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate); + sdparams.max_level = max_subdivisions; - sdparams.objecttoworld = get_transform(b_ob.matrix_world()); + sdparams.objecttoworld = get_transform(b_ob.matrix_world()); } /* Sync */ -static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh) +static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh) { - if(scene->need_motion() == Scene::MOTION_NONE) - return; + if (scene->need_motion() == Scene::MOTION_NONE) + return; - BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob); + BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob); - if(!b_fluid_domain) - return; + if (!b_fluid_domain) + return; - /* If the mesh has modifiers following the fluid domain we can't export motion. */ - if(b_fluid_domain.fluid_mesh_vertices.length() != mesh->verts.size()) - return; + /* If the mesh has modifiers following the fluid domain we can't export motion. */ + if (b_fluid_domain.fluid_mesh_vertices.length() != mesh->verts.size()) + return; - /* Find or add attribute */ - float3 *P = &mesh->verts[0]; - Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + /* Find or add attribute */ + float3 *P = &mesh->verts[0]; + Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - if(!attr_mP) { - attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); - } + if (!attr_mP) { + attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); + } - /* Only export previous and next frame, we don't have any in between data. */ - float motion_times[2] = {-1.0f, 1.0f}; - for(int step = 0; step < 2; step++) { - float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f; - float3 *mP = attr_mP->data_float3() + step*mesh->verts.size(); + /* Only export previous and next frame, we don't have any in between data. */ + float motion_times[2] = {-1.0f, 1.0f}; + for (int step = 0; step < 2; step++) { + float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f; + float3 *mP = attr_mP->data_float3() + step * mesh->verts.size(); - BL::DomainFluidSettings::fluid_mesh_vertices_iterator fvi; - int i = 0; + BL::DomainFluidSettings::fluid_mesh_vertices_iterator fvi; + int i = 0; - for(b_fluid_domain.fluid_mesh_vertices.begin(fvi); fvi != b_fluid_domain.fluid_mesh_vertices.end(); ++fvi, ++i) { - mP[i] = P[i] + get_float3(fvi->velocity()) * relative_time; - } - } + for (b_fluid_domain.fluid_mesh_vertices.begin(fvi); + fvi != b_fluid_domain.fluid_mesh_vertices.end(); + ++fvi, ++i) { + mP[i] = P[i] + get_float3(fvi->velocity()) * relative_time; + } + } } -Mesh *BlenderSync::sync_mesh(BL::Depsgraph& b_depsgraph, - BL::Object& b_ob, - BL::Object& b_ob_instance, +Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph, + BL::Object &b_ob, + BL::Object &b_ob_instance, bool object_updated, bool show_self, bool show_particles) { - /* test if we can instance or if the object is modified */ - BL::ID b_ob_data = b_ob.data(); - BL::ID key = (BKE_object_is_modified(b_ob))? b_ob_instance: b_ob_data; - BL::Material material_override = view_layer.material_override; - - /* find shader indices */ - vector<Shader*> used_shaders; - - BL::Object::material_slots_iterator slot; - for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) { - if(material_override) { - find_shader(material_override, used_shaders, scene->default_surface); - } - else { - BL::ID b_material(slot->material()); - find_shader(b_material, used_shaders, scene->default_surface); - } - } - - if(used_shaders.size() == 0) { - if(material_override) - find_shader(material_override, used_shaders, scene->default_surface); - else - used_shaders.push_back(scene->default_surface); - } - - /* test if we need to sync */ - int requested_geometry_flags = Mesh::GEOMETRY_NONE; - if(view_layer.use_surfaces) { - requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES; - } - if(view_layer.use_hair) { - requested_geometry_flags |= Mesh::GEOMETRY_CURVES; - } - Mesh *mesh; - - if(!mesh_map.sync(&mesh, key)) { - /* if transform was applied to mesh, need full update */ - if(object_updated && mesh->transform_applied); - /* test if shaders changed, these can be object level so mesh - * does not get tagged for recalc */ - else if(mesh->used_shaders != used_shaders); - else if(requested_geometry_flags != mesh->geometry_flags); - else { - /* even if not tagged for recalc, we may need to sync anyway - * because the shader needs different mesh attributes */ - bool attribute_recalc = false; - - foreach(Shader *shader, mesh->used_shaders) - if(shader->need_update_mesh) - attribute_recalc = true; - - if(!attribute_recalc) - return mesh; - } - } - - /* ensure we only sync instanced meshes once */ - if(mesh_synced.find(mesh) != mesh_synced.end()) - return mesh; - - progress.set_sync_status("Synchronizing object", b_ob.name()); - - mesh_synced.insert(mesh); - - /* create derived mesh */ - array<int> oldtriangles; - array<Mesh::SubdFace> oldsubd_faces; - array<int> oldsubd_face_corners; - oldtriangles.steal_data(mesh->triangles); - oldsubd_faces.steal_data(mesh->subd_faces); - oldsubd_face_corners.steal_data(mesh->subd_face_corners); - - /* compares curve_keys rather than strands in order to handle quick hair - * adjustments in dynamic BVH - other methods could probably do this better*/ - array<float3> oldcurve_keys; - array<float> oldcurve_radius; - oldcurve_keys.steal_data(mesh->curve_keys); - oldcurve_radius.steal_data(mesh->curve_radius); - - mesh->clear(); - mesh->used_shaders = used_shaders; - mesh->name = ustring(b_ob_data.name().c_str()); - - if(requested_geometry_flags != Mesh::GEOMETRY_NONE) { - /* Adaptive subdivision setup. Not for baking since that requires - * exact mapping to the Blender mesh. */ - if(scene->bake_manager->get_baking()) { - mesh->subdivision_type = Mesh::SUBDIVISION_NONE; - } - else { - mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental); - } - - /* For some reason, meshes do not need this... */ - bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); - - BL::Mesh b_mesh = object_to_mesh(b_data, - b_ob, - b_depsgraph, - need_undeformed, - mesh->subdivision_type); - - if(b_mesh) { - /* Sync mesh itself. */ - if(view_layer.use_surfaces && show_self) { - if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) - create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, - dicing_rate, max_subdivisions); - else - create_mesh(scene, mesh, b_mesh, used_shaders, false); - - create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current()); - } - - /* Sync hair curves. */ - if(view_layer.use_hair && show_particles && mesh->subdivision_type == Mesh::SUBDIVISION_NONE) { - sync_curves(mesh, b_mesh, b_ob, false); - } - - free_object_to_mesh(b_data, b_ob, b_mesh); - } - } - mesh->geometry_flags = requested_geometry_flags; - - /* fluid motion */ - sync_mesh_fluid_motion(b_ob, scene, mesh); - - /* tag update */ - bool rebuild = (oldtriangles != mesh->triangles) || - (oldsubd_faces != mesh->subd_faces) || - (oldsubd_face_corners != mesh->subd_face_corners) || - (oldcurve_keys != mesh->curve_keys) || - (oldcurve_radius != mesh->curve_radius); - - mesh->tag_update(scene, rebuild); - - return mesh; + /* test if we can instance or if the object is modified */ + BL::ID b_ob_data = b_ob.data(); + BL::ID key = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data; + BL::Material material_override = view_layer.material_override; + + /* find shader indices */ + vector<Shader *> used_shaders; + + BL::Object::material_slots_iterator slot; + for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) { + if (material_override) { + find_shader(material_override, used_shaders, scene->default_surface); + } + else { + BL::ID b_material(slot->material()); + find_shader(b_material, used_shaders, scene->default_surface); + } + } + + if (used_shaders.size() == 0) { + if (material_override) + find_shader(material_override, used_shaders, scene->default_surface); + else + used_shaders.push_back(scene->default_surface); + } + + /* test if we need to sync */ + int requested_geometry_flags = Mesh::GEOMETRY_NONE; + if (view_layer.use_surfaces) { + requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES; + } + if (view_layer.use_hair) { + requested_geometry_flags |= Mesh::GEOMETRY_CURVES; + } + Mesh *mesh; + + if (!mesh_map.sync(&mesh, key)) { + /* if transform was applied to mesh, need full update */ + if (object_updated && mesh->transform_applied) + ; + /* test if shaders changed, these can be object level so mesh + * does not get tagged for recalc */ + else if (mesh->used_shaders != used_shaders) + ; + else if (requested_geometry_flags != mesh->geometry_flags) + ; + else { + /* even if not tagged for recalc, we may need to sync anyway + * because the shader needs different mesh attributes */ + bool attribute_recalc = false; + + foreach (Shader *shader, mesh->used_shaders) + if (shader->need_update_mesh) + attribute_recalc = true; + + if (!attribute_recalc) + return mesh; + } + } + + /* ensure we only sync instanced meshes once */ + if (mesh_synced.find(mesh) != mesh_synced.end()) + return mesh; + + progress.set_sync_status("Synchronizing object", b_ob.name()); + + mesh_synced.insert(mesh); + + /* create derived mesh */ + array<int> oldtriangles; + array<Mesh::SubdFace> oldsubd_faces; + array<int> oldsubd_face_corners; + oldtriangles.steal_data(mesh->triangles); + oldsubd_faces.steal_data(mesh->subd_faces); + oldsubd_face_corners.steal_data(mesh->subd_face_corners); + + /* compares curve_keys rather than strands in order to handle quick hair + * adjustments in dynamic BVH - other methods could probably do this better*/ + array<float3> oldcurve_keys; + array<float> oldcurve_radius; + oldcurve_keys.steal_data(mesh->curve_keys); + oldcurve_radius.steal_data(mesh->curve_radius); + + mesh->clear(); + mesh->used_shaders = used_shaders; + mesh->name = ustring(b_ob_data.name().c_str()); + + if (requested_geometry_flags != Mesh::GEOMETRY_NONE) { + /* Adaptive subdivision setup. Not for baking since that requires + * exact mapping to the Blender mesh. */ + if (scene->bake_manager->get_baking()) { + mesh->subdivision_type = Mesh::SUBDIVISION_NONE; + } + else { + mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental); + } + + /* For some reason, meshes do not need this... */ + bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); + + BL::Mesh b_mesh = object_to_mesh( + b_data, b_ob, b_depsgraph, need_undeformed, mesh->subdivision_type); + + if (b_mesh) { + /* Sync mesh itself. */ + if (view_layer.use_surfaces && show_self) { + if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) + create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, dicing_rate, max_subdivisions); + else + create_mesh(scene, mesh, b_mesh, used_shaders, false); + + create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current()); + } + + /* Sync hair curves. */ + if (view_layer.use_hair && show_particles && + mesh->subdivision_type == Mesh::SUBDIVISION_NONE) { + sync_curves(mesh, b_mesh, b_ob, false); + } + + free_object_to_mesh(b_data, b_ob, b_mesh); + } + } + mesh->geometry_flags = requested_geometry_flags; + + /* fluid motion */ + sync_mesh_fluid_motion(b_ob, scene, mesh); + + /* tag update */ + bool rebuild = (oldtriangles != mesh->triangles) || (oldsubd_faces != mesh->subd_faces) || + (oldsubd_face_corners != mesh->subd_face_corners) || + (oldcurve_keys != mesh->curve_keys) || (oldcurve_radius != mesh->curve_radius); + + mesh->tag_update(scene, rebuild); + + return mesh; } -void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph, - BL::Object& b_ob, +void BlenderSync::sync_mesh_motion(BL::Depsgraph &b_depsgraph, + BL::Object &b_ob, Object *object, float motion_time) { - /* ensure we only sync instanced meshes once */ - Mesh *mesh = object->mesh; - - if(mesh_motion_synced.find(mesh) != mesh_motion_synced.end()) - return; - - mesh_motion_synced.insert(mesh); - - /* ensure we only motion sync meshes that also had mesh synced, to avoid - * unnecessary work and to ensure that its attributes were clear */ - if(mesh_synced.find(mesh) == mesh_synced.end()) - return; - - /* Find time matching motion step required by mesh. */ - int motion_step = mesh->motion_step(motion_time); - if(motion_step < 0) { - return; - } - - /* skip empty meshes */ - const size_t numverts = mesh->verts.size(); - const size_t numkeys = mesh->curve_keys.size(); - - if(!numverts && !numkeys) - return; - - /* skip objects without deforming modifiers. this is not totally reliable, - * would need a more extensive check to see which objects are animated */ - BL::Mesh b_mesh(PointerRNA_NULL); - - /* fluid motion is exported immediate with mesh, skip here */ - BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob); - if(b_fluid_domain) - return; - - if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { - /* get derived mesh */ - b_mesh = object_to_mesh(b_data, - b_ob, - b_depsgraph, - false, - Mesh::SUBDIVISION_NONE); - } - - if(!b_mesh) { - /* if we have no motion blur on this frame, but on other frames, copy */ - if(numverts) { - /* triangles */ - Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if(attr_mP) { - Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); - Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); - float3 *P = &mesh->verts[0]; - float3 *N = (attr_N)? attr_N->data_float3(): NULL; - - memcpy(attr_mP->data_float3() + motion_step*numverts, P, sizeof(float3)*numverts); - if(attr_mN) - memcpy(attr_mN->data_float3() + motion_step*numverts, N, sizeof(float3)*numverts); - } - } - - if(numkeys) { - /* curves */ - Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if(attr_mP) { - float3 *keys = &mesh->curve_keys[0]; - memcpy(attr_mP->data_float3() + motion_step*numkeys, keys, sizeof(float3)*numkeys); - } - } - - return; - } - - /* TODO(sergey): Perform preliminary check for number of verticies. */ - if(numverts) { - /* Find attributes. */ - Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); - Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); - bool new_attribute = false; - /* Add new attributes if they don't exist already. */ - if(!attr_mP) { - attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); - if(attr_N) - attr_mN = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL); - - new_attribute = true; - } - /* Load vertex data from mesh. */ - float3 *mP = attr_mP->data_float3() + motion_step*numverts; - float3 *mN = (attr_mN)? attr_mN->data_float3() + motion_step*numverts: NULL; - /* NOTE: We don't copy more that existing amount of vertices to prevent - * possible memory corruption. - */ - BL::Mesh::vertices_iterator v; - int i = 0; - for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i) { - mP[i] = get_float3(v->co()); - if(mN) - mN[i] = get_float3(v->normal()); - } - if(new_attribute) { - /* In case of new attribute, we verify if there really was any motion. */ - if(b_mesh.vertices.length() != numverts || - memcmp(mP, &mesh->verts[0], sizeof(float3)*numverts) == 0) - { - /* no motion, remove attributes again */ - if(b_mesh.vertices.length() != numverts) { - VLOG(1) << "Topology differs, disabling motion blur for object " - << b_ob.name(); - } - else { - VLOG(1) << "No actual deformation motion for object " - << b_ob.name(); - } - mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); - if(attr_mN) - mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL); - } - else if(motion_step > 0) { - VLOG(1) << "Filling deformation motion for object " << b_ob.name(); - /* motion, fill up previous steps that we might have skipped because - * they had no motion, but we need them anyway now */ - float3 *P = &mesh->verts[0]; - float3 *N = (attr_N)? attr_N->data_float3(): NULL; - for(int step = 0; step < motion_step; step++) { - memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts); - if(attr_mN) - memcpy(attr_mN->data_float3() + step*numverts, N, sizeof(float3)*numverts); - } - } - } - else { - if(b_mesh.vertices.length() != numverts) { - VLOG(1) << "Topology differs, discarding motion blur for object " - << b_ob.name() << " at time " << motion_step; - memcpy(mP, &mesh->verts[0], sizeof(float3)*numverts); - if(mN != NULL) { - memcpy(mN, attr_N->data_float3(), sizeof(float3)*numverts); - } - } - } - } - - /* hair motion */ - if(numkeys) - sync_curves(mesh, b_mesh, b_ob, true, motion_step); - - /* free derived mesh */ - free_object_to_mesh(b_data, b_ob, b_mesh); + /* ensure we only sync instanced meshes once */ + Mesh *mesh = object->mesh; + + if (mesh_motion_synced.find(mesh) != mesh_motion_synced.end()) + return; + + mesh_motion_synced.insert(mesh); + + /* ensure we only motion sync meshes that also had mesh synced, to avoid + * unnecessary work and to ensure that its attributes were clear */ + if (mesh_synced.find(mesh) == mesh_synced.end()) + return; + + /* Find time matching motion step required by mesh. */ + int motion_step = mesh->motion_step(motion_time); + if (motion_step < 0) { + return; + } + + /* skip empty meshes */ + const size_t numverts = mesh->verts.size(); + const size_t numkeys = mesh->curve_keys.size(); + + if (!numverts && !numkeys) + return; + + /* skip objects without deforming modifiers. this is not totally reliable, + * would need a more extensive check to see which objects are animated */ + BL::Mesh b_mesh(PointerRNA_NULL); + + /* fluid motion is exported immediate with mesh, skip here */ + BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob); + if (b_fluid_domain) + return; + + if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { + /* get derived mesh */ + b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE); + } + + if (!b_mesh) { + /* if we have no motion blur on this frame, but on other frames, copy */ + if (numverts) { + /* triangles */ + Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if (attr_mP) { + Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); + Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); + float3 *P = &mesh->verts[0]; + float3 *N = (attr_N) ? attr_N->data_float3() : NULL; + + memcpy(attr_mP->data_float3() + motion_step * numverts, P, sizeof(float3) * numverts); + if (attr_mN) + memcpy(attr_mN->data_float3() + motion_step * numverts, N, sizeof(float3) * numverts); + } + } + + if (numkeys) { + /* curves */ + Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if (attr_mP) { + float3 *keys = &mesh->curve_keys[0]; + memcpy(attr_mP->data_float3() + motion_step * numkeys, keys, sizeof(float3) * numkeys); + } + } + + return; + } + + /* TODO(sergey): Perform preliminary check for number of verticies. */ + if (numverts) { + /* Find attributes. */ + Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); + Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); + bool new_attribute = false; + /* Add new attributes if they don't exist already. */ + if (!attr_mP) { + attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); + if (attr_N) + attr_mN = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL); + + new_attribute = true; + } + /* Load vertex data from mesh. */ + float3 *mP = attr_mP->data_float3() + motion_step * numverts; + float3 *mN = (attr_mN) ? attr_mN->data_float3() + motion_step * numverts : NULL; + /* NOTE: We don't copy more that existing amount of vertices to prevent + * possible memory corruption. + */ + BL::Mesh::vertices_iterator v; + int i = 0; + for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i) { + mP[i] = get_float3(v->co()); + if (mN) + mN[i] = get_float3(v->normal()); + } + if (new_attribute) { + /* In case of new attribute, we verify if there really was any motion. */ + if (b_mesh.vertices.length() != numverts || + memcmp(mP, &mesh->verts[0], sizeof(float3) * numverts) == 0) { + /* no motion, remove attributes again */ + if (b_mesh.vertices.length() != numverts) { + VLOG(1) << "Topology differs, disabling motion blur for object " << b_ob.name(); + } + else { + VLOG(1) << "No actual deformation motion for object " << b_ob.name(); + } + mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); + if (attr_mN) + mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL); + } + else if (motion_step > 0) { + VLOG(1) << "Filling deformation motion for object " << b_ob.name(); + /* motion, fill up previous steps that we might have skipped because + * they had no motion, but we need them anyway now */ + float3 *P = &mesh->verts[0]; + float3 *N = (attr_N) ? attr_N->data_float3() : NULL; + for (int step = 0; step < motion_step; step++) { + memcpy(attr_mP->data_float3() + step * numverts, P, sizeof(float3) * numverts); + if (attr_mN) + memcpy(attr_mN->data_float3() + step * numverts, N, sizeof(float3) * numverts); + } + } + } + else { + if (b_mesh.vertices.length() != numverts) { + VLOG(1) << "Topology differs, discarding motion blur for object " << b_ob.name() + << " at time " << motion_step; + memcpy(mP, &mesh->verts[0], sizeof(float3) * numverts); + if (mN != NULL) { + memcpy(mN, attr_N->data_float3(), sizeof(float3) * numverts); + } + } + } + } + + /* hair motion */ + if (numkeys) + sync_curves(mesh, b_mesh, b_ob, true, motion_step); + + /* free derived mesh */ + free_object_to_mesh(b_data, b_ob, b_mesh); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index a296488a14a..095ecd59985 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -37,646 +37,631 @@ CCL_NAMESPACE_BEGIN /* Utilities */ -bool BlenderSync::BKE_object_is_modified(BL::Object& b_ob) +bool BlenderSync::BKE_object_is_modified(BL::Object &b_ob) { - /* test if we can instance or if the object is modified */ - if(b_ob.type() == BL::Object::type_META) { - /* multi-user and dupli metaballs are fused, can't instance */ - return true; - } - else if(ccl::BKE_object_is_modified(b_ob, b_scene, preview)) { - /* modifiers */ - return true; - } - else { - /* object level material links */ - BL::Object::material_slots_iterator slot; - for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) - if(slot->link() == BL::MaterialSlot::link_OBJECT) - return true; - } - - return false; + /* test if we can instance or if the object is modified */ + if (b_ob.type() == BL::Object::type_META) { + /* multi-user and dupli metaballs are fused, can't instance */ + return true; + } + else if (ccl::BKE_object_is_modified(b_ob, b_scene, preview)) { + /* modifiers */ + return true; + } + else { + /* object level material links */ + BL::Object::material_slots_iterator slot; + for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) + if (slot->link() == BL::MaterialSlot::link_OBJECT) + return true; + } + + return false; } -bool BlenderSync::object_is_mesh(BL::Object& b_ob) +bool BlenderSync::object_is_mesh(BL::Object &b_ob) { - BL::ID b_ob_data = b_ob.data(); - - if(!b_ob_data) { - return false; - } - - if(b_ob.type() == BL::Object::type_CURVE) { - /* Skip exporting curves without faces, overhead can be - * significant if there are many for path animation. */ - BL::Curve b_curve(b_ob.data()); - - return (b_curve.bevel_object() || - b_curve.extrude() != 0.0f || - b_curve.bevel_depth() != 0.0f || - b_curve.dimensions() == BL::Curve::dimensions_2D || - b_ob.modifiers.length()); - } - else { - return (b_ob_data.is_a(&RNA_Mesh) || - b_ob_data.is_a(&RNA_Curve) || - b_ob_data.is_a(&RNA_MetaBall)); - } + BL::ID b_ob_data = b_ob.data(); + + if (!b_ob_data) { + return false; + } + + if (b_ob.type() == BL::Object::type_CURVE) { + /* Skip exporting curves without faces, overhead can be + * significant if there are many for path animation. */ + BL::Curve b_curve(b_ob.data()); + + return (b_curve.bevel_object() || b_curve.extrude() != 0.0f || b_curve.bevel_depth() != 0.0f || + b_curve.dimensions() == BL::Curve::dimensions_2D || b_ob.modifiers.length()); + } + else { + return (b_ob_data.is_a(&RNA_Mesh) || b_ob_data.is_a(&RNA_Curve) || + b_ob_data.is_a(&RNA_MetaBall)); + } } -bool BlenderSync::object_is_light(BL::Object& b_ob) +bool BlenderSync::object_is_light(BL::Object &b_ob) { - BL::ID b_ob_data = b_ob.data(); + BL::ID b_ob_data = b_ob.data(); - return (b_ob_data && b_ob_data.is_a(&RNA_Light)); + return (b_ob_data && b_ob_data.is_a(&RNA_Light)); } -static uint object_ray_visibility(BL::Object& b_ob) +static uint object_ray_visibility(BL::Object &b_ob) { - PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility"); - uint flag = 0; + PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility"); + uint flag = 0; - flag |= get_boolean(cvisibility, "camera")? PATH_RAY_CAMERA: 0; - flag |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0; - flag |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0; - flag |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0; - flag |= get_boolean(cvisibility, "shadow")? PATH_RAY_SHADOW: 0; - flag |= get_boolean(cvisibility, "scatter")? PATH_RAY_VOLUME_SCATTER: 0; + flag |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0; + flag |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0; + flag |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0; + flag |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0; + flag |= get_boolean(cvisibility, "shadow") ? PATH_RAY_SHADOW : 0; + flag |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0; - return flag; + return flag; } /* Light */ -void BlenderSync::sync_light(BL::Object& b_parent, +void BlenderSync::sync_light(BL::Object &b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], - BL::Object& b_ob, - BL::Object& b_ob_instance, + BL::Object &b_ob, + BL::Object &b_ob_instance, int random_id, - Transform& tfm, + Transform &tfm, bool *use_portal) { - /* test if we need to sync */ - Light *light; - ObjectKey key(b_parent, persistent_id, b_ob_instance); - - if(!light_map.sync(&light, b_ob, b_parent, key)) { - if(light->is_portal) - *use_portal = true; - return; - } - - BL::Light b_light(b_ob.data()); - - /* type */ - switch(b_light.type()) { - case BL::Light::type_POINT: { - BL::PointLight b_point_light(b_light); - light->size = b_point_light.shadow_soft_size(); - light->type = LIGHT_POINT; - break; - } - case BL::Light::type_SPOT: { - BL::SpotLight b_spot_light(b_light); - light->size = b_spot_light.shadow_soft_size(); - light->type = LIGHT_SPOT; - light->spot_angle = b_spot_light.spot_size(); - light->spot_smooth = b_spot_light.spot_blend(); - break; - } - /* Hemi were removed from 2.8 */ - // case BL::Light::type_HEMI: { - // light->type = LIGHT_DISTANT; - // light->size = 0.0f; - // break; - // } - case BL::Light::type_SUN: { - BL::SunLight b_sun_light(b_light); - light->size = b_sun_light.shadow_soft_size(); - light->type = LIGHT_DISTANT; - break; - } - case BL::Light::type_AREA: { - BL::AreaLight b_area_light(b_light); - light->size = 1.0f; - light->axisu = transform_get_column(&tfm, 0); - light->axisv = transform_get_column(&tfm, 1); - light->sizeu = b_area_light.size(); - switch(b_area_light.shape()) { - case BL::AreaLight::shape_SQUARE: - light->sizev = light->sizeu; - light->round = false; - break; - case BL::AreaLight::shape_RECTANGLE: - light->sizev = b_area_light.size_y(); - light->round = false; - break; - case BL::AreaLight::shape_DISK: - light->sizev = light->sizeu; - light->round = true; - break; - case BL::AreaLight::shape_ELLIPSE: - light->sizev = b_area_light.size_y(); - light->round = true; - break; - } - light->type = LIGHT_AREA; - break; - } - } - - /* location and (inverted!) direction */ - light->co = transform_get_column(&tfm, 3); - light->dir = -transform_get_column(&tfm, 2); - light->tfm = tfm; - - /* shader */ - vector<Shader*> used_shaders; - find_shader(b_light, used_shaders, scene->default_light); - light->shader = used_shaders[0]; - - /* shadow */ - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles"); - light->cast_shadow = get_boolean(clight, "cast_shadow"); - light->use_mis = get_boolean(clight, "use_multiple_importance_sampling"); - - int samples = get_int(clight, "samples"); - if(get_boolean(cscene, "use_square_samples")) - light->samples = samples * samples; - else - light->samples = samples; - - light->max_bounces = get_int(clight, "max_bounces"); - - if(b_ob != b_ob_instance) { - light->random_id = random_id; - } - else { - light->random_id = hash_int_2d(hash_string(b_ob.name().c_str()), 0); - } - - if(light->type == LIGHT_AREA) - light->is_portal = get_boolean(clight, "is_portal"); - else - light->is_portal = false; - - if(light->is_portal) - *use_portal = true; - - /* visibility */ - uint visibility = object_ray_visibility(b_ob); - light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0; - light->use_glossy = (visibility & PATH_RAY_GLOSSY) != 0; - light->use_transmission = (visibility & PATH_RAY_TRANSMIT) != 0; - light->use_scatter = (visibility & PATH_RAY_VOLUME_SCATTER) != 0; - - /* tag */ - light->tag_update(scene); + /* test if we need to sync */ + Light *light; + ObjectKey key(b_parent, persistent_id, b_ob_instance); + + if (!light_map.sync(&light, b_ob, b_parent, key)) { + if (light->is_portal) + *use_portal = true; + return; + } + + BL::Light b_light(b_ob.data()); + + /* type */ + switch (b_light.type()) { + case BL::Light::type_POINT: { + BL::PointLight b_point_light(b_light); + light->size = b_point_light.shadow_soft_size(); + light->type = LIGHT_POINT; + break; + } + case BL::Light::type_SPOT: { + BL::SpotLight b_spot_light(b_light); + light->size = b_spot_light.shadow_soft_size(); + light->type = LIGHT_SPOT; + light->spot_angle = b_spot_light.spot_size(); + light->spot_smooth = b_spot_light.spot_blend(); + break; + } + /* Hemi were removed from 2.8 */ + // case BL::Light::type_HEMI: { + // light->type = LIGHT_DISTANT; + // light->size = 0.0f; + // break; + // } + case BL::Light::type_SUN: { + BL::SunLight b_sun_light(b_light); + light->size = b_sun_light.shadow_soft_size(); + light->type = LIGHT_DISTANT; + break; + } + case BL::Light::type_AREA: { + BL::AreaLight b_area_light(b_light); + light->size = 1.0f; + light->axisu = transform_get_column(&tfm, 0); + light->axisv = transform_get_column(&tfm, 1); + light->sizeu = b_area_light.size(); + switch (b_area_light.shape()) { + case BL::AreaLight::shape_SQUARE: + light->sizev = light->sizeu; + light->round = false; + break; + case BL::AreaLight::shape_RECTANGLE: + light->sizev = b_area_light.size_y(); + light->round = false; + break; + case BL::AreaLight::shape_DISK: + light->sizev = light->sizeu; + light->round = true; + break; + case BL::AreaLight::shape_ELLIPSE: + light->sizev = b_area_light.size_y(); + light->round = true; + break; + } + light->type = LIGHT_AREA; + break; + } + } + + /* location and (inverted!) direction */ + light->co = transform_get_column(&tfm, 3); + light->dir = -transform_get_column(&tfm, 2); + light->tfm = tfm; + + /* shader */ + vector<Shader *> used_shaders; + find_shader(b_light, used_shaders, scene->default_light); + light->shader = used_shaders[0]; + + /* shadow */ + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles"); + light->cast_shadow = get_boolean(clight, "cast_shadow"); + light->use_mis = get_boolean(clight, "use_multiple_importance_sampling"); + + int samples = get_int(clight, "samples"); + if (get_boolean(cscene, "use_square_samples")) + light->samples = samples * samples; + else + light->samples = samples; + + light->max_bounces = get_int(clight, "max_bounces"); + + if (b_ob != b_ob_instance) { + light->random_id = random_id; + } + else { + light->random_id = hash_int_2d(hash_string(b_ob.name().c_str()), 0); + } + + if (light->type == LIGHT_AREA) + light->is_portal = get_boolean(clight, "is_portal"); + else + light->is_portal = false; + + if (light->is_portal) + *use_portal = true; + + /* visibility */ + uint visibility = object_ray_visibility(b_ob); + light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0; + light->use_glossy = (visibility & PATH_RAY_GLOSSY) != 0; + light->use_transmission = (visibility & PATH_RAY_TRANSMIT) != 0; + light->use_scatter = (visibility & PATH_RAY_VOLUME_SCATTER) != 0; + + /* tag */ + light->tag_update(scene); } void BlenderSync::sync_background_light(bool use_portal) { - BL::World b_world = b_scene.world(); - - if(b_world) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles"); - - enum SamplingMethod { - SAMPLING_NONE = 0, - SAMPLING_AUTOMATIC, - SAMPLING_MANUAL, - SAMPLING_NUM - }; - int sampling_method = get_enum(cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC); - bool sample_as_light = (sampling_method != SAMPLING_NONE); - - if(sample_as_light || use_portal) { - /* test if we need to sync */ - Light *light; - ObjectKey key(b_world, 0, b_world); - - if(light_map.sync(&light, b_world, b_world, key) || - world_recalc || - b_world.ptr.data != world_map) - { - light->type = LIGHT_BACKGROUND; - if(sampling_method == SAMPLING_MANUAL) { - light->map_resolution = get_int(cworld, "sample_map_resolution"); - } - else { - light->map_resolution = 0; - } - light->shader = scene->default_background; - light->use_mis = sample_as_light; - light->max_bounces = get_int(cworld, "max_bounces"); - - int samples = get_int(cworld, "samples"); - if(get_boolean(cscene, "use_square_samples")) - light->samples = samples * samples; - else - light->samples = samples; - - light->tag_update(scene); - light_map.set_recalc(b_world); - } - } - } - - world_map = b_world.ptr.data; - world_recalc = false; + BL::World b_world = b_scene.world(); + + if (b_world) { + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles"); + + enum SamplingMethod { SAMPLING_NONE = 0, SAMPLING_AUTOMATIC, SAMPLING_MANUAL, SAMPLING_NUM }; + int sampling_method = get_enum(cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC); + bool sample_as_light = (sampling_method != SAMPLING_NONE); + + if (sample_as_light || use_portal) { + /* test if we need to sync */ + Light *light; + ObjectKey key(b_world, 0, b_world); + + if (light_map.sync(&light, b_world, b_world, key) || world_recalc || + b_world.ptr.data != world_map) { + light->type = LIGHT_BACKGROUND; + if (sampling_method == SAMPLING_MANUAL) { + light->map_resolution = get_int(cworld, "sample_map_resolution"); + } + else { + light->map_resolution = 0; + } + light->shader = scene->default_background; + light->use_mis = sample_as_light; + light->max_bounces = get_int(cworld, "max_bounces"); + + int samples = get_int(cworld, "samples"); + if (get_boolean(cscene, "use_square_samples")) + light->samples = samples * samples; + else + light->samples = samples; + + light->tag_update(scene); + light_map.set_recalc(b_world); + } + } + } + + world_map = b_world.ptr.data; + world_recalc = false; } /* Object */ -Object *BlenderSync::sync_object(BL::Depsgraph& b_depsgraph, - BL::ViewLayer& b_view_layer, - BL::DepsgraphObjectInstance& b_instance, +Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, + BL::ViewLayer &b_view_layer, + BL::DepsgraphObjectInstance &b_instance, float motion_time, bool show_self, bool show_particles, - BlenderObjectCulling& culling, + BlenderObjectCulling &culling, bool *use_portal) { - const bool is_instance = b_instance.is_instance(); - BL::Object b_ob = b_instance.object(); - BL::Object b_parent = is_instance ? b_instance.parent() - : b_instance.object(); - BL::Object b_ob_instance = is_instance ? b_instance.instance_object() - : b_ob; - const bool motion = motion_time != 0.0f; - /*const*/ Transform tfm = get_transform(b_ob.matrix_world()); - int *persistent_id = NULL; - BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id_array; - if(is_instance) { - persistent_id_array = b_instance.persistent_id(); - persistent_id = persistent_id_array.data; - } - - /* light is handled separately */ - if(!motion && object_is_light(b_ob)) { - /* TODO: don't use lights for excluded layers used as mask layer, - * when dynamic overrides are back. */ + const bool is_instance = b_instance.is_instance(); + BL::Object b_ob = b_instance.object(); + BL::Object b_parent = is_instance ? b_instance.parent() : b_instance.object(); + BL::Object b_ob_instance = is_instance ? b_instance.instance_object() : b_ob; + const bool motion = motion_time != 0.0f; + /*const*/ Transform tfm = get_transform(b_ob.matrix_world()); + int *persistent_id = NULL; + BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id_array; + if (is_instance) { + persistent_id_array = b_instance.persistent_id(); + persistent_id = persistent_id_array.data; + } + + /* light is handled separately */ + if (!motion && object_is_light(b_ob)) { + /* TODO: don't use lights for excluded layers used as mask layer, + * when dynamic overrides are back. */ #if 0 - if(!((layer_flag & view_layer.holdout_layer) && - (layer_flag & view_layer.exclude_layer))) + if(!((layer_flag & view_layer.holdout_layer) && + (layer_flag & view_layer.exclude_layer))) #endif - { - sync_light(b_parent, - persistent_id, - b_ob, - b_ob_instance, - is_instance ? b_instance.random_id() : 0, - tfm, - use_portal); - } - - return NULL; - } - - /* only interested in object that we can create meshes from */ - if(!object_is_mesh(b_ob)) { - return NULL; - } - - /* Perform object culling. */ - if(culling.test(scene, b_ob, tfm)) { - return NULL; - } - - /* Visibility flags for both parent and child. */ - PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); - bool use_holdout = get_boolean(cobject, "is_holdout") || - b_parent.holdout_get(PointerRNA_NULL, b_view_layer); - uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY; - - if(b_parent.ptr.data != b_ob.ptr.data) { - visibility &= object_ray_visibility(b_parent); - } - - /* TODO: make holdout objects on excluded layer invisible for non-camera rays. */ + { + sync_light(b_parent, + persistent_id, + b_ob, + b_ob_instance, + is_instance ? b_instance.random_id() : 0, + tfm, + use_portal); + } + + return NULL; + } + + /* only interested in object that we can create meshes from */ + if (!object_is_mesh(b_ob)) { + return NULL; + } + + /* Perform object culling. */ + if (culling.test(scene, b_ob, tfm)) { + return NULL; + } + + /* Visibility flags for both parent and child. */ + PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + bool use_holdout = get_boolean(cobject, "is_holdout") || + b_parent.holdout_get(PointerRNA_NULL, b_view_layer); + uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY; + + if (b_parent.ptr.data != b_ob.ptr.data) { + visibility &= object_ray_visibility(b_parent); + } + + /* TODO: make holdout objects on excluded layer invisible for non-camera rays. */ #if 0 - if(use_holdout && (layer_flag & view_layer.exclude_layer)) { - visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA); - } + if(use_holdout && (layer_flag & view_layer.exclude_layer)) { + visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA); + } #endif - /* Clear camera visibility for indirect only objects. */ - bool use_indirect_only = b_parent.indirect_only_get(PointerRNA_NULL, b_view_layer); - if(use_indirect_only) { - visibility &= ~PATH_RAY_CAMERA; - } - - /* Don't export completely invisible objects. */ - if(visibility == 0) { - return NULL; - } - - /* key to lookup object */ - ObjectKey key(b_parent, persistent_id, b_ob_instance); - Object *object; - - /* motion vector case */ - if(motion) { - object = object_map.find(key); - - if(object && object->use_motion()) { - /* Set transform at matching motion time step. */ - int time_index = object->motion_step(motion_time); - if(time_index >= 0) { - object->motion[time_index] = tfm; - } - - /* mesh deformation */ - if(object->mesh) - sync_mesh_motion(b_depsgraph, b_ob, object, motion_time); - } - - return object; - } - - /* test if we need to sync */ - bool object_updated = false; - - if(object_map.sync(&object, b_ob, b_parent, key)) - object_updated = true; - - /* mesh sync */ - object->mesh = sync_mesh(b_depsgraph, b_ob, b_ob_instance, object_updated, show_self, show_particles); - - /* special case not tracked by object update flags */ - - /* holdout */ - if(use_holdout != object->use_holdout) { - object->use_holdout = use_holdout; - scene->object_manager->tag_update(scene); - object_updated = true; - } - - if(visibility != object->visibility) { - object->visibility = visibility; - object_updated = true; - } - - bool is_shadow_catcher = get_boolean(cobject, "is_shadow_catcher"); - if(is_shadow_catcher != object->is_shadow_catcher) { - object->is_shadow_catcher = is_shadow_catcher; - object_updated = true; - } - - /* sync the asset name for Cryptomatte */ - BL::Object parent = b_ob.parent(); - ustring parent_name; - if(parent) { - while(parent.parent()) { - parent = parent.parent(); - } - parent_name = parent.name(); - } - else { - parent_name = b_ob.name(); - } - if(object->asset_name != parent_name) { - object->asset_name = parent_name; - object_updated = true; - } - - /* object sync - * transform comparison should not be needed, but duplis don't work perfect - * in the depsgraph and may not signal changes, so this is a workaround */ - if(object_updated || (object->mesh && object->mesh->need_update) || tfm != object->tfm) { - object->name = b_ob.name().c_str(); - object->pass_id = b_ob.pass_index(); - object->tfm = tfm; - object->motion.clear(); - - /* motion blur */ - Scene::MotionType need_motion = scene->need_motion(); - if(need_motion != Scene::MOTION_NONE && object->mesh) { - Mesh *mesh = object->mesh; - mesh->use_motion_blur = false; - mesh->motion_steps = 0; - - uint motion_steps; - - if(need_motion == Scene::MOTION_BLUR) { - motion_steps = object_motion_steps(b_parent, b_ob); - mesh->motion_steps = motion_steps; - if(motion_steps && object_use_deform_motion(b_parent, b_ob)) { - mesh->use_motion_blur = true; - } - } - else { - motion_steps = 3; - mesh->motion_steps = motion_steps; - } - - object->motion.clear(); - object->motion.resize(motion_steps, transform_empty()); - - if(motion_steps) { - object->motion[motion_steps/2] = tfm; - - for(size_t step = 0; step < motion_steps; step++) { - motion_times.insert(object->motion_time(step)); - } - } - } - - /* dupli texture coordinates and random_id */ - if(is_instance) { - object->dupli_generated = 0.5f*get_float3(b_instance.orco()) - make_float3(0.5f, 0.5f, 0.5f); - object->dupli_uv = get_float2(b_instance.uv()); - object->random_id = b_instance.random_id(); - } - else { - object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f); - object->dupli_uv = make_float2(0.0f, 0.0f); - object->random_id = hash_int_2d(hash_string(object->name.c_str()), 0); - } - - object->tag_update(scene); - } - - if(is_instance) { - /* Sync possible particle data. */ - sync_dupli_particle(b_parent, b_instance, object); - } - - return object; + /* Clear camera visibility for indirect only objects. */ + bool use_indirect_only = b_parent.indirect_only_get(PointerRNA_NULL, b_view_layer); + if (use_indirect_only) { + visibility &= ~PATH_RAY_CAMERA; + } + + /* Don't export completely invisible objects. */ + if (visibility == 0) { + return NULL; + } + + /* key to lookup object */ + ObjectKey key(b_parent, persistent_id, b_ob_instance); + Object *object; + + /* motion vector case */ + if (motion) { + object = object_map.find(key); + + if (object && object->use_motion()) { + /* Set transform at matching motion time step. */ + int time_index = object->motion_step(motion_time); + if (time_index >= 0) { + object->motion[time_index] = tfm; + } + + /* mesh deformation */ + if (object->mesh) + sync_mesh_motion(b_depsgraph, b_ob, object, motion_time); + } + + return object; + } + + /* test if we need to sync */ + bool object_updated = false; + + if (object_map.sync(&object, b_ob, b_parent, key)) + object_updated = true; + + /* mesh sync */ + object->mesh = sync_mesh( + b_depsgraph, b_ob, b_ob_instance, object_updated, show_self, show_particles); + + /* special case not tracked by object update flags */ + + /* holdout */ + if (use_holdout != object->use_holdout) { + object->use_holdout = use_holdout; + scene->object_manager->tag_update(scene); + object_updated = true; + } + + if (visibility != object->visibility) { + object->visibility = visibility; + object_updated = true; + } + + bool is_shadow_catcher = get_boolean(cobject, "is_shadow_catcher"); + if (is_shadow_catcher != object->is_shadow_catcher) { + object->is_shadow_catcher = is_shadow_catcher; + object_updated = true; + } + + /* sync the asset name for Cryptomatte */ + BL::Object parent = b_ob.parent(); + ustring parent_name; + if (parent) { + while (parent.parent()) { + parent = parent.parent(); + } + parent_name = parent.name(); + } + else { + parent_name = b_ob.name(); + } + if (object->asset_name != parent_name) { + object->asset_name = parent_name; + object_updated = true; + } + + /* object sync + * transform comparison should not be needed, but duplis don't work perfect + * in the depsgraph and may not signal changes, so this is a workaround */ + if (object_updated || (object->mesh && object->mesh->need_update) || tfm != object->tfm) { + object->name = b_ob.name().c_str(); + object->pass_id = b_ob.pass_index(); + object->tfm = tfm; + object->motion.clear(); + + /* motion blur */ + Scene::MotionType need_motion = scene->need_motion(); + if (need_motion != Scene::MOTION_NONE && object->mesh) { + Mesh *mesh = object->mesh; + mesh->use_motion_blur = false; + mesh->motion_steps = 0; + + uint motion_steps; + + if (need_motion == Scene::MOTION_BLUR) { + motion_steps = object_motion_steps(b_parent, b_ob); + mesh->motion_steps = motion_steps; + if (motion_steps && object_use_deform_motion(b_parent, b_ob)) { + mesh->use_motion_blur = true; + } + } + else { + motion_steps = 3; + mesh->motion_steps = motion_steps; + } + + object->motion.clear(); + object->motion.resize(motion_steps, transform_empty()); + + if (motion_steps) { + object->motion[motion_steps / 2] = tfm; + + for (size_t step = 0; step < motion_steps; step++) { + motion_times.insert(object->motion_time(step)); + } + } + } + + /* dupli texture coordinates and random_id */ + if (is_instance) { + object->dupli_generated = 0.5f * get_float3(b_instance.orco()) - + make_float3(0.5f, 0.5f, 0.5f); + object->dupli_uv = get_float2(b_instance.uv()); + object->random_id = b_instance.random_id(); + } + else { + object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f); + object->dupli_uv = make_float2(0.0f, 0.0f); + object->random_id = hash_int_2d(hash_string(object->name.c_str()), 0); + } + + object->tag_update(scene); + } + + if (is_instance) { + /* Sync possible particle data. */ + sync_dupli_particle(b_parent, b_instance, object); + } + + return object; } /* Object Loop */ -void BlenderSync::sync_objects(BL::Depsgraph& b_depsgraph, float motion_time) +void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time) { - /* layer data */ - bool motion = motion_time != 0.0f; - - if(!motion) { - /* prepare for sync */ - light_map.pre_sync(); - mesh_map.pre_sync(); - object_map.pre_sync(); - particle_system_map.pre_sync(); - motion_times.clear(); - } - else { - mesh_motion_synced.clear(); - } - - /* initialize culling */ - BlenderObjectCulling culling(scene, b_scene); - - /* object loop */ - bool cancel = false; - bool use_portal = false; - - BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); - - BL::Depsgraph::object_instances_iterator b_instance_iter; - for(b_depsgraph.object_instances.begin(b_instance_iter); - b_instance_iter != b_depsgraph.object_instances.end() && !cancel; - ++b_instance_iter) - { - BL::DepsgraphObjectInstance b_instance = *b_instance_iter; - BL::Object b_ob = b_instance.object(); - - /* load per-object culling data */ - culling.init_object(scene, b_ob); - - /* test if object needs to be hidden */ - const bool show_self = b_instance.show_self(); - const bool show_particles = b_instance.show_particles(); - - if(show_self || show_particles) { - /* object itself */ - sync_object(b_depsgraph, - b_view_layer, - b_instance, - motion_time, - show_self, - show_particles, - culling, - &use_portal); - } - - cancel = progress.get_cancel(); - } - - progress.set_sync_status(""); - - if(!cancel && !motion) { - sync_background_light(use_portal); - - /* handle removed data and modified pointers */ - if(light_map.post_sync()) - scene->light_manager->tag_update(scene); - if(mesh_map.post_sync()) - scene->mesh_manager->tag_update(scene); - if(object_map.post_sync()) - scene->object_manager->tag_update(scene); - if(particle_system_map.post_sync()) - scene->particle_system_manager->tag_update(scene); - } - - if(motion) - mesh_motion_synced.clear(); + /* layer data */ + bool motion = motion_time != 0.0f; + + if (!motion) { + /* prepare for sync */ + light_map.pre_sync(); + mesh_map.pre_sync(); + object_map.pre_sync(); + particle_system_map.pre_sync(); + motion_times.clear(); + } + else { + mesh_motion_synced.clear(); + } + + /* initialize culling */ + BlenderObjectCulling culling(scene, b_scene); + + /* object loop */ + bool cancel = false; + bool use_portal = false; + + BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); + + BL::Depsgraph::object_instances_iterator b_instance_iter; + for (b_depsgraph.object_instances.begin(b_instance_iter); + b_instance_iter != b_depsgraph.object_instances.end() && !cancel; + ++b_instance_iter) { + BL::DepsgraphObjectInstance b_instance = *b_instance_iter; + BL::Object b_ob = b_instance.object(); + + /* load per-object culling data */ + culling.init_object(scene, b_ob); + + /* test if object needs to be hidden */ + const bool show_self = b_instance.show_self(); + const bool show_particles = b_instance.show_particles(); + + if (show_self || show_particles) { + /* object itself */ + sync_object(b_depsgraph, + b_view_layer, + b_instance, + motion_time, + show_self, + show_particles, + culling, + &use_portal); + } + + cancel = progress.get_cancel(); + } + + progress.set_sync_status(""); + + if (!cancel && !motion) { + sync_background_light(use_portal); + + /* handle removed data and modified pointers */ + if (light_map.post_sync()) + scene->light_manager->tag_update(scene); + if (mesh_map.post_sync()) + scene->mesh_manager->tag_update(scene); + if (object_map.post_sync()) + scene->object_manager->tag_update(scene); + if (particle_system_map.post_sync()) + scene->particle_system_manager->tag_update(scene); + } + + if (motion) + mesh_motion_synced.clear(); } -void BlenderSync::sync_motion(BL::RenderSettings& b_render, - BL::Depsgraph& b_depsgraph, - BL::Object& b_override, - int width, int height, +void BlenderSync::sync_motion(BL::RenderSettings &b_render, + BL::Depsgraph &b_depsgraph, + BL::Object &b_override, + int width, + int height, void **python_thread_state) { - if(scene->need_motion() == Scene::MOTION_NONE) - return; - - /* get camera object here to deal with camera switch */ - BL::Object b_cam = b_scene.camera(); - if(b_override) - b_cam = b_override; - - Camera prevcam = *(scene->camera); - - int frame_center = b_scene.frame_current(); - float subframe_center = b_scene.frame_subframe(); - float frame_center_delta = 0.0f; - - if(scene->need_motion() != Scene::MOTION_PASS && - scene->camera->motion_position != Camera::MOTION_POSITION_CENTER) - { - float shuttertime = scene->camera->shuttertime; - if(scene->camera->motion_position == Camera::MOTION_POSITION_END) { - frame_center_delta = -shuttertime * 0.5f; - } - else { - assert(scene->camera->motion_position == Camera::MOTION_POSITION_START); - frame_center_delta = shuttertime * 0.5f; - } - - float time = frame_center + subframe_center + frame_center_delta; - int frame = (int)floorf(time); - float subframe = time - frame; - python_thread_state_restore(python_thread_state); - b_engine.frame_set(frame, subframe); - python_thread_state_save(python_thread_state); - sync_camera_motion(b_render, b_cam, width, height, 0.0f); - sync_objects(b_depsgraph, 0.0f); - } - - /* always sample these times for camera motion */ - motion_times.insert(-1.0f); - motion_times.insert(1.0f); - - /* note iteration over motion_times set happens in sorted order */ - foreach(float relative_time, motion_times) { - /* center time is already handled. */ - if(relative_time == 0.0f) { - continue; - } - - VLOG(1) << "Synchronizing motion for the relative time " - << relative_time << "."; - - /* fixed shutter time to get previous and next frame for motion pass */ - float shuttertime = scene->motion_shutter_time(); - - /* compute frame and subframe time */ - float time = frame_center + subframe_center + frame_center_delta + relative_time * shuttertime * 0.5f; - int frame = (int)floorf(time); - float subframe = time - frame; - - /* change frame */ - python_thread_state_restore(python_thread_state); - b_engine.frame_set(frame, subframe); - python_thread_state_save(python_thread_state); - - /* sync camera, only supports two times at the moment */ - if(relative_time == -1.0f || relative_time == 1.0f) { - sync_camera_motion(b_render, - b_cam, - width, height, - relative_time); - } - - /* sync object */ - sync_objects(b_depsgraph, relative_time); - } - - /* we need to set the python thread state again because this - * function assumes it is being executed from python and will - * try to save the thread state */ - python_thread_state_restore(python_thread_state); - b_engine.frame_set(frame_center, subframe_center); - python_thread_state_save(python_thread_state); - - /* tag camera for motion update */ - if(scene->camera->motion_modified(prevcam)) - scene->camera->tag_update(); + if (scene->need_motion() == Scene::MOTION_NONE) + return; + + /* get camera object here to deal with camera switch */ + BL::Object b_cam = b_scene.camera(); + if (b_override) + b_cam = b_override; + + Camera prevcam = *(scene->camera); + + int frame_center = b_scene.frame_current(); + float subframe_center = b_scene.frame_subframe(); + float frame_center_delta = 0.0f; + + if (scene->need_motion() != Scene::MOTION_PASS && + scene->camera->motion_position != Camera::MOTION_POSITION_CENTER) { + float shuttertime = scene->camera->shuttertime; + if (scene->camera->motion_position == Camera::MOTION_POSITION_END) { + frame_center_delta = -shuttertime * 0.5f; + } + else { + assert(scene->camera->motion_position == Camera::MOTION_POSITION_START); + frame_center_delta = shuttertime * 0.5f; + } + + float time = frame_center + subframe_center + frame_center_delta; + int frame = (int)floorf(time); + float subframe = time - frame; + python_thread_state_restore(python_thread_state); + b_engine.frame_set(frame, subframe); + python_thread_state_save(python_thread_state); + sync_camera_motion(b_render, b_cam, width, height, 0.0f); + sync_objects(b_depsgraph, 0.0f); + } + + /* always sample these times for camera motion */ + motion_times.insert(-1.0f); + motion_times.insert(1.0f); + + /* note iteration over motion_times set happens in sorted order */ + foreach (float relative_time, motion_times) { + /* center time is already handled. */ + if (relative_time == 0.0f) { + continue; + } + + VLOG(1) << "Synchronizing motion for the relative time " << relative_time << "."; + + /* fixed shutter time to get previous and next frame for motion pass */ + float shuttertime = scene->motion_shutter_time(); + + /* compute frame and subframe time */ + float time = frame_center + subframe_center + frame_center_delta + + relative_time * shuttertime * 0.5f; + int frame = (int)floorf(time); + float subframe = time - frame; + + /* change frame */ + python_thread_state_restore(python_thread_state); + b_engine.frame_set(frame, subframe); + python_thread_state_save(python_thread_state); + + /* sync camera, only supports two times at the moment */ + if (relative_time == -1.0f || relative_time == 1.0f) { + sync_camera_motion(b_render, b_cam, width, height, relative_time); + } + + /* sync object */ + sync_objects(b_depsgraph, relative_time); + } + + /* we need to set the python thread state again because this + * function assumes it is being executed from python and will + * try to save the thread state */ + python_thread_state_restore(python_thread_state); + b_engine.frame_set(frame_center, subframe_center); + python_thread_state_save(python_thread_state); + + /* tag camera for motion update */ + if (scene->camera->motion_modified(prevcam)) + scene->camera->tag_update(); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_object_cull.cpp b/intern/cycles/blender/blender_object_cull.cpp index 680d9d7b1ff..74f8fb1dc53 100644 --- a/intern/cycles/blender/blender_object_cull.cpp +++ b/intern/cycles/blender/blender_object_cull.cpp @@ -22,72 +22,69 @@ CCL_NAMESPACE_BEGIN -BlenderObjectCulling::BlenderObjectCulling(Scene *scene, BL::Scene& b_scene) - : use_scene_camera_cull_(false), - use_camera_cull_(false), - camera_cull_margin_(0.0f), - use_scene_distance_cull_(false), - use_distance_cull_(false), - distance_cull_margin_(0.0f) +BlenderObjectCulling::BlenderObjectCulling(Scene *scene, BL::Scene &b_scene) + : use_scene_camera_cull_(false), + use_camera_cull_(false), + camera_cull_margin_(0.0f), + use_scene_distance_cull_(false), + use_distance_cull_(false), + distance_cull_margin_(0.0f) { - if(b_scene.render().use_simplify()) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - - use_scene_camera_cull_ = scene->camera->type != CAMERA_PANORAMA && - !b_scene.render().use_multiview() && - get_boolean(cscene, "use_camera_cull"); - use_scene_distance_cull_ = scene->camera->type != CAMERA_PANORAMA && - !b_scene.render().use_multiview() && - get_boolean(cscene, "use_distance_cull"); - - camera_cull_margin_ = get_float(cscene, "camera_cull_margin"); - distance_cull_margin_ = get_float(cscene, "distance_cull_margin"); - - if(distance_cull_margin_ == 0.0f) { - use_scene_distance_cull_ = false; - } - } + if (b_scene.render().use_simplify()) { + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + + use_scene_camera_cull_ = scene->camera->type != CAMERA_PANORAMA && + !b_scene.render().use_multiview() && + get_boolean(cscene, "use_camera_cull"); + use_scene_distance_cull_ = scene->camera->type != CAMERA_PANORAMA && + !b_scene.render().use_multiview() && + get_boolean(cscene, "use_distance_cull"); + + camera_cull_margin_ = get_float(cscene, "camera_cull_margin"); + distance_cull_margin_ = get_float(cscene, "distance_cull_margin"); + + if (distance_cull_margin_ == 0.0f) { + use_scene_distance_cull_ = false; + } + } } -void BlenderObjectCulling::init_object(Scene *scene, BL::Object& b_ob) +void BlenderObjectCulling::init_object(Scene *scene, BL::Object &b_ob) { - if(!use_scene_camera_cull_ && !use_scene_distance_cull_) { - return; - } + if (!use_scene_camera_cull_ && !use_scene_distance_cull_) { + return; + } - PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); - use_camera_cull_ = use_scene_camera_cull_ && get_boolean(cobject, "use_camera_cull"); - use_distance_cull_ = use_scene_distance_cull_ && get_boolean(cobject, "use_distance_cull"); + use_camera_cull_ = use_scene_camera_cull_ && get_boolean(cobject, "use_camera_cull"); + use_distance_cull_ = use_scene_distance_cull_ && get_boolean(cobject, "use_distance_cull"); - if(use_camera_cull_ || use_distance_cull_) { - /* Need to have proper projection matrix. */ - scene->camera->update(scene); - } + if (use_camera_cull_ || use_distance_cull_) { + /* Need to have proper projection matrix. */ + scene->camera->update(scene); + } } -bool BlenderObjectCulling::test(Scene *scene, BL::Object& b_ob, Transform& tfm) +bool BlenderObjectCulling::test(Scene *scene, BL::Object &b_ob, Transform &tfm) { - if(!use_camera_cull_ && !use_distance_cull_) { - return false; - } - - /* Compute world space bounding box corners. */ - float3 bb[8]; - BL::Array<float, 24> boundbox = b_ob.bound_box(); - for(int i = 0; i < 8; ++i) { - float3 p = make_float3(boundbox[3 * i + 0], - boundbox[3 * i + 1], - boundbox[3 * i + 2]); - bb[i] = transform_point(&tfm, p); - } - - bool camera_culled = use_camera_cull_ && test_camera(scene, bb); - bool distance_culled = use_distance_cull_ && test_distance(scene, bb); - - return ((camera_culled && distance_culled) || - (camera_culled && !use_distance_cull_) || - (distance_culled && !use_camera_cull_)); + if (!use_camera_cull_ && !use_distance_cull_) { + return false; + } + + /* Compute world space bounding box corners. */ + float3 bb[8]; + BL::Array<float, 24> boundbox = b_ob.bound_box(); + for (int i = 0; i < 8; ++i) { + float3 p = make_float3(boundbox[3 * i + 0], boundbox[3 * i + 1], boundbox[3 * i + 2]); + bb[i] = transform_point(&tfm, p); + } + + bool camera_culled = use_camera_cull_ && test_camera(scene, bb); + bool distance_culled = use_distance_cull_ && test_distance(scene, bb); + + return ((camera_culled && distance_culled) || (camera_culled && !use_distance_cull_) || + (distance_culled && !use_camera_cull_)); } /* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order @@ -95,54 +92,50 @@ bool BlenderObjectCulling::test(Scene *scene, BL::Object& b_ob, Transform& tfm) */ bool BlenderObjectCulling::test_camera(Scene *scene, float3 bb[8]) { - Camera *cam = scene->camera; - const ProjectionTransform& worldtondc = cam->worldtondc; - float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), - bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); - bool all_behind = true; - for(int i = 0; i < 8; ++i) { - float3 p = bb[i]; - float4 b = make_float4(p.x, p.y, p.z, 1.0f); - float4 c = make_float4(dot(worldtondc.x, b), - dot(worldtondc.y, b), - dot(worldtondc.z, b), - dot(worldtondc.w, b)); - p = float4_to_float3(c / c.w); - if(c.z < 0.0f) { - p.x = 1.0f - p.x; - p.y = 1.0f - p.y; - } - if(c.z >= -camera_cull_margin_) { - all_behind = false; - } - bb_min = min(bb_min, p); - bb_max = max(bb_max, p); - } - if(all_behind) { - return true; - } - return (bb_min.x >= 1.0f + camera_cull_margin_ || - bb_min.y >= 1.0f + camera_cull_margin_ || - bb_max.x <= -camera_cull_margin_ || - bb_max.y <= -camera_cull_margin_); + Camera *cam = scene->camera; + const ProjectionTransform &worldtondc = cam->worldtondc; + float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), + bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + bool all_behind = true; + for (int i = 0; i < 8; ++i) { + float3 p = bb[i]; + float4 b = make_float4(p.x, p.y, p.z, 1.0f); + float4 c = make_float4( + dot(worldtondc.x, b), dot(worldtondc.y, b), dot(worldtondc.z, b), dot(worldtondc.w, b)); + p = float4_to_float3(c / c.w); + if (c.z < 0.0f) { + p.x = 1.0f - p.x; + p.y = 1.0f - p.y; + } + if (c.z >= -camera_cull_margin_) { + all_behind = false; + } + bb_min = min(bb_min, p); + bb_max = max(bb_max, p); + } + if (all_behind) { + return true; + } + return (bb_min.x >= 1.0f + camera_cull_margin_ || bb_min.y >= 1.0f + camera_cull_margin_ || + bb_max.x <= -camera_cull_margin_ || bb_max.y <= -camera_cull_margin_); } bool BlenderObjectCulling::test_distance(Scene *scene, float3 bb[8]) { - float3 camera_position = transform_get_column(&scene->camera->matrix, 3); - float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), - bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); - - /* Find min & max points for x & y & z on bounding box */ - for(int i = 0; i < 8; ++i) { - float3 p = bb[i]; - bb_min = min(bb_min, p); - bb_max = max(bb_max, p); - } - - float3 closest_point = max(min(bb_max,camera_position),bb_min); - return (len_squared(camera_position - closest_point) > - distance_cull_margin_ * distance_cull_margin_); + float3 camera_position = transform_get_column(&scene->camera->matrix, 3); + float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), + bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + /* Find min & max points for x & y & z on bounding box */ + for (int i = 0; i < 8; ++i) { + float3 p = bb[i]; + bb_min = min(bb_min, p); + bb_max = max(bb_max, p); + } + + float3 closest_point = max(min(bb_max, camera_position), bb_min); + return (len_squared(camera_position - closest_point) > + distance_cull_margin_ * distance_cull_margin_); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_object_cull.h b/intern/cycles/blender/blender_object_cull.h index 6e2a22438ec..0879db4f802 100644 --- a/intern/cycles/blender/blender_object_cull.h +++ b/intern/cycles/blender/blender_object_cull.h @@ -24,26 +24,25 @@ CCL_NAMESPACE_BEGIN class Scene; -class BlenderObjectCulling -{ -public: - BlenderObjectCulling(Scene *scene, BL::Scene& b_scene); - - void init_object(Scene *scene, BL::Object& b_ob); - bool test(Scene *scene, BL::Object& b_ob, Transform& tfm); - -private: - bool test_camera(Scene *scene, float3 bb[8]); - bool test_distance(Scene *scene, float3 bb[8]); - - bool use_scene_camera_cull_; - bool use_camera_cull_; - float camera_cull_margin_; - bool use_scene_distance_cull_; - bool use_distance_cull_; - float distance_cull_margin_; +class BlenderObjectCulling { + public: + BlenderObjectCulling(Scene *scene, BL::Scene &b_scene); + + void init_object(Scene *scene, BL::Object &b_ob); + bool test(Scene *scene, BL::Object &b_ob, Transform &tfm); + + private: + bool test_camera(Scene *scene, float3 bb[8]); + bool test_distance(Scene *scene, float3 bb[8]); + + bool use_scene_camera_cull_; + bool use_camera_cull_; + float camera_cull_margin_; + bool use_scene_distance_cull_; + bool use_distance_cull_; + float distance_cull_margin_; }; CCL_NAMESPACE_END -#endif /* __BLENDER_OBJECT_CULL_H__ */ +#endif /* __BLENDER_OBJECT_CULL_H__ */ diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp index a733a499826..d74f132ed60 100644 --- a/intern/cycles/blender/blender_particles.cpp +++ b/intern/cycles/blender/blender_particles.cpp @@ -27,66 +27,66 @@ CCL_NAMESPACE_BEGIN /* Utilities */ -bool BlenderSync::sync_dupli_particle(BL::Object& b_ob, - BL::DepsgraphObjectInstance& b_instance, +bool BlenderSync::sync_dupli_particle(BL::Object &b_ob, + BL::DepsgraphObjectInstance &b_instance, Object *object) { - /* test if this dupli was generated from a particle sytem */ - BL::ParticleSystem b_psys = b_instance.particle_system(); - if(!b_psys) - return false; - - object->hide_on_missing_motion = true; - - /* test if we need particle data */ - if(!object->mesh->need_attribute(scene, ATTR_STD_PARTICLE)) - return false; - - /* don't handle child particles yet */ - BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_instance.persistent_id(); - - if(persistent_id[0] >= b_psys.particles.length()) - return false; - - /* find particle system */ - ParticleSystemKey key(b_ob, persistent_id); - ParticleSystem *psys; - - bool first_use = !particle_system_map.is_used(key); - bool need_update = particle_system_map.sync(&psys, b_ob, b_instance.object(), key); - - /* no update needed? */ - if(!need_update && !object->mesh->need_update && !scene->object_manager->need_update) - return true; - - /* first time used in this sync loop? clear and tag update */ - if(first_use) { - psys->particles.clear(); - psys->tag_update(scene); - } - - /* add particle */ - BL::Particle b_pa = b_psys.particles[persistent_id[0]]; - Particle pa; - - pa.index = persistent_id[0]; - pa.age = b_scene.frame_current() - b_pa.birth_time(); - pa.lifetime = b_pa.lifetime(); - pa.location = get_float3(b_pa.location()); - pa.rotation = get_float4(b_pa.rotation()); - pa.size = b_pa.size(); - pa.velocity = get_float3(b_pa.velocity()); - pa.angular_velocity = get_float3(b_pa.angular_velocity()); - - psys->particles.push_back_slow(pa); - - if(object->particle_index != psys->particles.size() - 1) - scene->object_manager->tag_update(scene); - object->particle_system = psys; - object->particle_index = psys->particles.size() - 1; - - /* return that this object has particle data */ - return true; + /* test if this dupli was generated from a particle sytem */ + BL::ParticleSystem b_psys = b_instance.particle_system(); + if (!b_psys) + return false; + + object->hide_on_missing_motion = true; + + /* test if we need particle data */ + if (!object->mesh->need_attribute(scene, ATTR_STD_PARTICLE)) + return false; + + /* don't handle child particles yet */ + BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_instance.persistent_id(); + + if (persistent_id[0] >= b_psys.particles.length()) + return false; + + /* find particle system */ + ParticleSystemKey key(b_ob, persistent_id); + ParticleSystem *psys; + + bool first_use = !particle_system_map.is_used(key); + bool need_update = particle_system_map.sync(&psys, b_ob, b_instance.object(), key); + + /* no update needed? */ + if (!need_update && !object->mesh->need_update && !scene->object_manager->need_update) + return true; + + /* first time used in this sync loop? clear and tag update */ + if (first_use) { + psys->particles.clear(); + psys->tag_update(scene); + } + + /* add particle */ + BL::Particle b_pa = b_psys.particles[persistent_id[0]]; + Particle pa; + + pa.index = persistent_id[0]; + pa.age = b_scene.frame_current() - b_pa.birth_time(); + pa.lifetime = b_pa.lifetime(); + pa.location = get_float3(b_pa.location()); + pa.rotation = get_float4(b_pa.rotation()); + pa.size = b_pa.size(); + pa.velocity = get_float3(b_pa.velocity()); + pa.angular_velocity = get_float3(b_pa.angular_velocity()); + + psys->particles.push_back_slow(pa); + + if (object->particle_index != psys->particles.size() - 1) + scene->object_manager->tag_update(scene); + object->particle_system = psys; + object->particle_index = psys->particles.size() - 1; + + /* return that this object has particle data */ + return true; } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index ccd783073a3..ffd1c70a4e4 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -35,14 +35,14 @@ #include "util/util_types.h" #ifdef WITH_OSL -#include "render/osl.h" +# include "render/osl.h" -#include <OSL/oslquery.h> -#include <OSL/oslconfig.h> +# include <OSL/oslquery.h> +# include <OSL/oslconfig.h> #endif #ifdef WITH_OPENCL -#include "device/device_intern.h" +# include "device/device_intern.h" #endif CCL_NAMESPACE_BEGIN @@ -54,9 +54,9 @@ bool debug_flags_set = false; void *pylong_as_voidptr_typesafe(PyObject *object) { - if(object == Py_None) - return NULL; - return PyLong_AsVoidPtr(object); + if (object == Py_None) + return NULL; + return PyLong_AsVoidPtr(object); } /* Synchronize debug flags from a given Blender scene. @@ -64,48 +64,48 @@ void *pylong_as_voidptr_typesafe(PyObject *object) */ bool debug_flags_sync_from_scene(BL::Scene b_scene) { - DebugFlagsRef flags = DebugFlags(); - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - /* Backup some settings for comparison. */ - DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type; - /* Synchronize shared flags. */ - flags.viewport_static_bvh = get_enum(cscene, "debug_bvh_type"); - /* Synchronize CPU flags. */ - flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2"); - flags.cpu.avx = get_boolean(cscene, "debug_use_cpu_avx"); - flags.cpu.sse41 = get_boolean(cscene, "debug_use_cpu_sse41"); - flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3"); - flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2"); - flags.cpu.bvh_layout = (BVHLayout)get_enum(cscene, "debug_bvh_layout"); - flags.cpu.split_kernel = get_boolean(cscene, "debug_use_cpu_split_kernel"); - /* Synchronize CUDA flags. */ - flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile"); - flags.cuda.split_kernel = get_boolean(cscene, "debug_use_cuda_split_kernel"); - /* Synchronize OpenCL device type. */ - switch(get_enum(cscene, "debug_opencl_device_type")) { - case 0: - flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE; - break; - case 1: - flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ALL; - break; - case 2: - flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_DEFAULT; - break; - case 3: - flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_CPU; - break; - case 4: - flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_GPU; - break; - case 5: - flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ACCELERATOR; - break; - } - /* Synchronize other OpenCL flags. */ - flags.opencl.debug = get_boolean(cscene, "debug_use_opencl_debug"); - flags.opencl.mem_limit = ((size_t)get_int(cscene, "debug_opencl_mem_limit"))*1024*1024; - return flags.opencl.device_type != opencl_device_type; + DebugFlagsRef flags = DebugFlags(); + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + /* Backup some settings for comparison. */ + DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type; + /* Synchronize shared flags. */ + flags.viewport_static_bvh = get_enum(cscene, "debug_bvh_type"); + /* Synchronize CPU flags. */ + flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2"); + flags.cpu.avx = get_boolean(cscene, "debug_use_cpu_avx"); + flags.cpu.sse41 = get_boolean(cscene, "debug_use_cpu_sse41"); + flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3"); + flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2"); + flags.cpu.bvh_layout = (BVHLayout)get_enum(cscene, "debug_bvh_layout"); + flags.cpu.split_kernel = get_boolean(cscene, "debug_use_cpu_split_kernel"); + /* Synchronize CUDA flags. */ + flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile"); + flags.cuda.split_kernel = get_boolean(cscene, "debug_use_cuda_split_kernel"); + /* Synchronize OpenCL device type. */ + switch (get_enum(cscene, "debug_opencl_device_type")) { + case 0: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE; + break; + case 1: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ALL; + break; + case 2: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_DEFAULT; + break; + case 3: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_CPU; + break; + case 4: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_GPU; + break; + case 5: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ACCELERATOR; + break; + } + /* Synchronize other OpenCL flags. */ + flags.opencl.debug = get_boolean(cscene, "debug_use_opencl_debug"); + flags.opencl.mem_limit = ((size_t)get_int(cscene, "debug_opencl_mem_limit")) * 1024 * 1024; + return flags.opencl.device_type != opencl_device_type; } /* Reset debug flags to default values. @@ -113,928 +113,958 @@ bool debug_flags_sync_from_scene(BL::Scene b_scene) */ bool debug_flags_reset() { - DebugFlagsRef flags = DebugFlags(); - /* Backup some settings for comparison. */ - DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type; - flags.reset(); - return flags.opencl.device_type != opencl_device_type; + DebugFlagsRef flags = DebugFlags(); + /* Backup some settings for comparison. */ + DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type; + flags.reset(); + return flags.opencl.device_type != opencl_device_type; } -} /* namespace */ +} /* namespace */ void python_thread_state_save(void **python_thread_state) { - *python_thread_state = (void*)PyEval_SaveThread(); + *python_thread_state = (void *)PyEval_SaveThread(); } void python_thread_state_restore(void **python_thread_state) { - PyEval_RestoreThread((PyThreadState*)*python_thread_state); - *python_thread_state = NULL; + PyEval_RestoreThread((PyThreadState *)*python_thread_state); + *python_thread_state = NULL; } static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce) { - const char *result = _PyUnicode_AsString(py_str); - if(result) { - /* 99% of the time this is enough but we better support non unicode - * chars since blender doesnt limit this. - */ - return result; - } - else { - PyErr_Clear(); - if(PyBytes_Check(py_str)) { - return PyBytes_AS_STRING(py_str); - } - else if((*coerce = PyUnicode_EncodeFSDefault(py_str))) { - return PyBytes_AS_STRING(*coerce); - } - else { - /* Clear the error, so Cycles can be at leadt used without - * GPU and OSL support, - */ - PyErr_Clear(); - return ""; - } - } + const char *result = _PyUnicode_AsString(py_str); + if (result) { + /* 99% of the time this is enough but we better support non unicode + * chars since blender doesnt limit this. + */ + return result; + } + else { + PyErr_Clear(); + if (PyBytes_Check(py_str)) { + return PyBytes_AS_STRING(py_str); + } + else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) { + return PyBytes_AS_STRING(*coerce); + } + else { + /* Clear the error, so Cycles can be at leadt used without + * GPU and OSL support, + */ + PyErr_Clear(); + return ""; + } + } } static PyObject *init_func(PyObject * /*self*/, PyObject *args) { - PyObject *path, *user_path; - int headless; + PyObject *path, *user_path; + int headless; - if(!PyArg_ParseTuple(args, "OOi", &path, &user_path, &headless)) { - return NULL; - } + if (!PyArg_ParseTuple(args, "OOi", &path, &user_path, &headless)) { + return NULL; + } - PyObject *path_coerce = NULL, *user_path_coerce = NULL; - path_init(PyC_UnicodeAsByte(path, &path_coerce), - PyC_UnicodeAsByte(user_path, &user_path_coerce)); - Py_XDECREF(path_coerce); - Py_XDECREF(user_path_coerce); + PyObject *path_coerce = NULL, *user_path_coerce = NULL; + path_init(PyC_UnicodeAsByte(path, &path_coerce), + PyC_UnicodeAsByte(user_path, &user_path_coerce)); + Py_XDECREF(path_coerce); + Py_XDECREF(user_path_coerce); - BlenderSession::headless = headless; + BlenderSession::headless = headless; - VLOG(2) << "Debug flags initialized to:\n" - << DebugFlags(); + VLOG(2) << "Debug flags initialized to:\n" << DebugFlags(); - Py_RETURN_NONE; + Py_RETURN_NONE; } - static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/) { - ShaderManager::free_memory(); - TaskScheduler::free_memory(); - Device::free_memory(); - Py_RETURN_NONE; + ShaderManager::free_memory(); + TaskScheduler::free_memory(); + Device::free_memory(); + Py_RETURN_NONE; } static PyObject *create_func(PyObject * /*self*/, PyObject *args) { - PyObject *pyengine, *pypreferences, *pydata, *pyregion, *pyv3d, *pyrv3d; - int preview_osl; - - if(!PyArg_ParseTuple(args, "OOOOOOi", &pyengine, &pypreferences, &pydata, - &pyregion, &pyv3d, &pyrv3d, &preview_osl)) - { - return NULL; - } - - /* RNA */ - PointerRNA engineptr; - RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)PyLong_AsVoidPtr(pyengine), &engineptr); - BL::RenderEngine engine(engineptr); - - PointerRNA preferencesptr; - RNA_pointer_create(NULL, &RNA_Preferences, (void*)PyLong_AsVoidPtr(pypreferences), &preferencesptr); - BL::Preferences preferences(preferencesptr); - - PointerRNA dataptr; - RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr); - BL::BlendData data(dataptr); - - PointerRNA regionptr; - RNA_pointer_create(NULL, &RNA_Region, pylong_as_voidptr_typesafe(pyregion), ®ionptr); - BL::Region region(regionptr); - - PointerRNA v3dptr; - RNA_pointer_create(NULL, &RNA_SpaceView3D, pylong_as_voidptr_typesafe(pyv3d), &v3dptr); - BL::SpaceView3D v3d(v3dptr); - - PointerRNA rv3dptr; - RNA_pointer_create(NULL, &RNA_RegionView3D, pylong_as_voidptr_typesafe(pyrv3d), &rv3dptr); - BL::RegionView3D rv3d(rv3dptr); - - /* create session */ - BlenderSession *session; - - if(rv3d) { - /* interactive viewport session */ - int width = region.width(); - int height = region.height(); - - session = new BlenderSession(engine, preferences, data, v3d, rv3d, width, height); - } - else { - /* offline session or preview render */ - session = new BlenderSession(engine, preferences, data, preview_osl); - } - - return PyLong_FromVoidPtr(session); + PyObject *pyengine, *pypreferences, *pydata, *pyregion, *pyv3d, *pyrv3d; + int preview_osl; + + if (!PyArg_ParseTuple(args, + "OOOOOOi", + &pyengine, + &pypreferences, + &pydata, + &pyregion, + &pyv3d, + &pyrv3d, + &preview_osl)) { + return NULL; + } + + /* RNA */ + PointerRNA engineptr; + RNA_pointer_create(NULL, &RNA_RenderEngine, (void *)PyLong_AsVoidPtr(pyengine), &engineptr); + BL::RenderEngine engine(engineptr); + + PointerRNA preferencesptr; + RNA_pointer_create( + NULL, &RNA_Preferences, (void *)PyLong_AsVoidPtr(pypreferences), &preferencesptr); + BL::Preferences preferences(preferencesptr); + + PointerRNA dataptr; + RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr); + BL::BlendData data(dataptr); + + PointerRNA regionptr; + RNA_pointer_create(NULL, &RNA_Region, pylong_as_voidptr_typesafe(pyregion), ®ionptr); + BL::Region region(regionptr); + + PointerRNA v3dptr; + RNA_pointer_create(NULL, &RNA_SpaceView3D, pylong_as_voidptr_typesafe(pyv3d), &v3dptr); + BL::SpaceView3D v3d(v3dptr); + + PointerRNA rv3dptr; + RNA_pointer_create(NULL, &RNA_RegionView3D, pylong_as_voidptr_typesafe(pyrv3d), &rv3dptr); + BL::RegionView3D rv3d(rv3dptr); + + /* create session */ + BlenderSession *session; + + if (rv3d) { + /* interactive viewport session */ + int width = region.width(); + int height = region.height(); + + session = new BlenderSession(engine, preferences, data, v3d, rv3d, width, height); + } + else { + /* offline session or preview render */ + session = new BlenderSession(engine, preferences, data, preview_osl); + } + + return PyLong_FromVoidPtr(session); } static PyObject *free_func(PyObject * /*self*/, PyObject *value) { - delete (BlenderSession*)PyLong_AsVoidPtr(value); + delete (BlenderSession *)PyLong_AsVoidPtr(value); - Py_RETURN_NONE; + Py_RETURN_NONE; } static PyObject *render_func(PyObject * /*self*/, PyObject *args) { - PyObject *pysession, *pydepsgraph; + PyObject *pysession, *pydepsgraph; - if(!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph)) - return NULL; + if (!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph)) + return NULL; - BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); + BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession); - PointerRNA depsgraphptr; - RNA_pointer_create(NULL, &RNA_Depsgraph, (ID*)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); - BL::Depsgraph b_depsgraph(depsgraphptr); + PointerRNA depsgraphptr; + RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); + BL::Depsgraph b_depsgraph(depsgraphptr); - python_thread_state_save(&session->python_thread_state); + python_thread_state_save(&session->python_thread_state); - session->render(b_depsgraph); + session->render(b_depsgraph); - python_thread_state_restore(&session->python_thread_state); + python_thread_state_restore(&session->python_thread_state); - Py_RETURN_NONE; + Py_RETURN_NONE; } /* pixel_array and result passed as pointers */ static PyObject *bake_func(PyObject * /*self*/, PyObject *args) { - PyObject *pysession, *pydepsgraph, *pyobject; - PyObject *pypixel_array, *pyresult; - const char *pass_type; - int num_pixels, depth, object_id, pass_filter; - - if(!PyArg_ParseTuple(args, "OOOsiiOiiO", &pysession, &pydepsgraph, &pyobject, &pass_type, &pass_filter, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult)) - return NULL; - - BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); - - PointerRNA depsgraphptr; - RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); - BL::Depsgraph b_depsgraph(depsgraphptr); - - PointerRNA objectptr; - RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyobject), &objectptr); - BL::Object b_object(objectptr); - - void *b_result = PyLong_AsVoidPtr(pyresult); - - PointerRNA bakepixelptr; - RNA_pointer_create(NULL, &RNA_BakePixel, PyLong_AsVoidPtr(pypixel_array), &bakepixelptr); - BL::BakePixel b_bake_pixel(bakepixelptr); - - python_thread_state_save(&session->python_thread_state); - - session->bake(b_depsgraph, b_object, pass_type, pass_filter, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result); - - python_thread_state_restore(&session->python_thread_state); - - Py_RETURN_NONE; + PyObject *pysession, *pydepsgraph, *pyobject; + PyObject *pypixel_array, *pyresult; + const char *pass_type; + int num_pixels, depth, object_id, pass_filter; + + if (!PyArg_ParseTuple(args, + "OOOsiiOiiO", + &pysession, + &pydepsgraph, + &pyobject, + &pass_type, + &pass_filter, + &object_id, + &pypixel_array, + &num_pixels, + &depth, + &pyresult)) + return NULL; + + BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession); + + PointerRNA depsgraphptr; + RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); + BL::Depsgraph b_depsgraph(depsgraphptr); + + PointerRNA objectptr; + RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyobject), &objectptr); + BL::Object b_object(objectptr); + + void *b_result = PyLong_AsVoidPtr(pyresult); + + PointerRNA bakepixelptr; + RNA_pointer_create(NULL, &RNA_BakePixel, PyLong_AsVoidPtr(pypixel_array), &bakepixelptr); + BL::BakePixel b_bake_pixel(bakepixelptr); + + python_thread_state_save(&session->python_thread_state); + + session->bake(b_depsgraph, + b_object, + pass_type, + pass_filter, + object_id, + b_bake_pixel, + (size_t)num_pixels, + depth, + (float *)b_result); + + python_thread_state_restore(&session->python_thread_state); + + Py_RETURN_NONE; } static PyObject *draw_func(PyObject * /*self*/, PyObject *args) { - PyObject *pysession, *pygraph, *pyv3d, *pyrv3d; + PyObject *pysession, *pygraph, *pyv3d, *pyrv3d; - if(!PyArg_ParseTuple(args, "OOOO", &pysession, &pygraph, &pyv3d, &pyrv3d)) - return NULL; + if (!PyArg_ParseTuple(args, "OOOO", &pysession, &pygraph, &pyv3d, &pyrv3d)) + return NULL; - BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); + BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession); - if(PyLong_AsVoidPtr(pyrv3d)) { - /* 3d view drawing */ - int viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); + if (PyLong_AsVoidPtr(pyrv3d)) { + /* 3d view drawing */ + int viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); - session->draw(viewport[2], viewport[3]); - } + session->draw(viewport[2], viewport[3]); + } - Py_RETURN_NONE; + Py_RETURN_NONE; } static PyObject *reset_func(PyObject * /*self*/, PyObject *args) { - PyObject *pysession, *pydata, *pydepsgraph; + PyObject *pysession, *pydata, *pydepsgraph; - if(!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pydepsgraph)) - return NULL; + if (!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pydepsgraph)) + return NULL; - BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); + BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession); - PointerRNA dataptr; - RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr); - BL::BlendData b_data(dataptr); + PointerRNA dataptr; + RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr); + BL::BlendData b_data(dataptr); - PointerRNA depsgraphptr; - RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); - BL::Depsgraph b_depsgraph(depsgraphptr); + PointerRNA depsgraphptr; + RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); + BL::Depsgraph b_depsgraph(depsgraphptr); - python_thread_state_save(&session->python_thread_state); + python_thread_state_save(&session->python_thread_state); - session->reset_session(b_data, b_depsgraph); + session->reset_session(b_data, b_depsgraph); - python_thread_state_restore(&session->python_thread_state); + python_thread_state_restore(&session->python_thread_state); - Py_RETURN_NONE; + Py_RETURN_NONE; } static PyObject *sync_func(PyObject * /*self*/, PyObject *args) { - PyObject *pysession, *pydepsgraph; + PyObject *pysession, *pydepsgraph; - if(!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph)) - return NULL; + if (!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph)) + return NULL; - BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); + BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession); - PointerRNA depsgraphptr; - RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); - BL::Depsgraph b_depsgraph(depsgraphptr); + PointerRNA depsgraphptr; + RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr); + BL::Depsgraph b_depsgraph(depsgraphptr); - python_thread_state_save(&session->python_thread_state); + python_thread_state_save(&session->python_thread_state); - session->synchronize(b_depsgraph); + session->synchronize(b_depsgraph); - python_thread_state_restore(&session->python_thread_state); + python_thread_state_restore(&session->python_thread_state); - Py_RETURN_NONE; + Py_RETURN_NONE; } -static PyObject *available_devices_func(PyObject * /*self*/, PyObject * args) +static PyObject *available_devices_func(PyObject * /*self*/, PyObject *args) { - const char *type_name; - if(!PyArg_ParseTuple(args, "s", &type_name)) { - return NULL; - } - - DeviceType type = Device::type_from_string(type_name); - uint mask = (type == DEVICE_NONE) ? DEVICE_MASK_ALL : DEVICE_MASK(type); - mask |= DEVICE_MASK_CPU; - - vector<DeviceInfo> devices = Device::available_devices(mask); - PyObject *ret = PyTuple_New(devices.size()); - - for(size_t i = 0; i < devices.size(); i++) { - DeviceInfo& device = devices[i]; - string type_name = Device::string_from_type(device.type); - PyObject *device_tuple = PyTuple_New(3); - PyTuple_SET_ITEM(device_tuple, 0, PyUnicode_FromString(device.description.c_str())); - PyTuple_SET_ITEM(device_tuple, 1, PyUnicode_FromString(type_name.c_str())); - PyTuple_SET_ITEM(device_tuple, 2, PyUnicode_FromString(device.id.c_str())); - PyTuple_SET_ITEM(ret, i, device_tuple); - } - - return ret; + const char *type_name; + if (!PyArg_ParseTuple(args, "s", &type_name)) { + return NULL; + } + + DeviceType type = Device::type_from_string(type_name); + uint mask = (type == DEVICE_NONE) ? DEVICE_MASK_ALL : DEVICE_MASK(type); + mask |= DEVICE_MASK_CPU; + + vector<DeviceInfo> devices = Device::available_devices(mask); + PyObject *ret = PyTuple_New(devices.size()); + + for (size_t i = 0; i < devices.size(); i++) { + DeviceInfo &device = devices[i]; + string type_name = Device::string_from_type(device.type); + PyObject *device_tuple = PyTuple_New(3); + PyTuple_SET_ITEM(device_tuple, 0, PyUnicode_FromString(device.description.c_str())); + PyTuple_SET_ITEM(device_tuple, 1, PyUnicode_FromString(type_name.c_str())); + PyTuple_SET_ITEM(device_tuple, 2, PyUnicode_FromString(device.id.c_str())); + PyTuple_SET_ITEM(ret, i, device_tuple); + } + + return ret; } #ifdef WITH_OSL static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args) { - PyObject *pydata, *pynodegroup, *pynode; - const char *filepath = NULL; - - if(!PyArg_ParseTuple(args, "OOOs", &pydata, &pynodegroup, &pynode, &filepath)) - return NULL; - - /* RNA */ - PointerRNA dataptr; - RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr); - BL::BlendData b_data(dataptr); - - PointerRNA nodeptr; - RNA_pointer_create((ID*)PyLong_AsVoidPtr(pynodegroup), &RNA_ShaderNodeScript, (void*)PyLong_AsVoidPtr(pynode), &nodeptr); - BL::ShaderNodeScript b_node(nodeptr); - - /* update bytecode hash */ - string bytecode = b_node.bytecode(); - - if(!bytecode.empty()) { - MD5Hash md5; - md5.append((const uint8_t*)bytecode.c_str(), bytecode.size()); - b_node.bytecode_hash(md5.get_hex().c_str()); - } - else - b_node.bytecode_hash(""); - - /* query from file path */ - OSL::OSLQuery query; - - if(!OSLShaderManager::osl_query(query, filepath)) - Py_RETURN_FALSE; - - /* add new sockets from parameters */ - set<void*> used_sockets; - - for(int i = 0; i < query.nparams(); i++) { - const OSL::OSLQuery::Parameter *param = query.getparam(i); - - /* skip unsupported types */ - if(param->varlenarray || param->isstruct || param->type.arraylen > 1) - continue; - - /* determine socket type */ - string socket_type; - BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE; - float4 default_float4 = make_float4(0.0f, 0.0f, 0.0f, 1.0f); - float default_float = 0.0f; - int default_int = 0; - string default_string = ""; - - if(param->isclosure) { - socket_type = "NodeSocketShader"; - data_type = BL::NodeSocket::type_SHADER; - } - else if(param->type.vecsemantics == TypeDesc::COLOR) { - socket_type = "NodeSocketColor"; - data_type = BL::NodeSocket::type_RGBA; - - if(param->validdefault) { - default_float4[0] = param->fdefault[0]; - default_float4[1] = param->fdefault[1]; - default_float4[2] = param->fdefault[2]; - } - } - else if(param->type.vecsemantics == TypeDesc::POINT || - param->type.vecsemantics == TypeDesc::VECTOR || - param->type.vecsemantics == TypeDesc::NORMAL) - { - socket_type = "NodeSocketVector"; - data_type = BL::NodeSocket::type_VECTOR; - - if(param->validdefault) { - default_float4[0] = param->fdefault[0]; - default_float4[1] = param->fdefault[1]; - default_float4[2] = param->fdefault[2]; - } - } - else if(param->type.aggregate == TypeDesc::SCALAR) { - if(param->type.basetype == TypeDesc::INT) { - socket_type = "NodeSocketInt"; - data_type = BL::NodeSocket::type_INT; - if(param->validdefault) - default_int = param->idefault[0]; - } - else if(param->type.basetype == TypeDesc::FLOAT) { - socket_type = "NodeSocketFloat"; - data_type = BL::NodeSocket::type_VALUE; - if(param->validdefault) - default_float = param->fdefault[0]; - } - else if(param->type.basetype == TypeDesc::STRING) { - socket_type = "NodeSocketString"; - data_type = BL::NodeSocket::type_STRING; - if(param->validdefault) - default_string = param->sdefault[0].string(); - } - else - continue; - } - else - continue; - - /* find socket socket */ - BL::NodeSocket b_sock(PointerRNA_NULL); - if(param->isoutput) { - b_sock = b_node.outputs[param->name.string()]; - /* remove if type no longer matches */ - if(b_sock && b_sock.bl_idname() != socket_type) { - b_node.outputs.remove(b_data, b_sock); - b_sock = BL::NodeSocket(PointerRNA_NULL); - } - } - else { - b_sock = b_node.inputs[param->name.string()]; - /* remove if type no longer matches */ - if(b_sock && b_sock.bl_idname() != socket_type) { - b_node.inputs.remove(b_data, b_sock); - b_sock = BL::NodeSocket(PointerRNA_NULL); - } - } - - if(!b_sock) { - /* create new socket */ - if(param->isoutput) - b_sock = b_node.outputs.create(b_data, socket_type.c_str(), param->name.c_str(), param->name.c_str()); - else - b_sock = b_node.inputs.create(b_data, socket_type.c_str(), param->name.c_str(), param->name.c_str()); - - /* set default value */ - if(data_type == BL::NodeSocket::type_VALUE) { - set_float(b_sock.ptr, "default_value", default_float); - } - else if(data_type == BL::NodeSocket::type_INT) { - set_int(b_sock.ptr, "default_value", default_int); - } - else if(data_type == BL::NodeSocket::type_RGBA) { - set_float4(b_sock.ptr, "default_value", default_float4); - } - else if(data_type == BL::NodeSocket::type_VECTOR) { - set_float3(b_sock.ptr, "default_value", float4_to_float3(default_float4)); - } - else if(data_type == BL::NodeSocket::type_STRING) { - set_string(b_sock.ptr, "default_value", default_string); - } - } - - used_sockets.insert(b_sock.ptr.data); - } - - /* remove unused parameters */ - bool removed; - - do { - BL::Node::inputs_iterator b_input; - BL::Node::outputs_iterator b_output; - - removed = false; - - for(b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) { - if(used_sockets.find(b_input->ptr.data) == used_sockets.end()) { - b_node.inputs.remove(b_data, *b_input); - removed = true; - break; - } - } - - for(b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) { - if(used_sockets.find(b_output->ptr.data) == used_sockets.end()) { - b_node.outputs.remove(b_data, *b_output); - removed = true; - break; - } - } - } while(removed); - - Py_RETURN_TRUE; + PyObject *pydata, *pynodegroup, *pynode; + const char *filepath = NULL; + + if (!PyArg_ParseTuple(args, "OOOs", &pydata, &pynodegroup, &pynode, &filepath)) + return NULL; + + /* RNA */ + PointerRNA dataptr; + RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr); + BL::BlendData b_data(dataptr); + + PointerRNA nodeptr; + RNA_pointer_create((ID *)PyLong_AsVoidPtr(pynodegroup), + &RNA_ShaderNodeScript, + (void *)PyLong_AsVoidPtr(pynode), + &nodeptr); + BL::ShaderNodeScript b_node(nodeptr); + + /* update bytecode hash */ + string bytecode = b_node.bytecode(); + + if (!bytecode.empty()) { + MD5Hash md5; + md5.append((const uint8_t *)bytecode.c_str(), bytecode.size()); + b_node.bytecode_hash(md5.get_hex().c_str()); + } + else + b_node.bytecode_hash(""); + + /* query from file path */ + OSL::OSLQuery query; + + if (!OSLShaderManager::osl_query(query, filepath)) + Py_RETURN_FALSE; + + /* add new sockets from parameters */ + set<void *> used_sockets; + + for (int i = 0; i < query.nparams(); i++) { + const OSL::OSLQuery::Parameter *param = query.getparam(i); + + /* skip unsupported types */ + if (param->varlenarray || param->isstruct || param->type.arraylen > 1) + continue; + + /* determine socket type */ + string socket_type; + BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE; + float4 default_float4 = make_float4(0.0f, 0.0f, 0.0f, 1.0f); + float default_float = 0.0f; + int default_int = 0; + string default_string = ""; + + if (param->isclosure) { + socket_type = "NodeSocketShader"; + data_type = BL::NodeSocket::type_SHADER; + } + else if (param->type.vecsemantics == TypeDesc::COLOR) { + socket_type = "NodeSocketColor"; + data_type = BL::NodeSocket::type_RGBA; + + if (param->validdefault) { + default_float4[0] = param->fdefault[0]; + default_float4[1] = param->fdefault[1]; + default_float4[2] = param->fdefault[2]; + } + } + else if (param->type.vecsemantics == TypeDesc::POINT || + param->type.vecsemantics == TypeDesc::VECTOR || + param->type.vecsemantics == TypeDesc::NORMAL) { + socket_type = "NodeSocketVector"; + data_type = BL::NodeSocket::type_VECTOR; + + if (param->validdefault) { + default_float4[0] = param->fdefault[0]; + default_float4[1] = param->fdefault[1]; + default_float4[2] = param->fdefault[2]; + } + } + else if (param->type.aggregate == TypeDesc::SCALAR) { + if (param->type.basetype == TypeDesc::INT) { + socket_type = "NodeSocketInt"; + data_type = BL::NodeSocket::type_INT; + if (param->validdefault) + default_int = param->idefault[0]; + } + else if (param->type.basetype == TypeDesc::FLOAT) { + socket_type = "NodeSocketFloat"; + data_type = BL::NodeSocket::type_VALUE; + if (param->validdefault) + default_float = param->fdefault[0]; + } + else if (param->type.basetype == TypeDesc::STRING) { + socket_type = "NodeSocketString"; + data_type = BL::NodeSocket::type_STRING; + if (param->validdefault) + default_string = param->sdefault[0].string(); + } + else + continue; + } + else + continue; + + /* find socket socket */ + BL::NodeSocket b_sock(PointerRNA_NULL); + if (param->isoutput) { + b_sock = b_node.outputs[param->name.string()]; + /* remove if type no longer matches */ + if (b_sock && b_sock.bl_idname() != socket_type) { + b_node.outputs.remove(b_data, b_sock); + b_sock = BL::NodeSocket(PointerRNA_NULL); + } + } + else { + b_sock = b_node.inputs[param->name.string()]; + /* remove if type no longer matches */ + if (b_sock && b_sock.bl_idname() != socket_type) { + b_node.inputs.remove(b_data, b_sock); + b_sock = BL::NodeSocket(PointerRNA_NULL); + } + } + + if (!b_sock) { + /* create new socket */ + if (param->isoutput) + b_sock = b_node.outputs.create( + b_data, socket_type.c_str(), param->name.c_str(), param->name.c_str()); + else + b_sock = b_node.inputs.create( + b_data, socket_type.c_str(), param->name.c_str(), param->name.c_str()); + + /* set default value */ + if (data_type == BL::NodeSocket::type_VALUE) { + set_float(b_sock.ptr, "default_value", default_float); + } + else if (data_type == BL::NodeSocket::type_INT) { + set_int(b_sock.ptr, "default_value", default_int); + } + else if (data_type == BL::NodeSocket::type_RGBA) { + set_float4(b_sock.ptr, "default_value", default_float4); + } + else if (data_type == BL::NodeSocket::type_VECTOR) { + set_float3(b_sock.ptr, "default_value", float4_to_float3(default_float4)); + } + else if (data_type == BL::NodeSocket::type_STRING) { + set_string(b_sock.ptr, "default_value", default_string); + } + } + + used_sockets.insert(b_sock.ptr.data); + } + + /* remove unused parameters */ + bool removed; + + do { + BL::Node::inputs_iterator b_input; + BL::Node::outputs_iterator b_output; + + removed = false; + + for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) { + if (used_sockets.find(b_input->ptr.data) == used_sockets.end()) { + b_node.inputs.remove(b_data, *b_input); + removed = true; + break; + } + } + + for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) { + if (used_sockets.find(b_output->ptr.data) == used_sockets.end()) { + b_node.outputs.remove(b_data, *b_output); + removed = true; + break; + } + } + } while (removed); + + Py_RETURN_TRUE; } static PyObject *osl_compile_func(PyObject * /*self*/, PyObject *args) { - const char *inputfile = NULL, *outputfile = NULL; + const char *inputfile = NULL, *outputfile = NULL; - if(!PyArg_ParseTuple(args, "ss", &inputfile, &outputfile)) - return NULL; + if (!PyArg_ParseTuple(args, "ss", &inputfile, &outputfile)) + return NULL; - /* return */ - if(!OSLShaderManager::osl_compile(inputfile, outputfile)) - Py_RETURN_FALSE; + /* return */ + if (!OSLShaderManager::osl_compile(inputfile, outputfile)) + Py_RETURN_FALSE; - Py_RETURN_TRUE; + Py_RETURN_TRUE; } #endif static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/) { - string system_info = Device::device_capabilities(); - return PyUnicode_FromString(system_info.c_str()); + string system_info = Device::device_capabilities(); + return PyUnicode_FromString(system_info.c_str()); } #ifdef WITH_OPENCL static PyObject *opencl_disable_func(PyObject * /*self*/, PyObject * /*value*/) { - VLOG(2) << "Disabling OpenCL platform."; - DebugFlags().opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE; - Py_RETURN_NONE; + VLOG(2) << "Disabling OpenCL platform."; + DebugFlags().opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE; + Py_RETURN_NONE; } static PyObject *opencl_compile_func(PyObject * /*self*/, PyObject *args) { - PyObject *sequence = PySequence_Fast(args, "Arguments must be a sequence"); - if(sequence == NULL) { - Py_RETURN_FALSE; - } - - vector<string> parameters; - for(Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) { - PyObject *item = PySequence_Fast_GET_ITEM(sequence, i); - PyObject *item_as_string = PyObject_Str(item); - const char *parameter_string = PyUnicode_AsUTF8(item_as_string); - parameters.push_back(parameter_string); - Py_DECREF(item_as_string); - } - Py_DECREF(sequence); - - if (device_opencl_compile_kernel(parameters)) { - Py_RETURN_TRUE; - } - else { - Py_RETURN_FALSE; - } + PyObject *sequence = PySequence_Fast(args, "Arguments must be a sequence"); + if (sequence == NULL) { + Py_RETURN_FALSE; + } + + vector<string> parameters; + for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) { + PyObject *item = PySequence_Fast_GET_ITEM(sequence, i); + PyObject *item_as_string = PyObject_Str(item); + const char *parameter_string = PyUnicode_AsUTF8(item_as_string); + parameters.push_back(parameter_string); + Py_DECREF(item_as_string); + } + Py_DECREF(sequence); + + if (device_opencl_compile_kernel(parameters)) { + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } } #endif -static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string>& filepaths) +static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepaths) { - if(PyUnicode_Check(pyfilepaths)) { - const char *filepath = PyUnicode_AsUTF8(pyfilepaths); - filepaths.push_back(filepath); - return true; - } - - PyObject *sequence = PySequence_Fast(pyfilepaths, "File paths must be a string or sequence of strings"); - if(sequence == NULL) { - return false; - } - - for(Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) { - PyObject *item = PySequence_Fast_GET_ITEM(sequence, i); - const char *filepath = PyUnicode_AsUTF8(item); - if(filepath == NULL) { - PyErr_SetString(PyExc_ValueError, "File paths must be a string or sequence of strings."); - Py_DECREF(sequence); - return false; - } - filepaths.push_back(filepath); - } - Py_DECREF(sequence); - - return true; + if (PyUnicode_Check(pyfilepaths)) { + const char *filepath = PyUnicode_AsUTF8(pyfilepaths); + filepaths.push_back(filepath); + return true; + } + + PyObject *sequence = PySequence_Fast(pyfilepaths, + "File paths must be a string or sequence of strings"); + if (sequence == NULL) { + return false; + } + + for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) { + PyObject *item = PySequence_Fast_GET_ITEM(sequence, i); + const char *filepath = PyUnicode_AsUTF8(item); + if (filepath == NULL) { + PyErr_SetString(PyExc_ValueError, "File paths must be a string or sequence of strings."); + Py_DECREF(sequence); + return false; + } + filepaths.push_back(filepath); + } + Py_DECREF(sequence); + + return true; } static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords) { - static const char *keyword_list[] = {"preferences", "scene", "view_layer", - "input", "output", - "tile_size", "samples", NULL}; - PyObject *pypreferences, *pyscene, *pyviewlayer; - PyObject *pyinput, *pyoutput = NULL; - int tile_size = 0, samples = 0; - - if (!PyArg_ParseTupleAndKeywords(args, keywords, "OOOO|Oii", (char**)keyword_list, - &pypreferences, &pyscene, &pyviewlayer, - &pyinput, &pyoutput, - &tile_size, &samples)) { - return NULL; - } - - /* Get device specification from preferences and scene. */ - PointerRNA preferencesptr; - RNA_pointer_create(NULL, &RNA_Preferences, (void*)PyLong_AsVoidPtr(pypreferences), &preferencesptr); - BL::Preferences b_preferences(preferencesptr); - - PointerRNA sceneptr; - RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr); - BL::Scene b_scene(sceneptr); - - DeviceInfo device = blender_device_info(b_preferences, b_scene, true); - - /* Get denoising parameters from view layer. */ - PointerRNA viewlayerptr; - RNA_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &RNA_ViewLayer, PyLong_AsVoidPtr(pyviewlayer), &viewlayerptr); - PointerRNA cviewlayer = RNA_pointer_get(&viewlayerptr, "cycles"); - - DenoiseParams params; - params.radius = get_int(cviewlayer, "denoising_radius"); - params.strength = get_float(cviewlayer, "denoising_strength"); - params.feature_strength = get_float(cviewlayer, "denoising_feature_strength"); - params.relative_pca = get_boolean(cviewlayer, "denoising_relative_pca"); - params.neighbor_frames = get_int(cviewlayer, "denoising_neighbor_frames"); - - /* Parse file paths list. */ - vector<string> input, output; - - if(!image_parse_filepaths(pyinput, input)) { - return NULL; - } - - if(pyoutput) { - if(!image_parse_filepaths(pyoutput, output)) { - return NULL; - } - } - else { - output = input; - } - - if(input.empty()) { - PyErr_SetString(PyExc_ValueError, "No input file paths specified."); - return NULL; - } - if(input.size() != output.size()) { - PyErr_SetString(PyExc_ValueError, "Number of input and output file paths does not match."); - return NULL; - } - - /* Create denoiser. */ - Denoiser denoiser(device); - denoiser.params = params; - denoiser.input = input; - denoiser.output = output; - - if (tile_size > 0) { - denoiser.tile_size = make_int2(tile_size, tile_size); - } - if (samples > 0) { - denoiser.samples_override = samples; - } - - /* Run denoiser. */ - if(!denoiser.run()) { - PyErr_SetString(PyExc_ValueError, denoiser.error.c_str()); - return NULL; - } - - Py_RETURN_NONE; + static const char *keyword_list[] = { + "preferences", "scene", "view_layer", "input", "output", "tile_size", "samples", NULL}; + PyObject *pypreferences, *pyscene, *pyviewlayer; + PyObject *pyinput, *pyoutput = NULL; + int tile_size = 0, samples = 0; + + if (!PyArg_ParseTupleAndKeywords(args, + keywords, + "OOOO|Oii", + (char **)keyword_list, + &pypreferences, + &pyscene, + &pyviewlayer, + &pyinput, + &pyoutput, + &tile_size, + &samples)) { + return NULL; + } + + /* Get device specification from preferences and scene. */ + PointerRNA preferencesptr; + RNA_pointer_create( + NULL, &RNA_Preferences, (void *)PyLong_AsVoidPtr(pypreferences), &preferencesptr); + BL::Preferences b_preferences(preferencesptr); + + PointerRNA sceneptr; + RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene), &sceneptr); + BL::Scene b_scene(sceneptr); + + DeviceInfo device = blender_device_info(b_preferences, b_scene, true); + + /* Get denoising parameters from view layer. */ + PointerRNA viewlayerptr; + RNA_pointer_create((ID *)PyLong_AsVoidPtr(pyscene), + &RNA_ViewLayer, + PyLong_AsVoidPtr(pyviewlayer), + &viewlayerptr); + PointerRNA cviewlayer = RNA_pointer_get(&viewlayerptr, "cycles"); + + DenoiseParams params; + params.radius = get_int(cviewlayer, "denoising_radius"); + params.strength = get_float(cviewlayer, "denoising_strength"); + params.feature_strength = get_float(cviewlayer, "denoising_feature_strength"); + params.relative_pca = get_boolean(cviewlayer, "denoising_relative_pca"); + params.neighbor_frames = get_int(cviewlayer, "denoising_neighbor_frames"); + + /* Parse file paths list. */ + vector<string> input, output; + + if (!image_parse_filepaths(pyinput, input)) { + return NULL; + } + + if (pyoutput) { + if (!image_parse_filepaths(pyoutput, output)) { + return NULL; + } + } + else { + output = input; + } + + if (input.empty()) { + PyErr_SetString(PyExc_ValueError, "No input file paths specified."); + return NULL; + } + if (input.size() != output.size()) { + PyErr_SetString(PyExc_ValueError, "Number of input and output file paths does not match."); + return NULL; + } + + /* Create denoiser. */ + Denoiser denoiser(device); + denoiser.params = params; + denoiser.input = input; + denoiser.output = output; + + if (tile_size > 0) { + denoiser.tile_size = make_int2(tile_size, tile_size); + } + if (samples > 0) { + denoiser.samples_override = samples; + } + + /* Run denoiser. */ + if (!denoiser.run()) { + PyErr_SetString(PyExc_ValueError, denoiser.error.c_str()); + return NULL; + } + + Py_RETURN_NONE; } static PyObject *merge_func(PyObject * /*self*/, PyObject *args, PyObject *keywords) { - static const char *keyword_list[] = {"input", "output", NULL}; - PyObject *pyinput, *pyoutput = NULL; - - if (!PyArg_ParseTupleAndKeywords(args, keywords, "OO", (char**)keyword_list, &pyinput, &pyoutput)) { - return NULL; - } - - /* Parse input list. */ - vector<string> input; - if(!image_parse_filepaths(pyinput, input)) { - return NULL; - } - - /* Parse output string. */ - if(!PyUnicode_Check(pyoutput)) { - PyErr_SetString(PyExc_ValueError, "Output must be a string."); - return NULL; - } - string output = PyUnicode_AsUTF8(pyoutput); - - /* Merge. */ - ImageMerger merger; - merger.input = input; - merger.output = output; - - if(!merger.run()) { - PyErr_SetString(PyExc_ValueError, merger.error.c_str()); - return NULL; - } - - Py_RETURN_NONE; + static const char *keyword_list[] = {"input", "output", NULL}; + PyObject *pyinput, *pyoutput = NULL; + + if (!PyArg_ParseTupleAndKeywords( + args, keywords, "OO", (char **)keyword_list, &pyinput, &pyoutput)) { + return NULL; + } + + /* Parse input list. */ + vector<string> input; + if (!image_parse_filepaths(pyinput, input)) { + return NULL; + } + + /* Parse output string. */ + if (!PyUnicode_Check(pyoutput)) { + PyErr_SetString(PyExc_ValueError, "Output must be a string."); + return NULL; + } + string output = PyUnicode_AsUTF8(pyoutput); + + /* Merge. */ + ImageMerger merger; + merger.input = input; + merger.output = output; + + if (!merger.run()) { + PyErr_SetString(PyExc_ValueError, merger.error.c_str()); + return NULL; + } + + Py_RETURN_NONE; } - static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args) { - PyObject *pyscene; - if(!PyArg_ParseTuple(args, "O", &pyscene)) { - return NULL; - } + PyObject *pyscene; + if (!PyArg_ParseTuple(args, "O", &pyscene)) { + return NULL; + } - PointerRNA sceneptr; - RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr); - BL::Scene b_scene(sceneptr); + PointerRNA sceneptr; + RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene), &sceneptr); + BL::Scene b_scene(sceneptr); - if(debug_flags_sync_from_scene(b_scene)) { - VLOG(2) << "Tagging device list for update."; - Device::tag_update(); - } + if (debug_flags_sync_from_scene(b_scene)) { + VLOG(2) << "Tagging device list for update."; + Device::tag_update(); + } - VLOG(2) << "Debug flags set to:\n" - << DebugFlags(); + VLOG(2) << "Debug flags set to:\n" << DebugFlags(); - debug_flags_set = true; + debug_flags_set = true; - Py_RETURN_NONE; + Py_RETURN_NONE; } static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/) { - if(debug_flags_reset()) { - VLOG(2) << "Tagging device list for update."; - Device::tag_update(); - } - if(debug_flags_set) { - VLOG(2) << "Debug flags reset to:\n" - << DebugFlags(); - debug_flags_set = false; - } - Py_RETURN_NONE; + if (debug_flags_reset()) { + VLOG(2) << "Tagging device list for update."; + Device::tag_update(); + } + if (debug_flags_set) { + VLOG(2) << "Debug flags reset to:\n" << DebugFlags(); + debug_flags_set = false; + } + Py_RETURN_NONE; } static PyObject *set_resumable_chunk_func(PyObject * /*self*/, PyObject *args) { - int num_resumable_chunks, current_resumable_chunk; - if(!PyArg_ParseTuple(args, "ii", - &num_resumable_chunks, - ¤t_resumable_chunk)) { - Py_RETURN_NONE; - } - - if(num_resumable_chunks <= 0) { - fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n"); - abort(); - Py_RETURN_NONE; - } - if(current_resumable_chunk < 1 || - current_resumable_chunk > num_resumable_chunks) - { - fprintf(stderr, "Cycles: Bad value for current resumable chunk number.\n"); - abort(); - Py_RETURN_NONE; - } - - VLOG(1) << "Initialized resumable render: " - << "num_resumable_chunks=" << num_resumable_chunks << ", " - << "current_resumable_chunk=" << current_resumable_chunk; - BlenderSession::num_resumable_chunks = num_resumable_chunks; - BlenderSession::current_resumable_chunk = current_resumable_chunk; - - printf("Cycles: Will render chunk %d of %d\n", - current_resumable_chunk, - num_resumable_chunks); - - Py_RETURN_NONE; + int num_resumable_chunks, current_resumable_chunk; + if (!PyArg_ParseTuple(args, "ii", &num_resumable_chunks, ¤t_resumable_chunk)) { + Py_RETURN_NONE; + } + + if (num_resumable_chunks <= 0) { + fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n"); + abort(); + Py_RETURN_NONE; + } + if (current_resumable_chunk < 1 || current_resumable_chunk > num_resumable_chunks) { + fprintf(stderr, "Cycles: Bad value for current resumable chunk number.\n"); + abort(); + Py_RETURN_NONE; + } + + VLOG(1) << "Initialized resumable render: " + << "num_resumable_chunks=" << num_resumable_chunks << ", " + << "current_resumable_chunk=" << current_resumable_chunk; + BlenderSession::num_resumable_chunks = num_resumable_chunks; + BlenderSession::current_resumable_chunk = current_resumable_chunk; + + printf("Cycles: Will render chunk %d of %d\n", current_resumable_chunk, num_resumable_chunks); + + Py_RETURN_NONE; } static PyObject *set_resumable_chunk_range_func(PyObject * /*self*/, PyObject *args) { - int num_chunks, start_chunk, end_chunk; - if(!PyArg_ParseTuple(args, "iii", - &num_chunks, - &start_chunk, - &end_chunk)) { - Py_RETURN_NONE; - } - - if(num_chunks <= 0) { - fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n"); - abort(); - Py_RETURN_NONE; - } - if(start_chunk < 1 || start_chunk > num_chunks) { - fprintf(stderr, "Cycles: Bad value for start chunk number.\n"); - abort(); - Py_RETURN_NONE; - } - if(end_chunk < 1 || end_chunk > num_chunks) { - fprintf(stderr, "Cycles: Bad value for start chunk number.\n"); - abort(); - Py_RETURN_NONE; - } - if(start_chunk > end_chunk) { - fprintf(stderr, "Cycles: End chunk should be higher than start one.\n"); - abort(); - Py_RETURN_NONE; - } - - VLOG(1) << "Initialized resumable render: " - << "num_resumable_chunks=" << num_chunks << ", " - << "start_resumable_chunk=" << start_chunk - << "end_resumable_chunk=" << end_chunk; - BlenderSession::num_resumable_chunks = num_chunks; - BlenderSession::start_resumable_chunk = start_chunk; - BlenderSession::end_resumable_chunk = end_chunk; - - printf("Cycles: Will render chunks %d to %d of %d\n", - start_chunk, - end_chunk, - num_chunks); - - Py_RETURN_NONE; + int num_chunks, start_chunk, end_chunk; + if (!PyArg_ParseTuple(args, "iii", &num_chunks, &start_chunk, &end_chunk)) { + Py_RETURN_NONE; + } + + if (num_chunks <= 0) { + fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n"); + abort(); + Py_RETURN_NONE; + } + if (start_chunk < 1 || start_chunk > num_chunks) { + fprintf(stderr, "Cycles: Bad value for start chunk number.\n"); + abort(); + Py_RETURN_NONE; + } + if (end_chunk < 1 || end_chunk > num_chunks) { + fprintf(stderr, "Cycles: Bad value for start chunk number.\n"); + abort(); + Py_RETURN_NONE; + } + if (start_chunk > end_chunk) { + fprintf(stderr, "Cycles: End chunk should be higher than start one.\n"); + abort(); + Py_RETURN_NONE; + } + + VLOG(1) << "Initialized resumable render: " + << "num_resumable_chunks=" << num_chunks << ", " + << "start_resumable_chunk=" << start_chunk << "end_resumable_chunk=" << end_chunk; + BlenderSession::num_resumable_chunks = num_chunks; + BlenderSession::start_resumable_chunk = start_chunk; + BlenderSession::end_resumable_chunk = end_chunk; + + printf("Cycles: Will render chunks %d to %d of %d\n", start_chunk, end_chunk, num_chunks); + + Py_RETURN_NONE; } static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/) { - BlenderSession::print_render_stats = true; - Py_RETURN_NONE; + BlenderSession::print_render_stats = true; + Py_RETURN_NONE; } static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/) { - vector<DeviceType> device_types = Device::available_types(); - bool has_cuda = false, has_opencl = false; - foreach(DeviceType device_type, device_types) { - has_cuda |= (device_type == DEVICE_CUDA); - has_opencl |= (device_type == DEVICE_OPENCL); - } - PyObject *list = PyTuple_New(2); - PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda)); - PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_opencl)); - return list; + vector<DeviceType> device_types = Device::available_types(); + bool has_cuda = false, has_opencl = false; + foreach (DeviceType device_type, device_types) { + has_cuda |= (device_type == DEVICE_CUDA); + has_opencl |= (device_type == DEVICE_OPENCL); + } + PyObject *list = PyTuple_New(2); + PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda)); + PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_opencl)); + return list; } static PyMethodDef methods[] = { - {"init", init_func, METH_VARARGS, ""}, - {"exit", exit_func, METH_VARARGS, ""}, - {"create", create_func, METH_VARARGS, ""}, - {"free", free_func, METH_O, ""}, - {"render", render_func, METH_VARARGS, ""}, - {"bake", bake_func, METH_VARARGS, ""}, - {"draw", draw_func, METH_VARARGS, ""}, - {"sync", sync_func, METH_VARARGS, ""}, - {"reset", reset_func, METH_VARARGS, ""}, + {"init", init_func, METH_VARARGS, ""}, + {"exit", exit_func, METH_VARARGS, ""}, + {"create", create_func, METH_VARARGS, ""}, + {"free", free_func, METH_O, ""}, + {"render", render_func, METH_VARARGS, ""}, + {"bake", bake_func, METH_VARARGS, ""}, + {"draw", draw_func, METH_VARARGS, ""}, + {"sync", sync_func, METH_VARARGS, ""}, + {"reset", reset_func, METH_VARARGS, ""}, #ifdef WITH_OSL - {"osl_update_node", osl_update_node_func, METH_VARARGS, ""}, - {"osl_compile", osl_compile_func, METH_VARARGS, ""}, + {"osl_update_node", osl_update_node_func, METH_VARARGS, ""}, + {"osl_compile", osl_compile_func, METH_VARARGS, ""}, #endif - {"available_devices", available_devices_func, METH_VARARGS, ""}, - {"system_info", system_info_func, METH_NOARGS, ""}, + {"available_devices", available_devices_func, METH_VARARGS, ""}, + {"system_info", system_info_func, METH_NOARGS, ""}, #ifdef WITH_OPENCL - {"opencl_disable", opencl_disable_func, METH_NOARGS, ""}, - {"opencl_compile", opencl_compile_func, METH_VARARGS, ""}, + {"opencl_disable", opencl_disable_func, METH_NOARGS, ""}, + {"opencl_compile", opencl_compile_func, METH_VARARGS, ""}, #endif - /* Standalone denoising */ - {"denoise", (PyCFunction)denoise_func, METH_VARARGS|METH_KEYWORDS, ""}, - {"merge", (PyCFunction)merge_func, METH_VARARGS|METH_KEYWORDS, ""}, + /* Standalone denoising */ + {"denoise", (PyCFunction)denoise_func, METH_VARARGS | METH_KEYWORDS, ""}, + {"merge", (PyCFunction)merge_func, METH_VARARGS | METH_KEYWORDS, ""}, - /* Debugging routines */ - {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""}, - {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""}, + /* Debugging routines */ + {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""}, + {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""}, - /* Statistics. */ - {"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""}, + /* Statistics. */ + {"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""}, - /* Resumable render */ - {"set_resumable_chunk", set_resumable_chunk_func, METH_VARARGS, ""}, - {"set_resumable_chunk_range", set_resumable_chunk_range_func, METH_VARARGS, ""}, + /* Resumable render */ + {"set_resumable_chunk", set_resumable_chunk_func, METH_VARARGS, ""}, + {"set_resumable_chunk_range", set_resumable_chunk_range_func, METH_VARARGS, ""}, - /* Compute Device selection */ - {"get_device_types", get_device_types_func, METH_VARARGS, ""}, + /* Compute Device selection */ + {"get_device_types", get_device_types_func, METH_VARARGS, ""}, - {NULL, NULL, 0, NULL}, + {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "_cycles", - "Blender cycles render integration", - -1, - methods, - NULL, NULL, NULL, NULL, + PyModuleDef_HEAD_INIT, + "_cycles", + "Blender cycles render integration", + -1, + methods, + NULL, + NULL, + NULL, + NULL, }; CCL_NAMESPACE_END void *CCL_python_module_init() { - PyObject *mod = PyModule_Create(&ccl::module); + PyObject *mod = PyModule_Create(&ccl::module); #ifdef WITH_OSL - /* TODO(sergey): This gives us library we've been linking against. - * In theory with dynamic OSL library it might not be - * accurate, but there's nothing in OSL API which we - * might use to get version in runtime. - */ - int curversion = OSL_LIBRARY_VERSION_CODE; - PyModule_AddObject(mod, "with_osl", Py_True); - Py_INCREF(Py_True); - PyModule_AddObject(mod, "osl_version", - Py_BuildValue("(iii)", - curversion / 10000, (curversion / 100) % 100, curversion % 100)); - PyModule_AddObject(mod, "osl_version_string", - PyUnicode_FromFormat("%2d, %2d, %2d", - curversion / 10000, (curversion / 100) % 100, curversion % 100)); + /* TODO(sergey): This gives us library we've been linking against. + * In theory with dynamic OSL library it might not be + * accurate, but there's nothing in OSL API which we + * might use to get version in runtime. + */ + int curversion = OSL_LIBRARY_VERSION_CODE; + PyModule_AddObject(mod, "with_osl", Py_True); + Py_INCREF(Py_True); + PyModule_AddObject( + mod, + "osl_version", + Py_BuildValue("(iii)", curversion / 10000, (curversion / 100) % 100, curversion % 100)); + PyModule_AddObject( + mod, + "osl_version_string", + PyUnicode_FromFormat( + "%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100)); #else - PyModule_AddObject(mod, "with_osl", Py_False); - Py_INCREF(Py_False); - PyModule_AddStringConstant(mod, "osl_version", "unknown"); - PyModule_AddStringConstant(mod, "osl_version_string", "unknown"); + PyModule_AddObject(mod, "with_osl", Py_False); + Py_INCREF(Py_False); + PyModule_AddStringConstant(mod, "osl_version", "unknown"); + PyModule_AddStringConstant(mod, "osl_version_string", "unknown"); #endif #ifdef WITH_CYCLES_DEBUG - PyModule_AddObject(mod, "with_cycles_debug", Py_True); - Py_INCREF(Py_True); + PyModule_AddObject(mod, "with_cycles_debug", Py_True); + Py_INCREF(Py_True); #else - PyModule_AddObject(mod, "with_cycles_debug", Py_False); - Py_INCREF(Py_False); + PyModule_AddObject(mod, "with_cycles_debug", Py_False); + Py_INCREF(Py_False); #endif #ifdef WITH_NETWORK - PyModule_AddObject(mod, "with_network", Py_True); - Py_INCREF(Py_True); + PyModule_AddObject(mod, "with_network", Py_True); + Py_INCREF(Py_True); #else /* WITH_NETWORK */ - PyModule_AddObject(mod, "with_network", Py_False); - Py_INCREF(Py_False); -#endif /* WITH_NETWORK */ + PyModule_AddObject(mod, "with_network", Py_False); + Py_INCREF(Py_False); +#endif /* WITH_NETWORK */ #ifdef WITH_EMBREE - PyModule_AddObject(mod, "with_embree", Py_True); - Py_INCREF(Py_True); + PyModule_AddObject(mod, "with_embree", Py_True); + Py_INCREF(Py_True); #else /* WITH_EMBREE */ - PyModule_AddObject(mod, "with_embree", Py_False); - Py_INCREF(Py_False); -#endif /* WITH_EMBREE */ + PyModule_AddObject(mod, "with_embree", Py_False); + Py_INCREF(Py_False); +#endif /* WITH_EMBREE */ - return (void*)mod; + return (void *)mod; } diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index cf856c3b3d4..29a97bf6546 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -53,1051 +53,1070 @@ int BlenderSession::start_resumable_chunk = 0; int BlenderSession::end_resumable_chunk = 0; bool BlenderSession::print_render_stats = false; -BlenderSession::BlenderSession(BL::RenderEngine& b_engine, - BL::Preferences& b_userpref, - BL::BlendData& b_data, +BlenderSession::BlenderSession(BL::RenderEngine &b_engine, + BL::Preferences &b_userpref, + BL::BlendData &b_data, bool preview_osl) -: session(NULL), - sync(NULL), - b_engine(b_engine), - b_userpref(b_userpref), - b_data(b_data), - b_render(b_engine.render()), - b_depsgraph(PointerRNA_NULL), - b_scene(PointerRNA_NULL), - b_v3d(PointerRNA_NULL), - b_rv3d(PointerRNA_NULL), - width(0), - height(0), - preview_osl(preview_osl), - python_thread_state(NULL) + : session(NULL), + sync(NULL), + b_engine(b_engine), + b_userpref(b_userpref), + b_data(b_data), + b_render(b_engine.render()), + b_depsgraph(PointerRNA_NULL), + b_scene(PointerRNA_NULL), + b_v3d(PointerRNA_NULL), + b_rv3d(PointerRNA_NULL), + width(0), + height(0), + preview_osl(preview_osl), + python_thread_state(NULL) { - /* offline render */ - background = true; - last_redraw_time = 0.0; - start_resize_time = 0.0; - last_status_time = 0.0; + /* offline render */ + background = true; + last_redraw_time = 0.0; + start_resize_time = 0.0; + last_status_time = 0.0; } -BlenderSession::BlenderSession(BL::RenderEngine& b_engine, - BL::Preferences& b_userpref, - BL::BlendData& b_data, - BL::SpaceView3D& b_v3d, - BL::RegionView3D& b_rv3d, - int width, int height) -: session(NULL), - sync(NULL), - b_engine(b_engine), - b_userpref(b_userpref), - b_data(b_data), - b_render(b_engine.render()), - b_depsgraph(PointerRNA_NULL), - b_scene(PointerRNA_NULL), - b_v3d(b_v3d), - b_rv3d(b_rv3d), - width(width), - height(height), - preview_osl(false), - python_thread_state(NULL) +BlenderSession::BlenderSession(BL::RenderEngine &b_engine, + BL::Preferences &b_userpref, + BL::BlendData &b_data, + BL::SpaceView3D &b_v3d, + BL::RegionView3D &b_rv3d, + int width, + int height) + : session(NULL), + sync(NULL), + b_engine(b_engine), + b_userpref(b_userpref), + b_data(b_data), + b_render(b_engine.render()), + b_depsgraph(PointerRNA_NULL), + b_scene(PointerRNA_NULL), + b_v3d(b_v3d), + b_rv3d(b_rv3d), + width(width), + height(height), + preview_osl(false), + python_thread_state(NULL) { - /* 3d view render */ - background = false; - last_redraw_time = 0.0; - start_resize_time = 0.0; - last_status_time = 0.0; + /* 3d view render */ + background = false; + last_redraw_time = 0.0; + start_resize_time = 0.0; + last_status_time = 0.0; } BlenderSession::~BlenderSession() { - free_session(); + free_session(); } void BlenderSession::create() { - create_session(); + create_session(); } void BlenderSession::create_session() { - SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background); - SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); - bool session_pause = BlenderSync::get_session_pause(b_scene, background); - - /* reset status/progress */ - last_status = ""; - last_error = ""; - last_progress = -1.0f; - start_resize_time = 0.0; - - /* create session */ - session = new Session(session_params); - session->scene = scene; - session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this)); - session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this)); - session->set_pause(session_pause); - - /* create scene */ - scene = new Scene(scene_params, session->device); - scene->name = b_scene.name(); - - /* setup callbacks for builtin image support */ - scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3); - scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4, _5); - scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4, _5); - - session->scene = scene; - - /* There is no single depsgraph to use for the entire render. - * So we need to handle this differently. - * - * We could loop over the final render result render layers in pipeline and keep Cycles unaware of multiple layers, - * or perhaps move syncing further down in the pipeline. - */ - /* create sync */ - sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); - BL::Object b_camera_override(b_engine.camera_override()); - if(b_v3d) { - sync->sync_view(b_v3d, b_rv3d, width, height); - } - else { - sync->sync_camera(b_render, b_camera_override, width, height, ""); - } - - /* set buffer parameters */ - BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height); - session->reset(buffer_params, session_params.samples); - - b_engine.use_highlight_tiles(session_params.progressive_refine == false); - - update_resumable_tile_manager(session_params.samples); + SessionParams session_params = BlenderSync::get_session_params( + b_engine, b_userpref, b_scene, background); + SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); + bool session_pause = BlenderSync::get_session_pause(b_scene, background); + + /* reset status/progress */ + last_status = ""; + last_error = ""; + last_progress = -1.0f; + start_resize_time = 0.0; + + /* create session */ + session = new Session(session_params); + session->scene = scene; + session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this)); + session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this)); + session->set_pause(session_pause); + + /* create scene */ + scene = new Scene(scene_params, session->device); + scene->name = b_scene.name(); + + /* setup callbacks for builtin image support */ + scene->image_manager->builtin_image_info_cb = function_bind( + &BlenderSession::builtin_image_info, this, _1, _2, _3); + scene->image_manager->builtin_image_pixels_cb = function_bind( + &BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4, _5); + scene->image_manager->builtin_image_float_pixels_cb = function_bind( + &BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4, _5); + + session->scene = scene; + + /* There is no single depsgraph to use for the entire render. + * So we need to handle this differently. + * + * We could loop over the final render result render layers in pipeline and keep Cycles unaware of multiple layers, + * or perhaps move syncing further down in the pipeline. + */ + /* create sync */ + sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); + BL::Object b_camera_override(b_engine.camera_override()); + if (b_v3d) { + sync->sync_view(b_v3d, b_rv3d, width, height); + } + else { + sync->sync_camera(b_render, b_camera_override, width, height, ""); + } + + /* set buffer parameters */ + BufferParams buffer_params = BlenderSync::get_buffer_params( + b_render, b_v3d, b_rv3d, scene->camera, width, height); + session->reset(buffer_params, session_params.samples); + + b_engine.use_highlight_tiles(session_params.progressive_refine == false); + + update_resumable_tile_manager(session_params.samples); } -void BlenderSession::reset_session(BL::BlendData& b_data, BL::Depsgraph& b_depsgraph) +void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph) { - this->b_data = b_data; - this->b_depsgraph = b_depsgraph; - this->b_scene = b_depsgraph.scene_eval(); - - if(preview_osl) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - RNA_boolean_set(&cscene, "shading_system", preview_osl); - } - - if(b_v3d) { - this->b_render = b_scene.render(); - } - else { - this->b_render = b_engine.render(); - width = render_resolution_x(b_render); - height = render_resolution_y(b_render); - } - - if(session == NULL) { - create(); - } - - if(b_v3d) { - /* NOTE: We need to create session, but all the code from below - * will make viewport render to stuck on initialization. - */ - return; - } - - SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background); - SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); - - if(scene->params.modified(scene_params) || - session->params.modified(session_params) || - !scene_params.persistent_data) - { - /* if scene or session parameters changed, it's easier to simply re-create - * them rather than trying to distinguish which settings need to be updated - */ - free_session(); - create_session(); - return; - } - - session->progress.reset(); - scene->reset(); - - session->tile_manager.set_tile_order(session_params.tile_order); - - /* peak memory usage should show current render peak, not peak for all renders - * made by this render session - */ - session->stats.mem_peak = session->stats.mem_used; - - /* There is no single depsgraph to use for the entire render. - * See note on create_session(). - */ - /* sync object should be re-created */ - sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); - - BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL); - BL::RegionView3D b_null_region_view3d(PointerRNA_NULL); - BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, - b_null_space_view3d, - b_null_region_view3d, - scene->camera, - width, height); - session->reset(buffer_params, session_params.samples); - - b_engine.use_highlight_tiles(session_params.progressive_refine == false); - - /* reset time */ - start_resize_time = 0.0; + this->b_data = b_data; + this->b_depsgraph = b_depsgraph; + this->b_scene = b_depsgraph.scene_eval(); + + if (preview_osl) { + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + RNA_boolean_set(&cscene, "shading_system", preview_osl); + } + + if (b_v3d) { + this->b_render = b_scene.render(); + } + else { + this->b_render = b_engine.render(); + width = render_resolution_x(b_render); + height = render_resolution_y(b_render); + } + + if (session == NULL) { + create(); + } + + if (b_v3d) { + /* NOTE: We need to create session, but all the code from below + * will make viewport render to stuck on initialization. + */ + return; + } + + SessionParams session_params = BlenderSync::get_session_params( + b_engine, b_userpref, b_scene, background); + SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); + + if (scene->params.modified(scene_params) || session->params.modified(session_params) || + !scene_params.persistent_data) { + /* if scene or session parameters changed, it's easier to simply re-create + * them rather than trying to distinguish which settings need to be updated + */ + free_session(); + create_session(); + return; + } + + session->progress.reset(); + scene->reset(); + + session->tile_manager.set_tile_order(session_params.tile_order); + + /* peak memory usage should show current render peak, not peak for all renders + * made by this render session + */ + session->stats.mem_peak = session->stats.mem_used; + + /* There is no single depsgraph to use for the entire render. + * See note on create_session(). + */ + /* sync object should be re-created */ + sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); + + BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL); + BL::RegionView3D b_null_region_view3d(PointerRNA_NULL); + BufferParams buffer_params = BlenderSync::get_buffer_params( + b_render, b_null_space_view3d, b_null_region_view3d, scene->camera, width, height); + session->reset(buffer_params, session_params.samples); + + b_engine.use_highlight_tiles(session_params.progressive_refine == false); + + /* reset time */ + start_resize_time = 0.0; } void BlenderSession::free_session() { - if(sync) - delete sync; + if (sync) + delete sync; - delete session; + delete session; } -static ShaderEvalType get_shader_type(const string& pass_type) +static ShaderEvalType get_shader_type(const string &pass_type) { - const char *shader_type = pass_type.c_str(); - - /* data passes */ - if(strcmp(shader_type, "NORMAL")==0) - return SHADER_EVAL_NORMAL; - else if(strcmp(shader_type, "UV")==0) - return SHADER_EVAL_UV; - else if(strcmp(shader_type, "ROUGHNESS")==0) - return SHADER_EVAL_ROUGHNESS; - else if(strcmp(shader_type, "DIFFUSE_COLOR")==0) - return SHADER_EVAL_DIFFUSE_COLOR; - else if(strcmp(shader_type, "GLOSSY_COLOR")==0) - return SHADER_EVAL_GLOSSY_COLOR; - else if(strcmp(shader_type, "TRANSMISSION_COLOR")==0) - return SHADER_EVAL_TRANSMISSION_COLOR; - else if(strcmp(shader_type, "SUBSURFACE_COLOR")==0) - return SHADER_EVAL_SUBSURFACE_COLOR; - else if(strcmp(shader_type, "EMIT")==0) - return SHADER_EVAL_EMISSION; - - /* light passes */ - else if(strcmp(shader_type, "AO")==0) - return SHADER_EVAL_AO; - else if(strcmp(shader_type, "COMBINED")==0) - return SHADER_EVAL_COMBINED; - else if(strcmp(shader_type, "SHADOW")==0) - return SHADER_EVAL_SHADOW; - else if(strcmp(shader_type, "DIFFUSE")==0) - return SHADER_EVAL_DIFFUSE; - else if(strcmp(shader_type, "GLOSSY")==0) - return SHADER_EVAL_GLOSSY; - else if(strcmp(shader_type, "TRANSMISSION")==0) - return SHADER_EVAL_TRANSMISSION; - else if(strcmp(shader_type, "SUBSURFACE")==0) - return SHADER_EVAL_SUBSURFACE; - - /* extra */ - else if(strcmp(shader_type, "ENVIRONMENT")==0) - return SHADER_EVAL_ENVIRONMENT; - - else - return SHADER_EVAL_BAKE; + const char *shader_type = pass_type.c_str(); + + /* data passes */ + if (strcmp(shader_type, "NORMAL") == 0) + return SHADER_EVAL_NORMAL; + else if (strcmp(shader_type, "UV") == 0) + return SHADER_EVAL_UV; + else if (strcmp(shader_type, "ROUGHNESS") == 0) + return SHADER_EVAL_ROUGHNESS; + else if (strcmp(shader_type, "DIFFUSE_COLOR") == 0) + return SHADER_EVAL_DIFFUSE_COLOR; + else if (strcmp(shader_type, "GLOSSY_COLOR") == 0) + return SHADER_EVAL_GLOSSY_COLOR; + else if (strcmp(shader_type, "TRANSMISSION_COLOR") == 0) + return SHADER_EVAL_TRANSMISSION_COLOR; + else if (strcmp(shader_type, "SUBSURFACE_COLOR") == 0) + return SHADER_EVAL_SUBSURFACE_COLOR; + else if (strcmp(shader_type, "EMIT") == 0) + return SHADER_EVAL_EMISSION; + + /* light passes */ + else if (strcmp(shader_type, "AO") == 0) + return SHADER_EVAL_AO; + else if (strcmp(shader_type, "COMBINED") == 0) + return SHADER_EVAL_COMBINED; + else if (strcmp(shader_type, "SHADOW") == 0) + return SHADER_EVAL_SHADOW; + else if (strcmp(shader_type, "DIFFUSE") == 0) + return SHADER_EVAL_DIFFUSE; + else if (strcmp(shader_type, "GLOSSY") == 0) + return SHADER_EVAL_GLOSSY; + else if (strcmp(shader_type, "TRANSMISSION") == 0) + return SHADER_EVAL_TRANSMISSION; + else if (strcmp(shader_type, "SUBSURFACE") == 0) + return SHADER_EVAL_SUBSURFACE; + + /* extra */ + else if (strcmp(shader_type, "ENVIRONMENT") == 0) + return SHADER_EVAL_ENVIRONMENT; + + else + return SHADER_EVAL_BAKE; } -static BL::RenderResult begin_render_result(BL::RenderEngine& b_engine, - int x, int y, - int w, int h, +static BL::RenderResult begin_render_result(BL::RenderEngine &b_engine, + int x, + int y, + int w, + int h, const char *layername, const char *viewname) { - return b_engine.begin_result(x, y, w, h, layername, viewname); + return b_engine.begin_result(x, y, w, h, layername, viewname); } -static void end_render_result(BL::RenderEngine& b_engine, - BL::RenderResult& b_rr, +static void end_render_result(BL::RenderEngine &b_engine, + BL::RenderResult &b_rr, bool cancel, bool highlight, bool do_merge_results) { - b_engine.end_result(b_rr, (int)cancel, (int) highlight, (int)do_merge_results); + b_engine.end_result(b_rr, (int)cancel, (int)highlight, (int)do_merge_results); } -void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_update_only, bool highlight) +void BlenderSession::do_write_update_render_tile(RenderTile &rtile, + bool do_update_only, + bool highlight) { - int x = rtile.x - session->tile_manager.params.full_x; - int y = rtile.y - session->tile_manager.params.full_y; - int w = rtile.w; - int h = rtile.h; - - /* get render result */ - BL::RenderResult b_rr = begin_render_result(b_engine, x, y, w, h, b_rlay_name.c_str(), b_rview_name.c_str()); - - /* can happen if the intersected rectangle gives 0 width or height */ - if(b_rr.ptr.data == NULL) { - return; - } - - BL::RenderResult::layers_iterator b_single_rlay; - b_rr.layers.begin(b_single_rlay); - - /* layer will be missing if it was disabled in the UI */ - if(b_single_rlay == b_rr.layers.end()) - return; - - BL::RenderLayer b_rlay = *b_single_rlay; - - if(do_update_only) { - /* Sample would be zero at initial tile update, which is only needed - * to tag tile form blender side as IN PROGRESS for proper highlight - * no buffers should be sent to blender yet. For denoise we also - * keep showing the noisy buffers until denoise is done. */ - bool merge = (rtile.sample != 0) && (rtile.task != RenderTile::DENOISE); - - if(merge) { - update_render_result(b_rr, b_rlay, rtile); - } - - end_render_result(b_engine, b_rr, true, highlight, merge); - } - else { - /* Write final render result. */ - write_render_result(b_rr, b_rlay, rtile); - end_render_result(b_engine, b_rr, false, false, true); - } + int x = rtile.x - session->tile_manager.params.full_x; + int y = rtile.y - session->tile_manager.params.full_y; + int w = rtile.w; + int h = rtile.h; + + /* get render result */ + BL::RenderResult b_rr = begin_render_result( + b_engine, x, y, w, h, b_rlay_name.c_str(), b_rview_name.c_str()); + + /* can happen if the intersected rectangle gives 0 width or height */ + if (b_rr.ptr.data == NULL) { + return; + } + + BL::RenderResult::layers_iterator b_single_rlay; + b_rr.layers.begin(b_single_rlay); + + /* layer will be missing if it was disabled in the UI */ + if (b_single_rlay == b_rr.layers.end()) + return; + + BL::RenderLayer b_rlay = *b_single_rlay; + + if (do_update_only) { + /* Sample would be zero at initial tile update, which is only needed + * to tag tile form blender side as IN PROGRESS for proper highlight + * no buffers should be sent to blender yet. For denoise we also + * keep showing the noisy buffers until denoise is done. */ + bool merge = (rtile.sample != 0) && (rtile.task != RenderTile::DENOISE); + + if (merge) { + update_render_result(b_rr, b_rlay, rtile); + } + + end_render_result(b_engine, b_rr, true, highlight, merge); + } + else { + /* Write final render result. */ + write_render_result(b_rr, b_rlay, rtile); + end_render_result(b_engine, b_rr, false, false, true); + } } -void BlenderSession::write_render_tile(RenderTile& rtile) +void BlenderSession::write_render_tile(RenderTile &rtile) { - do_write_update_render_tile(rtile, false, false); + do_write_update_render_tile(rtile, false, false); } -void BlenderSession::update_render_tile(RenderTile& rtile, bool highlight) +void BlenderSession::update_render_tile(RenderTile &rtile, bool highlight) { - /* use final write for preview renders, otherwise render result wouldn't be - * be updated in blender side - * would need to be investigated a bit further, but for now shall be fine - */ - if(!b_engine.is_preview()) - do_write_update_render_tile(rtile, true, highlight); - else - do_write_update_render_tile(rtile, false, false); + /* use final write for preview renders, otherwise render result wouldn't be + * be updated in blender side + * would need to be investigated a bit further, but for now shall be fine + */ + if (!b_engine.is_preview()) + do_write_update_render_tile(rtile, true, highlight); + else + do_write_update_render_tile(rtile, false, false); } -static void add_cryptomatte_layer(BL::RenderResult& b_rr, string name, string manifest) +static void add_cryptomatte_layer(BL::RenderResult &b_rr, string name, string manifest) { - string identifier = string_printf("%08x", util_murmur_hash3(name.c_str(), name.length(), 0)); - string prefix = "cryptomatte/" + identifier.substr(0, 7) + "/"; + string identifier = string_printf("%08x", util_murmur_hash3(name.c_str(), name.length(), 0)); + string prefix = "cryptomatte/" + identifier.substr(0, 7) + "/"; - render_add_metadata(b_rr, prefix+"name", name); - render_add_metadata(b_rr, prefix+"hash", "MurmurHash3_32"); - render_add_metadata(b_rr, prefix+"conversion", "uint32_to_float32"); - render_add_metadata(b_rr, prefix+"manifest", manifest); + render_add_metadata(b_rr, prefix + "name", name); + render_add_metadata(b_rr, prefix + "hash", "MurmurHash3_32"); + render_add_metadata(b_rr, prefix + "conversion", "uint32_to_float32"); + render_add_metadata(b_rr, prefix + "manifest", manifest); } -void BlenderSession::stamp_view_layer_metadata(Scene *scene, const string& view_layer_name) +void BlenderSession::stamp_view_layer_metadata(Scene *scene, const string &view_layer_name) { - BL::RenderResult b_rr = b_engine.get_result(); - string prefix = "cycles." + view_layer_name + "."; - - /* Configured number of samples for the view layer. */ - b_rr.stamp_data_add_field( - (prefix + "samples").c_str(), - to_string(session->params.samples).c_str()); - - /* Store ranged samples information. */ - if(session->tile_manager.range_num_samples != -1) { - b_rr.stamp_data_add_field( - (prefix + "range_start_sample").c_str(), - to_string(session->tile_manager.range_start_sample).c_str()); - b_rr.stamp_data_add_field( - (prefix + "range_num_samples").c_str(), - to_string(session->tile_manager.range_num_samples).c_str()); - } - - /* Write cryptomatte metadata. */ - if(scene->film->cryptomatte_passes & CRYPT_OBJECT) { - add_cryptomatte_layer(b_rr, view_layer_name + ".CryptoObject", - scene->object_manager->get_cryptomatte_objects(scene)); - } - if(scene->film->cryptomatte_passes & CRYPT_MATERIAL) { - add_cryptomatte_layer(b_rr, view_layer_name + ".CryptoMaterial", - scene->shader_manager->get_cryptomatte_materials(scene)); - } - if(scene->film->cryptomatte_passes & CRYPT_ASSET) { - add_cryptomatte_layer(b_rr, view_layer_name + ".CryptoAsset", - scene->object_manager->get_cryptomatte_assets(scene)); - } - - /* Store synchronization and bare-render times. */ - double total_time, render_time; - session->progress.get_time(total_time, render_time); - b_rr.stamp_data_add_field((prefix + "total_time").c_str(), - time_human_readable_from_seconds(total_time).c_str()); - b_rr.stamp_data_add_field((prefix + "render_time").c_str(), - time_human_readable_from_seconds(render_time).c_str()); - b_rr.stamp_data_add_field((prefix + "synchronization_time").c_str(), - time_human_readable_from_seconds(total_time - render_time).c_str()); + BL::RenderResult b_rr = b_engine.get_result(); + string prefix = "cycles." + view_layer_name + "."; + + /* Configured number of samples for the view layer. */ + b_rr.stamp_data_add_field((prefix + "samples").c_str(), + to_string(session->params.samples).c_str()); + + /* Store ranged samples information. */ + if (session->tile_manager.range_num_samples != -1) { + b_rr.stamp_data_add_field((prefix + "range_start_sample").c_str(), + to_string(session->tile_manager.range_start_sample).c_str()); + b_rr.stamp_data_add_field((prefix + "range_num_samples").c_str(), + to_string(session->tile_manager.range_num_samples).c_str()); + } + + /* Write cryptomatte metadata. */ + if (scene->film->cryptomatte_passes & CRYPT_OBJECT) { + add_cryptomatte_layer(b_rr, + view_layer_name + ".CryptoObject", + scene->object_manager->get_cryptomatte_objects(scene)); + } + if (scene->film->cryptomatte_passes & CRYPT_MATERIAL) { + add_cryptomatte_layer(b_rr, + view_layer_name + ".CryptoMaterial", + scene->shader_manager->get_cryptomatte_materials(scene)); + } + if (scene->film->cryptomatte_passes & CRYPT_ASSET) { + add_cryptomatte_layer(b_rr, + view_layer_name + ".CryptoAsset", + scene->object_manager->get_cryptomatte_assets(scene)); + } + + /* Store synchronization and bare-render times. */ + double total_time, render_time; + session->progress.get_time(total_time, render_time); + b_rr.stamp_data_add_field((prefix + "total_time").c_str(), + time_human_readable_from_seconds(total_time).c_str()); + b_rr.stamp_data_add_field((prefix + "render_time").c_str(), + time_human_readable_from_seconds(render_time).c_str()); + b_rr.stamp_data_add_field((prefix + "synchronization_time").c_str(), + time_human_readable_from_seconds(total_time - render_time).c_str()); } -void BlenderSession::render(BL::Depsgraph& b_depsgraph_) +void BlenderSession::render(BL::Depsgraph &b_depsgraph_) { - b_depsgraph = b_depsgraph_; - - /* set callback to write out render results */ - session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1); - session->update_render_tile_cb = function_bind(&BlenderSession::update_render_tile, this, _1, _2); - - /* get buffer parameters */ - SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background); - BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height); - - /* render each layer */ - BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); - - /* temporary render result to find needed passes and views */ - BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_view_layer.name().c_str(), NULL); - BL::RenderResult::layers_iterator b_single_rlay; - b_rr.layers.begin(b_single_rlay); - BL::RenderLayer b_rlay = *b_single_rlay; - b_rlay_name = b_view_layer.name(); - - /* add passes */ - vector<Pass> passes = sync->sync_render_passes(b_rlay, b_view_layer); - buffer_params.passes = passes; - - PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles"); - bool full_denoising = get_boolean(crl, "use_denoising"); - bool write_denoising_passes = get_boolean(crl, "denoising_store_passes"); - - bool run_denoising = full_denoising || write_denoising_passes; - - session->tile_manager.schedule_denoising = run_denoising; - buffer_params.denoising_data_pass = run_denoising; - buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES); - buffer_params.denoising_prefiltered_pass = write_denoising_passes; - - session->params.run_denoising = run_denoising; - session->params.full_denoising = full_denoising; - session->params.write_denoising_passes = write_denoising_passes; - session->params.denoising.radius = get_int(crl, "denoising_radius"); - session->params.denoising.strength = get_float(crl, "denoising_strength"); - session->params.denoising.feature_strength = get_float(crl, "denoising_feature_strength"); - session->params.denoising.relative_pca = get_boolean(crl, "denoising_relative_pca"); - - scene->film->denoising_data_pass = buffer_params.denoising_data_pass; - scene->film->denoising_clean_pass = buffer_params.denoising_clean_pass; - scene->film->denoising_prefiltered_pass = buffer_params.denoising_prefiltered_pass; - - scene->film->pass_alpha_threshold = b_view_layer.pass_alpha_threshold(); - scene->film->tag_passes_update(scene, passes); - scene->film->tag_update(scene); - scene->integrator->tag_update(scene); - - BL::RenderResult::views_iterator b_view_iter; - - int num_views = 0; - for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) { - num_views++; - } - - int view_index = 0; - for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter, ++view_index) { - b_rview_name = b_view_iter->name(); - - /* set the current view */ - b_engine.active_view_set(b_rview_name.c_str()); - - /* update scene */ - BL::Object b_camera_override(b_engine.camera_override()); - sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str()); - sync->sync_data(b_render, - b_depsgraph, - b_v3d, - b_camera_override, - width, height, - &python_thread_state); - builtin_images_load(); - - /* Attempt to free all data which is held by Blender side, since at this - * point we knwo that we've got everything to render current view layer. - */ - /* At the moment we only free if we are not doing multi-view (or if we are rendering the last view). - * See T58142/D4239 for discussion. - */ - if(view_index == num_views - 1) { - free_blender_memory_if_possible(); - } - - /* Make sure all views have different noise patterns. - hardcoded value just to make it random */ - if(view_index != 0) { - scene->integrator->seed += hash_int_2d(scene->integrator->seed, hash_int(view_index * 0xdeadbeef)); - scene->integrator->tag_update(scene); - } - - /* Update number of samples per layer. */ - int samples = sync->get_layer_samples(); - bool bound_samples = sync->get_layer_bound_samples(); - int effective_layer_samples; - - if(samples != 0 && (!bound_samples || (samples < session_params.samples))) - effective_layer_samples = samples; - else - effective_layer_samples = session_params.samples; - - /* Update tile manager if we're doing resumable render. */ - update_resumable_tile_manager(effective_layer_samples); - - /* Update session itself. */ - session->reset(buffer_params, effective_layer_samples); - - /* render */ - session->start(); - session->wait(); - - if(!b_engine.is_preview() && background && print_render_stats) { - RenderStats stats; - session->collect_statistics(&stats); - printf("Render statistics:\n%s\n", stats.full_report().c_str()); - } - - if(session->progress.get_cancel()) - break; - } - - /* add metadata */ - stamp_view_layer_metadata(scene, b_rlay_name); - - /* free result without merging */ - end_render_result(b_engine, b_rr, true, true, false); - - double total_time, render_time; - session->progress.get_time(total_time, render_time); - VLOG(1) << "Total render time: " << total_time; - VLOG(1) << "Render time (without synchronization): " << render_time; - - /* clear callback */ - session->write_render_tile_cb = function_null; - session->update_render_tile_cb = function_null; - - /* TODO: find a way to clear this data for persistent data render */ + b_depsgraph = b_depsgraph_; + + /* set callback to write out render results */ + session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1); + session->update_render_tile_cb = function_bind( + &BlenderSession::update_render_tile, this, _1, _2); + + /* get buffer parameters */ + SessionParams session_params = BlenderSync::get_session_params( + b_engine, b_userpref, b_scene, background); + BufferParams buffer_params = BlenderSync::get_buffer_params( + b_render, b_v3d, b_rv3d, scene->camera, width, height); + + /* render each layer */ + BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); + + /* temporary render result to find needed passes and views */ + BL::RenderResult b_rr = begin_render_result( + b_engine, 0, 0, 1, 1, b_view_layer.name().c_str(), NULL); + BL::RenderResult::layers_iterator b_single_rlay; + b_rr.layers.begin(b_single_rlay); + BL::RenderLayer b_rlay = *b_single_rlay; + b_rlay_name = b_view_layer.name(); + + /* add passes */ + vector<Pass> passes = sync->sync_render_passes(b_rlay, b_view_layer); + buffer_params.passes = passes; + + PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles"); + bool full_denoising = get_boolean(crl, "use_denoising"); + bool write_denoising_passes = get_boolean(crl, "denoising_store_passes"); + + bool run_denoising = full_denoising || write_denoising_passes; + + session->tile_manager.schedule_denoising = run_denoising; + buffer_params.denoising_data_pass = run_denoising; + buffer_params.denoising_clean_pass = (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES); + buffer_params.denoising_prefiltered_pass = write_denoising_passes; + + session->params.run_denoising = run_denoising; + session->params.full_denoising = full_denoising; + session->params.write_denoising_passes = write_denoising_passes; + session->params.denoising.radius = get_int(crl, "denoising_radius"); + session->params.denoising.strength = get_float(crl, "denoising_strength"); + session->params.denoising.feature_strength = get_float(crl, "denoising_feature_strength"); + session->params.denoising.relative_pca = get_boolean(crl, "denoising_relative_pca"); + + scene->film->denoising_data_pass = buffer_params.denoising_data_pass; + scene->film->denoising_clean_pass = buffer_params.denoising_clean_pass; + scene->film->denoising_prefiltered_pass = buffer_params.denoising_prefiltered_pass; + + scene->film->pass_alpha_threshold = b_view_layer.pass_alpha_threshold(); + scene->film->tag_passes_update(scene, passes); + scene->film->tag_update(scene); + scene->integrator->tag_update(scene); + + BL::RenderResult::views_iterator b_view_iter; + + int num_views = 0; + for (b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) { + num_views++; + } + + int view_index = 0; + for (b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); + ++b_view_iter, ++view_index) { + b_rview_name = b_view_iter->name(); + + /* set the current view */ + b_engine.active_view_set(b_rview_name.c_str()); + + /* update scene */ + BL::Object b_camera_override(b_engine.camera_override()); + sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str()); + sync->sync_data( + b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state); + builtin_images_load(); + + /* Attempt to free all data which is held by Blender side, since at this + * point we knwo that we've got everything to render current view layer. + */ + /* At the moment we only free if we are not doing multi-view (or if we are rendering the last view). + * See T58142/D4239 for discussion. + */ + if (view_index == num_views - 1) { + free_blender_memory_if_possible(); + } + + /* Make sure all views have different noise patterns. - hardcoded value just to make it random */ + if (view_index != 0) { + scene->integrator->seed += hash_int_2d(scene->integrator->seed, + hash_int(view_index * 0xdeadbeef)); + scene->integrator->tag_update(scene); + } + + /* Update number of samples per layer. */ + int samples = sync->get_layer_samples(); + bool bound_samples = sync->get_layer_bound_samples(); + int effective_layer_samples; + + if (samples != 0 && (!bound_samples || (samples < session_params.samples))) + effective_layer_samples = samples; + else + effective_layer_samples = session_params.samples; + + /* Update tile manager if we're doing resumable render. */ + update_resumable_tile_manager(effective_layer_samples); + + /* Update session itself. */ + session->reset(buffer_params, effective_layer_samples); + + /* render */ + session->start(); + session->wait(); + + if (!b_engine.is_preview() && background && print_render_stats) { + RenderStats stats; + session->collect_statistics(&stats); + printf("Render statistics:\n%s\n", stats.full_report().c_str()); + } + + if (session->progress.get_cancel()) + break; + } + + /* add metadata */ + stamp_view_layer_metadata(scene, b_rlay_name); + + /* free result without merging */ + end_render_result(b_engine, b_rr, true, true, false); + + double total_time, render_time; + session->progress.get_time(total_time, render_time); + VLOG(1) << "Total render time: " << total_time; + VLOG(1) << "Render time (without synchronization): " << render_time; + + /* clear callback */ + session->write_render_tile_cb = function_null; + session->update_render_tile_cb = function_null; + + /* TODO: find a way to clear this data for persistent data render */ #if 0 - /* free all memory used (host and device), so we wouldn't leave render - * engine with extra memory allocated - */ + /* free all memory used (host and device), so we wouldn't leave render + * engine with extra memory allocated + */ - session->device_free(); + session->device_free(); - delete sync; - sync = NULL; + delete sync; + sync = NULL; #endif } -static void populate_bake_data(BakeData *data, const - int object_id, - BL::BakePixel& pixel_array, +static void populate_bake_data(BakeData *data, + const int object_id, + BL::BakePixel &pixel_array, const int num_pixels) { - BL::BakePixel bp = pixel_array; - - int i; - for(i = 0; i < num_pixels; i++) { - if(bp.object_id() == object_id) { - data->set(i, bp.primitive_id(), bp.uv(), bp.du_dx(), bp.du_dy(), bp.dv_dx(), bp.dv_dy()); - } else { - data->set_null(i); - } - bp = bp.next(); - } + BL::BakePixel bp = pixel_array; + + int i; + for (i = 0; i < num_pixels; i++) { + if (bp.object_id() == object_id) { + data->set(i, bp.primitive_id(), bp.uv(), bp.du_dx(), bp.du_dy(), bp.dv_dx(), bp.dv_dy()); + } + else { + data->set_null(i); + } + bp = bp.next(); + } } static int bake_pass_filter_get(const int pass_filter) { - int flag = BAKE_FILTER_NONE; - - if((pass_filter & BL::BakeSettings::pass_filter_DIRECT) != 0) - flag |= BAKE_FILTER_DIRECT; - if((pass_filter & BL::BakeSettings::pass_filter_INDIRECT) != 0) - flag |= BAKE_FILTER_INDIRECT; - if((pass_filter & BL::BakeSettings::pass_filter_COLOR) != 0) - flag |= BAKE_FILTER_COLOR; - - if((pass_filter & BL::BakeSettings::pass_filter_DIFFUSE) != 0) - flag |= BAKE_FILTER_DIFFUSE; - if((pass_filter & BL::BakeSettings::pass_filter_GLOSSY) != 0) - flag |= BAKE_FILTER_GLOSSY; - if((pass_filter & BL::BakeSettings::pass_filter_TRANSMISSION) != 0) - flag |= BAKE_FILTER_TRANSMISSION; - if((pass_filter & BL::BakeSettings::pass_filter_SUBSURFACE) != 0) - flag |= BAKE_FILTER_SUBSURFACE; - - if((pass_filter & BL::BakeSettings::pass_filter_EMIT) != 0) - flag |= BAKE_FILTER_EMISSION; - if((pass_filter & BL::BakeSettings::pass_filter_AO) != 0) - flag |= BAKE_FILTER_AO; - - return flag; + int flag = BAKE_FILTER_NONE; + + if ((pass_filter & BL::BakeSettings::pass_filter_DIRECT) != 0) + flag |= BAKE_FILTER_DIRECT; + if ((pass_filter & BL::BakeSettings::pass_filter_INDIRECT) != 0) + flag |= BAKE_FILTER_INDIRECT; + if ((pass_filter & BL::BakeSettings::pass_filter_COLOR) != 0) + flag |= BAKE_FILTER_COLOR; + + if ((pass_filter & BL::BakeSettings::pass_filter_DIFFUSE) != 0) + flag |= BAKE_FILTER_DIFFUSE; + if ((pass_filter & BL::BakeSettings::pass_filter_GLOSSY) != 0) + flag |= BAKE_FILTER_GLOSSY; + if ((pass_filter & BL::BakeSettings::pass_filter_TRANSMISSION) != 0) + flag |= BAKE_FILTER_TRANSMISSION; + if ((pass_filter & BL::BakeSettings::pass_filter_SUBSURFACE) != 0) + flag |= BAKE_FILTER_SUBSURFACE; + + if ((pass_filter & BL::BakeSettings::pass_filter_EMIT) != 0) + flag |= BAKE_FILTER_EMISSION; + if ((pass_filter & BL::BakeSettings::pass_filter_AO) != 0) + flag |= BAKE_FILTER_AO; + + return flag; } -void BlenderSession::bake(BL::Depsgraph& b_depsgraph_, - BL::Object& b_object, - const string& pass_type, +void BlenderSession::bake(BL::Depsgraph &b_depsgraph_, + BL::Object &b_object, + const string &pass_type, const int pass_filter, const int object_id, - BL::BakePixel& pixel_array, + BL::BakePixel &pixel_array, const size_t num_pixels, const int /*depth*/, float result[]) { - b_depsgraph = b_depsgraph_; - - ShaderEvalType shader_type = get_shader_type(pass_type); - - /* Set baking flag in advance, so kernel loading can check if we need - * any baking capabilities. - */ - scene->bake_manager->set_baking(true); - - /* ensure kernels are loaded before we do any scene updates */ - session->load_kernels(); - - if(shader_type == SHADER_EVAL_UV) { - /* force UV to be available */ - Pass::add(PASS_UV, scene->film->passes); - } - - int bake_pass_filter = bake_pass_filter_get(pass_filter); - bake_pass_filter = BakeManager::shader_type_to_pass_filter(shader_type, bake_pass_filter); - - /* force use_light_pass to be true if we bake more than just colors */ - if(bake_pass_filter & ~BAKE_FILTER_COLOR) { - Pass::add(PASS_LIGHT, scene->film->passes); - } - - /* create device and update scene */ - scene->film->tag_update(scene); - scene->integrator->tag_update(scene); - - if(!session->progress.get_cancel()) { - /* update scene */ - BL::Object b_camera_override(b_engine.camera_override()); - sync->sync_camera(b_render, b_camera_override, width, height, ""); - sync->sync_data(b_render, - b_depsgraph, - b_v3d, - b_camera_override, - width, height, - &python_thread_state); - builtin_images_load(); - } - - BakeData *bake_data = NULL; - - if(!session->progress.get_cancel()) { - /* get buffer parameters */ - SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background); - BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height); - - scene->bake_manager->set_shader_limit((size_t)b_engine.tile_x(), (size_t)b_engine.tile_y()); - - /* set number of samples */ - session->tile_manager.set_samples(session_params.samples); - session->reset(buffer_params, session_params.samples); - session->update_scene(); - - /* find object index. todo: is arbitrary - copied from mesh_displace.cpp */ - size_t object_index = OBJECT_NONE; - int tri_offset = 0; - - for(size_t i = 0; i < scene->objects.size(); i++) { - if(strcmp(scene->objects[i]->name.c_str(), b_object.name().c_str()) == 0) { - object_index = i; - tri_offset = scene->objects[i]->mesh->tri_offset; - break; - } - } - - /* Object might have been disabled for rendering or excluded in some - * other way, in that case Blender will report a warning afterwards. */ - if (object_index != OBJECT_NONE) { - int object = object_index; - - bake_data = scene->bake_manager->init(object, tri_offset, num_pixels); - populate_bake_data(bake_data, object_id, pixel_array, num_pixels); - } - - /* set number of samples */ - session->tile_manager.set_samples(session_params.samples); - session->reset(buffer_params, session_params.samples); - session->update_scene(); - - session->progress.set_update_callback(function_bind(&BlenderSession::update_bake_progress, this)); - } - - /* Perform bake. Check cancel to avoid crash with incomplete scene data. */ - if(!session->progress.get_cancel() && bake_data) { - scene->bake_manager->bake(scene->device, &scene->dscene, scene, session->progress, shader_type, bake_pass_filter, bake_data, result); - } - - /* free all memory used (host and device), so we wouldn't leave render - * engine with extra memory allocated - */ - - session->device_free(); - - delete sync; - sync = NULL; + b_depsgraph = b_depsgraph_; + + ShaderEvalType shader_type = get_shader_type(pass_type); + + /* Set baking flag in advance, so kernel loading can check if we need + * any baking capabilities. + */ + scene->bake_manager->set_baking(true); + + /* ensure kernels are loaded before we do any scene updates */ + session->load_kernels(); + + if (shader_type == SHADER_EVAL_UV) { + /* force UV to be available */ + Pass::add(PASS_UV, scene->film->passes); + } + + int bake_pass_filter = bake_pass_filter_get(pass_filter); + bake_pass_filter = BakeManager::shader_type_to_pass_filter(shader_type, bake_pass_filter); + + /* force use_light_pass to be true if we bake more than just colors */ + if (bake_pass_filter & ~BAKE_FILTER_COLOR) { + Pass::add(PASS_LIGHT, scene->film->passes); + } + + /* create device and update scene */ + scene->film->tag_update(scene); + scene->integrator->tag_update(scene); + + if (!session->progress.get_cancel()) { + /* update scene */ + BL::Object b_camera_override(b_engine.camera_override()); + sync->sync_camera(b_render, b_camera_override, width, height, ""); + sync->sync_data( + b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state); + builtin_images_load(); + } + + BakeData *bake_data = NULL; + + if (!session->progress.get_cancel()) { + /* get buffer parameters */ + SessionParams session_params = BlenderSync::get_session_params( + b_engine, b_userpref, b_scene, background); + BufferParams buffer_params = BlenderSync::get_buffer_params( + b_render, b_v3d, b_rv3d, scene->camera, width, height); + + scene->bake_manager->set_shader_limit((size_t)b_engine.tile_x(), (size_t)b_engine.tile_y()); + + /* set number of samples */ + session->tile_manager.set_samples(session_params.samples); + session->reset(buffer_params, session_params.samples); + session->update_scene(); + + /* find object index. todo: is arbitrary - copied from mesh_displace.cpp */ + size_t object_index = OBJECT_NONE; + int tri_offset = 0; + + for (size_t i = 0; i < scene->objects.size(); i++) { + if (strcmp(scene->objects[i]->name.c_str(), b_object.name().c_str()) == 0) { + object_index = i; + tri_offset = scene->objects[i]->mesh->tri_offset; + break; + } + } + + /* Object might have been disabled for rendering or excluded in some + * other way, in that case Blender will report a warning afterwards. */ + if (object_index != OBJECT_NONE) { + int object = object_index; + + bake_data = scene->bake_manager->init(object, tri_offset, num_pixels); + populate_bake_data(bake_data, object_id, pixel_array, num_pixels); + } + + /* set number of samples */ + session->tile_manager.set_samples(session_params.samples); + session->reset(buffer_params, session_params.samples); + session->update_scene(); + + session->progress.set_update_callback( + function_bind(&BlenderSession::update_bake_progress, this)); + } + + /* Perform bake. Check cancel to avoid crash with incomplete scene data. */ + if (!session->progress.get_cancel() && bake_data) { + scene->bake_manager->bake(scene->device, + &scene->dscene, + scene, + session->progress, + shader_type, + bake_pass_filter, + bake_data, + result); + } + + /* free all memory used (host and device), so we wouldn't leave render + * engine with extra memory allocated + */ + + session->device_free(); + + delete sync; + sync = NULL; } -void BlenderSession::do_write_update_render_result(BL::RenderResult& b_rr, - BL::RenderLayer& b_rlay, - RenderTile& rtile, +void BlenderSession::do_write_update_render_result(BL::RenderResult &b_rr, + BL::RenderLayer &b_rlay, + RenderTile &rtile, bool do_update_only) { - RenderBuffers *buffers = rtile.buffers; - - /* copy data from device */ - if(!buffers->copy_from_device()) - return; - - float exposure = scene->film->exposure; - - vector<float> pixels(rtile.w*rtile.h*4); - - /* Adjust absolute sample number to the range. */ - int sample = rtile.sample; - const int range_start_sample = session->tile_manager.range_start_sample; - if(range_start_sample != -1) { - sample -= range_start_sample; - } - - if(!do_update_only) { - /* copy each pass */ - BL::RenderLayer::passes_iterator b_iter; - - for(b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) { - BL::RenderPass b_pass(*b_iter); - - /* find matching pass type */ - PassType pass_type = BlenderSync::get_pass_type(b_pass); - int components = b_pass.channels(); - - bool read = false; - if(pass_type != PASS_NONE) { - /* copy pixels */ - read = buffers->get_pass_rect(pass_type, exposure, sample, components, &pixels[0], b_pass.name()); - } - else { - int denoising_offset = BlenderSync::get_denoising_pass(b_pass); - if(denoising_offset >= 0) { - read = buffers->get_denoising_pass_rect(denoising_offset, exposure, sample, components, &pixels[0]); - } - } - - if(!read) { - memset(&pixels[0], 0, pixels.size()*sizeof(float)); - } - - b_pass.rect(&pixels[0]); - } - } - else { - /* copy combined pass */ - BL::RenderPass b_combined_pass(b_rlay.passes.find_by_name("Combined", b_rview_name.c_str())); - if(buffers->get_pass_rect(PASS_COMBINED, exposure, sample, 4, &pixels[0], "Combined")) - b_combined_pass.rect(&pixels[0]); - } - - /* tag result as updated */ - b_engine.update_result(b_rr); + RenderBuffers *buffers = rtile.buffers; + + /* copy data from device */ + if (!buffers->copy_from_device()) + return; + + float exposure = scene->film->exposure; + + vector<float> pixels(rtile.w * rtile.h * 4); + + /* Adjust absolute sample number to the range. */ + int sample = rtile.sample; + const int range_start_sample = session->tile_manager.range_start_sample; + if (range_start_sample != -1) { + sample -= range_start_sample; + } + + if (!do_update_only) { + /* copy each pass */ + BL::RenderLayer::passes_iterator b_iter; + + for (b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) { + BL::RenderPass b_pass(*b_iter); + + /* find matching pass type */ + PassType pass_type = BlenderSync::get_pass_type(b_pass); + int components = b_pass.channels(); + + bool read = false; + if (pass_type != PASS_NONE) { + /* copy pixels */ + read = buffers->get_pass_rect( + pass_type, exposure, sample, components, &pixels[0], b_pass.name()); + } + else { + int denoising_offset = BlenderSync::get_denoising_pass(b_pass); + if (denoising_offset >= 0) { + read = buffers->get_denoising_pass_rect( + denoising_offset, exposure, sample, components, &pixels[0]); + } + } + + if (!read) { + memset(&pixels[0], 0, pixels.size() * sizeof(float)); + } + + b_pass.rect(&pixels[0]); + } + } + else { + /* copy combined pass */ + BL::RenderPass b_combined_pass(b_rlay.passes.find_by_name("Combined", b_rview_name.c_str())); + if (buffers->get_pass_rect(PASS_COMBINED, exposure, sample, 4, &pixels[0], "Combined")) + b_combined_pass.rect(&pixels[0]); + } + + /* tag result as updated */ + b_engine.update_result(b_rr); } -void BlenderSession::write_render_result(BL::RenderResult& b_rr, - BL::RenderLayer& b_rlay, - RenderTile& rtile) +void BlenderSession::write_render_result(BL::RenderResult &b_rr, + BL::RenderLayer &b_rlay, + RenderTile &rtile) { - do_write_update_render_result(b_rr, b_rlay, rtile, false); + do_write_update_render_result(b_rr, b_rlay, rtile, false); } -void BlenderSession::update_render_result(BL::RenderResult& b_rr, - BL::RenderLayer& b_rlay, - RenderTile& rtile) +void BlenderSession::update_render_result(BL::RenderResult &b_rr, + BL::RenderLayer &b_rlay, + RenderTile &rtile) { - do_write_update_render_result(b_rr, b_rlay, rtile, true); + do_write_update_render_result(b_rr, b_rlay, rtile, true); } -void BlenderSession::synchronize(BL::Depsgraph& b_depsgraph_) +void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_) { - /* only used for viewport render */ - if(!b_v3d) - return; - - /* on session/scene parameter changes, we recreate session entirely */ - SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background); - SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); - bool session_pause = BlenderSync::get_session_pause(b_scene, background); - - if(session->params.modified(session_params) || - scene->params.modified(scene_params)) - { - free_session(); - create_session(); - return; - } - - /* increase samples, but never decrease */ - session->set_samples(session_params.samples); - session->set_pause(session_pause); - - /* copy recalc flags, outside of mutex so we can decide to do the real - * synchronization at a later time to not block on running updates */ - sync->sync_recalc(b_depsgraph_); - - /* don't do synchronization if on pause */ - if(session_pause) { - tag_update(); - return; - } - - /* try to acquire mutex. if we don't want to or can't, come back later */ - if(!session->ready_to_reset() || !session->scene->mutex.try_lock()) { - tag_update(); - return; - } - - /* data and camera synchronize */ - b_depsgraph = b_depsgraph_; - - BL::Object b_camera_override(b_engine.camera_override()); - sync->sync_data(b_render, - b_depsgraph, - b_v3d, - b_camera_override, - width, height, - &python_thread_state); - - if(b_rv3d) - sync->sync_view(b_v3d, b_rv3d, width, height); - else - sync->sync_camera(b_render, b_camera_override, width, height, ""); - - builtin_images_load(); - - /* unlock */ - session->scene->mutex.unlock(); - - /* reset if needed */ - if(scene->need_reset()) { - BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height); - session->reset(buffer_params, session_params.samples); - - /* reset time */ - start_resize_time = 0.0; - } - - /* Start rendering thread, if it's not running already. Do this - * after all scene data has been synced at least once. */ - session->start(); + /* only used for viewport render */ + if (!b_v3d) + return; + + /* on session/scene parameter changes, we recreate session entirely */ + SessionParams session_params = BlenderSync::get_session_params( + b_engine, b_userpref, b_scene, background); + SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); + bool session_pause = BlenderSync::get_session_pause(b_scene, background); + + if (session->params.modified(session_params) || scene->params.modified(scene_params)) { + free_session(); + create_session(); + return; + } + + /* increase samples, but never decrease */ + session->set_samples(session_params.samples); + session->set_pause(session_pause); + + /* copy recalc flags, outside of mutex so we can decide to do the real + * synchronization at a later time to not block on running updates */ + sync->sync_recalc(b_depsgraph_); + + /* don't do synchronization if on pause */ + if (session_pause) { + tag_update(); + return; + } + + /* try to acquire mutex. if we don't want to or can't, come back later */ + if (!session->ready_to_reset() || !session->scene->mutex.try_lock()) { + tag_update(); + return; + } + + /* data and camera synchronize */ + b_depsgraph = b_depsgraph_; + + BL::Object b_camera_override(b_engine.camera_override()); + sync->sync_data( + b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state); + + if (b_rv3d) + sync->sync_view(b_v3d, b_rv3d, width, height); + else + sync->sync_camera(b_render, b_camera_override, width, height, ""); + + builtin_images_load(); + + /* unlock */ + session->scene->mutex.unlock(); + + /* reset if needed */ + if (scene->need_reset()) { + BufferParams buffer_params = BlenderSync::get_buffer_params( + b_render, b_v3d, b_rv3d, scene->camera, width, height); + session->reset(buffer_params, session_params.samples); + + /* reset time */ + start_resize_time = 0.0; + } + + /* Start rendering thread, if it's not running already. Do this + * after all scene data has been synced at least once. */ + session->start(); } bool BlenderSession::draw(int w, int h) { - /* pause in redraw in case update is not being called due to final render */ - session->set_pause(BlenderSync::get_session_pause(b_scene, background)); - - /* before drawing, we verify camera and viewport size changes, because - * we do not get update callbacks for those, we must detect them here */ - if(session->ready_to_reset()) { - bool reset = false; - - /* if dimensions changed, reset */ - if(width != w || height != h) { - if(start_resize_time == 0.0) { - /* don't react immediately to resizes to avoid flickery resizing - * of the viewport, and some window managers changing the window - * size temporarily on unminimize */ - start_resize_time = time_dt(); - tag_redraw(); - } - else if(time_dt() - start_resize_time < 0.2) { - tag_redraw(); - } - else { - width = w; - height = h; - reset = true; - } - } - - /* try to acquire mutex. if we can't, come back later */ - if(!session->scene->mutex.try_lock()) { - tag_update(); - } - else { - /* update camera from 3d view */ - - sync->sync_view(b_v3d, b_rv3d, width, height); - - if(scene->camera->need_update) - reset = true; - - session->scene->mutex.unlock(); - } - - /* reset if requested */ - if(reset) { - SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background); - BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height); - bool session_pause = BlenderSync::get_session_pause(b_scene, background); - - if(session_pause == false) { - session->reset(buffer_params, session_params.samples); - start_resize_time = 0.0; - } - } - } - else { - tag_update(); - } - - /* update status and progress for 3d view draw */ - update_status_progress(); - - /* draw */ - BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height); - DeviceDrawParams draw_params; - - if(session->params.display_buffer_linear) { - draw_params.bind_display_space_shader_cb = function_bind(&BL::RenderEngine::bind_display_space_shader, &b_engine, b_scene); - draw_params.unbind_display_space_shader_cb = function_bind(&BL::RenderEngine::unbind_display_space_shader, &b_engine); - } - - return !session->draw(buffer_params, draw_params); + /* pause in redraw in case update is not being called due to final render */ + session->set_pause(BlenderSync::get_session_pause(b_scene, background)); + + /* before drawing, we verify camera and viewport size changes, because + * we do not get update callbacks for those, we must detect them here */ + if (session->ready_to_reset()) { + bool reset = false; + + /* if dimensions changed, reset */ + if (width != w || height != h) { + if (start_resize_time == 0.0) { + /* don't react immediately to resizes to avoid flickery resizing + * of the viewport, and some window managers changing the window + * size temporarily on unminimize */ + start_resize_time = time_dt(); + tag_redraw(); + } + else if (time_dt() - start_resize_time < 0.2) { + tag_redraw(); + } + else { + width = w; + height = h; + reset = true; + } + } + + /* try to acquire mutex. if we can't, come back later */ + if (!session->scene->mutex.try_lock()) { + tag_update(); + } + else { + /* update camera from 3d view */ + + sync->sync_view(b_v3d, b_rv3d, width, height); + + if (scene->camera->need_update) + reset = true; + + session->scene->mutex.unlock(); + } + + /* reset if requested */ + if (reset) { + SessionParams session_params = BlenderSync::get_session_params( + b_engine, b_userpref, b_scene, background); + BufferParams buffer_params = BlenderSync::get_buffer_params( + b_render, b_v3d, b_rv3d, scene->camera, width, height); + bool session_pause = BlenderSync::get_session_pause(b_scene, background); + + if (session_pause == false) { + session->reset(buffer_params, session_params.samples); + start_resize_time = 0.0; + } + } + } + else { + tag_update(); + } + + /* update status and progress for 3d view draw */ + update_status_progress(); + + /* draw */ + BufferParams buffer_params = BlenderSync::get_buffer_params( + b_render, b_v3d, b_rv3d, scene->camera, width, height); + DeviceDrawParams draw_params; + + if (session->params.display_buffer_linear) { + draw_params.bind_display_space_shader_cb = function_bind( + &BL::RenderEngine::bind_display_space_shader, &b_engine, b_scene); + draw_params.unbind_display_space_shader_cb = function_bind( + &BL::RenderEngine::unbind_display_space_shader, &b_engine); + } + + return !session->draw(buffer_params, draw_params); } -void BlenderSession::get_status(string& status, string& substatus) +void BlenderSession::get_status(string &status, string &substatus) { - session->progress.get_status(status, substatus); + session->progress.get_status(status, substatus); } -void BlenderSession::get_kernel_status(string& kernel_status) +void BlenderSession::get_kernel_status(string &kernel_status) { - session->progress.get_kernel_status(kernel_status); + session->progress.get_kernel_status(kernel_status); } -void BlenderSession::get_progress(float& progress, double& total_time, double& render_time) +void BlenderSession::get_progress(float &progress, double &total_time, double &render_time) { - session->progress.get_time(total_time, render_time); - progress = session->progress.get_progress(); + session->progress.get_time(total_time, render_time); + progress = session->progress.get_progress(); } void BlenderSession::update_bake_progress() { - float progress = session->progress.get_progress(); + float progress = session->progress.get_progress(); - if(progress != last_progress) { - b_engine.update_progress(progress); - last_progress = progress; - } + if (progress != last_progress) { + b_engine.update_progress(progress); + last_progress = progress; + } } void BlenderSession::update_status_progress() { - string timestatus, status, substatus, kernel_status; - string scene_status = ""; - float progress; - double total_time, remaining_time = 0, render_time; - float mem_used = (float)session->stats.mem_used / 1024.0f / 1024.0f; - float mem_peak = (float)session->stats.mem_peak / 1024.0f / 1024.0f; - - get_status(status, substatus); - get_kernel_status(kernel_status); - get_progress(progress, total_time, render_time); - - if(progress > 0) - remaining_time = (1.0 - (double)progress) * (render_time / (double)progress); - - if(background) { - scene_status += " | " + scene->name; - if(b_rlay_name != "") - scene_status += ", " + b_rlay_name; - - if(b_rview_name != "") - scene_status += ", " + b_rview_name; - - if(remaining_time > 0) { - timestatus += "Remaining:" + time_human_readable_from_seconds(remaining_time) + " | "; - } - - timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", (double)mem_used, (double)mem_peak); - - if(status.size() > 0) - status = " | " + status; - if(substatus.size() > 0) - status += " | " + substatus; - if(kernel_status.size() > 0) - status += " | " + kernel_status; - } - - double current_time = time_dt(); - /* When rendering in a window, redraw the status at least once per second to keep the elapsed and remaining time up-to-date. - * For headless rendering, only report when something significant changes to keep the console output readable. */ - if(status != last_status || (!headless && (current_time - last_status_time) > 1.0)) { - b_engine.update_stats("", (timestatus + scene_status + status).c_str()); - b_engine.update_memory_stats(mem_used, mem_peak); - last_status = status; - last_status_time = current_time; - } - if(progress != last_progress) { - b_engine.update_progress(progress); - last_progress = progress; - } - - if(session->progress.get_error()) { - string error = session->progress.get_error_message(); - if(error != last_error) { - /* TODO(sergey): Currently C++ RNA API doesn't let us to - * use mnemonic name for the variable. Would be nice to - * have this figured out. - * - * For until then, 1 << 5 means RPT_ERROR. - */ - b_engine.report(1 << 5, error.c_str()); - b_engine.error_set(error.c_str()); - last_error = error; - } - } + string timestatus, status, substatus, kernel_status; + string scene_status = ""; + float progress; + double total_time, remaining_time = 0, render_time; + float mem_used = (float)session->stats.mem_used / 1024.0f / 1024.0f; + float mem_peak = (float)session->stats.mem_peak / 1024.0f / 1024.0f; + + get_status(status, substatus); + get_kernel_status(kernel_status); + get_progress(progress, total_time, render_time); + + if (progress > 0) + remaining_time = (1.0 - (double)progress) * (render_time / (double)progress); + + if (background) { + scene_status += " | " + scene->name; + if (b_rlay_name != "") + scene_status += ", " + b_rlay_name; + + if (b_rview_name != "") + scene_status += ", " + b_rview_name; + + if (remaining_time > 0) { + timestatus += "Remaining:" + time_human_readable_from_seconds(remaining_time) + " | "; + } + + timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", (double)mem_used, (double)mem_peak); + + if (status.size() > 0) + status = " | " + status; + if (substatus.size() > 0) + status += " | " + substatus; + if (kernel_status.size() > 0) + status += " | " + kernel_status; + } + + double current_time = time_dt(); + /* When rendering in a window, redraw the status at least once per second to keep the elapsed and remaining time up-to-date. + * For headless rendering, only report when something significant changes to keep the console output readable. */ + if (status != last_status || (!headless && (current_time - last_status_time) > 1.0)) { + b_engine.update_stats("", (timestatus + scene_status + status).c_str()); + b_engine.update_memory_stats(mem_used, mem_peak); + last_status = status; + last_status_time = current_time; + } + if (progress != last_progress) { + b_engine.update_progress(progress); + last_progress = progress; + } + + if (session->progress.get_error()) { + string error = session->progress.get_error_message(); + if (error != last_error) { + /* TODO(sergey): Currently C++ RNA API doesn't let us to + * use mnemonic name for the variable. Would be nice to + * have this figured out. + * + * For until then, 1 << 5 means RPT_ERROR. + */ + b_engine.report(1 << 5, error.c_str()); + b_engine.error_set(error.c_str()); + last_error = error; + } + } } void BlenderSession::tag_update() { - /* tell blender that we want to get another update callback */ - b_engine.tag_update(); + /* tell blender that we want to get another update callback */ + b_engine.tag_update(); } void BlenderSession::tag_redraw() { - if(background) { - /* update stats and progress, only for background here because - * in 3d view we do it in draw for thread safety reasons */ - update_status_progress(); - - /* offline render, redraw if timeout passed */ - if(time_dt() - last_redraw_time > 1.0) { - b_engine.tag_redraw(); - last_redraw_time = time_dt(); - } - } - else { - /* tell blender that we want to redraw */ - b_engine.tag_redraw(); - } + if (background) { + /* update stats and progress, only for background here because + * in 3d view we do it in draw for thread safety reasons */ + update_status_progress(); + + /* offline render, redraw if timeout passed */ + if (time_dt() - last_redraw_time > 1.0) { + b_engine.tag_redraw(); + last_redraw_time = time_dt(); + } + } + else { + /* tell blender that we want to redraw */ + b_engine.tag_redraw(); + } } void BlenderSession::test_cancel() { - /* test if we need to cancel rendering */ - if(background) - if(b_engine.test_break()) - session->progress.set_cancel("Cancelled"); + /* test if we need to cancel rendering */ + if (background) + if (b_engine.test_break()) + session->progress.set_cancel("Cancelled"); } /* builtin image file name is actually an image datablock name with @@ -1107,89 +1126,88 @@ void BlenderSession::test_cancel() */ int BlenderSession::builtin_image_frame(const string &builtin_name) { - int last = builtin_name.find_last_of('@'); - return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str()); + int last = builtin_name.find_last_of('@'); + return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str()); } void BlenderSession::builtin_image_info(const string &builtin_name, void *builtin_data, - ImageMetaData& metadata) + ImageMetaData &metadata) { - /* empty image */ - metadata.width = 1; - metadata.height = 1; - - if(!builtin_data) - return; - - /* recover ID pointer */ - PointerRNA ptr; - RNA_id_pointer_create((ID*)builtin_data, &ptr); - BL::ID b_id(ptr); - - if(b_id.is_a(&RNA_Image)) { - /* image data */ - BL::Image b_image(b_id); - - metadata.builtin_free_cache = !b_image.has_data(); - metadata.is_float = b_image.is_float(); - metadata.width = b_image.size()[0]; - metadata.height = b_image.size()[1]; - metadata.depth = 1; - metadata.channels = b_image.channels(); - } - else if(b_id.is_a(&RNA_Object)) { - /* smoke volume data */ - BL::Object b_ob(b_id); - BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob); - - metadata.is_float = true; - metadata.depth = 1; - metadata.channels = 1; - - if(!b_domain) - return; - - if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) - metadata.channels = 1; - else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) - metadata.channels = 4; - else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) - metadata.channels = 3; - else - return; - - int3 resolution = get_int3(b_domain.domain_resolution()); - int amplify = (b_domain.use_high_resolution())? b_domain.amplify() + 1: 1; - - /* Velocity and heat data is always low-resolution. */ - if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) - { - amplify = 1; - } - - metadata.width = resolution.x * amplify; - metadata.height = resolution.y * amplify; - metadata.depth = resolution.z * amplify; - } - else { - /* TODO(sergey): Check we're indeed in shader node tree. */ - PointerRNA ptr; - RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr); - BL::Node b_node(ptr); - if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) { - BL::ShaderNodeTexPointDensity b_point_density_node(b_node); - metadata.channels = 4; - metadata.width = b_point_density_node.resolution(); - metadata.height = metadata.width; - metadata.depth = metadata.width; - metadata.is_float = true; - } - } + /* empty image */ + metadata.width = 1; + metadata.height = 1; + + if (!builtin_data) + return; + + /* recover ID pointer */ + PointerRNA ptr; + RNA_id_pointer_create((ID *)builtin_data, &ptr); + BL::ID b_id(ptr); + + if (b_id.is_a(&RNA_Image)) { + /* image data */ + BL::Image b_image(b_id); + + metadata.builtin_free_cache = !b_image.has_data(); + metadata.is_float = b_image.is_float(); + metadata.width = b_image.size()[0]; + metadata.height = b_image.size()[1]; + metadata.depth = 1; + metadata.channels = b_image.channels(); + } + else if (b_id.is_a(&RNA_Object)) { + /* smoke volume data */ + BL::Object b_ob(b_id); + BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob); + + metadata.is_float = true; + metadata.depth = 1; + metadata.channels = 1; + + if (!b_domain) + return; + + if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY) || + builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME) || + builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT) || + builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) + metadata.channels = 1; + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) + metadata.channels = 4; + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) + metadata.channels = 3; + else + return; + + int3 resolution = get_int3(b_domain.domain_resolution()); + int amplify = (b_domain.use_high_resolution()) ? b_domain.amplify() + 1 : 1; + + /* Velocity and heat data is always low-resolution. */ + if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) || + builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { + amplify = 1; + } + + metadata.width = resolution.x * amplify; + metadata.height = resolution.y * amplify; + metadata.depth = resolution.z * amplify; + } + else { + /* TODO(sergey): Check we're indeed in shader node tree. */ + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr); + BL::Node b_node(ptr); + if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) { + BL::ShaderNodeTexPointDensity b_point_density_node(b_node); + metadata.channels = 4; + metadata.width = b_point_density_node.resolution(); + metadata.height = metadata.width; + metadata.depth = metadata.width; + metadata.is_float = true; + } + } } bool BlenderSession::builtin_image_pixels(const string &builtin_name, @@ -1198,61 +1216,61 @@ bool BlenderSession::builtin_image_pixels(const string &builtin_name, const size_t pixels_size, const bool free_cache) { - if(!builtin_data) { - return false; - } - - const int frame = builtin_image_frame(builtin_name); - - PointerRNA ptr; - RNA_id_pointer_create((ID*)builtin_data, &ptr); - BL::Image b_image(ptr); - - const int width = b_image.size()[0]; - const int height = b_image.size()[1]; - const int channels = b_image.channels(); - - unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame); - const size_t num_pixels = ((size_t)width) * height; - - if(image_pixels && num_pixels * channels == pixels_size) { - memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char)); - } - else { - if(channels == 1) { - memset(pixels, 0, pixels_size * sizeof(unsigned char)); - } - else { - const size_t num_pixels_safe = pixels_size / channels; - unsigned char *cp = pixels; - for(size_t i = 0; i < num_pixels_safe; i++, cp += channels) { - cp[0] = 255; - cp[1] = 0; - cp[2] = 255; - if(channels == 4) { - cp[3] = 255; - } - } - } - } - - if(image_pixels) { - MEM_freeN(image_pixels); - } - - /* Free image buffers to save memory during render. */ - if(free_cache) { - b_image.buffers_free(); - } - - /* Premultiply, byte images are always straight for Blender. */ - unsigned char *cp = pixels; - for(size_t i = 0; i < num_pixels; i++, cp += channels) { - cp[0] = (cp[0] * cp[3]) >> 8; - cp[1] = (cp[1] * cp[3]) >> 8; - cp[2] = (cp[2] * cp[3]) >> 8; - } - return true; + if (!builtin_data) { + return false; + } + + const int frame = builtin_image_frame(builtin_name); + + PointerRNA ptr; + RNA_id_pointer_create((ID *)builtin_data, &ptr); + BL::Image b_image(ptr); + + const int width = b_image.size()[0]; + const int height = b_image.size()[1]; + const int channels = b_image.channels(); + + unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame); + const size_t num_pixels = ((size_t)width) * height; + + if (image_pixels && num_pixels * channels == pixels_size) { + memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char)); + } + else { + if (channels == 1) { + memset(pixels, 0, pixels_size * sizeof(unsigned char)); + } + else { + const size_t num_pixels_safe = pixels_size / channels; + unsigned char *cp = pixels; + for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) { + cp[0] = 255; + cp[1] = 0; + cp[2] = 255; + if (channels == 4) { + cp[3] = 255; + } + } + } + } + + if (image_pixels) { + MEM_freeN(image_pixels); + } + + /* Free image buffers to save memory during render. */ + if (free_cache) { + b_image.buffers_free(); + } + + /* Premultiply, byte images are always straight for Blender. */ + unsigned char *cp = pixels; + for (size_t i = 0; i < num_pixels; i++, cp += channels) { + cp[0] = (cp[0] * cp[3]) >> 8; + cp[1] = (cp[1] * cp[3]) >> 8; + cp[2] = (cp[2] * cp[3]) >> 8; + } + return true; } bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, @@ -1261,225 +1279,225 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, const size_t pixels_size, const bool free_cache) { - if(!builtin_data) { - return false; - } - - PointerRNA ptr; - RNA_id_pointer_create((ID*)builtin_data, &ptr); - BL::ID b_id(ptr); - - if(b_id.is_a(&RNA_Image)) { - /* image data */ - BL::Image b_image(b_id); - int frame = builtin_image_frame(builtin_name); - - const int width = b_image.size()[0]; - const int height = b_image.size()[1]; - const int channels = b_image.channels(); - - float *image_pixels; - image_pixels = image_get_float_pixels_for_frame(b_image, frame); - const size_t num_pixels = ((size_t)width) * height; - - if(image_pixels && num_pixels * channels == pixels_size) { - memcpy(pixels, image_pixels, pixels_size * sizeof(float)); - } - else { - if(channels == 1) { - memset(pixels, 0, num_pixels * sizeof(float)); - } - else { - const size_t num_pixels_safe = pixels_size / channels; - float *fp = pixels; - for(int i = 0; i < num_pixels_safe; i++, fp += channels) { - fp[0] = 1.0f; - fp[1] = 0.0f; - fp[2] = 1.0f; - if(channels == 4) { - fp[3] = 1.0f; - } - } - } - } - - if(image_pixels) { - MEM_freeN(image_pixels); - } - - /* Free image buffers to save memory during render. */ - if(free_cache) { - b_image.buffers_free(); - } - - return true; - } - else if(b_id.is_a(&RNA_Object)) { - /* smoke volume data */ - BL::Object b_ob(b_id); - BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob); - - if(!b_domain) { - return false; - } - - int3 resolution = get_int3(b_domain.domain_resolution()); - int length, amplify = (b_domain.use_high_resolution())? b_domain.amplify() + 1: 1; - - /* Velocity and heat data is always low-resolution. */ - if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) || - builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) - { - amplify = 1; - } - - const int width = resolution.x * amplify; - const int height = resolution.y * amplify; - const int depth = resolution.z * amplify; - const size_t num_pixels = ((size_t)width) * height * depth; - - if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) { - SmokeDomainSettings_density_grid_get_length(&b_domain.ptr, &length); - if(length == num_pixels) { - SmokeDomainSettings_density_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) { - /* this is in range 0..1, and interpreted by the OpenGL smoke viewer - * as 1500..3000 K with the first part faded to zero density */ - SmokeDomainSettings_flame_grid_get_length(&b_domain.ptr, &length); - if(length == num_pixels) { - SmokeDomainSettings_flame_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) { - /* the RGB is "premultiplied" by density for better interpolation results */ - SmokeDomainSettings_color_grid_get_length(&b_domain.ptr, &length); - if(length == num_pixels*4) { - SmokeDomainSettings_color_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) { - SmokeDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length); - if(length == num_pixels*3) { - SmokeDomainSettings_velocity_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { - SmokeDomainSettings_heat_grid_get_length(&b_domain.ptr, &length); - if(length == num_pixels) { - SmokeDomainSettings_heat_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) { - SmokeDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length); - if(length == num_pixels) { - SmokeDomainSettings_temperature_grid_get(&b_domain.ptr, pixels); - return true; - } - } - else { - fprintf(stderr, - "Cycles error: unknown volume attribute %s, skipping\n", - builtin_name.c_str()); - pixels[0] = 0.0f; - return false; - } - - fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n"); - } - else { - /* We originally were passing view_layer here but in reality we need a - * a depsgraph to pass to the RE_point_density_minmax() function. - */ - /* TODO(sergey): Check we're indeed in shader node tree. */ - PointerRNA ptr; - RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr); - BL::Node b_node(ptr); - if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) { - BL::ShaderNodeTexPointDensity b_point_density_node(b_node); - int length; - b_point_density_node.calc_point_density(b_depsgraph, &length, &pixels); - } - } - - return false; + if (!builtin_data) { + return false; + } + + PointerRNA ptr; + RNA_id_pointer_create((ID *)builtin_data, &ptr); + BL::ID b_id(ptr); + + if (b_id.is_a(&RNA_Image)) { + /* image data */ + BL::Image b_image(b_id); + int frame = builtin_image_frame(builtin_name); + + const int width = b_image.size()[0]; + const int height = b_image.size()[1]; + const int channels = b_image.channels(); + + float *image_pixels; + image_pixels = image_get_float_pixels_for_frame(b_image, frame); + const size_t num_pixels = ((size_t)width) * height; + + if (image_pixels && num_pixels * channels == pixels_size) { + memcpy(pixels, image_pixels, pixels_size * sizeof(float)); + } + else { + if (channels == 1) { + memset(pixels, 0, num_pixels * sizeof(float)); + } + else { + const size_t num_pixels_safe = pixels_size / channels; + float *fp = pixels; + for (int i = 0; i < num_pixels_safe; i++, fp += channels) { + fp[0] = 1.0f; + fp[1] = 0.0f; + fp[2] = 1.0f; + if (channels == 4) { + fp[3] = 1.0f; + } + } + } + } + + if (image_pixels) { + MEM_freeN(image_pixels); + } + + /* Free image buffers to save memory during render. */ + if (free_cache) { + b_image.buffers_free(); + } + + return true; + } + else if (b_id.is_a(&RNA_Object)) { + /* smoke volume data */ + BL::Object b_ob(b_id); + BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob); + + if (!b_domain) { + return false; + } + + int3 resolution = get_int3(b_domain.domain_resolution()); + int length, amplify = (b_domain.use_high_resolution()) ? b_domain.amplify() + 1 : 1; + + /* Velocity and heat data is always low-resolution. */ + if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) || + builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { + amplify = 1; + } + + const int width = resolution.x * amplify; + const int height = resolution.y * amplify; + const int depth = resolution.z * amplify; + const size_t num_pixels = ((size_t)width) * height * depth; + + if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) { + SmokeDomainSettings_density_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + SmokeDomainSettings_density_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) { + /* this is in range 0..1, and interpreted by the OpenGL smoke viewer + * as 1500..3000 K with the first part faded to zero density */ + SmokeDomainSettings_flame_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + SmokeDomainSettings_flame_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) { + /* the RGB is "premultiplied" by density for better interpolation results */ + SmokeDomainSettings_color_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels * 4) { + SmokeDomainSettings_color_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) { + SmokeDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels * 3) { + SmokeDomainSettings_velocity_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) { + SmokeDomainSettings_heat_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + SmokeDomainSettings_heat_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) { + SmokeDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length); + if (length == num_pixels) { + SmokeDomainSettings_temperature_grid_get(&b_domain.ptr, pixels); + return true; + } + } + else { + fprintf( + stderr, "Cycles error: unknown volume attribute %s, skipping\n", builtin_name.c_str()); + pixels[0] = 0.0f; + return false; + } + + fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n"); + } + else { + /* We originally were passing view_layer here but in reality we need a + * a depsgraph to pass to the RE_point_density_minmax() function. + */ + /* TODO(sergey): Check we're indeed in shader node tree. */ + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr); + BL::Node b_node(ptr); + if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) { + BL::ShaderNodeTexPointDensity b_point_density_node(b_node); + int length; + b_point_density_node.calc_point_density(b_depsgraph, &length, &pixels); + } + } + + return false; } void BlenderSession::builtin_images_load() { - /* Force builtin images to be loaded along with Blender data sync. This - * is needed because we may be reading from depsgraph evaluated data which - * can be freed by Blender before Cycles reads it. */ - ImageManager *manager = session->scene->image_manager; - Device *device = session->device; - manager->device_load_builtin(device, session->scene, session->progress); + /* Force builtin images to be loaded along with Blender data sync. This + * is needed because we may be reading from depsgraph evaluated data which + * can be freed by Blender before Cycles reads it. */ + ImageManager *manager = session->scene->image_manager; + Device *device = session->device; + manager->device_load_builtin(device, session->scene, session->progress); } void BlenderSession::update_resumable_tile_manager(int num_samples) { - const int num_resumable_chunks = BlenderSession::num_resumable_chunks, - current_resumable_chunk = BlenderSession::current_resumable_chunk; - if(num_resumable_chunks == 0) { - return; - } - - if (num_resumable_chunks > num_samples) { - fprintf(stderr, "Cycles warning: more sample chunks (%d) than samples (%d), " - "this will cause some samples to be included in multiple chunks.\n", - num_resumable_chunks, num_samples); - } - - const float num_samples_per_chunk = (float)num_samples / num_resumable_chunks; - - float range_start_sample, range_num_samples; - if(current_resumable_chunk != 0) { - /* Single chunk rendering. */ - range_start_sample = num_samples_per_chunk * (current_resumable_chunk - 1); - range_num_samples = num_samples_per_chunk; - } - else { - /* Ranged-chunks. */ - const int num_chunks = end_resumable_chunk - start_resumable_chunk + 1; - range_start_sample = num_samples_per_chunk * (start_resumable_chunk - 1); - range_num_samples = num_chunks * num_samples_per_chunk; - } - - /* Round after doing the multiplications with num_chunks and num_samples_per_chunk - * to allow for many small chunks. */ - int rounded_range_start_sample = (int)floor(range_start_sample + 0.5f); - int rounded_range_num_samples = max((int)floor(range_num_samples + 0.5f), 1); - - /* Make sure we don't overshoot. */ - if(rounded_range_start_sample + rounded_range_num_samples > num_samples) { - rounded_range_num_samples = num_samples - rounded_range_num_samples; - } - - VLOG(1) << "Samples range start is " << range_start_sample << ", " - << "number of samples to render is " << range_num_samples; - - scene->integrator->start_sample = rounded_range_start_sample; - scene->integrator->tag_update(scene); - - session->tile_manager.range_start_sample = rounded_range_start_sample; - session->tile_manager.range_num_samples = rounded_range_num_samples; + const int num_resumable_chunks = BlenderSession::num_resumable_chunks, + current_resumable_chunk = BlenderSession::current_resumable_chunk; + if (num_resumable_chunks == 0) { + return; + } + + if (num_resumable_chunks > num_samples) { + fprintf(stderr, + "Cycles warning: more sample chunks (%d) than samples (%d), " + "this will cause some samples to be included in multiple chunks.\n", + num_resumable_chunks, + num_samples); + } + + const float num_samples_per_chunk = (float)num_samples / num_resumable_chunks; + + float range_start_sample, range_num_samples; + if (current_resumable_chunk != 0) { + /* Single chunk rendering. */ + range_start_sample = num_samples_per_chunk * (current_resumable_chunk - 1); + range_num_samples = num_samples_per_chunk; + } + else { + /* Ranged-chunks. */ + const int num_chunks = end_resumable_chunk - start_resumable_chunk + 1; + range_start_sample = num_samples_per_chunk * (start_resumable_chunk - 1); + range_num_samples = num_chunks * num_samples_per_chunk; + } + + /* Round after doing the multiplications with num_chunks and num_samples_per_chunk + * to allow for many small chunks. */ + int rounded_range_start_sample = (int)floor(range_start_sample + 0.5f); + int rounded_range_num_samples = max((int)floor(range_num_samples + 0.5f), 1); + + /* Make sure we don't overshoot. */ + if (rounded_range_start_sample + rounded_range_num_samples > num_samples) { + rounded_range_num_samples = num_samples - rounded_range_num_samples; + } + + VLOG(1) << "Samples range start is " << range_start_sample << ", " + << "number of samples to render is " << range_num_samples; + + scene->integrator->start_sample = rounded_range_start_sample; + scene->integrator->tag_update(scene); + + session->tile_manager.range_start_sample = rounded_range_start_sample; + session->tile_manager.range_num_samples = rounded_range_num_samples; } void BlenderSession::free_blender_memory_if_possible() { - if(!background) { - /* During interactive render we can not free anything: attempts to save - * memory would cause things to be allocated and evaluated for every - * updated sample. - */ - return; - } - b_engine.free_blender_memory(); + if (!background) { + /* During interactive render we can not free anything: attempts to save + * memory would cause things to be allocated and evaluated for every + * updated sample. + */ + return; + } + b_engine.free_blender_memory(); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index 2bfb9e56c37..f0107d4e0b1 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -33,159 +33,153 @@ class RenderBuffers; class RenderTile; class BlenderSession { -public: - BlenderSession(BL::RenderEngine& b_engine, - BL::Preferences& b_userpref, - BL::BlendData& b_data, - bool preview_osl); - - BlenderSession(BL::RenderEngine& b_engine, - BL::Preferences& b_userpref, - BL::BlendData& b_data, - BL::SpaceView3D& b_v3d, - BL::RegionView3D& b_rv3d, - int width, int height); - - ~BlenderSession(); - - void create(); - - /* session */ - void create_session(); - void free_session(); - - void reset_session(BL::BlendData& b_data, - BL::Depsgraph& b_depsgraph); - - /* offline render */ - void render(BL::Depsgraph& b_depsgraph); - - void bake(BL::Depsgraph& b_depsgrah, - BL::Object& b_object, - const string& pass_type, - const int custom_flag, - const int object_id, - BL::BakePixel& pixel_array, - const size_t num_pixels, - const int depth, - float pixels[]); - - void write_render_result(BL::RenderResult& b_rr, - BL::RenderLayer& b_rlay, - RenderTile& rtile); - void write_render_tile(RenderTile& rtile); - - /* update functions are used to update display buffer only after sample was rendered - * only needed for better visual feedback */ - void update_render_result(BL::RenderResult& b_rr, - BL::RenderLayer& b_rlay, - RenderTile& rtile); - void update_render_tile(RenderTile& rtile, bool highlight); - - /* interactive updates */ - void synchronize(BL::Depsgraph& b_depsgraph); - - /* drawing */ - bool draw(int w, int h); - void tag_redraw(); - void tag_update(); - void get_status(string& status, string& substatus); - void get_kernel_status(string& kernel_status); - void get_progress(float& progress, double& total_time, double& render_time); - void test_cancel(); - void update_status_progress(); - void update_bake_progress(); - - bool background; - Session *session; - Scene *scene; - BlenderSync *sync; - double last_redraw_time; - - BL::RenderEngine b_engine; - BL::Preferences b_userpref; - BL::BlendData b_data; - BL::RenderSettings b_render; - BL::Depsgraph b_depsgraph; - /* NOTE: Blender's scene might become invalid after call - * free_blender_memory_if_possible(). - */ - BL::Scene b_scene; - BL::SpaceView3D b_v3d; - BL::RegionView3D b_rv3d; - string b_rlay_name; - string b_rview_name; - - string last_status; - string last_error; - float last_progress; - double last_status_time; - - int width, height; - bool preview_osl; - double start_resize_time; - - void *python_thread_state; - - /* Global state which is common for all render sessions created from Blender. - * Usually denotes command line arguments. - */ - - /* Blender is running from the command line, no windows are shown and some - * extra render optimization is possible (possible to free draw-only data and - * so on. - */ - static bool headless; - - /* ** Resumable render ** */ - - /* Overall number of chunks in which the sample range is to be devided. */ - static int num_resumable_chunks; - - /* Current resumable chunk index to render. */ - static int current_resumable_chunk; - - /* Alternative to single-chunk rendering to render a range of chunks. */ - static int start_resumable_chunk; - static int end_resumable_chunk; - - static bool print_render_stats; - -protected: - void stamp_view_layer_metadata(Scene *scene, const string& view_layer_name); - - void do_write_update_render_result(BL::RenderResult& b_rr, - BL::RenderLayer& b_rlay, - RenderTile& rtile, - bool do_update_only); - void do_write_update_render_tile(RenderTile& rtile, bool do_update_only, bool highlight); - - int builtin_image_frame(const string &builtin_name); - void builtin_image_info(const string &builtin_name, - void *builtin_data, - ImageMetaData& metadata); - bool builtin_image_pixels(const string &builtin_name, - void *builtin_data, - unsigned char *pixels, - const size_t pixels_size, - const bool free_cache); - bool builtin_image_float_pixels(const string &builtin_name, - void *builtin_data, - float *pixels, - const size_t pixels_size, - const bool free_cache); - void builtin_images_load(); - - /* Update tile manager to reflect resumable render settings. */ - void update_resumable_tile_manager(int num_samples); - - /* Is used after each render layer synchronization is done with the goal - * of freeing render engine data which is held from Blender side (for - * example, dependency graph). - */ - void free_blender_memory_if_possible(); + public: + BlenderSession(BL::RenderEngine &b_engine, + BL::Preferences &b_userpref, + BL::BlendData &b_data, + bool preview_osl); + + BlenderSession(BL::RenderEngine &b_engine, + BL::Preferences &b_userpref, + BL::BlendData &b_data, + BL::SpaceView3D &b_v3d, + BL::RegionView3D &b_rv3d, + int width, + int height); + + ~BlenderSession(); + + void create(); + + /* session */ + void create_session(); + void free_session(); + + void reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph); + + /* offline render */ + void render(BL::Depsgraph &b_depsgraph); + + void bake(BL::Depsgraph &b_depsgrah, + BL::Object &b_object, + const string &pass_type, + const int custom_flag, + const int object_id, + BL::BakePixel &pixel_array, + const size_t num_pixels, + const int depth, + float pixels[]); + + void write_render_result(BL::RenderResult &b_rr, BL::RenderLayer &b_rlay, RenderTile &rtile); + void write_render_tile(RenderTile &rtile); + + /* update functions are used to update display buffer only after sample was rendered + * only needed for better visual feedback */ + void update_render_result(BL::RenderResult &b_rr, BL::RenderLayer &b_rlay, RenderTile &rtile); + void update_render_tile(RenderTile &rtile, bool highlight); + + /* interactive updates */ + void synchronize(BL::Depsgraph &b_depsgraph); + + /* drawing */ + bool draw(int w, int h); + void tag_redraw(); + void tag_update(); + void get_status(string &status, string &substatus); + void get_kernel_status(string &kernel_status); + void get_progress(float &progress, double &total_time, double &render_time); + void test_cancel(); + void update_status_progress(); + void update_bake_progress(); + + bool background; + Session *session; + Scene *scene; + BlenderSync *sync; + double last_redraw_time; + + BL::RenderEngine b_engine; + BL::Preferences b_userpref; + BL::BlendData b_data; + BL::RenderSettings b_render; + BL::Depsgraph b_depsgraph; + /* NOTE: Blender's scene might become invalid after call + * free_blender_memory_if_possible(). + */ + BL::Scene b_scene; + BL::SpaceView3D b_v3d; + BL::RegionView3D b_rv3d; + string b_rlay_name; + string b_rview_name; + + string last_status; + string last_error; + float last_progress; + double last_status_time; + + int width, height; + bool preview_osl; + double start_resize_time; + + void *python_thread_state; + + /* Global state which is common for all render sessions created from Blender. + * Usually denotes command line arguments. + */ + + /* Blender is running from the command line, no windows are shown and some + * extra render optimization is possible (possible to free draw-only data and + * so on. + */ + static bool headless; + + /* ** Resumable render ** */ + + /* Overall number of chunks in which the sample range is to be devided. */ + static int num_resumable_chunks; + + /* Current resumable chunk index to render. */ + static int current_resumable_chunk; + + /* Alternative to single-chunk rendering to render a range of chunks. */ + static int start_resumable_chunk; + static int end_resumable_chunk; + + static bool print_render_stats; + + protected: + void stamp_view_layer_metadata(Scene *scene, const string &view_layer_name); + + void do_write_update_render_result(BL::RenderResult &b_rr, + BL::RenderLayer &b_rlay, + RenderTile &rtile, + bool do_update_only); + void do_write_update_render_tile(RenderTile &rtile, bool do_update_only, bool highlight); + + int builtin_image_frame(const string &builtin_name); + void builtin_image_info(const string &builtin_name, void *builtin_data, ImageMetaData &metadata); + bool builtin_image_pixels(const string &builtin_name, + void *builtin_data, + unsigned char *pixels, + const size_t pixels_size, + const bool free_cache); + bool builtin_image_float_pixels(const string &builtin_name, + void *builtin_data, + float *pixels, + const size_t pixels_size, + const bool free_cache); + void builtin_images_load(); + + /* Update tile manager to reflect resumable render settings. */ + void update_resumable_tile_manager(int num_samples); + + /* Is used after each render layer synchronization is done with the goal + * of freeing render engine data which is held from Blender side (for + * example, dependency graph). + */ + void free_blender_memory_if_possible(); }; CCL_NAMESPACE_END -#endif /* __BLENDER_SESSION_H__ */ +#endif /* __BLENDER_SESSION_H__ */ diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 44ff29d4bf8..169c4d414a6 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -34,1449 +34,1416 @@ CCL_NAMESPACE_BEGIN -typedef map<void*, ShaderInput*> PtrInputMap; -typedef map<void*, ShaderOutput*> PtrOutputMap; -typedef map<string, ConvertNode*> ProxyMap; +typedef map<void *, ShaderInput *> PtrInputMap; +typedef map<void *, ShaderOutput *> PtrOutputMap; +typedef map<string, ConvertNode *> ProxyMap; /* Find */ -void BlenderSync::find_shader(BL::ID& id, - vector<Shader*>& used_shaders, - Shader *default_shader) +void BlenderSync::find_shader(BL::ID &id, vector<Shader *> &used_shaders, Shader *default_shader) { - Shader *shader = (id)? shader_map.find(id): default_shader; + Shader *shader = (id) ? shader_map.find(id) : default_shader; - used_shaders.push_back(shader); - shader->tag_used(scene); + used_shaders.push_back(shader); + shader->tag_used(scene); } /* RNA translation utilities */ -static VolumeSampling get_volume_sampling(PointerRNA& ptr) +static VolumeSampling get_volume_sampling(PointerRNA &ptr) { - return (VolumeSampling)get_enum(ptr, - "volume_sampling", - VOLUME_NUM_SAMPLING, - VOLUME_SAMPLING_DISTANCE); + return (VolumeSampling)get_enum( + ptr, "volume_sampling", VOLUME_NUM_SAMPLING, VOLUME_SAMPLING_DISTANCE); } -static VolumeInterpolation get_volume_interpolation(PointerRNA& ptr) +static VolumeInterpolation get_volume_interpolation(PointerRNA &ptr) { - return (VolumeInterpolation)get_enum(ptr, - "volume_interpolation", - VOLUME_NUM_INTERPOLATION, - VOLUME_INTERPOLATION_LINEAR); + return (VolumeInterpolation)get_enum( + ptr, "volume_interpolation", VOLUME_NUM_INTERPOLATION, VOLUME_INTERPOLATION_LINEAR); } -static DisplacementMethod get_displacement_method(PointerRNA& ptr) +static DisplacementMethod get_displacement_method(PointerRNA &ptr) { - return (DisplacementMethod)get_enum(ptr, - "displacement_method", - DISPLACE_NUM_METHODS, - DISPLACE_BUMP); + return (DisplacementMethod)get_enum( + ptr, "displacement_method", DISPLACE_NUM_METHODS, DISPLACE_BUMP); } static int validate_enum_value(int value, int num_values, int default_value) { - if(value >= num_values) { - return default_value; - } - return value; + if (value >= num_values) { + return default_value; + } + return value; } -template<typename NodeType> -static InterpolationType get_image_interpolation(NodeType& b_node) +template<typename NodeType> static InterpolationType get_image_interpolation(NodeType &b_node) { - int value = b_node.interpolation(); - return (InterpolationType)validate_enum_value(value, - INTERPOLATION_NUM_TYPES, - INTERPOLATION_LINEAR); + int value = b_node.interpolation(); + return (InterpolationType)validate_enum_value( + value, INTERPOLATION_NUM_TYPES, INTERPOLATION_LINEAR); } -template<typename NodeType> -static ExtensionType get_image_extension(NodeType& b_node) +template<typename NodeType> static ExtensionType get_image_extension(NodeType &b_node) { - int value = b_node.extension(); - return (ExtensionType)validate_enum_value(value, - EXTENSION_NUM_TYPES, - EXTENSION_REPEAT); + int value = b_node.extension(); + return (ExtensionType)validate_enum_value(value, EXTENSION_NUM_TYPES, EXTENSION_REPEAT); } /* Graph */ -static BL::NodeSocket get_node_output(BL::Node& b_node, const string& name) +static BL::NodeSocket get_node_output(BL::Node &b_node, const string &name) { - BL::Node::outputs_iterator b_out; + BL::Node::outputs_iterator b_out; - for(b_node.outputs.begin(b_out); b_out != b_node.outputs.end(); ++b_out) - if(b_out->name() == name) - return *b_out; + for (b_node.outputs.begin(b_out); b_out != b_node.outputs.end(); ++b_out) + if (b_out->name() == name) + return *b_out; - assert(0); + assert(0); - return *b_out; + return *b_out; } -static float3 get_node_output_rgba(BL::Node& b_node, const string& name) +static float3 get_node_output_rgba(BL::Node &b_node, const string &name) { - BL::NodeSocket b_sock = get_node_output(b_node, name); - float value[4]; - RNA_float_get_array(&b_sock.ptr, "default_value", value); - return make_float3(value[0], value[1], value[2]); + BL::NodeSocket b_sock = get_node_output(b_node, name); + float value[4]; + RNA_float_get_array(&b_sock.ptr, "default_value", value); + return make_float3(value[0], value[1], value[2]); } -static float get_node_output_value(BL::Node& b_node, const string& name) +static float get_node_output_value(BL::Node &b_node, const string &name) { - BL::NodeSocket b_sock = get_node_output(b_node, name); - return RNA_float_get(&b_sock.ptr, "default_value"); + BL::NodeSocket b_sock = get_node_output(b_node, name); + return RNA_float_get(&b_sock.ptr, "default_value"); } -static float3 get_node_output_vector(BL::Node& b_node, const string& name) +static float3 get_node_output_vector(BL::Node &b_node, const string &name) { - BL::NodeSocket b_sock = get_node_output(b_node, name); - float value[3]; - RNA_float_get_array(&b_sock.ptr, "default_value", value); - return make_float3(value[0], value[1], value[2]); + BL::NodeSocket b_sock = get_node_output(b_node, name); + float value[3]; + RNA_float_get_array(&b_sock.ptr, "default_value", value); + return make_float3(value[0], value[1], value[2]); } -static SocketType::Type convert_socket_type(BL::NodeSocket& b_socket) +static SocketType::Type convert_socket_type(BL::NodeSocket &b_socket) { - switch(b_socket.type()) { - case BL::NodeSocket::type_VALUE: - return SocketType::FLOAT; - case BL::NodeSocket::type_INT: - return SocketType::INT; - case BL::NodeSocket::type_VECTOR: - return SocketType::VECTOR; - case BL::NodeSocket::type_RGBA: - return SocketType::COLOR; - case BL::NodeSocket::type_STRING: - return SocketType::STRING; - case BL::NodeSocket::type_SHADER: - return SocketType::CLOSURE; - - default: - return SocketType::UNDEFINED; - } + switch (b_socket.type()) { + case BL::NodeSocket::type_VALUE: + return SocketType::FLOAT; + case BL::NodeSocket::type_INT: + return SocketType::INT; + case BL::NodeSocket::type_VECTOR: + return SocketType::VECTOR; + case BL::NodeSocket::type_RGBA: + return SocketType::COLOR; + case BL::NodeSocket::type_STRING: + return SocketType::STRING; + case BL::NodeSocket::type_SHADER: + return SocketType::CLOSURE; + + default: + return SocketType::UNDEFINED; + } } static void set_default_value(ShaderInput *input, - BL::NodeSocket& b_sock, - BL::BlendData& b_data, - BL::ID& b_id) + BL::NodeSocket &b_sock, + BL::BlendData &b_data, + BL::ID &b_id) { - Node *node = input->parent; - const SocketType& socket = input->socket_type; - - /* copy values for non linked inputs */ - switch(input->type()) { - case SocketType::FLOAT: { - node->set(socket, get_float(b_sock.ptr, "default_value")); - break; - } - case SocketType::INT: { - node->set(socket, get_int(b_sock.ptr, "default_value")); - break; - } - case SocketType::COLOR: { - node->set(socket, float4_to_float3(get_float4(b_sock.ptr, "default_value"))); - break; - } - case SocketType::NORMAL: - case SocketType::POINT: - case SocketType::VECTOR: { - node->set(socket, get_float3(b_sock.ptr, "default_value")); - break; - } - case SocketType::STRING: { - node->set(socket, (ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value"))); - break; - } - default: - break; - } + Node *node = input->parent; + const SocketType &socket = input->socket_type; + + /* copy values for non linked inputs */ + switch (input->type()) { + case SocketType::FLOAT: { + node->set(socket, get_float(b_sock.ptr, "default_value")); + break; + } + case SocketType::INT: { + node->set(socket, get_int(b_sock.ptr, "default_value")); + break; + } + case SocketType::COLOR: { + node->set(socket, float4_to_float3(get_float4(b_sock.ptr, "default_value"))); + break; + } + case SocketType::NORMAL: + case SocketType::POINT: + case SocketType::VECTOR: { + node->set(socket, get_float3(b_sock.ptr, "default_value")); + break; + } + case SocketType::STRING: { + node->set( + socket, + (ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value"))); + break; + } + default: + break; + } } -static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping& b_mapping) +static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping &b_mapping) { - if(!b_mapping) - return; + if (!b_mapping) + return; - mapping->translation = get_float3(b_mapping.translation()); - mapping->rotation = get_float3(b_mapping.rotation()); - mapping->scale = get_float3(b_mapping.scale()); - mapping->type = (TextureMapping::Type)b_mapping.vector_type(); + mapping->translation = get_float3(b_mapping.translation()); + mapping->rotation = get_float3(b_mapping.rotation()); + mapping->scale = get_float3(b_mapping.scale()); + mapping->type = (TextureMapping::Type)b_mapping.vector_type(); - mapping->x_mapping = (TextureMapping::Mapping)b_mapping.mapping_x(); - mapping->y_mapping = (TextureMapping::Mapping)b_mapping.mapping_y(); - mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z(); + mapping->x_mapping = (TextureMapping::Mapping)b_mapping.mapping_x(); + mapping->y_mapping = (TextureMapping::Mapping)b_mapping.mapping_y(); + mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z(); } -static void get_tex_mapping(TextureMapping *mapping, - BL::ShaderNodeMapping& b_mapping) +static void get_tex_mapping(TextureMapping *mapping, BL::ShaderNodeMapping &b_mapping) { - if(!b_mapping) - return; + if (!b_mapping) + return; - mapping->translation = get_float3(b_mapping.translation()); - mapping->rotation = get_float3(b_mapping.rotation()); - mapping->scale = get_float3(b_mapping.scale()); - mapping->type = (TextureMapping::Type)b_mapping.vector_type(); + mapping->translation = get_float3(b_mapping.translation()); + mapping->rotation = get_float3(b_mapping.rotation()); + mapping->scale = get_float3(b_mapping.scale()); + mapping->type = (TextureMapping::Type)b_mapping.vector_type(); - mapping->use_minmax = b_mapping.use_min() || b_mapping.use_max(); + mapping->use_minmax = b_mapping.use_min() || b_mapping.use_max(); - if(b_mapping.use_min()) - mapping->min = get_float3(b_mapping.min()); - if(b_mapping.use_max()) - mapping->max = get_float3(b_mapping.max()); + if (b_mapping.use_min()) + mapping->min = get_float3(b_mapping.min()); + if (b_mapping.use_max()) + mapping->max = get_float3(b_mapping.max()); } static ShaderNode *add_node(Scene *scene, - BL::RenderEngine& b_engine, - BL::BlendData& b_data, - BL::Depsgraph& b_depsgraph, - BL::Scene& b_scene, + BL::RenderEngine &b_engine, + BL::BlendData &b_data, + BL::Depsgraph &b_depsgraph, + BL::Scene &b_scene, ShaderGraph *graph, - BL::ShaderNodeTree& b_ntree, - BL::ShaderNode& b_node) + BL::ShaderNodeTree &b_ntree, + BL::ShaderNode &b_node) { - ShaderNode *node = NULL; - - /* existing blender nodes */ - if(b_node.is_a(&RNA_ShaderNodeRGBCurve)) { - BL::ShaderNodeRGBCurve b_curve_node(b_node); - BL::CurveMapping mapping(b_curve_node.mapping()); - RGBCurvesNode *curves = new RGBCurvesNode(); - curvemapping_color_to_array(mapping, - curves->curves, - RAMP_TABLE_SIZE, - true); - curvemapping_minmax(mapping, true, &curves->min_x, &curves->max_x); - node = curves; - } - if(b_node.is_a(&RNA_ShaderNodeVectorCurve)) { - BL::ShaderNodeVectorCurve b_curve_node(b_node); - BL::CurveMapping mapping(b_curve_node.mapping()); - VectorCurvesNode *curves = new VectorCurvesNode(); - curvemapping_color_to_array(mapping, - curves->curves, - RAMP_TABLE_SIZE, - false); - curvemapping_minmax(mapping, false, &curves->min_x, &curves->max_x); - node = curves; - } - else if(b_node.is_a(&RNA_ShaderNodeValToRGB)) { - RGBRampNode *ramp = new RGBRampNode(); - BL::ShaderNodeValToRGB b_ramp_node(b_node); - BL::ColorRamp b_color_ramp(b_ramp_node.color_ramp()); - colorramp_to_array(b_color_ramp, ramp->ramp, ramp->ramp_alpha, RAMP_TABLE_SIZE); - ramp->interpolate = b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT; - node = ramp; - } - else if(b_node.is_a(&RNA_ShaderNodeRGB)) { - ColorNode *color = new ColorNode(); - color->value = get_node_output_rgba(b_node, "Color"); - node = color; - } - else if(b_node.is_a(&RNA_ShaderNodeValue)) { - ValueNode *value = new ValueNode(); - value->value = get_node_output_value(b_node, "Value"); - node = value; - } - else if(b_node.is_a(&RNA_ShaderNodeCameraData)) { - node = new CameraNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeInvert)) { - node = new InvertNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeGamma)) { - node = new GammaNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeBrightContrast)) { - node = new BrightContrastNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeMixRGB)) { - BL::ShaderNodeMixRGB b_mix_node(b_node); - MixNode *mix = new MixNode(); - mix->type = (NodeMix)b_mix_node.blend_type(); - mix->use_clamp = b_mix_node.use_clamp(); - node = mix; - } - else if(b_node.is_a(&RNA_ShaderNodeSeparateRGB)) { - node = new SeparateRGBNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeCombineRGB)) { - node = new CombineRGBNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeSeparateHSV)) { - node = new SeparateHSVNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeCombineHSV)) { - node = new CombineHSVNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) { - node = new SeparateXYZNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeCombineXYZ)) { - node = new CombineXYZNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeHueSaturation)) { - node = new HSVNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeRGBToBW)) { - node = new RGBToBWNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeMath)) { - BL::ShaderNodeMath b_math_node(b_node); - MathNode *math = new MathNode(); - math->type = (NodeMath)b_math_node.operation(); - math->use_clamp = b_math_node.use_clamp(); - node = math; - } - else if(b_node.is_a(&RNA_ShaderNodeVectorMath)) { - BL::ShaderNodeVectorMath b_vector_math_node(b_node); - VectorMathNode *vmath = new VectorMathNode(); - vmath->type = (NodeVectorMath)b_vector_math_node.operation(); - node = vmath; - } - else if(b_node.is_a(&RNA_ShaderNodeVectorTransform)) { - BL::ShaderNodeVectorTransform b_vector_transform_node(b_node); - VectorTransformNode *vtransform = new VectorTransformNode(); - vtransform->type = (NodeVectorTransformType)b_vector_transform_node.vector_type(); - vtransform->convert_from = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_from(); - vtransform->convert_to = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to(); - node = vtransform; - } - else if(b_node.is_a(&RNA_ShaderNodeNormal)) { - BL::Node::outputs_iterator out_it; - b_node.outputs.begin(out_it); - - NormalNode *norm = new NormalNode(); - norm->direction = get_node_output_vector(b_node, "Normal"); - node = norm; - } - else if(b_node.is_a(&RNA_ShaderNodeMapping)) { - BL::ShaderNodeMapping b_mapping_node(b_node); - MappingNode *mapping = new MappingNode(); - - get_tex_mapping(&mapping->tex_mapping, b_mapping_node); - - node = mapping; - } - else if(b_node.is_a(&RNA_ShaderNodeFresnel)) { - node = new FresnelNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeLayerWeight)) { - node = new LayerWeightNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeAddShader)) { - node = new AddClosureNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeMixShader)) { - node = new MixClosureNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeAttribute)) { - BL::ShaderNodeAttribute b_attr_node(b_node); - AttributeNode *attr = new AttributeNode(); - attr->attribute = b_attr_node.attribute_name(); - node = attr; - } - else if(b_node.is_a(&RNA_ShaderNodeBackground)) { - node = new BackgroundNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeHoldout)) { - node = new HoldoutNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) { - BL::ShaderNodeBsdfAnisotropic b_aniso_node(b_node); - AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode(); - - switch(b_aniso_node.distribution()) { - case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN: - aniso->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID; - break; - case BL::ShaderNodeBsdfAnisotropic::distribution_GGX: - aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; - break; - case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX: - aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID; - break; - case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY: - aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; - break; - } - - node = aniso; - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) { - node = new DiffuseBsdfNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) { - BL::ShaderNodeSubsurfaceScattering b_subsurface_node(b_node); - - SubsurfaceScatteringNode *subsurface = new SubsurfaceScatteringNode(); - - switch(b_subsurface_node.falloff()) { - case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC: - subsurface->falloff = CLOSURE_BSSRDF_CUBIC_ID; - break; - case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN: - subsurface->falloff = CLOSURE_BSSRDF_GAUSSIAN_ID; - break; - case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY: - subsurface->falloff = CLOSURE_BSSRDF_BURLEY_ID; - break; - case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK: - subsurface->falloff = CLOSURE_BSSRDF_RANDOM_WALK_ID; - break; - } - - node = subsurface; - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) { - BL::ShaderNodeBsdfGlossy b_glossy_node(b_node); - GlossyBsdfNode *glossy = new GlossyBsdfNode(); - - switch(b_glossy_node.distribution()) { - case BL::ShaderNodeBsdfGlossy::distribution_SHARP: - glossy->distribution = CLOSURE_BSDF_REFLECTION_ID; - break; - case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN: - glossy->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; - break; - case BL::ShaderNodeBsdfGlossy::distribution_GGX: - glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID; - break; - case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY: - glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID; - break; - case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX: - glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; - break; - } - node = glossy; - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfGlass)) { - BL::ShaderNodeBsdfGlass b_glass_node(b_node); - GlassBsdfNode *glass = new GlassBsdfNode(); - switch(b_glass_node.distribution()) { - case BL::ShaderNodeBsdfGlass::distribution_SHARP: - glass->distribution = CLOSURE_BSDF_SHARP_GLASS_ID; - break; - case BL::ShaderNodeBsdfGlass::distribution_BECKMANN: - glass->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID; - break; - case BL::ShaderNodeBsdfGlass::distribution_GGX: - glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; - break; - case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX: - glass->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; - break; - } - node = glass; - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) { - BL::ShaderNodeBsdfRefraction b_refraction_node(b_node); - RefractionBsdfNode *refraction = new RefractionBsdfNode(); - switch(b_refraction_node.distribution()) { - case BL::ShaderNodeBsdfRefraction::distribution_SHARP: - refraction->distribution = CLOSURE_BSDF_REFRACTION_ID; - break; - case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN: - refraction->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - break; - case BL::ShaderNodeBsdfRefraction::distribution_GGX: - refraction->distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; - break; - } - node = refraction; - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfToon)) { - BL::ShaderNodeBsdfToon b_toon_node(b_node); - ToonBsdfNode *toon = new ToonBsdfNode(); - switch(b_toon_node.component()) { - case BL::ShaderNodeBsdfToon::component_DIFFUSE: - toon->component = CLOSURE_BSDF_DIFFUSE_TOON_ID; - break; - case BL::ShaderNodeBsdfToon::component_GLOSSY: - toon->component = CLOSURE_BSDF_GLOSSY_TOON_ID; - break; - } - node = toon; - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfHair)) { - BL::ShaderNodeBsdfHair b_hair_node(b_node); - HairBsdfNode *hair = new HairBsdfNode(); - switch(b_hair_node.component()) { - case BL::ShaderNodeBsdfHair::component_Reflection: - hair->component = CLOSURE_BSDF_HAIR_REFLECTION_ID; - break; - case BL::ShaderNodeBsdfHair::component_Transmission: - hair->component = CLOSURE_BSDF_HAIR_TRANSMISSION_ID; - break; - } - node = hair; - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfHairPrincipled)) { - BL::ShaderNodeBsdfHairPrincipled b_principled_hair_node(b_node); - PrincipledHairBsdfNode *principled_hair = new PrincipledHairBsdfNode(); - principled_hair->parametrization = (NodePrincipledHairParametrization) get_enum(b_principled_hair_node.ptr, "parametrization", NODE_PRINCIPLED_HAIR_NUM, NODE_PRINCIPLED_HAIR_REFLECTANCE); - node = principled_hair; - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) { - BL::ShaderNodeBsdfPrincipled b_principled_node(b_node); - PrincipledBsdfNode *principled = new PrincipledBsdfNode(); - switch (b_principled_node.distribution()) { - case BL::ShaderNodeBsdfPrincipled::distribution_GGX: - principled->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; - break; - case BL::ShaderNodeBsdfPrincipled::distribution_MULTI_GGX: - principled->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; - break; - } - switch (b_principled_node.subsurface_method()) { - case BL::ShaderNodeBsdfPrincipled::subsurface_method_BURLEY: - principled->subsurface_method = CLOSURE_BSSRDF_PRINCIPLED_ID; - break; - case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK: - principled->subsurface_method = CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID; - break; - } - node = principled; - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) { - node = new TranslucentBsdfNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) { - node = new TransparentBsdfNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) { - node = new VelvetBsdfNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeEmission)) { - node = new EmissionNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) { - BL::ShaderNodeAmbientOcclusion b_ao_node(b_node); - AmbientOcclusionNode *ao = new AmbientOcclusionNode(); - ao->samples = b_ao_node.samples(); - ao->inside = b_ao_node.inside(); - ao->only_local = b_ao_node.only_local(); - node = ao; - } - else if(b_node.is_a(&RNA_ShaderNodeVolumeScatter)) { - node = new ScatterVolumeNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) { - node = new AbsorptionVolumeNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeVolumePrincipled)) { - PrincipledVolumeNode *principled = new PrincipledVolumeNode(); - node = principled; - } - else if(b_node.is_a(&RNA_ShaderNodeNewGeometry)) { - node = new GeometryNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeWireframe)) { - BL::ShaderNodeWireframe b_wireframe_node(b_node); - WireframeNode *wire = new WireframeNode(); - wire->use_pixel_size = b_wireframe_node.use_pixel_size(); - node = wire; - } - else if(b_node.is_a(&RNA_ShaderNodeWavelength)) { - node = new WavelengthNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeBlackbody)) { - node = new BlackbodyNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeLightPath)) { - node = new LightPathNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeLightFalloff)) { - node = new LightFalloffNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeObjectInfo)) { - node = new ObjectInfoNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeParticleInfo)) { - node = new ParticleInfoNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeHairInfo)) { - node = new HairInfoNode(); - } - else if(b_node.is_a(&RNA_ShaderNodeBump)) { - BL::ShaderNodeBump b_bump_node(b_node); - BumpNode *bump = new BumpNode(); - bump->invert = b_bump_node.invert(); - node = bump; - } - else if(b_node.is_a(&RNA_ShaderNodeScript)) { + ShaderNode *node = NULL; + + /* existing blender nodes */ + if (b_node.is_a(&RNA_ShaderNodeRGBCurve)) { + BL::ShaderNodeRGBCurve b_curve_node(b_node); + BL::CurveMapping mapping(b_curve_node.mapping()); + RGBCurvesNode *curves = new RGBCurvesNode(); + curvemapping_color_to_array(mapping, curves->curves, RAMP_TABLE_SIZE, true); + curvemapping_minmax(mapping, true, &curves->min_x, &curves->max_x); + node = curves; + } + if (b_node.is_a(&RNA_ShaderNodeVectorCurve)) { + BL::ShaderNodeVectorCurve b_curve_node(b_node); + BL::CurveMapping mapping(b_curve_node.mapping()); + VectorCurvesNode *curves = new VectorCurvesNode(); + curvemapping_color_to_array(mapping, curves->curves, RAMP_TABLE_SIZE, false); + curvemapping_minmax(mapping, false, &curves->min_x, &curves->max_x); + node = curves; + } + else if (b_node.is_a(&RNA_ShaderNodeValToRGB)) { + RGBRampNode *ramp = new RGBRampNode(); + BL::ShaderNodeValToRGB b_ramp_node(b_node); + BL::ColorRamp b_color_ramp(b_ramp_node.color_ramp()); + colorramp_to_array(b_color_ramp, ramp->ramp, ramp->ramp_alpha, RAMP_TABLE_SIZE); + ramp->interpolate = b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT; + node = ramp; + } + else if (b_node.is_a(&RNA_ShaderNodeRGB)) { + ColorNode *color = new ColorNode(); + color->value = get_node_output_rgba(b_node, "Color"); + node = color; + } + else if (b_node.is_a(&RNA_ShaderNodeValue)) { + ValueNode *value = new ValueNode(); + value->value = get_node_output_value(b_node, "Value"); + node = value; + } + else if (b_node.is_a(&RNA_ShaderNodeCameraData)) { + node = new CameraNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeInvert)) { + node = new InvertNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeGamma)) { + node = new GammaNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeBrightContrast)) { + node = new BrightContrastNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeMixRGB)) { + BL::ShaderNodeMixRGB b_mix_node(b_node); + MixNode *mix = new MixNode(); + mix->type = (NodeMix)b_mix_node.blend_type(); + mix->use_clamp = b_mix_node.use_clamp(); + node = mix; + } + else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) { + node = new SeparateRGBNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeCombineRGB)) { + node = new CombineRGBNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeSeparateHSV)) { + node = new SeparateHSVNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeCombineHSV)) { + node = new CombineHSVNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) { + node = new SeparateXYZNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeCombineXYZ)) { + node = new CombineXYZNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeHueSaturation)) { + node = new HSVNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeRGBToBW)) { + node = new RGBToBWNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeMath)) { + BL::ShaderNodeMath b_math_node(b_node); + MathNode *math = new MathNode(); + math->type = (NodeMath)b_math_node.operation(); + math->use_clamp = b_math_node.use_clamp(); + node = math; + } + else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) { + BL::ShaderNodeVectorMath b_vector_math_node(b_node); + VectorMathNode *vmath = new VectorMathNode(); + vmath->type = (NodeVectorMath)b_vector_math_node.operation(); + node = vmath; + } + else if (b_node.is_a(&RNA_ShaderNodeVectorTransform)) { + BL::ShaderNodeVectorTransform b_vector_transform_node(b_node); + VectorTransformNode *vtransform = new VectorTransformNode(); + vtransform->type = (NodeVectorTransformType)b_vector_transform_node.vector_type(); + vtransform->convert_from = (NodeVectorTransformConvertSpace) + b_vector_transform_node.convert_from(); + vtransform->convert_to = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to(); + node = vtransform; + } + else if (b_node.is_a(&RNA_ShaderNodeNormal)) { + BL::Node::outputs_iterator out_it; + b_node.outputs.begin(out_it); + + NormalNode *norm = new NormalNode(); + norm->direction = get_node_output_vector(b_node, "Normal"); + node = norm; + } + else if (b_node.is_a(&RNA_ShaderNodeMapping)) { + BL::ShaderNodeMapping b_mapping_node(b_node); + MappingNode *mapping = new MappingNode(); + + get_tex_mapping(&mapping->tex_mapping, b_mapping_node); + + node = mapping; + } + else if (b_node.is_a(&RNA_ShaderNodeFresnel)) { + node = new FresnelNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeLayerWeight)) { + node = new LayerWeightNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeAddShader)) { + node = new AddClosureNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeMixShader)) { + node = new MixClosureNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeAttribute)) { + BL::ShaderNodeAttribute b_attr_node(b_node); + AttributeNode *attr = new AttributeNode(); + attr->attribute = b_attr_node.attribute_name(); + node = attr; + } + else if (b_node.is_a(&RNA_ShaderNodeBackground)) { + node = new BackgroundNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeHoldout)) { + node = new HoldoutNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) { + BL::ShaderNodeBsdfAnisotropic b_aniso_node(b_node); + AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode(); + + switch (b_aniso_node.distribution()) { + case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN: + aniso->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID; + break; + case BL::ShaderNodeBsdfAnisotropic::distribution_GGX: + aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; + break; + case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX: + aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID; + break; + case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY: + aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; + break; + } + + node = aniso; + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) { + node = new DiffuseBsdfNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) { + BL::ShaderNodeSubsurfaceScattering b_subsurface_node(b_node); + + SubsurfaceScatteringNode *subsurface = new SubsurfaceScatteringNode(); + + switch (b_subsurface_node.falloff()) { + case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC: + subsurface->falloff = CLOSURE_BSSRDF_CUBIC_ID; + break; + case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN: + subsurface->falloff = CLOSURE_BSSRDF_GAUSSIAN_ID; + break; + case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY: + subsurface->falloff = CLOSURE_BSSRDF_BURLEY_ID; + break; + case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK: + subsurface->falloff = CLOSURE_BSSRDF_RANDOM_WALK_ID; + break; + } + + node = subsurface; + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) { + BL::ShaderNodeBsdfGlossy b_glossy_node(b_node); + GlossyBsdfNode *glossy = new GlossyBsdfNode(); + + switch (b_glossy_node.distribution()) { + case BL::ShaderNodeBsdfGlossy::distribution_SHARP: + glossy->distribution = CLOSURE_BSDF_REFLECTION_ID; + break; + case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN: + glossy->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; + break; + case BL::ShaderNodeBsdfGlossy::distribution_GGX: + glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID; + break; + case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY: + glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID; + break; + case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX: + glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + break; + } + node = glossy; + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfGlass)) { + BL::ShaderNodeBsdfGlass b_glass_node(b_node); + GlassBsdfNode *glass = new GlassBsdfNode(); + switch (b_glass_node.distribution()) { + case BL::ShaderNodeBsdfGlass::distribution_SHARP: + glass->distribution = CLOSURE_BSDF_SHARP_GLASS_ID; + break; + case BL::ShaderNodeBsdfGlass::distribution_BECKMANN: + glass->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID; + break; + case BL::ShaderNodeBsdfGlass::distribution_GGX: + glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; + break; + case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX: + glass->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + break; + } + node = glass; + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) { + BL::ShaderNodeBsdfRefraction b_refraction_node(b_node); + RefractionBsdfNode *refraction = new RefractionBsdfNode(); + switch (b_refraction_node.distribution()) { + case BL::ShaderNodeBsdfRefraction::distribution_SHARP: + refraction->distribution = CLOSURE_BSDF_REFRACTION_ID; + break; + case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN: + refraction->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + break; + case BL::ShaderNodeBsdfRefraction::distribution_GGX: + refraction->distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + break; + } + node = refraction; + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfToon)) { + BL::ShaderNodeBsdfToon b_toon_node(b_node); + ToonBsdfNode *toon = new ToonBsdfNode(); + switch (b_toon_node.component()) { + case BL::ShaderNodeBsdfToon::component_DIFFUSE: + toon->component = CLOSURE_BSDF_DIFFUSE_TOON_ID; + break; + case BL::ShaderNodeBsdfToon::component_GLOSSY: + toon->component = CLOSURE_BSDF_GLOSSY_TOON_ID; + break; + } + node = toon; + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfHair)) { + BL::ShaderNodeBsdfHair b_hair_node(b_node); + HairBsdfNode *hair = new HairBsdfNode(); + switch (b_hair_node.component()) { + case BL::ShaderNodeBsdfHair::component_Reflection: + hair->component = CLOSURE_BSDF_HAIR_REFLECTION_ID; + break; + case BL::ShaderNodeBsdfHair::component_Transmission: + hair->component = CLOSURE_BSDF_HAIR_TRANSMISSION_ID; + break; + } + node = hair; + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfHairPrincipled)) { + BL::ShaderNodeBsdfHairPrincipled b_principled_hair_node(b_node); + PrincipledHairBsdfNode *principled_hair = new PrincipledHairBsdfNode(); + principled_hair->parametrization = (NodePrincipledHairParametrization)get_enum( + b_principled_hair_node.ptr, + "parametrization", + NODE_PRINCIPLED_HAIR_NUM, + NODE_PRINCIPLED_HAIR_REFLECTANCE); + node = principled_hair; + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) { + BL::ShaderNodeBsdfPrincipled b_principled_node(b_node); + PrincipledBsdfNode *principled = new PrincipledBsdfNode(); + switch (b_principled_node.distribution()) { + case BL::ShaderNodeBsdfPrincipled::distribution_GGX: + principled->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; + break; + case BL::ShaderNodeBsdfPrincipled::distribution_MULTI_GGX: + principled->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + break; + } + switch (b_principled_node.subsurface_method()) { + case BL::ShaderNodeBsdfPrincipled::subsurface_method_BURLEY: + principled->subsurface_method = CLOSURE_BSSRDF_PRINCIPLED_ID; + break; + case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK: + principled->subsurface_method = CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID; + break; + } + node = principled; + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) { + node = new TranslucentBsdfNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) { + node = new TransparentBsdfNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) { + node = new VelvetBsdfNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeEmission)) { + node = new EmissionNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) { + BL::ShaderNodeAmbientOcclusion b_ao_node(b_node); + AmbientOcclusionNode *ao = new AmbientOcclusionNode(); + ao->samples = b_ao_node.samples(); + ao->inside = b_ao_node.inside(); + ao->only_local = b_ao_node.only_local(); + node = ao; + } + else if (b_node.is_a(&RNA_ShaderNodeVolumeScatter)) { + node = new ScatterVolumeNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) { + node = new AbsorptionVolumeNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeVolumePrincipled)) { + PrincipledVolumeNode *principled = new PrincipledVolumeNode(); + node = principled; + } + else if (b_node.is_a(&RNA_ShaderNodeNewGeometry)) { + node = new GeometryNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeWireframe)) { + BL::ShaderNodeWireframe b_wireframe_node(b_node); + WireframeNode *wire = new WireframeNode(); + wire->use_pixel_size = b_wireframe_node.use_pixel_size(); + node = wire; + } + else if (b_node.is_a(&RNA_ShaderNodeWavelength)) { + node = new WavelengthNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeBlackbody)) { + node = new BlackbodyNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeLightPath)) { + node = new LightPathNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeLightFalloff)) { + node = new LightFalloffNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeObjectInfo)) { + node = new ObjectInfoNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeParticleInfo)) { + node = new ParticleInfoNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeHairInfo)) { + node = new HairInfoNode(); + } + else if (b_node.is_a(&RNA_ShaderNodeBump)) { + BL::ShaderNodeBump b_bump_node(b_node); + BumpNode *bump = new BumpNode(); + bump->invert = b_bump_node.invert(); + node = bump; + } + else if (b_node.is_a(&RNA_ShaderNodeScript)) { #ifdef WITH_OSL - if(scene->shader_manager->use_osl()) { - /* create script node */ - BL::ShaderNodeScript b_script_node(b_node); - - OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager; - string bytecode_hash = b_script_node.bytecode_hash(); - - if(!bytecode_hash.empty()) { - node = manager->osl_node("", bytecode_hash, b_script_node.bytecode()); - } - else { - string absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath()); - node = manager->osl_node(absolute_filepath, ""); - } - } + if (scene->shader_manager->use_osl()) { + /* create script node */ + BL::ShaderNodeScript b_script_node(b_node); + + OSLShaderManager *manager = (OSLShaderManager *)scene->shader_manager; + string bytecode_hash = b_script_node.bytecode_hash(); + + if (!bytecode_hash.empty()) { + node = manager->osl_node("", bytecode_hash, b_script_node.bytecode()); + } + else { + string absolute_filepath = blender_absolute_path( + b_data, b_ntree, b_script_node.filepath()); + node = manager->osl_node(absolute_filepath, ""); + } + } #else - (void) b_data; - (void) b_ntree; + (void)b_data; + (void)b_ntree; #endif - } - else if(b_node.is_a(&RNA_ShaderNodeTexImage)) { - BL::ShaderNodeTexImage b_image_node(b_node); - BL::Image b_image(b_image_node.image()); - BL::ImageUser b_image_user(b_image_node.image_user()); - ImageTextureNode *image = new ImageTextureNode(); - if(b_image) { - /* builtin images will use callback-based reading because - * they could only be loaded correct from blender side - */ - bool is_builtin = b_image.packed_file() || - b_image.source() == BL::Image::source_GENERATED || - b_image.source() == BL::Image::source_MOVIE || - (b_engine.is_preview() && - b_image.source() != BL::Image::source_SEQUENCE); - - if(is_builtin) { - /* for builtin images we're using image datablock name to find an image to - * read pixels from later - * - * also store frame number as well, so there's no differences in handling - * builtin names for packed images and movies - */ - int scene_frame = b_scene.frame_current(); - int image_frame = image_user_frame_number(b_image_user, - scene_frame); - image->filename = b_image.name() + "@" + string_printf("%d", image_frame); - image->builtin_data = b_image.ptr.data; - } - else { - image->filename = image_user_file_path(b_image_user, - b_image, - b_scene.frame_current()); - image->builtin_data = NULL; - } - - image->animated = b_image_node.image_user().use_auto_refresh(); - image->use_alpha = b_image.use_alpha(); - - /* TODO: restore */ - /* TODO(sergey): Does not work properly when we change builtin type. */ + } + else if (b_node.is_a(&RNA_ShaderNodeTexImage)) { + BL::ShaderNodeTexImage b_image_node(b_node); + BL::Image b_image(b_image_node.image()); + BL::ImageUser b_image_user(b_image_node.image_user()); + ImageTextureNode *image = new ImageTextureNode(); + if (b_image) { + /* builtin images will use callback-based reading because + * they could only be loaded correct from blender side + */ + bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED || + b_image.source() == BL::Image::source_MOVIE || + (b_engine.is_preview() && b_image.source() != BL::Image::source_SEQUENCE); + + if (is_builtin) { + /* for builtin images we're using image datablock name to find an image to + * read pixels from later + * + * also store frame number as well, so there's no differences in handling + * builtin names for packed images and movies + */ + int scene_frame = b_scene.frame_current(); + int image_frame = image_user_frame_number(b_image_user, scene_frame); + image->filename = b_image.name() + "@" + string_printf("%d", image_frame); + image->builtin_data = b_image.ptr.data; + } + else { + image->filename = image_user_file_path(b_image_user, b_image, b_scene.frame_current()); + image->builtin_data = NULL; + } + + image->animated = b_image_node.image_user().use_auto_refresh(); + image->use_alpha = b_image.use_alpha(); + + /* TODO: restore */ + /* TODO(sergey): Does not work properly when we change builtin type. */ #if 0 - if(b_image.is_updated()) { - scene->image_manager->tag_reload_image( - image->filename.string(), - image->builtin_data, - get_image_interpolation(b_image_node), - get_image_extension(b_image_node), - image->use_alpha); - } + if(b_image.is_updated()) { + scene->image_manager->tag_reload_image( + image->filename.string(), + image->builtin_data, + get_image_interpolation(b_image_node), + get_image_extension(b_image_node), + image->use_alpha); + } #endif - } - image->color_space = (NodeImageColorSpace)b_image_node.color_space(); - image->projection = (NodeImageProjection)b_image_node.projection(); - image->interpolation = get_image_interpolation(b_image_node); - image->extension = get_image_extension(b_image_node); - image->projection_blend = b_image_node.projection_blend(); - BL::TexMapping b_texture_mapping(b_image_node.texture_mapping()); - get_tex_mapping(&image->tex_mapping, b_texture_mapping); - node = image; - } - else if(b_node.is_a(&RNA_ShaderNodeTexEnvironment)) { - BL::ShaderNodeTexEnvironment b_env_node(b_node); - BL::Image b_image(b_env_node.image()); - BL::ImageUser b_image_user(b_env_node.image_user()); - EnvironmentTextureNode *env = new EnvironmentTextureNode(); - if(b_image) { - bool is_builtin = b_image.packed_file() || - b_image.source() == BL::Image::source_GENERATED || - b_image.source() == BL::Image::source_MOVIE || - (b_engine.is_preview() && - b_image.source() != BL::Image::source_SEQUENCE); - - if(is_builtin) { - int scene_frame = b_scene.frame_current(); - int image_frame = image_user_frame_number(b_image_user, - scene_frame); - env->filename = b_image.name() + "@" + string_printf("%d", image_frame); - env->builtin_data = b_image.ptr.data; - } - else { - env->filename = image_user_file_path(b_image_user, - b_image, - b_scene.frame_current()); - env->builtin_data = NULL; - } - - env->animated = b_env_node.image_user().use_auto_refresh(); - env->use_alpha = b_image.use_alpha(); - - /* TODO: restore */ - /* TODO(sergey): Does not work properly when we change builtin type. */ + } + image->color_space = (NodeImageColorSpace)b_image_node.color_space(); + image->projection = (NodeImageProjection)b_image_node.projection(); + image->interpolation = get_image_interpolation(b_image_node); + image->extension = get_image_extension(b_image_node); + image->projection_blend = b_image_node.projection_blend(); + BL::TexMapping b_texture_mapping(b_image_node.texture_mapping()); + get_tex_mapping(&image->tex_mapping, b_texture_mapping); + node = image; + } + else if (b_node.is_a(&RNA_ShaderNodeTexEnvironment)) { + BL::ShaderNodeTexEnvironment b_env_node(b_node); + BL::Image b_image(b_env_node.image()); + BL::ImageUser b_image_user(b_env_node.image_user()); + EnvironmentTextureNode *env = new EnvironmentTextureNode(); + if (b_image) { + bool is_builtin = b_image.packed_file() || b_image.source() == BL::Image::source_GENERATED || + b_image.source() == BL::Image::source_MOVIE || + (b_engine.is_preview() && b_image.source() != BL::Image::source_SEQUENCE); + + if (is_builtin) { + int scene_frame = b_scene.frame_current(); + int image_frame = image_user_frame_number(b_image_user, scene_frame); + env->filename = b_image.name() + "@" + string_printf("%d", image_frame); + env->builtin_data = b_image.ptr.data; + } + else { + env->filename = image_user_file_path(b_image_user, b_image, b_scene.frame_current()); + env->builtin_data = NULL; + } + + env->animated = b_env_node.image_user().use_auto_refresh(); + env->use_alpha = b_image.use_alpha(); + + /* TODO: restore */ + /* TODO(sergey): Does not work properly when we change builtin type. */ #if 0 - if(b_image.is_updated()) { - scene->image_manager->tag_reload_image( - env->filename.string(), - env->builtin_data, - get_image_interpolation(b_env_node), - EXTENSION_REPEAT, - env->use_alpha); - } + if(b_image.is_updated()) { + scene->image_manager->tag_reload_image( + env->filename.string(), + env->builtin_data, + get_image_interpolation(b_env_node), + EXTENSION_REPEAT, + env->use_alpha); + } #endif - } - env->color_space = (NodeImageColorSpace)b_env_node.color_space(); - env->interpolation = get_image_interpolation(b_env_node); - env->projection = (NodeEnvironmentProjection)b_env_node.projection(); - BL::TexMapping b_texture_mapping(b_env_node.texture_mapping()); - get_tex_mapping(&env->tex_mapping, b_texture_mapping); - node = env; - } - else if(b_node.is_a(&RNA_ShaderNodeTexGradient)) { - BL::ShaderNodeTexGradient b_gradient_node(b_node); - GradientTextureNode *gradient = new GradientTextureNode(); - gradient->type = (NodeGradientType)b_gradient_node.gradient_type(); - BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping()); - get_tex_mapping(&gradient->tex_mapping, b_texture_mapping); - node = gradient; - } - else if(b_node.is_a(&RNA_ShaderNodeTexVoronoi)) { - BL::ShaderNodeTexVoronoi b_voronoi_node(b_node); - VoronoiTextureNode *voronoi = new VoronoiTextureNode(); - voronoi->coloring = (NodeVoronoiColoring)b_voronoi_node.coloring(); - voronoi->metric = (NodeVoronoiDistanceMetric)b_voronoi_node.distance(); - voronoi->feature = (NodeVoronoiFeature)b_voronoi_node.feature(); - BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping()); - get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping); - node = voronoi; - } - else if(b_node.is_a(&RNA_ShaderNodeTexMagic)) { - BL::ShaderNodeTexMagic b_magic_node(b_node); - MagicTextureNode *magic = new MagicTextureNode(); - magic->depth = b_magic_node.turbulence_depth(); - BL::TexMapping b_texture_mapping(b_magic_node.texture_mapping()); - get_tex_mapping(&magic->tex_mapping, b_texture_mapping); - node = magic; - } - else if(b_node.is_a(&RNA_ShaderNodeTexWave)) { - BL::ShaderNodeTexWave b_wave_node(b_node); - WaveTextureNode *wave = new WaveTextureNode(); - wave->type = (NodeWaveType)b_wave_node.wave_type(); - wave->profile = (NodeWaveProfile)b_wave_node.wave_profile(); - BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping()); - get_tex_mapping(&wave->tex_mapping, b_texture_mapping); - node = wave; - } - else if(b_node.is_a(&RNA_ShaderNodeTexChecker)) { - BL::ShaderNodeTexChecker b_checker_node(b_node); - CheckerTextureNode *checker = new CheckerTextureNode(); - BL::TexMapping b_texture_mapping(b_checker_node.texture_mapping()); - get_tex_mapping(&checker->tex_mapping, b_texture_mapping); - node = checker; - } - else if(b_node.is_a(&RNA_ShaderNodeTexBrick)) { - BL::ShaderNodeTexBrick b_brick_node(b_node); - BrickTextureNode *brick = new BrickTextureNode(); - brick->offset = b_brick_node.offset(); - brick->offset_frequency = b_brick_node.offset_frequency(); - brick->squash = b_brick_node.squash(); - brick->squash_frequency = b_brick_node.squash_frequency(); - BL::TexMapping b_texture_mapping(b_brick_node.texture_mapping()); - get_tex_mapping(&brick->tex_mapping, b_texture_mapping); - node = brick; - } - else if(b_node.is_a(&RNA_ShaderNodeTexNoise)) { - BL::ShaderNodeTexNoise b_noise_node(b_node); - NoiseTextureNode *noise = new NoiseTextureNode(); - BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping()); - get_tex_mapping(&noise->tex_mapping, b_texture_mapping); - node = noise; - } - else if(b_node.is_a(&RNA_ShaderNodeTexMusgrave)) { - BL::ShaderNodeTexMusgrave b_musgrave_node(b_node); - MusgraveTextureNode *musgrave = new MusgraveTextureNode(); - musgrave->type = (NodeMusgraveType)b_musgrave_node.musgrave_type(); - BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping()); - get_tex_mapping(&musgrave->tex_mapping, b_texture_mapping); - node = musgrave; - } - else if(b_node.is_a(&RNA_ShaderNodeTexCoord)) { - BL::ShaderNodeTexCoord b_tex_coord_node(b_node); - TextureCoordinateNode *tex_coord = new TextureCoordinateNode(); - tex_coord->from_dupli = b_tex_coord_node.from_instancer(); - if(b_tex_coord_node.object()) { - tex_coord->use_transform = true; - tex_coord->ob_tfm = get_transform(b_tex_coord_node.object().matrix_world()); - } - node = tex_coord; - } - else if(b_node.is_a(&RNA_ShaderNodeTexSky)) { - BL::ShaderNodeTexSky b_sky_node(b_node); - SkyTextureNode *sky = new SkyTextureNode(); - sky->type = (NodeSkyType)b_sky_node.sky_type(); - sky->sun_direction = normalize(get_float3(b_sky_node.sun_direction())); - sky->turbidity = b_sky_node.turbidity(); - sky->ground_albedo = b_sky_node.ground_albedo(); - BL::TexMapping b_texture_mapping(b_sky_node.texture_mapping()); - get_tex_mapping(&sky->tex_mapping, b_texture_mapping); - node = sky; - } - else if(b_node.is_a(&RNA_ShaderNodeTexIES)) { - BL::ShaderNodeTexIES b_ies_node(b_node); - IESLightNode *ies = new IESLightNode(); - switch(b_ies_node.mode()) { - case BL::ShaderNodeTexIES::mode_EXTERNAL: - ies->filename = blender_absolute_path(b_data, b_ntree, b_ies_node.filepath()); - break; - case BL::ShaderNodeTexIES::mode_INTERNAL: - ies->ies = get_text_datablock_content(b_ies_node.ies().ptr); - if(ies->ies.empty()) { - ies->ies = "\n"; - } - break; - } - node = ies; - } - else if(b_node.is_a(&RNA_ShaderNodeNormalMap)) { - BL::ShaderNodeNormalMap b_normal_map_node(b_node); - NormalMapNode *nmap = new NormalMapNode(); - nmap->space = (NodeNormalMapSpace)b_normal_map_node.space(); - nmap->attribute = b_normal_map_node.uv_map(); - node = nmap; - } - else if(b_node.is_a(&RNA_ShaderNodeTangent)) { - BL::ShaderNodeTangent b_tangent_node(b_node); - TangentNode *tangent = new TangentNode(); - tangent->direction_type = (NodeTangentDirectionType)b_tangent_node.direction_type(); - tangent->axis = (NodeTangentAxis)b_tangent_node.axis(); - tangent->attribute = b_tangent_node.uv_map(); - node = tangent; - } - else if(b_node.is_a(&RNA_ShaderNodeUVMap)) { - BL::ShaderNodeUVMap b_uvmap_node(b_node); - UVMapNode *uvm = new UVMapNode(); - uvm->attribute = b_uvmap_node.uv_map(); - uvm->from_dupli = b_uvmap_node.from_instancer(); - node = uvm; - } - else if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) { - BL::ShaderNodeTexPointDensity b_point_density_node(b_node); - PointDensityTextureNode *point_density = new PointDensityTextureNode(); - point_density->filename = b_point_density_node.name(); - point_density->space = (NodeTexVoxelSpace)b_point_density_node.space(); - point_density->interpolation = get_image_interpolation(b_point_density_node); - point_density->builtin_data = b_point_density_node.ptr.data; - point_density->image_manager = scene->image_manager; - - /* TODO(sergey): Use more proper update flag. */ - if(true) { - point_density->add_image(); - b_point_density_node.cache_point_density(b_depsgraph); - scene->image_manager->tag_reload_image( - point_density->filename.string(), - point_density->builtin_data, - point_density->interpolation, - EXTENSION_CLIP, - true); - } - node = point_density; - - /* Transformation form world space to texture space. - * - * NOTE: Do this after the texture is cached, this is because getting - * min/max will need to access this cache. - */ - BL::Object b_ob(b_point_density_node.object()); - if(b_ob) { - float3 loc, size; - point_density_texture_space(b_depsgraph, - b_point_density_node, - loc, - size); - point_density->tfm = - transform_translate(-loc) * transform_scale(size) * - transform_inverse(get_transform(b_ob.matrix_world())); - } - } - else if(b_node.is_a(&RNA_ShaderNodeBevel)) { - BL::ShaderNodeBevel b_bevel_node(b_node); - BevelNode *bevel = new BevelNode(); - bevel->samples = b_bevel_node.samples(); - node = bevel; - } - else if(b_node.is_a(&RNA_ShaderNodeDisplacement)) { - BL::ShaderNodeDisplacement b_disp_node(b_node); - DisplacementNode *disp = new DisplacementNode(); - disp->space = (NodeNormalMapSpace)b_disp_node.space(); - node = disp; - } - else if(b_node.is_a(&RNA_ShaderNodeVectorDisplacement)) { - BL::ShaderNodeVectorDisplacement b_disp_node(b_node); - VectorDisplacementNode *disp = new VectorDisplacementNode(); - disp->space = (NodeNormalMapSpace)b_disp_node.space(); - disp->attribute = ""; - node = disp; - } - - if(node) { - node->name = b_node.name(); - graph->add(node); - } - - return node; + } + env->color_space = (NodeImageColorSpace)b_env_node.color_space(); + env->interpolation = get_image_interpolation(b_env_node); + env->projection = (NodeEnvironmentProjection)b_env_node.projection(); + BL::TexMapping b_texture_mapping(b_env_node.texture_mapping()); + get_tex_mapping(&env->tex_mapping, b_texture_mapping); + node = env; + } + else if (b_node.is_a(&RNA_ShaderNodeTexGradient)) { + BL::ShaderNodeTexGradient b_gradient_node(b_node); + GradientTextureNode *gradient = new GradientTextureNode(); + gradient->type = (NodeGradientType)b_gradient_node.gradient_type(); + BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping()); + get_tex_mapping(&gradient->tex_mapping, b_texture_mapping); + node = gradient; + } + else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) { + BL::ShaderNodeTexVoronoi b_voronoi_node(b_node); + VoronoiTextureNode *voronoi = new VoronoiTextureNode(); + voronoi->coloring = (NodeVoronoiColoring)b_voronoi_node.coloring(); + voronoi->metric = (NodeVoronoiDistanceMetric)b_voronoi_node.distance(); + voronoi->feature = (NodeVoronoiFeature)b_voronoi_node.feature(); + BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping()); + get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping); + node = voronoi; + } + else if (b_node.is_a(&RNA_ShaderNodeTexMagic)) { + BL::ShaderNodeTexMagic b_magic_node(b_node); + MagicTextureNode *magic = new MagicTextureNode(); + magic->depth = b_magic_node.turbulence_depth(); + BL::TexMapping b_texture_mapping(b_magic_node.texture_mapping()); + get_tex_mapping(&magic->tex_mapping, b_texture_mapping); + node = magic; + } + else if (b_node.is_a(&RNA_ShaderNodeTexWave)) { + BL::ShaderNodeTexWave b_wave_node(b_node); + WaveTextureNode *wave = new WaveTextureNode(); + wave->type = (NodeWaveType)b_wave_node.wave_type(); + wave->profile = (NodeWaveProfile)b_wave_node.wave_profile(); + BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping()); + get_tex_mapping(&wave->tex_mapping, b_texture_mapping); + node = wave; + } + else if (b_node.is_a(&RNA_ShaderNodeTexChecker)) { + BL::ShaderNodeTexChecker b_checker_node(b_node); + CheckerTextureNode *checker = new CheckerTextureNode(); + BL::TexMapping b_texture_mapping(b_checker_node.texture_mapping()); + get_tex_mapping(&checker->tex_mapping, b_texture_mapping); + node = checker; + } + else if (b_node.is_a(&RNA_ShaderNodeTexBrick)) { + BL::ShaderNodeTexBrick b_brick_node(b_node); + BrickTextureNode *brick = new BrickTextureNode(); + brick->offset = b_brick_node.offset(); + brick->offset_frequency = b_brick_node.offset_frequency(); + brick->squash = b_brick_node.squash(); + brick->squash_frequency = b_brick_node.squash_frequency(); + BL::TexMapping b_texture_mapping(b_brick_node.texture_mapping()); + get_tex_mapping(&brick->tex_mapping, b_texture_mapping); + node = brick; + } + else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) { + BL::ShaderNodeTexNoise b_noise_node(b_node); + NoiseTextureNode *noise = new NoiseTextureNode(); + BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping()); + get_tex_mapping(&noise->tex_mapping, b_texture_mapping); + node = noise; + } + else if (b_node.is_a(&RNA_ShaderNodeTexMusgrave)) { + BL::ShaderNodeTexMusgrave b_musgrave_node(b_node); + MusgraveTextureNode *musgrave = new MusgraveTextureNode(); + musgrave->type = (NodeMusgraveType)b_musgrave_node.musgrave_type(); + BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping()); + get_tex_mapping(&musgrave->tex_mapping, b_texture_mapping); + node = musgrave; + } + else if (b_node.is_a(&RNA_ShaderNodeTexCoord)) { + BL::ShaderNodeTexCoord b_tex_coord_node(b_node); + TextureCoordinateNode *tex_coord = new TextureCoordinateNode(); + tex_coord->from_dupli = b_tex_coord_node.from_instancer(); + if (b_tex_coord_node.object()) { + tex_coord->use_transform = true; + tex_coord->ob_tfm = get_transform(b_tex_coord_node.object().matrix_world()); + } + node = tex_coord; + } + else if (b_node.is_a(&RNA_ShaderNodeTexSky)) { + BL::ShaderNodeTexSky b_sky_node(b_node); + SkyTextureNode *sky = new SkyTextureNode(); + sky->type = (NodeSkyType)b_sky_node.sky_type(); + sky->sun_direction = normalize(get_float3(b_sky_node.sun_direction())); + sky->turbidity = b_sky_node.turbidity(); + sky->ground_albedo = b_sky_node.ground_albedo(); + BL::TexMapping b_texture_mapping(b_sky_node.texture_mapping()); + get_tex_mapping(&sky->tex_mapping, b_texture_mapping); + node = sky; + } + else if (b_node.is_a(&RNA_ShaderNodeTexIES)) { + BL::ShaderNodeTexIES b_ies_node(b_node); + IESLightNode *ies = new IESLightNode(); + switch (b_ies_node.mode()) { + case BL::ShaderNodeTexIES::mode_EXTERNAL: + ies->filename = blender_absolute_path(b_data, b_ntree, b_ies_node.filepath()); + break; + case BL::ShaderNodeTexIES::mode_INTERNAL: + ies->ies = get_text_datablock_content(b_ies_node.ies().ptr); + if (ies->ies.empty()) { + ies->ies = "\n"; + } + break; + } + node = ies; + } + else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) { + BL::ShaderNodeNormalMap b_normal_map_node(b_node); + NormalMapNode *nmap = new NormalMapNode(); + nmap->space = (NodeNormalMapSpace)b_normal_map_node.space(); + nmap->attribute = b_normal_map_node.uv_map(); + node = nmap; + } + else if (b_node.is_a(&RNA_ShaderNodeTangent)) { + BL::ShaderNodeTangent b_tangent_node(b_node); + TangentNode *tangent = new TangentNode(); + tangent->direction_type = (NodeTangentDirectionType)b_tangent_node.direction_type(); + tangent->axis = (NodeTangentAxis)b_tangent_node.axis(); + tangent->attribute = b_tangent_node.uv_map(); + node = tangent; + } + else if (b_node.is_a(&RNA_ShaderNodeUVMap)) { + BL::ShaderNodeUVMap b_uvmap_node(b_node); + UVMapNode *uvm = new UVMapNode(); + uvm->attribute = b_uvmap_node.uv_map(); + uvm->from_dupli = b_uvmap_node.from_instancer(); + node = uvm; + } + else if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) { + BL::ShaderNodeTexPointDensity b_point_density_node(b_node); + PointDensityTextureNode *point_density = new PointDensityTextureNode(); + point_density->filename = b_point_density_node.name(); + point_density->space = (NodeTexVoxelSpace)b_point_density_node.space(); + point_density->interpolation = get_image_interpolation(b_point_density_node); + point_density->builtin_data = b_point_density_node.ptr.data; + point_density->image_manager = scene->image_manager; + + /* TODO(sergey): Use more proper update flag. */ + if (true) { + point_density->add_image(); + b_point_density_node.cache_point_density(b_depsgraph); + scene->image_manager->tag_reload_image(point_density->filename.string(), + point_density->builtin_data, + point_density->interpolation, + EXTENSION_CLIP, + true); + } + node = point_density; + + /* Transformation form world space to texture space. + * + * NOTE: Do this after the texture is cached, this is because getting + * min/max will need to access this cache. + */ + BL::Object b_ob(b_point_density_node.object()); + if (b_ob) { + float3 loc, size; + point_density_texture_space(b_depsgraph, b_point_density_node, loc, size); + point_density->tfm = transform_translate(-loc) * transform_scale(size) * + transform_inverse(get_transform(b_ob.matrix_world())); + } + } + else if (b_node.is_a(&RNA_ShaderNodeBevel)) { + BL::ShaderNodeBevel b_bevel_node(b_node); + BevelNode *bevel = new BevelNode(); + bevel->samples = b_bevel_node.samples(); + node = bevel; + } + else if (b_node.is_a(&RNA_ShaderNodeDisplacement)) { + BL::ShaderNodeDisplacement b_disp_node(b_node); + DisplacementNode *disp = new DisplacementNode(); + disp->space = (NodeNormalMapSpace)b_disp_node.space(); + node = disp; + } + else if (b_node.is_a(&RNA_ShaderNodeVectorDisplacement)) { + BL::ShaderNodeVectorDisplacement b_disp_node(b_node); + VectorDisplacementNode *disp = new VectorDisplacementNode(); + disp->space = (NodeNormalMapSpace)b_disp_node.space(); + disp->attribute = ""; + node = disp; + } + + if (node) { + node->name = b_node.name(); + graph->add(node); + } + + return node; } static bool node_use_modified_socket_name(ShaderNode *node) { - if(node->special_type == SHADER_SPECIAL_TYPE_SCRIPT) - return false; + if (node->special_type == SHADER_SPECIAL_TYPE_SCRIPT) + return false; - return true; + return true; } static ShaderInput *node_find_input_by_name(ShaderNode *node, - BL::Node& b_node, - BL::NodeSocket& b_socket) + BL::Node &b_node, + BL::NodeSocket &b_socket) { - string name = b_socket.name(); + string name = b_socket.name(); - if(node_use_modified_socket_name(node)) { - BL::Node::inputs_iterator b_input; - bool found = false; - int counter = 0, total = 0; + if (node_use_modified_socket_name(node)) { + BL::Node::inputs_iterator b_input; + bool found = false; + int counter = 0, total = 0; - for(b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) { - if(b_input->name() == name) { - if(!found) - counter++; - total++; - } + for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) { + if (b_input->name() == name) { + if (!found) + counter++; + total++; + } - if(b_input->ptr.data == b_socket.ptr.data) - found = true; - } + if (b_input->ptr.data == b_socket.ptr.data) + found = true; + } - /* rename if needed */ - if(name == "Shader") - name = "Closure"; + /* rename if needed */ + if (name == "Shader") + name = "Closure"; - if(total > 1) - name = string_printf("%s%d", name.c_str(), counter); - } + if (total > 1) + name = string_printf("%s%d", name.c_str(), counter); + } - return node->input(name.c_str()); + return node->input(name.c_str()); } static ShaderOutput *node_find_output_by_name(ShaderNode *node, - BL::Node& b_node, - BL::NodeSocket& b_socket) + BL::Node &b_node, + BL::NodeSocket &b_socket) { - string name = b_socket.name(); + string name = b_socket.name(); - if(node_use_modified_socket_name(node)) { - BL::Node::outputs_iterator b_output; - bool found = false; - int counter = 0, total = 0; + if (node_use_modified_socket_name(node)) { + BL::Node::outputs_iterator b_output; + bool found = false; + int counter = 0, total = 0; - for(b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) { - if(b_output->name() == name) { - if(!found) - counter++; - total++; - } + for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) { + if (b_output->name() == name) { + if (!found) + counter++; + total++; + } - if(b_output->ptr.data == b_socket.ptr.data) - found = true; - } + if (b_output->ptr.data == b_socket.ptr.data) + found = true; + } - /* rename if needed */ - if(name == "Shader") - name = "Closure"; + /* rename if needed */ + if (name == "Shader") + name = "Closure"; - if(total > 1) - name = string_printf("%s%d", name.c_str(), counter); - } + if (total > 1) + name = string_printf("%s%d", name.c_str(), counter); + } - return node->output(name.c_str()); + return node->output(name.c_str()); } static void add_nodes(Scene *scene, - BL::RenderEngine& b_engine, - BL::BlendData& b_data, - BL::Depsgraph& b_depsgraph, - BL::Scene& b_scene, + BL::RenderEngine &b_engine, + BL::BlendData &b_data, + BL::Depsgraph &b_depsgraph, + BL::Scene &b_scene, ShaderGraph *graph, - BL::ShaderNodeTree& b_ntree, + BL::ShaderNodeTree &b_ntree, const ProxyMap &proxy_input_map, const ProxyMap &proxy_output_map) { - /* add nodes */ - BL::ShaderNodeTree::nodes_iterator b_node; - PtrInputMap input_map; - PtrOutputMap output_map; - - BL::Node::inputs_iterator b_input; - BL::Node::outputs_iterator b_output; - - /* find the node to use for output if there are multiple */ - BL::ShaderNode output_node = b_ntree.get_output_node(BL::ShaderNodeOutputMaterial::target_CYCLES); - - /* add nodes */ - for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) { - if(b_node->mute() || b_node->is_a(&RNA_NodeReroute)) { - /* replace muted node with internal links */ - BL::Node::internal_links_iterator b_link; - for(b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) { - BL::NodeSocket to_socket(b_link->to_socket()); - SocketType::Type to_socket_type = convert_socket_type(to_socket); - if(to_socket_type == SocketType::UNDEFINED) { - continue; - } - - ConvertNode *proxy = new ConvertNode(to_socket_type, to_socket_type, true); - - input_map[b_link->from_socket().ptr.data] = proxy->inputs[0]; - output_map[b_link->to_socket().ptr.data] = proxy->outputs[0]; - - graph->add(proxy); - } - } - else if(b_node->is_a(&RNA_ShaderNodeGroup) || - b_node->is_a(&RNA_NodeCustomGroup) || - b_node->is_a(&RNA_ShaderNodeCustomGroup)) { - - BL::ShaderNodeTree b_group_ntree(PointerRNA_NULL); - if(b_node->is_a(&RNA_ShaderNodeGroup)) - b_group_ntree = BL::ShaderNodeTree(((BL::NodeGroup)(*b_node)).node_tree()); - else if (b_node->is_a(&RNA_NodeCustomGroup)) - b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(*b_node)).node_tree()); - else - b_group_ntree = BL::ShaderNodeTree(((BL::ShaderNodeCustomGroup)(*b_node)).node_tree()); - - ProxyMap group_proxy_input_map, group_proxy_output_map; - - /* Add a proxy node for each socket - * Do this even if the node group has no internal tree, - * so that links have something to connect to and assert won't fail. - */ - for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) { - SocketType::Type input_type = convert_socket_type(*b_input); - if(input_type == SocketType::UNDEFINED) { - continue; - } - - ConvertNode *proxy = new ConvertNode(input_type, input_type, true); - graph->add(proxy); - - /* register the proxy node for internal binding */ - group_proxy_input_map[b_input->identifier()] = proxy; - - input_map[b_input->ptr.data] = proxy->inputs[0]; - - set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree); - } - for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) { - SocketType::Type output_type = convert_socket_type(*b_output); - if(output_type == SocketType::UNDEFINED) { - continue; - } - - ConvertNode *proxy = new ConvertNode(output_type, output_type, true); - graph->add(proxy); - - /* register the proxy node for internal binding */ - group_proxy_output_map[b_output->identifier()] = proxy; - - output_map[b_output->ptr.data] = proxy->outputs[0]; - } - - if(b_group_ntree) { - add_nodes(scene, - b_engine, - b_data, - b_depsgraph, - b_scene, - graph, - b_group_ntree, - group_proxy_input_map, - group_proxy_output_map); - } - } - else if(b_node->is_a(&RNA_NodeGroupInput)) { - /* map each socket to a proxy node */ - for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) { - ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output->identifier()); - if(proxy_it != proxy_input_map.end()) { - ConvertNode *proxy = proxy_it->second; - - output_map[b_output->ptr.data] = proxy->outputs[0]; - } - } - } - else if(b_node->is_a(&RNA_NodeGroupOutput)) { - BL::NodeGroupOutput b_output_node(*b_node); - /* only the active group output is used */ - if(b_output_node.is_active_output()) { - /* map each socket to a proxy node */ - for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) { - ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input->identifier()); - if(proxy_it != proxy_output_map.end()) { - ConvertNode *proxy = proxy_it->second; - - input_map[b_input->ptr.data] = proxy->inputs[0]; - - set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree); - } - } - } - } - else { - ShaderNode *node = NULL; - - if(b_node->ptr.data == output_node.ptr.data) { - node = graph->output(); - } - else { - BL::ShaderNode b_shader_node(*b_node); - node = add_node(scene, - b_engine, - b_data, - b_depsgraph, - b_scene, - graph, - b_ntree, - b_shader_node); - } - - if(node) { - /* map node sockets for linking */ - for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) { - ShaderInput *input = node_find_input_by_name(node, *b_node, *b_input); - if(!input) { - /* XXX should not happen, report error? */ - continue; - } - input_map[b_input->ptr.data] = input; - - set_default_value(input, *b_input, b_data, b_ntree); - } - for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) { - ShaderOutput *output = node_find_output_by_name(node, *b_node, *b_output); - if(!output) { - /* XXX should not happen, report error? */ - continue; - } - output_map[b_output->ptr.data] = output; - } - } - } - } - - /* connect nodes */ - BL::NodeTree::links_iterator b_link; - - for(b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) { - /* Ignore invalid links to avoid unwanted cycles created in graph. */ - if(!b_link->is_valid()) { - continue; - } - /* get blender link data */ - BL::NodeSocket b_from_sock = b_link->from_socket(); - BL::NodeSocket b_to_sock = b_link->to_socket(); - - ShaderOutput *output = 0; - ShaderInput *input = 0; - - PtrOutputMap::iterator output_it = output_map.find(b_from_sock.ptr.data); - if(output_it != output_map.end()) - output = output_it->second; - PtrInputMap::iterator input_it = input_map.find(b_to_sock.ptr.data); - if(input_it != input_map.end()) - input = input_it->second; - - /* either node may be NULL when the node was not exported, typically - * because the node type is not supported */ - if(output && input) - graph->connect(output, input); - } + /* add nodes */ + BL::ShaderNodeTree::nodes_iterator b_node; + PtrInputMap input_map; + PtrOutputMap output_map; + + BL::Node::inputs_iterator b_input; + BL::Node::outputs_iterator b_output; + + /* find the node to use for output if there are multiple */ + BL::ShaderNode output_node = b_ntree.get_output_node( + BL::ShaderNodeOutputMaterial::target_CYCLES); + + /* add nodes */ + for (b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) { + if (b_node->mute() || b_node->is_a(&RNA_NodeReroute)) { + /* replace muted node with internal links */ + BL::Node::internal_links_iterator b_link; + for (b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); + ++b_link) { + BL::NodeSocket to_socket(b_link->to_socket()); + SocketType::Type to_socket_type = convert_socket_type(to_socket); + if (to_socket_type == SocketType::UNDEFINED) { + continue; + } + + ConvertNode *proxy = new ConvertNode(to_socket_type, to_socket_type, true); + + input_map[b_link->from_socket().ptr.data] = proxy->inputs[0]; + output_map[b_link->to_socket().ptr.data] = proxy->outputs[0]; + + graph->add(proxy); + } + } + else if (b_node->is_a(&RNA_ShaderNodeGroup) || b_node->is_a(&RNA_NodeCustomGroup) || + b_node->is_a(&RNA_ShaderNodeCustomGroup)) { + + BL::ShaderNodeTree b_group_ntree(PointerRNA_NULL); + if (b_node->is_a(&RNA_ShaderNodeGroup)) + b_group_ntree = BL::ShaderNodeTree(((BL::NodeGroup)(*b_node)).node_tree()); + else if (b_node->is_a(&RNA_NodeCustomGroup)) + b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(*b_node)).node_tree()); + else + b_group_ntree = BL::ShaderNodeTree(((BL::ShaderNodeCustomGroup)(*b_node)).node_tree()); + + ProxyMap group_proxy_input_map, group_proxy_output_map; + + /* Add a proxy node for each socket + * Do this even if the node group has no internal tree, + * so that links have something to connect to and assert won't fail. + */ + for (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) { + SocketType::Type input_type = convert_socket_type(*b_input); + if (input_type == SocketType::UNDEFINED) { + continue; + } + + ConvertNode *proxy = new ConvertNode(input_type, input_type, true); + graph->add(proxy); + + /* register the proxy node for internal binding */ + group_proxy_input_map[b_input->identifier()] = proxy; + + input_map[b_input->ptr.data] = proxy->inputs[0]; + + set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree); + } + for (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) { + SocketType::Type output_type = convert_socket_type(*b_output); + if (output_type == SocketType::UNDEFINED) { + continue; + } + + ConvertNode *proxy = new ConvertNode(output_type, output_type, true); + graph->add(proxy); + + /* register the proxy node for internal binding */ + group_proxy_output_map[b_output->identifier()] = proxy; + + output_map[b_output->ptr.data] = proxy->outputs[0]; + } + + if (b_group_ntree) { + add_nodes(scene, + b_engine, + b_data, + b_depsgraph, + b_scene, + graph, + b_group_ntree, + group_proxy_input_map, + group_proxy_output_map); + } + } + else if (b_node->is_a(&RNA_NodeGroupInput)) { + /* map each socket to a proxy node */ + for (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) { + ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output->identifier()); + if (proxy_it != proxy_input_map.end()) { + ConvertNode *proxy = proxy_it->second; + + output_map[b_output->ptr.data] = proxy->outputs[0]; + } + } + } + else if (b_node->is_a(&RNA_NodeGroupOutput)) { + BL::NodeGroupOutput b_output_node(*b_node); + /* only the active group output is used */ + if (b_output_node.is_active_output()) { + /* map each socket to a proxy node */ + for (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) { + ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input->identifier()); + if (proxy_it != proxy_output_map.end()) { + ConvertNode *proxy = proxy_it->second; + + input_map[b_input->ptr.data] = proxy->inputs[0]; + + set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree); + } + } + } + } + else { + ShaderNode *node = NULL; + + if (b_node->ptr.data == output_node.ptr.data) { + node = graph->output(); + } + else { + BL::ShaderNode b_shader_node(*b_node); + node = add_node( + scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree, b_shader_node); + } + + if (node) { + /* map node sockets for linking */ + for (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) { + ShaderInput *input = node_find_input_by_name(node, *b_node, *b_input); + if (!input) { + /* XXX should not happen, report error? */ + continue; + } + input_map[b_input->ptr.data] = input; + + set_default_value(input, *b_input, b_data, b_ntree); + } + for (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) { + ShaderOutput *output = node_find_output_by_name(node, *b_node, *b_output); + if (!output) { + /* XXX should not happen, report error? */ + continue; + } + output_map[b_output->ptr.data] = output; + } + } + } + } + + /* connect nodes */ + BL::NodeTree::links_iterator b_link; + + for (b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) { + /* Ignore invalid links to avoid unwanted cycles created in graph. */ + if (!b_link->is_valid()) { + continue; + } + /* get blender link data */ + BL::NodeSocket b_from_sock = b_link->from_socket(); + BL::NodeSocket b_to_sock = b_link->to_socket(); + + ShaderOutput *output = 0; + ShaderInput *input = 0; + + PtrOutputMap::iterator output_it = output_map.find(b_from_sock.ptr.data); + if (output_it != output_map.end()) + output = output_it->second; + PtrInputMap::iterator input_it = input_map.find(b_to_sock.ptr.data); + if (input_it != input_map.end()) + input = input_it->second; + + /* either node may be NULL when the node was not exported, typically + * because the node type is not supported */ + if (output && input) + graph->connect(output, input); + } } static void add_nodes(Scene *scene, - BL::RenderEngine& b_engine, - BL::BlendData& b_data, - BL::Depsgraph& b_depsgraph, - BL::Scene& b_scene, + BL::RenderEngine &b_engine, + BL::BlendData &b_data, + BL::Depsgraph &b_depsgraph, + BL::Scene &b_scene, ShaderGraph *graph, - BL::ShaderNodeTree& b_ntree) + BL::ShaderNodeTree &b_ntree) { - static const ProxyMap empty_proxy_map; - add_nodes(scene, - b_engine, - b_data, - b_depsgraph, - b_scene, - graph, - b_ntree, - empty_proxy_map, - empty_proxy_map); + static const ProxyMap empty_proxy_map; + add_nodes(scene, + b_engine, + b_data, + b_depsgraph, + b_scene, + graph, + b_ntree, + empty_proxy_map, + empty_proxy_map); } /* Sync Materials */ -void BlenderSync::sync_materials(BL::Depsgraph& b_depsgraph, bool update_all) +void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all) { - shader_map.set_default(scene->default_surface); - - TaskPool pool; - set<Shader*> updated_shaders; - - BL::Depsgraph::ids_iterator b_id; - for(b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) { - if(!b_id->is_a(&RNA_Material)) { - continue; - } - - BL::Material b_mat(*b_id); - Shader *shader; - - /* test if we need to sync */ - if(shader_map.sync(&shader, b_mat) || shader->need_sync_object || update_all) { - ShaderGraph *graph = new ShaderGraph(); - - shader->name = b_mat.name().c_str(); - shader->pass_id = b_mat.pass_index(); - shader->need_sync_object = false; - - /* create nodes */ - if(b_mat.use_nodes() && b_mat.node_tree()) { - BL::ShaderNodeTree b_ntree(b_mat.node_tree()); - - add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree); - } - else { - DiffuseBsdfNode *diffuse = new DiffuseBsdfNode(); - diffuse->color = get_float3(b_mat.diffuse_color()); - graph->add(diffuse); - - ShaderNode *out = graph->output(); - graph->connect(diffuse->output("BSDF"), out->input("Surface")); - } - - /* settings */ - PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles"); - shader->use_mis = get_boolean(cmat, "sample_as_light"); - shader->use_transparent_shadow = get_boolean(cmat, "use_transparent_shadow"); - shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume"); - shader->volume_sampling_method = get_volume_sampling(cmat); - shader->volume_interpolation_method = get_volume_interpolation(cmat); - shader->displacement_method = get_displacement_method(cmat); - - shader->set_graph(graph); - - /* By simplifying the shader graph as soon as possible, some - * redundant shader nodes might be removed which prevents loading - * unnecessary attributes later. - * - * However, since graph simplification also accounts for e.g. mix - * weight, this would cause frequent expensive resyncs in interactive - * sessions, so for those sessions optimization is only performed - * right before compiling. - */ - if(!preview) { - pool.push(function_bind(&ShaderGraph::simplify, graph, scene)); - /* NOTE: Update shaders out of the threads since those routines - * are accessing and writing to a global context. - */ - updated_shaders.insert(shader); - } - else { - /* NOTE: Update tagging can access links which are being - * optimized out. - */ - shader->tag_update(scene); - } - } - } - - pool.wait_work(); - - foreach(Shader *shader, updated_shaders) { - shader->tag_update(scene); - } + shader_map.set_default(scene->default_surface); + + TaskPool pool; + set<Shader *> updated_shaders; + + BL::Depsgraph::ids_iterator b_id; + for (b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) { + if (!b_id->is_a(&RNA_Material)) { + continue; + } + + BL::Material b_mat(*b_id); + Shader *shader; + + /* test if we need to sync */ + if (shader_map.sync(&shader, b_mat) || shader->need_sync_object || update_all) { + ShaderGraph *graph = new ShaderGraph(); + + shader->name = b_mat.name().c_str(); + shader->pass_id = b_mat.pass_index(); + shader->need_sync_object = false; + + /* create nodes */ + if (b_mat.use_nodes() && b_mat.node_tree()) { + BL::ShaderNodeTree b_ntree(b_mat.node_tree()); + + add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree); + } + else { + DiffuseBsdfNode *diffuse = new DiffuseBsdfNode(); + diffuse->color = get_float3(b_mat.diffuse_color()); + graph->add(diffuse); + + ShaderNode *out = graph->output(); + graph->connect(diffuse->output("BSDF"), out->input("Surface")); + } + + /* settings */ + PointerRNA cmat = RNA_pointer_get(&b_mat.ptr, "cycles"); + shader->use_mis = get_boolean(cmat, "sample_as_light"); + shader->use_transparent_shadow = get_boolean(cmat, "use_transparent_shadow"); + shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume"); + shader->volume_sampling_method = get_volume_sampling(cmat); + shader->volume_interpolation_method = get_volume_interpolation(cmat); + shader->displacement_method = get_displacement_method(cmat); + + shader->set_graph(graph); + + /* By simplifying the shader graph as soon as possible, some + * redundant shader nodes might be removed which prevents loading + * unnecessary attributes later. + * + * However, since graph simplification also accounts for e.g. mix + * weight, this would cause frequent expensive resyncs in interactive + * sessions, so for those sessions optimization is only performed + * right before compiling. + */ + if (!preview) { + pool.push(function_bind(&ShaderGraph::simplify, graph, scene)); + /* NOTE: Update shaders out of the threads since those routines + * are accessing and writing to a global context. + */ + updated_shaders.insert(shader); + } + else { + /* NOTE: Update tagging can access links which are being + * optimized out. + */ + shader->tag_update(scene); + } + } + } + + pool.wait_work(); + + foreach (Shader *shader, updated_shaders) { + shader->tag_update(scene); + } } /* Sync World */ -void BlenderSync::sync_world(BL::Depsgraph& b_depsgraph, bool update_all) +void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, bool update_all) { - Background *background = scene->background; - Background prevbackground = *background; - - BL::World b_world = b_scene.world(); - - if(world_recalc || update_all || b_world.ptr.data != world_map) { - Shader *shader = scene->default_background; - ShaderGraph *graph = new ShaderGraph(); - - /* create nodes */ - if(b_world && b_world.use_nodes() && b_world.node_tree()) { - BL::ShaderNodeTree b_ntree(b_world.node_tree()); - - add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree); - - /* volume */ - PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles"); - shader->heterogeneous_volume = !get_boolean(cworld, "homogeneous_volume"); - shader->volume_sampling_method = get_volume_sampling(cworld); - shader->volume_interpolation_method = get_volume_interpolation(cworld); - } - else if(b_world) { - BackgroundNode *background = new BackgroundNode(); - background->color = get_float3(b_world.color()); - graph->add(background); - - ShaderNode *out = graph->output(); - graph->connect(background->output("Background"), out->input("Surface")); - } - - if(b_world) { - /* AO */ - BL::WorldLighting b_light = b_world.light_settings(); - - background->use_ao = b_light.use_ambient_occlusion(); - background->ao_factor = b_light.ao_factor(); - background->ao_distance = b_light.distance(); - - /* visibility */ - PointerRNA cvisibility = RNA_pointer_get(&b_world.ptr, "cycles_visibility"); - uint visibility = 0; - - visibility |= get_boolean(cvisibility, "camera")? PATH_RAY_CAMERA: 0; - visibility |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0; - visibility |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0; - visibility |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0; - visibility |= get_boolean(cvisibility, "scatter")? PATH_RAY_VOLUME_SCATTER: 0; - - background->visibility = visibility; - } - else { - background->use_ao = false; - background->ao_factor = 0.0f; - background->ao_distance = FLT_MAX; - } - - shader->set_graph(graph); - shader->tag_update(scene); - background->tag_update(scene); - } - - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - - /* when doing preview render check for BI's transparency settings, - * this is so because Blender's preview render routines are not able - * to tweak all cycles's settings depending on different circumstances - */ - if(b_engine.is_preview() == false) - background->transparent = get_boolean(cscene, "film_transparent"); - else - background->transparent = b_scene.render().alpha_mode() == BL::RenderSettings::alpha_mode_TRANSPARENT; - - if(background->transparent) { - background->transparent_glass = get_boolean(cscene, "film_transparent_glass"); - background->transparent_roughness_threshold = get_float(cscene, "film_transparent_roughness"); - } - else { - background->transparent_glass = false; - background->transparent_roughness_threshold = 0.0f; - } - - background->use_shader = view_layer.use_background_shader; - background->use_ao = background->use_ao && view_layer.use_background_ao; - - if(background->modified(prevbackground)) - background->tag_update(scene); + Background *background = scene->background; + Background prevbackground = *background; + + BL::World b_world = b_scene.world(); + + if (world_recalc || update_all || b_world.ptr.data != world_map) { + Shader *shader = scene->default_background; + ShaderGraph *graph = new ShaderGraph(); + + /* create nodes */ + if (b_world && b_world.use_nodes() && b_world.node_tree()) { + BL::ShaderNodeTree b_ntree(b_world.node_tree()); + + add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree); + + /* volume */ + PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles"); + shader->heterogeneous_volume = !get_boolean(cworld, "homogeneous_volume"); + shader->volume_sampling_method = get_volume_sampling(cworld); + shader->volume_interpolation_method = get_volume_interpolation(cworld); + } + else if (b_world) { + BackgroundNode *background = new BackgroundNode(); + background->color = get_float3(b_world.color()); + graph->add(background); + + ShaderNode *out = graph->output(); + graph->connect(background->output("Background"), out->input("Surface")); + } + + if (b_world) { + /* AO */ + BL::WorldLighting b_light = b_world.light_settings(); + + background->use_ao = b_light.use_ambient_occlusion(); + background->ao_factor = b_light.ao_factor(); + background->ao_distance = b_light.distance(); + + /* visibility */ + PointerRNA cvisibility = RNA_pointer_get(&b_world.ptr, "cycles_visibility"); + uint visibility = 0; + + visibility |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0; + visibility |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0; + visibility |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0; + visibility |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0; + visibility |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0; + + background->visibility = visibility; + } + else { + background->use_ao = false; + background->ao_factor = 0.0f; + background->ao_distance = FLT_MAX; + } + + shader->set_graph(graph); + shader->tag_update(scene); + background->tag_update(scene); + } + + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + + /* when doing preview render check for BI's transparency settings, + * this is so because Blender's preview render routines are not able + * to tweak all cycles's settings depending on different circumstances + */ + if (b_engine.is_preview() == false) + background->transparent = get_boolean(cscene, "film_transparent"); + else + background->transparent = b_scene.render().alpha_mode() == + BL::RenderSettings::alpha_mode_TRANSPARENT; + + if (background->transparent) { + background->transparent_glass = get_boolean(cscene, "film_transparent_glass"); + background->transparent_roughness_threshold = get_float(cscene, "film_transparent_roughness"); + } + else { + background->transparent_glass = false; + background->transparent_roughness_threshold = 0.0f; + } + + background->use_shader = view_layer.use_background_shader; + background->use_ao = background->use_ao && view_layer.use_background_ao; + + if (background->modified(prevbackground)) + background->tag_update(scene); } /* Sync Lights */ -void BlenderSync::sync_lights(BL::Depsgraph& b_depsgraph, bool update_all) +void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all) { - shader_map.set_default(scene->default_light); - - BL::Depsgraph::ids_iterator b_id; - for(b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) { - if(!b_id->is_a(&RNA_Light)) { - continue; - } - - BL::Light b_light(*b_id); - Shader *shader; - - /* test if we need to sync */ - if(shader_map.sync(&shader, b_light) || update_all) { - ShaderGraph *graph = new ShaderGraph(); - - /* create nodes */ - if(b_light.use_nodes() && b_light.node_tree()) { - shader->name = b_light.name().c_str(); - - BL::ShaderNodeTree b_ntree(b_light.node_tree()); - - add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree); - } - else { - float strength = 1.0f; - - if(b_light.type() == BL::Light::type_POINT || - b_light.type() == BL::Light::type_SPOT || - b_light.type() == BL::Light::type_AREA) - { - strength = 100.0f; - } - - EmissionNode *emission = new EmissionNode(); - emission->color = get_float3(b_light.color()); - emission->strength = strength; - graph->add(emission); - - ShaderNode *out = graph->output(); - graph->connect(emission->output("Emission"), out->input("Surface")); - } - - shader->set_graph(graph); - shader->tag_update(scene); - } - } + shader_map.set_default(scene->default_light); + + BL::Depsgraph::ids_iterator b_id; + for (b_depsgraph.ids.begin(b_id); b_id != b_depsgraph.ids.end(); ++b_id) { + if (!b_id->is_a(&RNA_Light)) { + continue; + } + + BL::Light b_light(*b_id); + Shader *shader; + + /* test if we need to sync */ + if (shader_map.sync(&shader, b_light) || update_all) { + ShaderGraph *graph = new ShaderGraph(); + + /* create nodes */ + if (b_light.use_nodes() && b_light.node_tree()) { + shader->name = b_light.name().c_str(); + + BL::ShaderNodeTree b_ntree(b_light.node_tree()); + + add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree); + } + else { + float strength = 1.0f; + + if (b_light.type() == BL::Light::type_POINT || b_light.type() == BL::Light::type_SPOT || + b_light.type() == BL::Light::type_AREA) { + strength = 100.0f; + } + + EmissionNode *emission = new EmissionNode(); + emission->color = get_float3(b_light.color()); + emission->strength = strength; + graph->add(emission); + + ShaderNode *out = graph->output(); + graph->connect(emission->output("Emission"), out->input("Surface")); + } + + shader->set_graph(graph); + shader->tag_update(scene); + } + } } -void BlenderSync::sync_shaders(BL::Depsgraph& b_depsgraph) +void BlenderSync::sync_shaders(BL::Depsgraph &b_depsgraph) { - /* for auto refresh images */ - bool auto_refresh_update = false; + /* for auto refresh images */ + bool auto_refresh_update = false; - if(preview) { - ImageManager *image_manager = scene->image_manager; - int frame = b_scene.frame_current(); - auto_refresh_update = image_manager->set_animation_frame_update(frame); - } + if (preview) { + ImageManager *image_manager = scene->image_manager; + int frame = b_scene.frame_current(); + auto_refresh_update = image_manager->set_animation_frame_update(frame); + } - shader_map.pre_sync(); + shader_map.pre_sync(); - sync_world(b_depsgraph, auto_refresh_update); - sync_lights(b_depsgraph, auto_refresh_update); - sync_materials(b_depsgraph, auto_refresh_update); + sync_world(b_depsgraph, auto_refresh_update); + sync_lights(b_depsgraph, auto_refresh_update); + sync_materials(b_depsgraph, auto_refresh_update); - /* false = don't delete unused shaders, not supported */ - shader_map.post_sync(false); + /* false = don't delete unused shaders, not supported */ + shader_map.post_sync(false); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 063a2cd4d16..0ab6d88487e 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -45,32 +45,33 @@ static const char *cryptomatte_prefix = "Crypto"; /* Constructor */ -BlenderSync::BlenderSync(BL::RenderEngine& b_engine, - BL::BlendData& b_data, - BL::Scene& b_scene, +BlenderSync::BlenderSync(BL::RenderEngine &b_engine, + BL::BlendData &b_data, + BL::Scene &b_scene, Scene *scene, bool preview, Progress &progress) -: b_engine(b_engine), - b_data(b_data), - b_scene(b_scene), - shader_map(&scene->shaders), - object_map(&scene->objects), - mesh_map(&scene->meshes), - light_map(&scene->lights), - particle_system_map(&scene->particle_systems), - world_map(NULL), - world_recalc(false), - scene(scene), - preview(preview), - experimental(false), - dicing_rate(1.0f), - max_subdivisions(12), - progress(progress) + : b_engine(b_engine), + b_data(b_data), + b_scene(b_scene), + shader_map(&scene->shaders), + object_map(&scene->objects), + mesh_map(&scene->meshes), + light_map(&scene->lights), + particle_system_map(&scene->particle_systems), + world_map(NULL), + world_recalc(false), + scene(scene), + preview(preview), + experimental(false), + dicing_rate(1.0f), + max_subdivisions(12), + progress(progress) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate") : RNA_float_get(&cscene, "dicing_rate"); - max_subdivisions = RNA_int_get(&cscene, "max_subdivisions"); + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate") : + RNA_float_get(&cscene, "dicing_rate"); + max_subdivisions = RNA_int_get(&cscene, "max_subdivisions"); } BlenderSync::~BlenderSync() @@ -79,788 +80,776 @@ BlenderSync::~BlenderSync() /* Sync */ -void BlenderSync::sync_recalc(BL::Depsgraph& b_depsgraph) +void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph) { - /* Sync recalc flags from blender to cycles. Actual update is done separate, - * so we can do it later on if doing it immediate is not suitable. */ - - bool has_updated_objects = b_depsgraph.id_type_updated(BL::DriverTarget::id_type_OBJECT); - - if(experimental) { - /* Mark all meshes as needing to be exported again if dicing changed. */ - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - bool dicing_prop_changed = false; - - float updated_dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate") - : RNA_float_get(&cscene, "dicing_rate"); - - if(dicing_rate != updated_dicing_rate) { - dicing_rate = updated_dicing_rate; - dicing_prop_changed = true; - } - - int updated_max_subdivisions = RNA_int_get(&cscene, "max_subdivisions"); - - if(max_subdivisions != updated_max_subdivisions) { - max_subdivisions = updated_max_subdivisions; - dicing_prop_changed = true; - } - - if(dicing_prop_changed) { - for(const pair<void*, Mesh*>& iter: mesh_map.key_to_scene_data()) { - Mesh *mesh = iter.second; - if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE) { - mesh_map.set_recalc(iter.first); - } - } - } - } - - /* Iterate over all IDs in this depsgraph. */ - BL::Depsgraph::updates_iterator b_update; - for(b_depsgraph.updates.begin(b_update); b_update != b_depsgraph.updates.end(); ++b_update) { - BL::ID b_id(b_update->id()); - - /* Material */ - if(b_id.is_a(&RNA_Material)) { - BL::Material b_mat(b_id); - shader_map.set_recalc(b_mat); - } - /* Light */ - else if(b_id.is_a(&RNA_Light)) { - BL::Light b_light(b_id); - shader_map.set_recalc(b_light); - } - /* Object */ - else if(b_id.is_a(&RNA_Object)) { - BL::Object b_ob(b_id); - const bool updated_geometry = b_update->is_updated_geometry(); - - if(b_update->is_updated_transform()) { - object_map.set_recalc(b_ob); - light_map.set_recalc(b_ob); - } - - if(object_is_mesh(b_ob)) { - if(updated_geometry || - (object_subdivision_type(b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE)) - { - BL::ID key = BKE_object_is_modified(b_ob)? b_ob: b_ob.data(); - mesh_map.set_recalc(key); - } - } - else if(object_is_light(b_ob)) { - if(updated_geometry) { - light_map.set_recalc(b_ob); - } - } - - if(updated_geometry) { - BL::Object::particle_systems_iterator b_psys; - for(b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) - particle_system_map.set_recalc(b_ob); - } - } - /* Mesh */ - else if(b_id.is_a(&RNA_Mesh)) { - BL::Mesh b_mesh(b_id); - mesh_map.set_recalc(b_mesh); - } - /* World */ - else if(b_id.is_a(&RNA_World)) { - BL::World b_world(b_id); - if(world_map == b_world.ptr.data) { - world_recalc = true; - } - } - } - - /* Updates shader with object dependency if objects changed. */ - if(has_updated_objects) { - if(scene->default_background->has_object_dependency) { - world_recalc = true; - } - - foreach(Shader *shader, scene->shaders) { - if(shader->has_object_dependency) { - shader->need_sync_object = true; - } - } - } + /* Sync recalc flags from blender to cycles. Actual update is done separate, + * so we can do it later on if doing it immediate is not suitable. */ + + bool has_updated_objects = b_depsgraph.id_type_updated(BL::DriverTarget::id_type_OBJECT); + + if (experimental) { + /* Mark all meshes as needing to be exported again if dicing changed. */ + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + bool dicing_prop_changed = false; + + float updated_dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate") : + RNA_float_get(&cscene, "dicing_rate"); + + if (dicing_rate != updated_dicing_rate) { + dicing_rate = updated_dicing_rate; + dicing_prop_changed = true; + } + + int updated_max_subdivisions = RNA_int_get(&cscene, "max_subdivisions"); + + if (max_subdivisions != updated_max_subdivisions) { + max_subdivisions = updated_max_subdivisions; + dicing_prop_changed = true; + } + + if (dicing_prop_changed) { + for (const pair<void *, Mesh *> &iter : mesh_map.key_to_scene_data()) { + Mesh *mesh = iter.second; + if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) { + mesh_map.set_recalc(iter.first); + } + } + } + } + + /* Iterate over all IDs in this depsgraph. */ + BL::Depsgraph::updates_iterator b_update; + for (b_depsgraph.updates.begin(b_update); b_update != b_depsgraph.updates.end(); ++b_update) { + BL::ID b_id(b_update->id()); + + /* Material */ + if (b_id.is_a(&RNA_Material)) { + BL::Material b_mat(b_id); + shader_map.set_recalc(b_mat); + } + /* Light */ + else if (b_id.is_a(&RNA_Light)) { + BL::Light b_light(b_id); + shader_map.set_recalc(b_light); + } + /* Object */ + else if (b_id.is_a(&RNA_Object)) { + BL::Object b_ob(b_id); + const bool updated_geometry = b_update->is_updated_geometry(); + + if (b_update->is_updated_transform()) { + object_map.set_recalc(b_ob); + light_map.set_recalc(b_ob); + } + + if (object_is_mesh(b_ob)) { + if (updated_geometry || + (object_subdivision_type(b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE)) { + BL::ID key = BKE_object_is_modified(b_ob) ? b_ob : b_ob.data(); + mesh_map.set_recalc(key); + } + } + else if (object_is_light(b_ob)) { + if (updated_geometry) { + light_map.set_recalc(b_ob); + } + } + + if (updated_geometry) { + BL::Object::particle_systems_iterator b_psys; + for (b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) + particle_system_map.set_recalc(b_ob); + } + } + /* Mesh */ + else if (b_id.is_a(&RNA_Mesh)) { + BL::Mesh b_mesh(b_id); + mesh_map.set_recalc(b_mesh); + } + /* World */ + else if (b_id.is_a(&RNA_World)) { + BL::World b_world(b_id); + if (world_map == b_world.ptr.data) { + world_recalc = true; + } + } + } + + /* Updates shader with object dependency if objects changed. */ + if (has_updated_objects) { + if (scene->default_background->has_object_dependency) { + world_recalc = true; + } + + foreach (Shader *shader, scene->shaders) { + if (shader->has_object_dependency) { + shader->need_sync_object = true; + } + } + } } -void BlenderSync::sync_data(BL::RenderSettings& b_render, - BL::Depsgraph& b_depsgraph, - BL::SpaceView3D& b_v3d, - BL::Object& b_override, - int width, int height, +void BlenderSync::sync_data(BL::RenderSettings &b_render, + BL::Depsgraph &b_depsgraph, + BL::SpaceView3D &b_v3d, + BL::Object &b_override, + int width, + int height, void **python_thread_state) { - BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); - - sync_view_layer(b_v3d, b_view_layer); - sync_integrator(); - sync_film(); - sync_shaders(b_depsgraph); - sync_images(); - sync_curve_settings(); - - mesh_synced.clear(); /* use for objects and motion sync */ - - if(scene->need_motion() == Scene::MOTION_PASS || - scene->need_motion() == Scene::MOTION_NONE || - scene->camera->motion_position == Camera::MOTION_POSITION_CENTER) - { - sync_objects(b_depsgraph); - } - sync_motion(b_render, - b_depsgraph, - b_override, - width, height, - python_thread_state); - - mesh_synced.clear(); - - free_data_after_sync(b_depsgraph); + BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); + + sync_view_layer(b_v3d, b_view_layer); + sync_integrator(); + sync_film(); + sync_shaders(b_depsgraph); + sync_images(); + sync_curve_settings(); + + mesh_synced.clear(); /* use for objects and motion sync */ + + if (scene->need_motion() == Scene::MOTION_PASS || scene->need_motion() == Scene::MOTION_NONE || + scene->camera->motion_position == Camera::MOTION_POSITION_CENTER) { + sync_objects(b_depsgraph); + } + sync_motion(b_render, b_depsgraph, b_override, width, height, python_thread_state); + + mesh_synced.clear(); + + free_data_after_sync(b_depsgraph); } /* Integrator */ void BlenderSync::sync_integrator() { - BL::RenderSettings r = b_scene.render(); - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - - experimental = (get_enum(cscene, "feature_set") != 0); - - Integrator *integrator = scene->integrator; - Integrator previntegrator = *integrator; - - integrator->max_bounce = get_int(cscene, "max_bounces"); - - integrator->max_diffuse_bounce = get_int(cscene, "diffuse_bounces"); - integrator->max_glossy_bounce = get_int(cscene, "glossy_bounces"); - integrator->max_transmission_bounce = get_int(cscene, "transmission_bounces"); - integrator->max_volume_bounce = get_int(cscene, "volume_bounces"); - - integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces"); - - integrator->volume_max_steps = get_int(cscene, "volume_max_steps"); - integrator->volume_step_size = get_float(cscene, "volume_step_size"); - - integrator->caustics_reflective = get_boolean(cscene, "caustics_reflective"); - integrator->caustics_refractive = get_boolean(cscene, "caustics_refractive"); - integrator->filter_glossy = get_float(cscene, "blur_glossy"); - - integrator->seed = get_int(cscene, "seed"); - if(get_boolean(cscene, "use_animated_seed")) { - integrator->seed = hash_int_2d(b_scene.frame_current(), - get_int(cscene, "seed")); - if(b_scene.frame_subframe() != 0.0f) { - /* TODO(sergey): Ideally should be some sort of hash_merge, - * but this is good enough for now. - */ - integrator->seed += hash_int_2d((int)(b_scene.frame_subframe() * (float)INT_MAX), - get_int(cscene, "seed")); - } - } - - integrator->sampling_pattern = (SamplingPattern)get_enum( - cscene, - "sampling_pattern", - SAMPLING_NUM_PATTERNS, - SAMPLING_PATTERN_SOBOL); - - integrator->sample_clamp_direct = get_float(cscene, "sample_clamp_direct"); - integrator->sample_clamp_indirect = get_float(cscene, "sample_clamp_indirect"); - if(!preview) { - if(integrator->motion_blur != r.use_motion_blur()) { - scene->object_manager->tag_update(scene); - scene->camera->tag_update(); - } - - integrator->motion_blur = r.use_motion_blur(); - } - - integrator->method = (Integrator::Method)get_enum(cscene, - "progressive", - Integrator::NUM_METHODS, - Integrator::PATH); - - integrator->sample_all_lights_direct = get_boolean(cscene, "sample_all_lights_direct"); - integrator->sample_all_lights_indirect = get_boolean(cscene, "sample_all_lights_indirect"); - integrator->light_sampling_threshold = get_float(cscene, "light_sampling_threshold"); - - int diffuse_samples = get_int(cscene, "diffuse_samples"); - int glossy_samples = get_int(cscene, "glossy_samples"); - int transmission_samples = get_int(cscene, "transmission_samples"); - int ao_samples = get_int(cscene, "ao_samples"); - int mesh_light_samples = get_int(cscene, "mesh_light_samples"); - int subsurface_samples = get_int(cscene, "subsurface_samples"); - int volume_samples = get_int(cscene, "volume_samples"); - - if(get_boolean(cscene, "use_square_samples")) { - integrator->diffuse_samples = diffuse_samples * diffuse_samples; - integrator->glossy_samples = glossy_samples * glossy_samples; - integrator->transmission_samples = transmission_samples * transmission_samples; - integrator->ao_samples = ao_samples * ao_samples; - integrator->mesh_light_samples = mesh_light_samples * mesh_light_samples; - integrator->subsurface_samples = subsurface_samples * subsurface_samples; - integrator->volume_samples = volume_samples * volume_samples; - } - else { - integrator->diffuse_samples = diffuse_samples; - integrator->glossy_samples = glossy_samples; - integrator->transmission_samples = transmission_samples; - integrator->ao_samples = ao_samples; - integrator->mesh_light_samples = mesh_light_samples; - integrator->subsurface_samples = subsurface_samples; - integrator->volume_samples = volume_samples; - } - - if(b_scene.render().use_simplify()) { - if(preview) { - integrator->ao_bounces = get_int(cscene, "ao_bounces"); - } - else { - integrator->ao_bounces = get_int(cscene, "ao_bounces_render"); - } - } - else { - integrator->ao_bounces = 0; - } - - if(integrator->modified(previntegrator)) - integrator->tag_update(scene); + BL::RenderSettings r = b_scene.render(); + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + + experimental = (get_enum(cscene, "feature_set") != 0); + + Integrator *integrator = scene->integrator; + Integrator previntegrator = *integrator; + + integrator->max_bounce = get_int(cscene, "max_bounces"); + + integrator->max_diffuse_bounce = get_int(cscene, "diffuse_bounces"); + integrator->max_glossy_bounce = get_int(cscene, "glossy_bounces"); + integrator->max_transmission_bounce = get_int(cscene, "transmission_bounces"); + integrator->max_volume_bounce = get_int(cscene, "volume_bounces"); + + integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces"); + + integrator->volume_max_steps = get_int(cscene, "volume_max_steps"); + integrator->volume_step_size = get_float(cscene, "volume_step_size"); + + integrator->caustics_reflective = get_boolean(cscene, "caustics_reflective"); + integrator->caustics_refractive = get_boolean(cscene, "caustics_refractive"); + integrator->filter_glossy = get_float(cscene, "blur_glossy"); + + integrator->seed = get_int(cscene, "seed"); + if (get_boolean(cscene, "use_animated_seed")) { + integrator->seed = hash_int_2d(b_scene.frame_current(), get_int(cscene, "seed")); + if (b_scene.frame_subframe() != 0.0f) { + /* TODO(sergey): Ideally should be some sort of hash_merge, + * but this is good enough for now. + */ + integrator->seed += hash_int_2d((int)(b_scene.frame_subframe() * (float)INT_MAX), + get_int(cscene, "seed")); + } + } + + integrator->sampling_pattern = (SamplingPattern)get_enum( + cscene, "sampling_pattern", SAMPLING_NUM_PATTERNS, SAMPLING_PATTERN_SOBOL); + + integrator->sample_clamp_direct = get_float(cscene, "sample_clamp_direct"); + integrator->sample_clamp_indirect = get_float(cscene, "sample_clamp_indirect"); + if (!preview) { + if (integrator->motion_blur != r.use_motion_blur()) { + scene->object_manager->tag_update(scene); + scene->camera->tag_update(); + } + + integrator->motion_blur = r.use_motion_blur(); + } + + integrator->method = (Integrator::Method)get_enum( + cscene, "progressive", Integrator::NUM_METHODS, Integrator::PATH); + + integrator->sample_all_lights_direct = get_boolean(cscene, "sample_all_lights_direct"); + integrator->sample_all_lights_indirect = get_boolean(cscene, "sample_all_lights_indirect"); + integrator->light_sampling_threshold = get_float(cscene, "light_sampling_threshold"); + + int diffuse_samples = get_int(cscene, "diffuse_samples"); + int glossy_samples = get_int(cscene, "glossy_samples"); + int transmission_samples = get_int(cscene, "transmission_samples"); + int ao_samples = get_int(cscene, "ao_samples"); + int mesh_light_samples = get_int(cscene, "mesh_light_samples"); + int subsurface_samples = get_int(cscene, "subsurface_samples"); + int volume_samples = get_int(cscene, "volume_samples"); + + if (get_boolean(cscene, "use_square_samples")) { + integrator->diffuse_samples = diffuse_samples * diffuse_samples; + integrator->glossy_samples = glossy_samples * glossy_samples; + integrator->transmission_samples = transmission_samples * transmission_samples; + integrator->ao_samples = ao_samples * ao_samples; + integrator->mesh_light_samples = mesh_light_samples * mesh_light_samples; + integrator->subsurface_samples = subsurface_samples * subsurface_samples; + integrator->volume_samples = volume_samples * volume_samples; + } + else { + integrator->diffuse_samples = diffuse_samples; + integrator->glossy_samples = glossy_samples; + integrator->transmission_samples = transmission_samples; + integrator->ao_samples = ao_samples; + integrator->mesh_light_samples = mesh_light_samples; + integrator->subsurface_samples = subsurface_samples; + integrator->volume_samples = volume_samples; + } + + if (b_scene.render().use_simplify()) { + if (preview) { + integrator->ao_bounces = get_int(cscene, "ao_bounces"); + } + else { + integrator->ao_bounces = get_int(cscene, "ao_bounces_render"); + } + } + else { + integrator->ao_bounces = 0; + } + + if (integrator->modified(previntegrator)) + integrator->tag_update(scene); } /* Film */ void BlenderSync::sync_film() { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - - Film *film = scene->film; - Film prevfilm = *film; - - film->exposure = get_float(cscene, "film_exposure"); - film->filter_type = (FilterType)get_enum(cscene, - "pixel_filter_type", - FILTER_NUM_TYPES, - FILTER_BLACKMAN_HARRIS); - film->filter_width = (film->filter_type == FILTER_BOX)? 1.0f: get_float(cscene, "filter_width"); - - if(b_scene.world()) { - BL::WorldMistSettings b_mist = b_scene.world().mist_settings(); - - film->mist_start = b_mist.start(); - film->mist_depth = b_mist.depth(); - - switch(b_mist.falloff()) { - case BL::WorldMistSettings::falloff_QUADRATIC: - film->mist_falloff = 2.0f; - break; - case BL::WorldMistSettings::falloff_LINEAR: - film->mist_falloff = 1.0f; - break; - case BL::WorldMistSettings::falloff_INVERSE_QUADRATIC: - film->mist_falloff = 0.5f; - break; - } - } - - if(film->modified(prevfilm)) - film->tag_update(scene); + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + + Film *film = scene->film; + Film prevfilm = *film; + + film->exposure = get_float(cscene, "film_exposure"); + film->filter_type = (FilterType)get_enum( + cscene, "pixel_filter_type", FILTER_NUM_TYPES, FILTER_BLACKMAN_HARRIS); + film->filter_width = (film->filter_type == FILTER_BOX) ? 1.0f : + get_float(cscene, "filter_width"); + + if (b_scene.world()) { + BL::WorldMistSettings b_mist = b_scene.world().mist_settings(); + + film->mist_start = b_mist.start(); + film->mist_depth = b_mist.depth(); + + switch (b_mist.falloff()) { + case BL::WorldMistSettings::falloff_QUADRATIC: + film->mist_falloff = 2.0f; + break; + case BL::WorldMistSettings::falloff_LINEAR: + film->mist_falloff = 1.0f; + break; + case BL::WorldMistSettings::falloff_INVERSE_QUADRATIC: + film->mist_falloff = 0.5f; + break; + } + } + + if (film->modified(prevfilm)) + film->tag_update(scene); } /* Render Layer */ -void BlenderSync::sync_view_layer(BL::SpaceView3D& /*b_v3d*/, BL::ViewLayer& b_view_layer) +void BlenderSync::sync_view_layer(BL::SpaceView3D & /*b_v3d*/, BL::ViewLayer &b_view_layer) { - /* render layer */ - view_layer.name = b_view_layer.name(); - view_layer.use_background_shader = b_view_layer.use_sky(); - view_layer.use_background_ao = b_view_layer.use_ao(); - view_layer.use_surfaces = b_view_layer.use_solid(); - view_layer.use_hair = b_view_layer.use_strand(); - - /* Material override. */ - view_layer.material_override = b_view_layer.material_override(); - - /* Sample override. */ - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - int use_layer_samples = get_enum(cscene, "use_layer_samples"); - - view_layer.bound_samples = (use_layer_samples == 1); - view_layer.samples = 0; - - if(use_layer_samples != 2) { - int samples = b_view_layer.samples(); - if(get_boolean(cscene, "use_square_samples")) - view_layer.samples = samples * samples; - else - view_layer.samples = samples; - } - + /* render layer */ + view_layer.name = b_view_layer.name(); + view_layer.use_background_shader = b_view_layer.use_sky(); + view_layer.use_background_ao = b_view_layer.use_ao(); + view_layer.use_surfaces = b_view_layer.use_solid(); + view_layer.use_hair = b_view_layer.use_strand(); + + /* Material override. */ + view_layer.material_override = b_view_layer.material_override(); + + /* Sample override. */ + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + int use_layer_samples = get_enum(cscene, "use_layer_samples"); + + view_layer.bound_samples = (use_layer_samples == 1); + view_layer.samples = 0; + + if (use_layer_samples != 2) { + int samples = b_view_layer.samples(); + if (get_boolean(cscene, "use_square_samples")) + view_layer.samples = samples * samples; + else + view_layer.samples = samples; + } } /* Images */ void BlenderSync::sync_images() { - /* Sync is a convention for this API, but currently it frees unused buffers. */ - - const bool is_interface_locked = b_engine.render() && - b_engine.render().use_lock_interface(); - if(is_interface_locked == false && BlenderSession::headless == false) { - /* If interface is not locked, it's possible image is needed for - * the display. - */ - return; - } - /* Free buffers used by images which are not needed for render. */ - BL::BlendData::images_iterator b_image; - for(b_data.images.begin(b_image); - b_image != b_data.images.end(); - ++b_image) - { - /* TODO(sergey): Consider making it an utility function to check - * whether image is considered builtin. - */ - const bool is_builtin = b_image->packed_file() || - b_image->source() == BL::Image::source_GENERATED || - b_image->source() == BL::Image::source_MOVIE || - b_engine.is_preview(); - if(is_builtin == false) { - b_image->buffers_free(); - } - /* TODO(sergey): Free builtin images not used by any shader. */ - } + /* Sync is a convention for this API, but currently it frees unused buffers. */ + + const bool is_interface_locked = b_engine.render() && b_engine.render().use_lock_interface(); + if (is_interface_locked == false && BlenderSession::headless == false) { + /* If interface is not locked, it's possible image is needed for + * the display. + */ + return; + } + /* Free buffers used by images which are not needed for render. */ + BL::BlendData::images_iterator b_image; + for (b_data.images.begin(b_image); b_image != b_data.images.end(); ++b_image) { + /* TODO(sergey): Consider making it an utility function to check + * whether image is considered builtin. + */ + const bool is_builtin = b_image->packed_file() || + b_image->source() == BL::Image::source_GENERATED || + b_image->source() == BL::Image::source_MOVIE || b_engine.is_preview(); + if (is_builtin == false) { + b_image->buffers_free(); + } + /* TODO(sergey): Free builtin images not used by any shader. */ + } } /* Passes */ -PassType BlenderSync::get_pass_type(BL::RenderPass& b_pass) +PassType BlenderSync::get_pass_type(BL::RenderPass &b_pass) { - string name = b_pass.name(); -#define MAP_PASS(passname, passtype) if(name == passname) return passtype; - /* NOTE: Keep in sync with defined names from DNA_scene_types.h */ - MAP_PASS("Combined", PASS_COMBINED); - MAP_PASS("Depth", PASS_DEPTH); - MAP_PASS("Mist", PASS_MIST); - MAP_PASS("Normal", PASS_NORMAL); - MAP_PASS("IndexOB", PASS_OBJECT_ID); - MAP_PASS("UV", PASS_UV); - MAP_PASS("Vector", PASS_MOTION); - MAP_PASS("IndexMA", PASS_MATERIAL_ID); - - MAP_PASS("DiffDir", PASS_DIFFUSE_DIRECT); - MAP_PASS("GlossDir", PASS_GLOSSY_DIRECT); - MAP_PASS("TransDir", PASS_TRANSMISSION_DIRECT); - MAP_PASS("SubsurfaceDir", PASS_SUBSURFACE_DIRECT); - MAP_PASS("VolumeDir", PASS_VOLUME_DIRECT); - - MAP_PASS("DiffInd", PASS_DIFFUSE_INDIRECT); - MAP_PASS("GlossInd", PASS_GLOSSY_INDIRECT); - MAP_PASS("TransInd", PASS_TRANSMISSION_INDIRECT); - MAP_PASS("SubsurfaceInd", PASS_SUBSURFACE_INDIRECT); - MAP_PASS("VolumeInd", PASS_VOLUME_INDIRECT); - - MAP_PASS("DiffCol", PASS_DIFFUSE_COLOR); - MAP_PASS("GlossCol", PASS_GLOSSY_COLOR); - MAP_PASS("TransCol", PASS_TRANSMISSION_COLOR); - MAP_PASS("SubsurfaceCol", PASS_SUBSURFACE_COLOR); - - MAP_PASS("Emit", PASS_EMISSION); - MAP_PASS("Env", PASS_BACKGROUND); - MAP_PASS("AO", PASS_AO); - MAP_PASS("Shadow", PASS_SHADOW); + string name = b_pass.name(); +#define MAP_PASS(passname, passtype) \ + if (name == passname) \ + return passtype; + /* NOTE: Keep in sync with defined names from DNA_scene_types.h */ + MAP_PASS("Combined", PASS_COMBINED); + MAP_PASS("Depth", PASS_DEPTH); + MAP_PASS("Mist", PASS_MIST); + MAP_PASS("Normal", PASS_NORMAL); + MAP_PASS("IndexOB", PASS_OBJECT_ID); + MAP_PASS("UV", PASS_UV); + MAP_PASS("Vector", PASS_MOTION); + MAP_PASS("IndexMA", PASS_MATERIAL_ID); + + MAP_PASS("DiffDir", PASS_DIFFUSE_DIRECT); + MAP_PASS("GlossDir", PASS_GLOSSY_DIRECT); + MAP_PASS("TransDir", PASS_TRANSMISSION_DIRECT); + MAP_PASS("SubsurfaceDir", PASS_SUBSURFACE_DIRECT); + MAP_PASS("VolumeDir", PASS_VOLUME_DIRECT); + + MAP_PASS("DiffInd", PASS_DIFFUSE_INDIRECT); + MAP_PASS("GlossInd", PASS_GLOSSY_INDIRECT); + MAP_PASS("TransInd", PASS_TRANSMISSION_INDIRECT); + MAP_PASS("SubsurfaceInd", PASS_SUBSURFACE_INDIRECT); + MAP_PASS("VolumeInd", PASS_VOLUME_INDIRECT); + + MAP_PASS("DiffCol", PASS_DIFFUSE_COLOR); + MAP_PASS("GlossCol", PASS_GLOSSY_COLOR); + MAP_PASS("TransCol", PASS_TRANSMISSION_COLOR); + MAP_PASS("SubsurfaceCol", PASS_SUBSURFACE_COLOR); + + MAP_PASS("Emit", PASS_EMISSION); + MAP_PASS("Env", PASS_BACKGROUND); + MAP_PASS("AO", PASS_AO); + MAP_PASS("Shadow", PASS_SHADOW); #ifdef __KERNEL_DEBUG__ - MAP_PASS("Debug BVH Traversed Nodes", PASS_BVH_TRAVERSED_NODES); - MAP_PASS("Debug BVH Traversed Instances", PASS_BVH_TRAVERSED_INSTANCES); - MAP_PASS("Debug BVH Intersections", PASS_BVH_INTERSECTIONS); - MAP_PASS("Debug Ray Bounces", PASS_RAY_BOUNCES); + MAP_PASS("Debug BVH Traversed Nodes", PASS_BVH_TRAVERSED_NODES); + MAP_PASS("Debug BVH Traversed Instances", PASS_BVH_TRAVERSED_INSTANCES); + MAP_PASS("Debug BVH Intersections", PASS_BVH_INTERSECTIONS); + MAP_PASS("Debug Ray Bounces", PASS_RAY_BOUNCES); #endif - MAP_PASS("Debug Render Time", PASS_RENDER_TIME); - if(string_startswith(name, cryptomatte_prefix)) { - return PASS_CRYPTOMATTE; - } + MAP_PASS("Debug Render Time", PASS_RENDER_TIME); + if (string_startswith(name, cryptomatte_prefix)) { + return PASS_CRYPTOMATTE; + } #undef MAP_PASS - return PASS_NONE; + return PASS_NONE; } -int BlenderSync::get_denoising_pass(BL::RenderPass& b_pass) +int BlenderSync::get_denoising_pass(BL::RenderPass &b_pass) { - string name = b_pass.name(); - - if(name == "Noisy Image") return DENOISING_PASS_PREFILTERED_COLOR; - - if(name.substr(0, 10) != "Denoising ") { - return -1; - } - name = name.substr(10); - -#define MAP_PASS(passname, offset) if(name == passname) return offset; - MAP_PASS("Normal", DENOISING_PASS_PREFILTERED_NORMAL); - MAP_PASS("Albedo", DENOISING_PASS_PREFILTERED_ALBEDO); - MAP_PASS("Depth", DENOISING_PASS_PREFILTERED_DEPTH); - MAP_PASS("Shadowing", DENOISING_PASS_PREFILTERED_SHADOWING); - MAP_PASS("Variance", DENOISING_PASS_PREFILTERED_VARIANCE); - MAP_PASS("Intensity", DENOISING_PASS_PREFILTERED_INTENSITY); - MAP_PASS("Clean", DENOISING_PASS_CLEAN); + string name = b_pass.name(); + + if (name == "Noisy Image") + return DENOISING_PASS_PREFILTERED_COLOR; + + if (name.substr(0, 10) != "Denoising ") { + return -1; + } + name = name.substr(10); + +#define MAP_PASS(passname, offset) \ + if (name == passname) \ + return offset; + MAP_PASS("Normal", DENOISING_PASS_PREFILTERED_NORMAL); + MAP_PASS("Albedo", DENOISING_PASS_PREFILTERED_ALBEDO); + MAP_PASS("Depth", DENOISING_PASS_PREFILTERED_DEPTH); + MAP_PASS("Shadowing", DENOISING_PASS_PREFILTERED_SHADOWING); + MAP_PASS("Variance", DENOISING_PASS_PREFILTERED_VARIANCE); + MAP_PASS("Intensity", DENOISING_PASS_PREFILTERED_INTENSITY); + MAP_PASS("Clean", DENOISING_PASS_CLEAN); #undef MAP_PASS - return -1; + return -1; } -vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay, - BL::ViewLayer& b_view_layer) +vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer) { - vector<Pass> passes; - Pass::add(PASS_COMBINED, passes); - - /* loop over passes */ - BL::RenderLayer::passes_iterator b_pass_iter; - - for(b_rlay.passes.begin(b_pass_iter); b_pass_iter != b_rlay.passes.end(); ++b_pass_iter) { - BL::RenderPass b_pass(*b_pass_iter); - PassType pass_type = get_pass_type(b_pass); - - if(pass_type == PASS_MOTION && scene->integrator->motion_blur) - continue; - if(pass_type != PASS_NONE) - Pass::add(pass_type, passes); - } - - PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles"); - bool full_denoising = get_boolean(crp, "use_denoising"); - bool write_denoising_passes = get_boolean(crp, "denoising_store_passes"); - - scene->film->denoising_flags = 0; - if(full_denoising || write_denoising_passes) { -#define MAP_OPTION(name, flag) if(!get_boolean(crp, name)) scene->film->denoising_flags |= flag; - MAP_OPTION("denoising_diffuse_direct", DENOISING_CLEAN_DIFFUSE_DIR); - MAP_OPTION("denoising_diffuse_indirect", DENOISING_CLEAN_DIFFUSE_IND); - MAP_OPTION("denoising_glossy_direct", DENOISING_CLEAN_GLOSSY_DIR); - MAP_OPTION("denoising_glossy_indirect", DENOISING_CLEAN_GLOSSY_IND); - MAP_OPTION("denoising_transmission_direct", DENOISING_CLEAN_TRANSMISSION_DIR); - MAP_OPTION("denoising_transmission_indirect", DENOISING_CLEAN_TRANSMISSION_IND); - MAP_OPTION("denoising_subsurface_direct", DENOISING_CLEAN_SUBSURFACE_DIR); - MAP_OPTION("denoising_subsurface_indirect", DENOISING_CLEAN_SUBSURFACE_IND); + vector<Pass> passes; + Pass::add(PASS_COMBINED, passes); + + /* loop over passes */ + BL::RenderLayer::passes_iterator b_pass_iter; + + for (b_rlay.passes.begin(b_pass_iter); b_pass_iter != b_rlay.passes.end(); ++b_pass_iter) { + BL::RenderPass b_pass(*b_pass_iter); + PassType pass_type = get_pass_type(b_pass); + + if (pass_type == PASS_MOTION && scene->integrator->motion_blur) + continue; + if (pass_type != PASS_NONE) + Pass::add(pass_type, passes); + } + + PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles"); + bool full_denoising = get_boolean(crp, "use_denoising"); + bool write_denoising_passes = get_boolean(crp, "denoising_store_passes"); + + scene->film->denoising_flags = 0; + if (full_denoising || write_denoising_passes) { +#define MAP_OPTION(name, flag) \ + if (!get_boolean(crp, name)) \ + scene->film->denoising_flags |= flag; + MAP_OPTION("denoising_diffuse_direct", DENOISING_CLEAN_DIFFUSE_DIR); + MAP_OPTION("denoising_diffuse_indirect", DENOISING_CLEAN_DIFFUSE_IND); + MAP_OPTION("denoising_glossy_direct", DENOISING_CLEAN_GLOSSY_DIR); + MAP_OPTION("denoising_glossy_indirect", DENOISING_CLEAN_GLOSSY_IND); + MAP_OPTION("denoising_transmission_direct", DENOISING_CLEAN_TRANSMISSION_DIR); + MAP_OPTION("denoising_transmission_indirect", DENOISING_CLEAN_TRANSMISSION_IND); + MAP_OPTION("denoising_subsurface_direct", DENOISING_CLEAN_SUBSURFACE_DIR); + MAP_OPTION("denoising_subsurface_indirect", DENOISING_CLEAN_SUBSURFACE_IND); #undef MAP_OPTION - b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str()); - } - - if(write_denoising_passes) { - b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str()); - b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str()); - b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str()); - b_engine.add_pass("Denoising Shadowing", 1, "X", b_view_layer.name().c_str()); - b_engine.add_pass("Denoising Variance", 3, "RGB", b_view_layer.name().c_str()); - b_engine.add_pass("Denoising Intensity", 1, "X", b_view_layer.name().c_str()); - - if(scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES) { - b_engine.add_pass("Denoising Clean", 3, "RGB", b_view_layer.name().c_str()); - } - } + b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str()); + } + + if (write_denoising_passes) { + b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Shadowing", 1, "X", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Variance", 3, "RGB", b_view_layer.name().c_str()); + b_engine.add_pass("Denoising Intensity", 1, "X", b_view_layer.name().c_str()); + + if (scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES) { + b_engine.add_pass("Denoising Clean", 3, "RGB", b_view_layer.name().c_str()); + } + } #ifdef __KERNEL_DEBUG__ - if(get_boolean(crp, "pass_debug_bvh_traversed_nodes")) { - b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str()); - Pass::add(PASS_BVH_TRAVERSED_NODES, passes); - } - if(get_boolean(crp, "pass_debug_bvh_traversed_instances")) { - b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_view_layer.name().c_str()); - Pass::add(PASS_BVH_TRAVERSED_INSTANCES, passes); - } - if(get_boolean(crp, "pass_debug_bvh_intersections")) { - b_engine.add_pass("Debug BVH Intersections", 1, "X", b_view_layer.name().c_str()); - Pass::add(PASS_BVH_INTERSECTIONS, passes); - } - if(get_boolean(crp, "pass_debug_ray_bounces")) { - b_engine.add_pass("Debug Ray Bounces", 1, "X", b_view_layer.name().c_str()); - Pass::add(PASS_RAY_BOUNCES, passes); - } + if (get_boolean(crp, "pass_debug_bvh_traversed_nodes")) { + b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str()); + Pass::add(PASS_BVH_TRAVERSED_NODES, passes); + } + if (get_boolean(crp, "pass_debug_bvh_traversed_instances")) { + b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_view_layer.name().c_str()); + Pass::add(PASS_BVH_TRAVERSED_INSTANCES, passes); + } + if (get_boolean(crp, "pass_debug_bvh_intersections")) { + b_engine.add_pass("Debug BVH Intersections", 1, "X", b_view_layer.name().c_str()); + Pass::add(PASS_BVH_INTERSECTIONS, passes); + } + if (get_boolean(crp, "pass_debug_ray_bounces")) { + b_engine.add_pass("Debug Ray Bounces", 1, "X", b_view_layer.name().c_str()); + Pass::add(PASS_RAY_BOUNCES, passes); + } #endif - if(get_boolean(crp, "pass_debug_render_time")) { - b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str()); - Pass::add(PASS_RENDER_TIME, passes); - } - if(get_boolean(crp, "use_pass_volume_direct")) { - b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str()); - Pass::add(PASS_VOLUME_DIRECT, passes); - } - if(get_boolean(crp, "use_pass_volume_indirect")) { - b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str()); - Pass::add(PASS_VOLUME_INDIRECT, passes); - } - - /* Cryptomatte stores two ID/weight pairs per RGBA layer. - * User facing paramter is the number of pairs. */ - int crypto_depth = min(16, get_int(crp, "pass_crypto_depth")) / 2; - scene->film->cryptomatte_depth = crypto_depth; - scene->film->cryptomatte_passes = CRYPT_NONE; - if(get_boolean(crp, "use_pass_crypto_object")) { - for(int i = 0; i < crypto_depth; ++i) { - string passname = cryptomatte_prefix + string_printf("Object%02d", i); - b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); - Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str()); - } - scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_OBJECT); - } - if(get_boolean(crp, "use_pass_crypto_material")) { - for(int i = 0; i < crypto_depth; ++i) { - string passname = cryptomatte_prefix + string_printf("Material%02d", i); - b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); - Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str()); - } - scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_MATERIAL); - } - if(get_boolean(crp, "use_pass_crypto_asset")) { - for(int i = 0; i < crypto_depth; ++i) { - string passname = cryptomatte_prefix + string_printf("Asset%02d", i); - b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); - Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str()); - } - scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_ASSET); - } - if(get_boolean(crp, "pass_crypto_accurate") && scene->film->cryptomatte_passes != CRYPT_NONE) { - scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_ACCURATE); - } - - return passes; + if (get_boolean(crp, "pass_debug_render_time")) { + b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str()); + Pass::add(PASS_RENDER_TIME, passes); + } + if (get_boolean(crp, "use_pass_volume_direct")) { + b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str()); + Pass::add(PASS_VOLUME_DIRECT, passes); + } + if (get_boolean(crp, "use_pass_volume_indirect")) { + b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str()); + Pass::add(PASS_VOLUME_INDIRECT, passes); + } + + /* Cryptomatte stores two ID/weight pairs per RGBA layer. + * User facing paramter is the number of pairs. */ + int crypto_depth = min(16, get_int(crp, "pass_crypto_depth")) / 2; + scene->film->cryptomatte_depth = crypto_depth; + scene->film->cryptomatte_passes = CRYPT_NONE; + if (get_boolean(crp, "use_pass_crypto_object")) { + for (int i = 0; i < crypto_depth; ++i) { + string passname = cryptomatte_prefix + string_printf("Object%02d", i); + b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); + Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str()); + } + scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | + CRYPT_OBJECT); + } + if (get_boolean(crp, "use_pass_crypto_material")) { + for (int i = 0; i < crypto_depth; ++i) { + string passname = cryptomatte_prefix + string_printf("Material%02d", i); + b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); + Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str()); + } + scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | + CRYPT_MATERIAL); + } + if (get_boolean(crp, "use_pass_crypto_asset")) { + for (int i = 0; i < crypto_depth; ++i) { + string passname = cryptomatte_prefix + string_printf("Asset%02d", i); + b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str()); + Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str()); + } + scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | + CRYPT_ASSET); + } + if (get_boolean(crp, "pass_crypto_accurate") && scene->film->cryptomatte_passes != CRYPT_NONE) { + scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | + CRYPT_ACCURATE); + } + + return passes; } -void BlenderSync::free_data_after_sync(BL::Depsgraph& b_depsgraph) +void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph) { - /* When viewport display is not needed during render we can force some - * caches to be releases from blender side in order to reduce peak memory - * footprint during synchronization process. - */ - const bool is_interface_locked = b_engine.render() && - b_engine.render().use_lock_interface(); - const bool can_free_caches = BlenderSession::headless || is_interface_locked; - if(!can_free_caches) { - return; - } - /* TODO(sergey): We can actually remove the whole dependency graph, - * but that will need some API support first. - */ - BL::Depsgraph::objects_iterator b_ob; - for(b_depsgraph.objects.begin(b_ob); - b_ob != b_depsgraph.objects.end(); - ++b_ob) - { - b_ob->cache_release(); - } + /* When viewport display is not needed during render we can force some + * caches to be releases from blender side in order to reduce peak memory + * footprint during synchronization process. + */ + const bool is_interface_locked = b_engine.render() && b_engine.render().use_lock_interface(); + const bool can_free_caches = BlenderSession::headless || is_interface_locked; + if (!can_free_caches) { + return; + } + /* TODO(sergey): We can actually remove the whole dependency graph, + * but that will need some API support first. + */ + BL::Depsgraph::objects_iterator b_ob; + for (b_depsgraph.objects.begin(b_ob); b_ob != b_depsgraph.objects.end(); ++b_ob) { + b_ob->cache_release(); + } } /* Scene Parameters */ -SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene, - bool background) +SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background) { - BL::RenderSettings r = b_scene.render(); - SceneParams params; - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system"); - - if(shadingsystem == 0) - params.shadingsystem = SHADINGSYSTEM_SVM; - else if(shadingsystem == 1) - params.shadingsystem = SHADINGSYSTEM_OSL; - - if(background || DebugFlags().viewport_static_bvh) - params.bvh_type = SceneParams::BVH_STATIC; - else - params.bvh_type = SceneParams::BVH_DYNAMIC; - - params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits"); - params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh"); - params.num_bvh_time_steps = RNA_int_get(&cscene, "debug_bvh_time_steps"); - - if(background && params.shadingsystem != SHADINGSYSTEM_OSL) - params.persistent_data = r.use_persistent_data(); - else - params.persistent_data = false; - - int texture_limit; - if(background) { - texture_limit = RNA_enum_get(&cscene, "texture_limit_render"); - } - else { - texture_limit = RNA_enum_get(&cscene, "texture_limit"); - } - if(texture_limit > 0 && b_scene.render().use_simplify()) { - params.texture_limit = 1 << (texture_limit + 6); - } - else { - params.texture_limit = 0; - } - - /* TODO(sergey): Once OSL supports per-microarchitecture optimization get - * rid of this. - */ - if(params.shadingsystem == SHADINGSYSTEM_OSL) { - params.bvh_layout = BVH_LAYOUT_BVH4; - } - else { - params.bvh_layout = DebugFlags().cpu.bvh_layout; - } + BL::RenderSettings r = b_scene.render(); + SceneParams params; + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system"); + + if (shadingsystem == 0) + params.shadingsystem = SHADINGSYSTEM_SVM; + else if (shadingsystem == 1) + params.shadingsystem = SHADINGSYSTEM_OSL; + + if (background || DebugFlags().viewport_static_bvh) + params.bvh_type = SceneParams::BVH_STATIC; + else + params.bvh_type = SceneParams::BVH_DYNAMIC; + + params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits"); + params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh"); + params.num_bvh_time_steps = RNA_int_get(&cscene, "debug_bvh_time_steps"); + + if (background && params.shadingsystem != SHADINGSYSTEM_OSL) + params.persistent_data = r.use_persistent_data(); + else + params.persistent_data = false; + + int texture_limit; + if (background) { + texture_limit = RNA_enum_get(&cscene, "texture_limit_render"); + } + else { + texture_limit = RNA_enum_get(&cscene, "texture_limit"); + } + if (texture_limit > 0 && b_scene.render().use_simplify()) { + params.texture_limit = 1 << (texture_limit + 6); + } + else { + params.texture_limit = 0; + } + + /* TODO(sergey): Once OSL supports per-microarchitecture optimization get + * rid of this. + */ + if (params.shadingsystem == SHADINGSYSTEM_OSL) { + params.bvh_layout = BVH_LAYOUT_BVH4; + } + else { + params.bvh_layout = DebugFlags().cpu.bvh_layout; + } #ifdef WITH_EMBREE - params.bvh_layout = RNA_boolean_get(&cscene, "use_bvh_embree") ? BVH_LAYOUT_EMBREE : params.bvh_layout; + params.bvh_layout = RNA_boolean_get(&cscene, "use_bvh_embree") ? BVH_LAYOUT_EMBREE : + params.bvh_layout; #endif - return params; + return params; } /* Session Parameters */ -bool BlenderSync::get_session_pause(BL::Scene& b_scene, bool background) +bool BlenderSync::get_session_pause(BL::Scene &b_scene, bool background) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - return (background)? false: get_boolean(cscene, "preview_pause"); + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + return (background) ? false : get_boolean(cscene, "preview_pause"); } -SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, - BL::Preferences& b_preferences, - BL::Scene& b_scene, +SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine, + BL::Preferences &b_preferences, + BL::Scene &b_scene, bool background) { - SessionParams params; - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - - /* feature set */ - params.experimental = (get_enum(cscene, "feature_set") != 0); - - /* Background */ - params.background = background; - - /* Device */ - params.threads = blender_device_threads(b_scene); - params.device = blender_device_info(b_preferences, b_scene, params.background); - - /* samples */ - int samples = get_int(cscene, "samples"); - int aa_samples = get_int(cscene, "aa_samples"); - int preview_samples = get_int(cscene, "preview_samples"); - int preview_aa_samples = get_int(cscene, "preview_aa_samples"); - - if(get_boolean(cscene, "use_square_samples")) { - aa_samples = aa_samples * aa_samples; - preview_aa_samples = preview_aa_samples * preview_aa_samples; - - samples = samples * samples; - preview_samples = preview_samples * preview_samples; - } - - if(get_enum(cscene, "progressive") == 0) { - if(background) { - params.samples = aa_samples; - } - else { - params.samples = preview_aa_samples; - if(params.samples == 0) - params.samples = INT_MAX; - } - } - else { - if(background) { - params.samples = samples; - } - else { - params.samples = preview_samples; - if(params.samples == 0) - params.samples = INT_MAX; - } - } - - /* Clamp samples. */ - params.samples = min(params.samples, Integrator::MAX_SAMPLES); - - /* tiles */ - const bool is_cpu = (params.device.type == DEVICE_CPU); - if(!is_cpu && !background) { - /* currently GPU could be much slower than CPU when using tiles, - * still need to be investigated, but meanwhile make it possible - * to work in viewport smoothly - */ - int debug_tile_size = get_int(cscene, "debug_tile_size"); - - params.tile_size = make_int2(debug_tile_size, debug_tile_size); - } - else { - int tile_x = b_engine.tile_x(); - int tile_y = b_engine.tile_y(); - - params.tile_size = make_int2(tile_x, tile_y); - } - - if((BlenderSession::headless == false) && background) { - params.tile_order = (TileOrder)get_enum(cscene, "tile_order"); - } - else { - params.tile_order = TILE_BOTTOM_TO_TOP; - } - - /* other parameters */ - params.start_resolution = get_int(cscene, "preview_start_resolution"); - params.pixel_size = b_engine.get_preview_pixel_size(b_scene); - - /* other parameters */ - params.cancel_timeout = (double)get_float(cscene, "debug_cancel_timeout"); - params.reset_timeout = (double)get_float(cscene, "debug_reset_timeout"); - params.text_timeout = (double)get_float(cscene, "debug_text_timeout"); - - /* progressive refine */ - BL::RenderSettings b_r = b_scene.render(); - params.progressive_refine = (b_engine.is_preview() || - get_boolean(cscene, "use_progressive_refine")) && - !b_r.use_save_buffers(); - - if(params.progressive_refine) { - BL::Scene::view_layers_iterator b_view_layer; - for(b_scene.view_layers.begin(b_view_layer); b_view_layer != b_scene.view_layers.end(); ++b_view_layer) { - PointerRNA crl = RNA_pointer_get(&b_view_layer->ptr, "cycles"); - if(get_boolean(crl, "use_denoising")) { - params.progressive_refine = false; - } - } - } - - if(background) { - if(params.progressive_refine) - params.progressive = true; - else - params.progressive = false; - - params.start_resolution = INT_MAX; - params.pixel_size = 1; - } - else - params.progressive = true; - - /* shading system - scene level needs full refresh */ - const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system"); - - if(shadingsystem == 0) - params.shadingsystem = SHADINGSYSTEM_SVM; - else if(shadingsystem == 1) - params.shadingsystem = SHADINGSYSTEM_OSL; - - /* color managagement */ - params.display_buffer_linear = b_engine.support_display_space_shader(b_scene); - - if(b_engine.is_preview()) { - /* For preview rendering we're using same timeout as - * blender's job update. - */ - params.progressive_update_timeout = 0.1; - } - - params.use_profiling = params.device.has_profiling && !b_engine.is_preview() && - background && BlenderSession::print_render_stats; - - return params; + SessionParams params; + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + + /* feature set */ + params.experimental = (get_enum(cscene, "feature_set") != 0); + + /* Background */ + params.background = background; + + /* Device */ + params.threads = blender_device_threads(b_scene); + params.device = blender_device_info(b_preferences, b_scene, params.background); + + /* samples */ + int samples = get_int(cscene, "samples"); + int aa_samples = get_int(cscene, "aa_samples"); + int preview_samples = get_int(cscene, "preview_samples"); + int preview_aa_samples = get_int(cscene, "preview_aa_samples"); + + if (get_boolean(cscene, "use_square_samples")) { + aa_samples = aa_samples * aa_samples; + preview_aa_samples = preview_aa_samples * preview_aa_samples; + + samples = samples * samples; + preview_samples = preview_samples * preview_samples; + } + + if (get_enum(cscene, "progressive") == 0) { + if (background) { + params.samples = aa_samples; + } + else { + params.samples = preview_aa_samples; + if (params.samples == 0) + params.samples = INT_MAX; + } + } + else { + if (background) { + params.samples = samples; + } + else { + params.samples = preview_samples; + if (params.samples == 0) + params.samples = INT_MAX; + } + } + + /* Clamp samples. */ + params.samples = min(params.samples, Integrator::MAX_SAMPLES); + + /* tiles */ + const bool is_cpu = (params.device.type == DEVICE_CPU); + if (!is_cpu && !background) { + /* currently GPU could be much slower than CPU when using tiles, + * still need to be investigated, but meanwhile make it possible + * to work in viewport smoothly + */ + int debug_tile_size = get_int(cscene, "debug_tile_size"); + + params.tile_size = make_int2(debug_tile_size, debug_tile_size); + } + else { + int tile_x = b_engine.tile_x(); + int tile_y = b_engine.tile_y(); + + params.tile_size = make_int2(tile_x, tile_y); + } + + if ((BlenderSession::headless == false) && background) { + params.tile_order = (TileOrder)get_enum(cscene, "tile_order"); + } + else { + params.tile_order = TILE_BOTTOM_TO_TOP; + } + + /* other parameters */ + params.start_resolution = get_int(cscene, "preview_start_resolution"); + params.pixel_size = b_engine.get_preview_pixel_size(b_scene); + + /* other parameters */ + params.cancel_timeout = (double)get_float(cscene, "debug_cancel_timeout"); + params.reset_timeout = (double)get_float(cscene, "debug_reset_timeout"); + params.text_timeout = (double)get_float(cscene, "debug_text_timeout"); + + /* progressive refine */ + BL::RenderSettings b_r = b_scene.render(); + params.progressive_refine = (b_engine.is_preview() || + get_boolean(cscene, "use_progressive_refine")) && + !b_r.use_save_buffers(); + + if (params.progressive_refine) { + BL::Scene::view_layers_iterator b_view_layer; + for (b_scene.view_layers.begin(b_view_layer); b_view_layer != b_scene.view_layers.end(); + ++b_view_layer) { + PointerRNA crl = RNA_pointer_get(&b_view_layer->ptr, "cycles"); + if (get_boolean(crl, "use_denoising")) { + params.progressive_refine = false; + } + } + } + + if (background) { + if (params.progressive_refine) + params.progressive = true; + else + params.progressive = false; + + params.start_resolution = INT_MAX; + params.pixel_size = 1; + } + else + params.progressive = true; + + /* shading system - scene level needs full refresh */ + const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system"); + + if (shadingsystem == 0) + params.shadingsystem = SHADINGSYSTEM_SVM; + else if (shadingsystem == 1) + params.shadingsystem = SHADINGSYSTEM_OSL; + + /* color managagement */ + params.display_buffer_linear = b_engine.support_display_space_shader(b_scene); + + if (b_engine.is_preview()) { + /* For preview rendering we're using same timeout as + * blender's job update. + */ + params.progressive_update_timeout = 0.1; + } + + params.use_profiling = params.device.has_profiling && !b_engine.is_preview() && background && + BlenderSession::print_render_stats; + + return params; } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 8af3fde3323..00afceebde3 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -49,171 +49,173 @@ class ShaderGraph; class ShaderNode; class BlenderSync { -public: - BlenderSync(BL::RenderEngine& b_engine, - BL::BlendData& b_data, - BL::Scene& b_scene, - Scene *scene, - bool preview, - Progress &progress); - ~BlenderSync(); - - /* sync */ - void sync_recalc(BL::Depsgraph& b_depsgraph); - void sync_data(BL::RenderSettings& b_render, - BL::Depsgraph& b_depsgraph, - BL::SpaceView3D& b_v3d, - BL::Object& b_override, - int width, int height, - void **python_thread_state); - void sync_view_layer(BL::SpaceView3D& b_v3d, BL::ViewLayer& b_view_layer); - vector<Pass> sync_render_passes(BL::RenderLayer& b_render_layer, - BL::ViewLayer& b_view_layer); - void sync_integrator(); - void sync_camera(BL::RenderSettings& b_render, - BL::Object& b_override, - int width, int height, - const char *viewname); - void sync_view(BL::SpaceView3D& b_v3d, - BL::RegionView3D& b_rv3d, - int width, int height); - inline int get_layer_samples() { return view_layer.samples; } - inline int get_layer_bound_samples() { return view_layer.bound_samples; } - - /* get parameters */ - static SceneParams get_scene_params(BL::Scene& b_scene, - bool background); - static SessionParams get_session_params(BL::RenderEngine& b_engine, - BL::Preferences& b_userpref, - BL::Scene& b_scene, - bool background); - static bool get_session_pause(BL::Scene& b_scene, bool background); - static BufferParams get_buffer_params(BL::RenderSettings& b_render, - BL::SpaceView3D& b_v3d, - BL::RegionView3D& b_rv3d, - Camera *cam, - int width, int height); - - static PassType get_pass_type(BL::RenderPass& b_pass); - static int get_denoising_pass(BL::RenderPass& b_pass); - -private: - /* sync */ - void sync_lights(BL::Depsgraph& b_depsgraph, bool update_all); - void sync_materials(BL::Depsgraph& b_depsgraph, bool update_all); - void sync_objects(BL::Depsgraph& b_depsgraph, float motion_time = 0.0f); - void sync_motion(BL::RenderSettings& b_render, - BL::Depsgraph& b_depsgraph, - BL::Object& b_override, - int width, int height, - void **python_thread_state); - void sync_film(); - void sync_view(); - void sync_world(BL::Depsgraph& b_depsgraph, bool update_all); - void sync_shaders(BL::Depsgraph& b_depsgraph); - void sync_curve_settings(); - - void sync_nodes(Shader *shader, BL::ShaderNodeTree& b_ntree); - Mesh *sync_mesh(BL::Depsgraph& b_depsgrpah, - BL::Object& b_ob, - BL::Object& b_ob_instance, - bool object_updated, - bool show_self, - bool show_particles); - void sync_curves(Mesh *mesh, - BL::Mesh& b_mesh, - BL::Object& b_ob, - bool motion, - int motion_step = 0); - Object *sync_object(BL::Depsgraph& b_depsgraph, - BL::ViewLayer& b_view_layer, - BL::DepsgraphObjectInstance& b_instance, - float motion_time, - bool show_self, - bool show_particles, - BlenderObjectCulling& culling, - bool *use_portal); - void sync_light(BL::Object& b_parent, - int persistent_id[OBJECT_PERSISTENT_ID_SIZE], - BL::Object& b_ob, - BL::Object& b_ob_instance, - int random_id, - Transform& tfm, - bool *use_portal); - void sync_background_light(bool use_portal); - void sync_mesh_motion(BL::Depsgraph& b_depsgraph, - BL::Object& b_ob, - Object *object, - float motion_time); - void sync_camera_motion(BL::RenderSettings& b_render, - BL::Object& b_ob, - int width, int height, - float motion_time); - - /* particles */ - bool sync_dupli_particle(BL::Object& b_ob, - BL::DepsgraphObjectInstance& b_instance, - Object *object); - - /* Images. */ - void sync_images(); - - /* Early data free. */ - void free_data_after_sync(BL::Depsgraph& b_depsgraph); - - /* util */ - void find_shader(BL::ID& id, vector<Shader*>& used_shaders, Shader *default_shader); - bool BKE_object_is_modified(BL::Object& b_ob); - bool object_is_mesh(BL::Object& b_ob); - bool object_is_light(BL::Object& b_ob); - - /* variables */ - BL::RenderEngine b_engine; - BL::BlendData b_data; - BL::Scene b_scene; - - id_map<void*, Shader> shader_map; - id_map<ObjectKey, Object> object_map; - id_map<void*, Mesh> mesh_map; - id_map<ObjectKey, Light> light_map; - id_map<ParticleSystemKey, ParticleSystem> particle_system_map; - set<Mesh*> mesh_synced; - set<Mesh*> mesh_motion_synced; - set<float> motion_times; - void *world_map; - bool world_recalc; - - Scene *scene; - bool preview; - bool experimental; - - float dicing_rate; - int max_subdivisions; - - struct RenderLayerInfo { - RenderLayerInfo() - : material_override(PointerRNA_NULL), - use_background_shader(true), - use_background_ao(true), - use_surfaces(true), - use_hair(true), - samples(0), - bound_samples(false) - {} - - string name; - BL::Material material_override; - bool use_background_shader; - bool use_background_ao; - bool use_surfaces; - bool use_hair; - int samples; - bool bound_samples; - } view_layer; - - Progress &progress; + public: + BlenderSync(BL::RenderEngine &b_engine, + BL::BlendData &b_data, + BL::Scene &b_scene, + Scene *scene, + bool preview, + Progress &progress); + ~BlenderSync(); + + /* sync */ + void sync_recalc(BL::Depsgraph &b_depsgraph); + void sync_data(BL::RenderSettings &b_render, + BL::Depsgraph &b_depsgraph, + BL::SpaceView3D &b_v3d, + BL::Object &b_override, + int width, + int height, + void **python_thread_state); + void sync_view_layer(BL::SpaceView3D &b_v3d, BL::ViewLayer &b_view_layer); + vector<Pass> sync_render_passes(BL::RenderLayer &b_render_layer, BL::ViewLayer &b_view_layer); + void sync_integrator(); + void sync_camera(BL::RenderSettings &b_render, + BL::Object &b_override, + int width, + int height, + const char *viewname); + void sync_view(BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, int width, int height); + inline int get_layer_samples() + { + return view_layer.samples; + } + inline int get_layer_bound_samples() + { + return view_layer.bound_samples; + } + + /* get parameters */ + static SceneParams get_scene_params(BL::Scene &b_scene, bool background); + static SessionParams get_session_params(BL::RenderEngine &b_engine, + BL::Preferences &b_userpref, + BL::Scene &b_scene, + bool background); + static bool get_session_pause(BL::Scene &b_scene, bool background); + static BufferParams get_buffer_params(BL::RenderSettings &b_render, + BL::SpaceView3D &b_v3d, + BL::RegionView3D &b_rv3d, + Camera *cam, + int width, + int height); + + static PassType get_pass_type(BL::RenderPass &b_pass); + static int get_denoising_pass(BL::RenderPass &b_pass); + + private: + /* sync */ + void sync_lights(BL::Depsgraph &b_depsgraph, bool update_all); + void sync_materials(BL::Depsgraph &b_depsgraph, bool update_all); + void sync_objects(BL::Depsgraph &b_depsgraph, float motion_time = 0.0f); + void sync_motion(BL::RenderSettings &b_render, + BL::Depsgraph &b_depsgraph, + BL::Object &b_override, + int width, + int height, + void **python_thread_state); + void sync_film(); + void sync_view(); + void sync_world(BL::Depsgraph &b_depsgraph, bool update_all); + void sync_shaders(BL::Depsgraph &b_depsgraph); + void sync_curve_settings(); + + void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree); + Mesh *sync_mesh(BL::Depsgraph &b_depsgrpah, + BL::Object &b_ob, + BL::Object &b_ob_instance, + bool object_updated, + bool show_self, + bool show_particles); + void sync_curves( + Mesh *mesh, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0); + Object *sync_object(BL::Depsgraph &b_depsgraph, + BL::ViewLayer &b_view_layer, + BL::DepsgraphObjectInstance &b_instance, + float motion_time, + bool show_self, + bool show_particles, + BlenderObjectCulling &culling, + bool *use_portal); + void sync_light(BL::Object &b_parent, + int persistent_id[OBJECT_PERSISTENT_ID_SIZE], + BL::Object &b_ob, + BL::Object &b_ob_instance, + int random_id, + Transform &tfm, + bool *use_portal); + void sync_background_light(bool use_portal); + void sync_mesh_motion(BL::Depsgraph &b_depsgraph, + BL::Object &b_ob, + Object *object, + float motion_time); + void sync_camera_motion( + BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time); + + /* particles */ + bool sync_dupli_particle(BL::Object &b_ob, + BL::DepsgraphObjectInstance &b_instance, + Object *object); + + /* Images. */ + void sync_images(); + + /* Early data free. */ + void free_data_after_sync(BL::Depsgraph &b_depsgraph); + + /* util */ + void find_shader(BL::ID &id, vector<Shader *> &used_shaders, Shader *default_shader); + bool BKE_object_is_modified(BL::Object &b_ob); + bool object_is_mesh(BL::Object &b_ob); + bool object_is_light(BL::Object &b_ob); + + /* variables */ + BL::RenderEngine b_engine; + BL::BlendData b_data; + BL::Scene b_scene; + + id_map<void *, Shader> shader_map; + id_map<ObjectKey, Object> object_map; + id_map<void *, Mesh> mesh_map; + id_map<ObjectKey, Light> light_map; + id_map<ParticleSystemKey, ParticleSystem> particle_system_map; + set<Mesh *> mesh_synced; + set<Mesh *> mesh_motion_synced; + set<float> motion_times; + void *world_map; + bool world_recalc; + + Scene *scene; + bool preview; + bool experimental; + + float dicing_rate; + int max_subdivisions; + + struct RenderLayerInfo { + RenderLayerInfo() + : material_override(PointerRNA_NULL), + use_background_shader(true), + use_background_ao(true), + use_surfaces(true), + use_hair(true), + samples(0), + bound_samples(false) + { + } + + string name; + BL::Material material_override; + bool use_background_shader; + bool use_background_ao; + bool use_surfaces; + bool use_hair; + int samples; + bool bound_samples; + } view_layer; + + Progress &progress; }; CCL_NAMESPACE_END -#endif /* __BLENDER_SYNC_H__ */ +#endif /* __BLENDER_SYNC_H__ */ diff --git a/intern/cycles/blender/blender_texture.cpp b/intern/cycles/blender/blender_texture.cpp index a0371a7eed8..7b05f361a29 100644 --- a/intern/cycles/blender/blender_texture.cpp +++ b/intern/cycles/blender/blender_texture.cpp @@ -22,36 +22,36 @@ namespace { /* Point density helpers. */ -void density_texture_space_invert(float3& loc, - float3& size) +void density_texture_space_invert(float3 &loc, float3 &size) { - if(size.x != 0.0f) size.x = 0.5f/size.x; - if(size.y != 0.0f) size.y = 0.5f/size.y; - if(size.z != 0.0f) size.z = 0.5f/size.z; - - loc = loc*size - make_float3(0.5f, 0.5f, 0.5f); + if (size.x != 0.0f) + size.x = 0.5f / size.x; + if (size.y != 0.0f) + size.y = 0.5f / size.y; + if (size.z != 0.0f) + size.z = 0.5f / size.z; + + loc = loc * size - make_float3(0.5f, 0.5f, 0.5f); } -} /* namespace */ +} /* namespace */ -void point_density_texture_space(BL::Depsgraph& b_depsgraph, - BL::ShaderNodeTexPointDensity& b_point_density_node, - float3& loc, - float3& size) +void point_density_texture_space(BL::Depsgraph &b_depsgraph, + BL::ShaderNodeTexPointDensity &b_point_density_node, + float3 &loc, + float3 &size) { - BL::Object b_ob(b_point_density_node.object()); - if(!b_ob) { - loc = make_float3(0.0f, 0.0f, 0.0f); - size = make_float3(0.0f, 0.0f, 0.0f); - return; - } - float3 min, max; - b_point_density_node.calc_point_density_minmax(b_depsgraph, - &min[0], - &max[0]); - loc = (min + max) * 0.5f; - size = (max - min) * 0.5f; - density_texture_space_invert(loc, size); + BL::Object b_ob(b_point_density_node.object()); + if (!b_ob) { + loc = make_float3(0.0f, 0.0f, 0.0f); + size = make_float3(0.0f, 0.0f, 0.0f); + return; + } + float3 min, max; + b_point_density_node.calc_point_density_minmax(b_depsgraph, &min[0], &max[0]); + loc = (min + max) * 0.5f; + size = (max - min) * 0.5f; + density_texture_space_invert(loc, size); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_texture.h b/intern/cycles/blender/blender_texture.h index b4e166c5cdd..896bf62da70 100644 --- a/intern/cycles/blender/blender_texture.h +++ b/intern/cycles/blender/blender_texture.h @@ -22,11 +22,11 @@ CCL_NAMESPACE_BEGIN -void point_density_texture_space(BL::Depsgraph& b_depsgraph, - BL::ShaderNodeTexPointDensity& b_point_density_node, - float3& loc, - float3& size); +void point_density_texture_space(BL::Depsgraph &b_depsgraph, + BL::ShaderNodeTexPointDensity &b_point_density_node, + float3 &loc, + float3 &size); CCL_NAMESPACE_END -#endif /* __BLENDER_TEXTURE_H__ */ +#endif /* __BLENDER_TEXTURE_H__ */ diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index f302b09459f..e68f92474bf 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -43,338 +43,320 @@ CCL_NAMESPACE_BEGIN void python_thread_state_save(void **python_thread_state); void python_thread_state_restore(void **python_thread_state); -static inline BL::Mesh object_to_mesh(BL::BlendData& data, - BL::Object& object, - BL::Depsgraph& depsgraph, +static inline BL::Mesh object_to_mesh(BL::BlendData &data, + BL::Object &object, + BL::Depsgraph &depsgraph, bool calc_undeformed, Mesh::SubdivisionType subdivision_type) { - /* TODO: make this work with copy-on-write, modifiers are already evaluated. */ + /* TODO: make this work with copy-on-write, modifiers are already evaluated. */ #if 0 - bool subsurf_mod_show_render = false; - bool subsurf_mod_show_viewport = false; + bool subsurf_mod_show_render = false; + bool subsurf_mod_show_viewport = false; - if(subdivision_type != Mesh::SUBDIVISION_NONE) { - BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; + if(subdivision_type != Mesh::SUBDIVISION_NONE) { + BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; - subsurf_mod_show_render = subsurf_mod.show_render(); - subsurf_mod_show_viewport = subsurf_mod.show_viewport(); + subsurf_mod_show_render = subsurf_mod.show_render(); + subsurf_mod_show_viewport = subsurf_mod.show_viewport(); - subsurf_mod.show_render(false); - subsurf_mod.show_viewport(false); - } + subsurf_mod.show_render(false); + subsurf_mod.show_viewport(false); + } #endif - BL::Mesh mesh(PointerRNA_NULL); - if(object.type() == BL::Object::type_MESH) { - /* TODO: calc_undeformed is not used. */ - mesh = BL::Mesh(object.data()); - - /* Make a copy to split faces if we use autosmooth, otherwise not needed. - * Also in edit mode do we need to make a copy, to ensure data layers like - * UV are not empty. */ - if (mesh.is_editmode() || - (mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) - { - mesh = data.meshes.new_from_object(depsgraph, object, false, false); - } - } - else { - mesh = data.meshes.new_from_object(depsgraph, object, true, calc_undeformed); - } + BL::Mesh mesh(PointerRNA_NULL); + if (object.type() == BL::Object::type_MESH) { + /* TODO: calc_undeformed is not used. */ + mesh = BL::Mesh(object.data()); + + /* Make a copy to split faces if we use autosmooth, otherwise not needed. + * Also in edit mode do we need to make a copy, to ensure data layers like + * UV are not empty. */ + if (mesh.is_editmode() || + (mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) { + mesh = data.meshes.new_from_object(depsgraph, object, false, false); + } + } + else { + mesh = data.meshes.new_from_object(depsgraph, object, true, calc_undeformed); + } #if 0 - if(subdivision_type != Mesh::SUBDIVISION_NONE) { - BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; + if(subdivision_type != Mesh::SUBDIVISION_NONE) { + BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; - subsurf_mod.show_render(subsurf_mod_show_render); - subsurf_mod.show_viewport(subsurf_mod_show_viewport); - } + subsurf_mod.show_render(subsurf_mod_show_render); + subsurf_mod.show_viewport(subsurf_mod_show_viewport); + } #endif - if((bool)mesh && subdivision_type == Mesh::SUBDIVISION_NONE) { - if(mesh.use_auto_smooth()) { - mesh.split_faces(false); - } + if ((bool)mesh && subdivision_type == Mesh::SUBDIVISION_NONE) { + if (mesh.use_auto_smooth()) { + mesh.split_faces(false); + } - mesh.calc_loop_triangles(); - } + mesh.calc_loop_triangles(); + } - return mesh; + return mesh; } -static inline void free_object_to_mesh(BL::BlendData& data, - BL::Object& object, - BL::Mesh& mesh) +static inline void free_object_to_mesh(BL::BlendData &data, BL::Object &object, BL::Mesh &mesh) { - /* Free mesh if we didn't just use the existing one. */ - if(object.data().ptr.data != mesh.ptr.data) { - data.meshes.remove(mesh, false, true, false); - } + /* Free mesh if we didn't just use the existing one. */ + if (object.data().ptr.data != mesh.ptr.data) { + data.meshes.remove(mesh, false, true, false); + } } -static inline void colorramp_to_array(BL::ColorRamp& ramp, - array<float3>& ramp_color, - array<float>& ramp_alpha, +static inline void colorramp_to_array(BL::ColorRamp &ramp, + array<float3> &ramp_color, + array<float> &ramp_alpha, int size) { - ramp_color.resize(size); - ramp_alpha.resize(size); + ramp_color.resize(size); + ramp_alpha.resize(size); - for(int i = 0; i < size; i++) { - float color[4]; + for (int i = 0; i < size; i++) { + float color[4]; - ramp.evaluate((float)i/(float)(size-1), color); - ramp_color[i] = make_float3(color[0], color[1], color[2]); - ramp_alpha[i] = color[3]; - } + ramp.evaluate((float)i / (float)(size - 1), color); + ramp_color[i] = make_float3(color[0], color[1], color[2]); + ramp_alpha[i] = color[3]; + } } -static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap& curve, - float *min_x, - float *max_x) +static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap &curve, float *min_x, float *max_x) { - *min_x = min(*min_x, curve.points[0].location()[0]); - *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]); + *min_x = min(*min_x, curve.points[0].location()[0]); + *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]); } -static inline void curvemapping_minmax(/*const*/ BL::CurveMapping& cumap, +static inline void curvemapping_minmax(/*const*/ BL::CurveMapping &cumap, bool rgb_curve, float *min_x, float *max_x) { - /* const int num_curves = cumap.curves.length(); */ /* Gives linking error so far. */ - const int num_curves = rgb_curve? 4: 3; - *min_x = FLT_MAX; - *max_x = -FLT_MAX; - for(int i = 0; i < num_curves; ++i) { - BL::CurveMap map(cumap.curves[i]); - curvemap_minmax_curve(map, min_x, max_x); - } + /* const int num_curves = cumap.curves.length(); */ /* Gives linking error so far. */ + const int num_curves = rgb_curve ? 4 : 3; + *min_x = FLT_MAX; + *max_x = -FLT_MAX; + for (int i = 0; i < num_curves; ++i) { + BL::CurveMap map(cumap.curves[i]); + curvemap_minmax_curve(map, min_x, max_x); + } } -static inline void curvemapping_to_array(BL::CurveMapping& cumap, - array<float>& data, - int size) +static inline void curvemapping_to_array(BL::CurveMapping &cumap, array<float> &data, int size) { - cumap.update(); - BL::CurveMap curve = cumap.curves[0]; - data.resize(size); - for(int i = 0; i < size; i++) { - float t = (float)i/(float)(size-1); - data[i] = curve.evaluate(t); - } + cumap.update(); + BL::CurveMap curve = cumap.curves[0]; + data.resize(size); + for (int i = 0; i < size; i++) { + float t = (float)i / (float)(size - 1); + data[i] = curve.evaluate(t); + } } -static inline void curvemapping_color_to_array(BL::CurveMapping& cumap, - array<float3>& data, +static inline void curvemapping_color_to_array(BL::CurveMapping &cumap, + array<float3> &data, int size, bool rgb_curve) { - float min_x = 0.0f, max_x = 1.0f; + float min_x = 0.0f, max_x = 1.0f; - /* TODO(sergey): There is no easy way to automatically guess what is - * the range to be used here for the case when mapping is applied on - * top of another mapping (i.e. R curve applied on top of common - * one). - * - * Using largest possible range form all curves works correct for the - * cases like vector curves and should be good enough heuristic for - * the color curves as well. - * - * There might be some better estimations here tho. - */ - curvemapping_minmax(cumap, rgb_curve, &min_x, &max_x); + /* TODO(sergey): There is no easy way to automatically guess what is + * the range to be used here for the case when mapping is applied on + * top of another mapping (i.e. R curve applied on top of common + * one). + * + * Using largest possible range form all curves works correct for the + * cases like vector curves and should be good enough heuristic for + * the color curves as well. + * + * There might be some better estimations here tho. + */ + curvemapping_minmax(cumap, rgb_curve, &min_x, &max_x); - const float range_x = max_x - min_x; + const float range_x = max_x - min_x; - cumap.update(); + cumap.update(); - BL::CurveMap mapR = cumap.curves[0]; - BL::CurveMap mapG = cumap.curves[1]; - BL::CurveMap mapB = cumap.curves[2]; + BL::CurveMap mapR = cumap.curves[0]; + BL::CurveMap mapG = cumap.curves[1]; + BL::CurveMap mapB = cumap.curves[2]; - data.resize(size); + data.resize(size); - if(rgb_curve) { - BL::CurveMap mapI = cumap.curves[3]; - for(int i = 0; i < size; i++) { - const float t = min_x + (float)i/(float)(size-1) * range_x; - data[i] = make_float3(mapR.evaluate(mapI.evaluate(t)), - mapG.evaluate(mapI.evaluate(t)), - mapB.evaluate(mapI.evaluate(t))); - } - } - else { - for(int i = 0; i < size; i++) { - float t = min_x + (float)i/(float)(size-1) * range_x; - data[i] = make_float3(mapR.evaluate(t), - mapG.evaluate(t), - mapB.evaluate(t)); - } - } + if (rgb_curve) { + BL::CurveMap mapI = cumap.curves[3]; + for (int i = 0; i < size; i++) { + const float t = min_x + (float)i / (float)(size - 1) * range_x; + data[i] = make_float3(mapR.evaluate(mapI.evaluate(t)), + mapG.evaluate(mapI.evaluate(t)), + mapB.evaluate(mapI.evaluate(t))); + } + } + else { + for (int i = 0; i < size; i++) { + float t = min_x + (float)i / (float)(size - 1) * range_x; + data[i] = make_float3(mapR.evaluate(t), mapG.evaluate(t), mapB.evaluate(t)); + } + } } -static inline bool BKE_object_is_modified(BL::Object& self, - BL::Scene& scene, - bool preview) +static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bool preview) { - return self.is_modified(scene, (preview)? (1<<0): (1<<1))? true: false; + return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false; } -static inline bool BKE_object_is_deform_modified(BL::Object& self, - BL::Scene& scene, - bool preview) +static inline bool BKE_object_is_deform_modified(BL::Object &self, BL::Scene &scene, bool preview) { - return self.is_deform_modified(scene, (preview)? (1<<0): (1<<1))? true: false; + return self.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false; } -static inline int render_resolution_x(BL::RenderSettings& b_render) +static inline int render_resolution_x(BL::RenderSettings &b_render) { - return b_render.resolution_x()*b_render.resolution_percentage()/100; + return b_render.resolution_x() * b_render.resolution_percentage() / 100; } -static inline int render_resolution_y(BL::RenderSettings& b_render) +static inline int render_resolution_y(BL::RenderSettings &b_render) { - return b_render.resolution_y()*b_render.resolution_percentage()/100; + return b_render.resolution_y() * b_render.resolution_percentage() / 100; } -static inline string image_user_file_path(BL::ImageUser& iuser, - BL::Image& ima, - int cfra) +static inline string image_user_file_path(BL::ImageUser &iuser, BL::Image &ima, int cfra) { - char filepath[1024]; - BKE_image_user_frame_calc(iuser.ptr.data, cfra); - BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath); - return string(filepath); + char filepath[1024]; + BKE_image_user_frame_calc(iuser.ptr.data, cfra); + BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath); + return string(filepath); } -static inline int image_user_frame_number(BL::ImageUser& iuser, int cfra) +static inline int image_user_frame_number(BL::ImageUser &iuser, int cfra) { - BKE_image_user_frame_calc(iuser.ptr.data, cfra); - return iuser.frame_current(); + BKE_image_user_frame_calc(iuser.ptr.data, cfra); + return iuser.frame_current(); } -static inline unsigned char *image_get_pixels_for_frame(BL::Image& image, - int frame) +static inline unsigned char *image_get_pixels_for_frame(BL::Image &image, int frame) { - return BKE_image_get_pixels_for_frame(image.ptr.data, frame); + return BKE_image_get_pixels_for_frame(image.ptr.data, frame); } -static inline float *image_get_float_pixels_for_frame(BL::Image& image, - int frame) +static inline float *image_get_float_pixels_for_frame(BL::Image &image, int frame) { - return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame); + return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame); } -static inline void render_add_metadata(BL::RenderResult& b_rr, string name, string value) +static inline void render_add_metadata(BL::RenderResult &b_rr, string name, string value) { - b_rr.stamp_data_add_field(name.c_str(), value.c_str()); + b_rr.stamp_data_add_field(name.c_str(), value.c_str()); } - /* Utilities */ -static inline Transform get_transform(const BL::Array<float, 16>& array) +static inline Transform get_transform(const BL::Array<float, 16> &array) { - ProjectionTransform projection; + ProjectionTransform projection; - /* We assume both types to be just 16 floats, and transpose because blender - * use column major matrix order while we use row major. */ - memcpy((void *)&projection, &array, sizeof(float)*16); - projection = projection_transpose(projection); + /* We assume both types to be just 16 floats, and transpose because blender + * use column major matrix order while we use row major. */ + memcpy((void *)&projection, &array, sizeof(float) * 16); + projection = projection_transpose(projection); - /* Drop last row, matrix is assumed to be affine transform. */ - return projection_to_transform(projection); + /* Drop last row, matrix is assumed to be affine transform. */ + return projection_to_transform(projection); } -static inline float2 get_float2(const BL::Array<float, 2>& array) +static inline float2 get_float2(const BL::Array<float, 2> &array) { - return make_float2(array[0], array[1]); + return make_float2(array[0], array[1]); } -static inline float3 get_float3(const BL::Array<float, 2>& array) +static inline float3 get_float3(const BL::Array<float, 2> &array) { - return make_float3(array[0], array[1], 0.0f); + return make_float3(array[0], array[1], 0.0f); } -static inline float3 get_float3(const BL::Array<float, 3>& array) +static inline float3 get_float3(const BL::Array<float, 3> &array) { - return make_float3(array[0], array[1], array[2]); + return make_float3(array[0], array[1], array[2]); } -static inline float3 get_float3(const BL::Array<float, 4>& array) +static inline float3 get_float3(const BL::Array<float, 4> &array) { - return make_float3(array[0], array[1], array[2]); + return make_float3(array[0], array[1], array[2]); } -static inline float4 get_float4(const BL::Array<float, 4>& array) +static inline float4 get_float4(const BL::Array<float, 4> &array) { - return make_float4(array[0], array[1], array[2], array[3]); + return make_float4(array[0], array[1], array[2], array[3]); } -static inline int3 get_int3(const BL::Array<int, 3>& array) +static inline int3 get_int3(const BL::Array<int, 3> &array) { - return make_int3(array[0], array[1], array[2]); + return make_int3(array[0], array[1], array[2]); } -static inline int4 get_int4(const BL::Array<int, 4>& array) +static inline int4 get_int4(const BL::Array<int, 4> &array) { - return make_int4(array[0], array[1], array[2], array[3]); + return make_int4(array[0], array[1], array[2], array[3]); } -static inline float3 get_float3(PointerRNA& ptr, const char *name) +static inline float3 get_float3(PointerRNA &ptr, const char *name) { - float3 f; - RNA_float_get_array(&ptr, name, &f.x); - return f; + float3 f; + RNA_float_get_array(&ptr, name, &f.x); + return f; } -static inline void set_float3(PointerRNA& ptr, const char *name, float3 value) +static inline void set_float3(PointerRNA &ptr, const char *name, float3 value) { - RNA_float_set_array(&ptr, name, &value.x); + RNA_float_set_array(&ptr, name, &value.x); } -static inline float4 get_float4(PointerRNA& ptr, const char *name) +static inline float4 get_float4(PointerRNA &ptr, const char *name) { - float4 f; - RNA_float_get_array(&ptr, name, &f.x); - return f; + float4 f; + RNA_float_get_array(&ptr, name, &f.x); + return f; } -static inline void set_float4(PointerRNA& ptr, const char *name, float4 value) +static inline void set_float4(PointerRNA &ptr, const char *name, float4 value) { - RNA_float_set_array(&ptr, name, &value.x); + RNA_float_set_array(&ptr, name, &value.x); } -static inline bool get_boolean(PointerRNA& ptr, const char *name) +static inline bool get_boolean(PointerRNA &ptr, const char *name) { - return RNA_boolean_get(&ptr, name)? true: false; + return RNA_boolean_get(&ptr, name) ? true : false; } -static inline void set_boolean(PointerRNA& ptr, const char *name, bool value) +static inline void set_boolean(PointerRNA &ptr, const char *name, bool value) { - RNA_boolean_set(&ptr, name, (int)value); + RNA_boolean_set(&ptr, name, (int)value); } -static inline float get_float(PointerRNA& ptr, const char *name) +static inline float get_float(PointerRNA &ptr, const char *name) { - return RNA_float_get(&ptr, name); + return RNA_float_get(&ptr, name); } -static inline void set_float(PointerRNA& ptr, const char *name, float value) +static inline void set_float(PointerRNA &ptr, const char *name, float value) { - RNA_float_set(&ptr, name, value); + RNA_float_set(&ptr, name, value); } -static inline int get_int(PointerRNA& ptr, const char *name) +static inline int get_int(PointerRNA &ptr, const char *name) { - return RNA_int_get(&ptr, name); + return RNA_int_get(&ptr, name); } -static inline void set_int(PointerRNA& ptr, const char *name, int value) +static inline void set_int(PointerRNA &ptr, const char *name, int value) { - RNA_int_set(&ptr, name, value); + RNA_int_set(&ptr, name, value); } /* Get a RNA enum value with sanity check: if the RNA value is above num_values @@ -384,215 +366,214 @@ static inline void set_int(PointerRNA& ptr, const char *name, int value) * from 0 to num_values-1. Be careful to use it with enums where some values are * deprecated! */ -static inline int get_enum(PointerRNA& ptr, +static inline int get_enum(PointerRNA &ptr, const char *name, int num_values = -1, int default_value = -1) { - int value = RNA_enum_get(&ptr, name); - if(num_values != -1 && value >= num_values) { - assert(default_value != -1); - value = default_value; - } - return value; + int value = RNA_enum_get(&ptr, name); + if (num_values != -1 && value >= num_values) { + assert(default_value != -1); + value = default_value; + } + return value; } -static inline string get_enum_identifier(PointerRNA& ptr, const char *name) +static inline string get_enum_identifier(PointerRNA &ptr, const char *name) { - PropertyRNA *prop = RNA_struct_find_property(&ptr, name); - const char *identifier = ""; - int value = RNA_property_enum_get(&ptr, prop); + PropertyRNA *prop = RNA_struct_find_property(&ptr, name); + const char *identifier = ""; + int value = RNA_property_enum_get(&ptr, prop); - RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier); + RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier); - return string(identifier); + return string(identifier); } -static inline void set_enum(PointerRNA& ptr, const char *name, int value) +static inline void set_enum(PointerRNA &ptr, const char *name, int value) { - RNA_enum_set(&ptr, name, value); + RNA_enum_set(&ptr, name, value); } -static inline void set_enum(PointerRNA& ptr, const char *name, const string &identifier) +static inline void set_enum(PointerRNA &ptr, const char *name, const string &identifier) { - RNA_enum_set_identifier(NULL, &ptr, name, identifier.c_str()); + RNA_enum_set_identifier(NULL, &ptr, name, identifier.c_str()); } -static inline string get_string(PointerRNA& ptr, const char *name) +static inline string get_string(PointerRNA &ptr, const char *name) { - char cstrbuf[1024]; - char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf)); - string str(cstr); - if(cstr != cstrbuf) - MEM_freeN(cstr); + char cstrbuf[1024]; + char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf)); + string str(cstr); + if (cstr != cstrbuf) + MEM_freeN(cstr); - return str; + return str; } -static inline void set_string(PointerRNA& ptr, const char *name, const string &value) +static inline void set_string(PointerRNA &ptr, const char *name, const string &value) { - RNA_string_set(&ptr, name, value.c_str()); + RNA_string_set(&ptr, name, value.c_str()); } /* Relative Paths */ -static inline string blender_absolute_path(BL::BlendData& b_data, - BL::ID& b_id, - const string& path) +static inline string blender_absolute_path(BL::BlendData &b_data, BL::ID &b_id, const string &path) { - if(path.size() >= 2 && path[0] == '/' && path[1] == '/') { - string dirname; + if (path.size() >= 2 && path[0] == '/' && path[1] == '/') { + string dirname; - if(b_id.library()) { - BL::ID b_library_id(b_id.library()); - dirname = blender_absolute_path(b_data, - b_library_id, - b_id.library().filepath()); - } - else - dirname = b_data.filepath(); + if (b_id.library()) { + BL::ID b_library_id(b_id.library()); + dirname = blender_absolute_path(b_data, b_library_id, b_id.library().filepath()); + } + else + dirname = b_data.filepath(); - return path_join(path_dirname(dirname), path.substr(2)); - } + return path_join(path_dirname(dirname), path.substr(2)); + } - return path; + return path; } -static inline string get_text_datablock_content(const PointerRNA& ptr) +static inline string get_text_datablock_content(const PointerRNA &ptr) { - if(ptr.data == NULL) { - return ""; - } + if (ptr.data == NULL) { + return ""; + } - string content; - BL::Text::lines_iterator iter; - for(iter.begin(ptr); iter; ++iter) { - content += iter->body() + "\n"; - } + string content; + BL::Text::lines_iterator iter; + for (iter.begin(ptr); iter; ++iter) { + content += iter->body() + "\n"; + } - return content; + return content; } /* Texture Space */ -static inline void mesh_texture_space(BL::Mesh& b_mesh, - float3& loc, - float3& size) +static inline void mesh_texture_space(BL::Mesh &b_mesh, float3 &loc, float3 &size) { - loc = get_float3(b_mesh.texspace_location()); - size = get_float3(b_mesh.texspace_size()); + loc = get_float3(b_mesh.texspace_location()); + size = get_float3(b_mesh.texspace_size()); - if(size.x != 0.0f) size.x = 0.5f/size.x; - if(size.y != 0.0f) size.y = 0.5f/size.y; - if(size.z != 0.0f) size.z = 0.5f/size.z; + if (size.x != 0.0f) + size.x = 0.5f / size.x; + if (size.y != 0.0f) + size.y = 0.5f / size.y; + if (size.z != 0.0f) + size.z = 0.5f / size.z; - loc = loc*size - make_float3(0.5f, 0.5f, 0.5f); + loc = loc * size - make_float3(0.5f, 0.5f, 0.5f); } /* Object motion steps, returns 0 if no motion blur needed. */ -static inline uint object_motion_steps(BL::Object& b_parent, BL::Object& b_ob) +static inline uint object_motion_steps(BL::Object &b_parent, BL::Object &b_ob) { - /* Get motion enabled and steps from object itself. */ - PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); - bool use_motion = get_boolean(cobject, "use_motion_blur"); - if(!use_motion) { - return 0; - } + /* Get motion enabled and steps from object itself. */ + PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + bool use_motion = get_boolean(cobject, "use_motion_blur"); + if (!use_motion) { + return 0; + } - uint steps = max(1, get_int(cobject, "motion_steps")); + uint steps = max(1, get_int(cobject, "motion_steps")); - /* Also check parent object, so motion blur and steps can be - * controlled by dupligroup duplicator for linked groups. */ - if(b_parent.ptr.data != b_ob.ptr.data) { - PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles"); - use_motion &= get_boolean(parent_cobject, "use_motion_blur"); + /* Also check parent object, so motion blur and steps can be + * controlled by dupligroup duplicator for linked groups. */ + if (b_parent.ptr.data != b_ob.ptr.data) { + PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles"); + use_motion &= get_boolean(parent_cobject, "use_motion_blur"); - if(!use_motion) { - return 0; - } + if (!use_motion) { + return 0; + } - steps = max(steps, get_int(parent_cobject, "motion_steps")); - } + steps = max(steps, get_int(parent_cobject, "motion_steps")); + } - /* Use uneven number of steps so we get one keyframe at the current frame, - * and use 2^(steps - 1) so objects with more/fewer steps still have samples - * at the same times, to avoid sampling at many different times. */ - return (2 << (steps - 1)) + 1; + /* Use uneven number of steps so we get one keyframe at the current frame, + * and use 2^(steps - 1) so objects with more/fewer steps still have samples + * at the same times, to avoid sampling at many different times. */ + return (2 << (steps - 1)) + 1; } /* object uses deformation motion blur */ -static inline bool object_use_deform_motion(BL::Object& b_parent, - BL::Object& b_ob) +static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ob) { - PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); - bool use_deform_motion = get_boolean(cobject, "use_deform_motion"); - /* If motion blur is enabled for the object we also check - * whether it's enabled for the parent object as well. - * - * This way we can control motion blur from the dupligroup - * duplicator much easier. - */ - if(use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) { - PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles"); - use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion"); - } - return use_deform_motion; + PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + bool use_deform_motion = get_boolean(cobject, "use_deform_motion"); + /* If motion blur is enabled for the object we also check + * whether it's enabled for the parent object as well. + * + * This way we can control motion blur from the dupligroup + * duplicator much easier. + */ + if (use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) { + PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles"); + use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion"); + } + return use_deform_motion; } -static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object& b_ob) +static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object &b_ob) { - BL::Object::modifiers_iterator b_mod; + BL::Object::modifiers_iterator b_mod; - for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) { - if(b_mod->is_a(&RNA_SmokeModifier)) { - BL::SmokeModifier b_smd(*b_mod); + for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) { + if (b_mod->is_a(&RNA_SmokeModifier)) { + BL::SmokeModifier b_smd(*b_mod); - if(b_smd.smoke_type() == BL::SmokeModifier::smoke_type_DOMAIN) - return b_smd.domain_settings(); - } - } + if (b_smd.smoke_type() == BL::SmokeModifier::smoke_type_DOMAIN) + return b_smd.domain_settings(); + } + } - return BL::SmokeDomainSettings(PointerRNA_NULL); + return BL::SmokeDomainSettings(PointerRNA_NULL); } static inline BL::DomainFluidSettings object_fluid_domain_find(BL::Object b_ob) { - BL::Object::modifiers_iterator b_mod; + BL::Object::modifiers_iterator b_mod; - for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) { - if(b_mod->is_a(&RNA_FluidSimulationModifier)) { - BL::FluidSimulationModifier b_fmd(*b_mod); - BL::FluidSettings fss = b_fmd.settings(); + for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) { + if (b_mod->is_a(&RNA_FluidSimulationModifier)) { + BL::FluidSimulationModifier b_fmd(*b_mod); + BL::FluidSettings fss = b_fmd.settings(); - if(fss.type() == BL::FluidSettings::type_DOMAIN) - return (BL::DomainFluidSettings)b_fmd.settings(); - } - } + if (fss.type() == BL::FluidSettings::type_DOMAIN) + return (BL::DomainFluidSettings)b_fmd.settings(); + } + } - return BL::DomainFluidSettings(PointerRNA_NULL); + return BL::DomainFluidSettings(PointerRNA_NULL); } -static inline Mesh::SubdivisionType object_subdivision_type(BL::Object& b_ob, bool preview, bool experimental) +static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob, + bool preview, + bool experimental) { - PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles"); + PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles"); - if(cobj.data && b_ob.modifiers.length() > 0 && experimental) { - BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length()-1]; - bool enabled = preview ? mod.show_viewport() : mod.show_render(); + if (cobj.data && b_ob.modifiers.length() > 0 && experimental) { + BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1]; + bool enabled = preview ? mod.show_viewport() : mod.show_render(); - if(enabled && mod.type() == BL::Modifier::type_SUBSURF && RNA_boolean_get(&cobj, "use_adaptive_subdivision")) { - BL::SubsurfModifier subsurf(mod); + if (enabled && mod.type() == BL::Modifier::type_SUBSURF && + RNA_boolean_get(&cobj, "use_adaptive_subdivision")) { + BL::SubsurfModifier subsurf(mod); - if(subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) { - return Mesh::SUBDIVISION_CATMULL_CLARK; - } - else { - return Mesh::SUBDIVISION_LINEAR; - } - } - } + if (subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) { + return Mesh::SUBDIVISION_CATMULL_CLARK; + } + else { + return Mesh::SUBDIVISION_LINEAR; + } + } + } - return Mesh::SUBDIVISION_NONE; + return Mesh::SUBDIVISION_NONE; } /* ID Map @@ -600,144 +581,143 @@ static inline Mesh::SubdivisionType object_subdivision_type(BL::Object& b_ob, bo * Utility class to keep in sync with blender data. * Used for objects, meshes, lights and shaders. */ -template<typename K, typename T> -class id_map { -public: - id_map(vector<T*> *scene_data_) - { - scene_data = scene_data_; - } - - T *find(const BL::ID& id) - { - return find(id.ptr.id.data); - } - - T *find(const K& key) - { - if(b_map.find(key) != b_map.end()) { - T *data = b_map[key]; - return data; - } - - return NULL; - } - - void set_recalc(const BL::ID& id) - { - b_recalc.insert(id.ptr.data); - } - - void set_recalc(void *id_ptr) - { - b_recalc.insert(id_ptr); - } - - bool has_recalc() - { - return !(b_recalc.empty()); - } - - void pre_sync() - { - used_set.clear(); - } - - bool sync(T **r_data, const BL::ID& id) - { - return sync(r_data, id, id, id.ptr.id.data); - } - - bool sync(T **r_data, const BL::ID& id, const BL::ID& parent, const K& key) - { - T *data = find(key); - bool recalc; - - if(!data) { - /* add data if it didn't exist yet */ - data = new T(); - scene_data->push_back(data); - b_map[key] = data; - recalc = true; - } - else { - recalc = (b_recalc.find(id.ptr.data) != b_recalc.end()); - if(parent.ptr.data) - recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end()); - } - - used(data); - - *r_data = data; - return recalc; - } - - bool is_used(const K& key) - { - T *data = find(key); - return (data) ? used_set.find(data) != used_set.end() : false; - } - - void used(T *data) - { - /* tag data as still in use */ - used_set.insert(data); - } - - void set_default(T *data) - { - b_map[NULL] = data; - } - - bool post_sync(bool do_delete = true) - { - /* remove unused data */ - vector<T*> new_scene_data; - typename vector<T*>::iterator it; - bool deleted = false; - - for(it = scene_data->begin(); it != scene_data->end(); it++) { - T *data = *it; - - if(do_delete && used_set.find(data) == used_set.end()) { - delete data; - deleted = true; - } - else - new_scene_data.push_back(data); - } - - *scene_data = new_scene_data; - - /* update mapping */ - map<K, T*> new_map; - typedef pair<const K, T*> TMapPair; - typename map<K, T*>::iterator jt; - - for(jt = b_map.begin(); jt != b_map.end(); jt++) { - TMapPair& pair = *jt; - - if(used_set.find(pair.second) != used_set.end()) - new_map[pair.first] = pair.second; - } - - used_set.clear(); - b_recalc.clear(); - b_map = new_map; - - return deleted; - } - - const map<K, T*>& key_to_scene_data() - { - return b_map; - } - -protected: - vector<T*> *scene_data; - map<K, T*> b_map; - set<T*> used_set; - set<void*> b_recalc; +template<typename K, typename T> class id_map { + public: + id_map(vector<T *> *scene_data_) + { + scene_data = scene_data_; + } + + T *find(const BL::ID &id) + { + return find(id.ptr.id.data); + } + + T *find(const K &key) + { + if (b_map.find(key) != b_map.end()) { + T *data = b_map[key]; + return data; + } + + return NULL; + } + + void set_recalc(const BL::ID &id) + { + b_recalc.insert(id.ptr.data); + } + + void set_recalc(void *id_ptr) + { + b_recalc.insert(id_ptr); + } + + bool has_recalc() + { + return !(b_recalc.empty()); + } + + void pre_sync() + { + used_set.clear(); + } + + bool sync(T **r_data, const BL::ID &id) + { + return sync(r_data, id, id, id.ptr.id.data); + } + + bool sync(T **r_data, const BL::ID &id, const BL::ID &parent, const K &key) + { + T *data = find(key); + bool recalc; + + if (!data) { + /* add data if it didn't exist yet */ + data = new T(); + scene_data->push_back(data); + b_map[key] = data; + recalc = true; + } + else { + recalc = (b_recalc.find(id.ptr.data) != b_recalc.end()); + if (parent.ptr.data) + recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end()); + } + + used(data); + + *r_data = data; + return recalc; + } + + bool is_used(const K &key) + { + T *data = find(key); + return (data) ? used_set.find(data) != used_set.end() : false; + } + + void used(T *data) + { + /* tag data as still in use */ + used_set.insert(data); + } + + void set_default(T *data) + { + b_map[NULL] = data; + } + + bool post_sync(bool do_delete = true) + { + /* remove unused data */ + vector<T *> new_scene_data; + typename vector<T *>::iterator it; + bool deleted = false; + + for (it = scene_data->begin(); it != scene_data->end(); it++) { + T *data = *it; + + if (do_delete && used_set.find(data) == used_set.end()) { + delete data; + deleted = true; + } + else + new_scene_data.push_back(data); + } + + *scene_data = new_scene_data; + + /* update mapping */ + map<K, T *> new_map; + typedef pair<const K, T *> TMapPair; + typename map<K, T *>::iterator jt; + + for (jt = b_map.begin(); jt != b_map.end(); jt++) { + TMapPair &pair = *jt; + + if (used_set.find(pair.second) != used_set.end()) + new_map[pair.first] = pair.second; + } + + used_set.clear(); + b_recalc.clear(); + b_map = new_map; + + return deleted; + } + + const map<K, T *> &key_to_scene_data() + { + return b_map; + } + + protected: + vector<T *> *scene_data; + map<K, T *> b_map; + set<T *> used_set; + set<void *> b_recalc; }; /* Object Key */ @@ -745,91 +725,95 @@ protected: enum { OBJECT_PERSISTENT_ID_SIZE = 16 }; struct ObjectKey { - void *parent; - int id[OBJECT_PERSISTENT_ID_SIZE]; - void *ob; - - ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_) - : parent(parent_), ob(ob_) - { - if(id_) - memcpy(id, id_, sizeof(id)); - else - memset(id, 0, sizeof(id)); - } - - bool operator<(const ObjectKey& k) const - { - if(ob < k.ob) { - return true; - } - else if(ob == k.ob) { - if(parent < k.parent) - return true; - else if(parent == k.parent) - return memcmp(id, k.id, sizeof(id)) < 0; - } - - return false; - } + void *parent; + int id[OBJECT_PERSISTENT_ID_SIZE]; + void *ob; + + ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_) + : parent(parent_), ob(ob_) + { + if (id_) + memcpy(id, id_, sizeof(id)); + else + memset(id, 0, sizeof(id)); + } + + bool operator<(const ObjectKey &k) const + { + if (ob < k.ob) { + return true; + } + else if (ob == k.ob) { + if (parent < k.parent) + return true; + else if (parent == k.parent) + return memcmp(id, k.id, sizeof(id)) < 0; + } + + return false; + } }; /* Particle System Key */ struct ParticleSystemKey { - void *ob; - int id[OBJECT_PERSISTENT_ID_SIZE]; - - ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE]) - : ob(ob_) - { - if(id_) - memcpy(id, id_, sizeof(id)); - else - memset(id, 0, sizeof(id)); - } - - bool operator<(const ParticleSystemKey& k) const - { - /* first id is particle index, we don't compare that */ - if(ob < k.ob) - return true; - else if(ob == k.ob) - return memcmp(id+1, k.id+1, sizeof(int)*(OBJECT_PERSISTENT_ID_SIZE-1)) < 0; - - return false; - } + void *ob; + int id[OBJECT_PERSISTENT_ID_SIZE]; + + ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE]) : ob(ob_) + { + if (id_) + memcpy(id, id_, sizeof(id)); + else + memset(id, 0, sizeof(id)); + } + + bool operator<(const ParticleSystemKey &k) const + { + /* first id is particle index, we don't compare that */ + if (ob < k.ob) + return true; + else if (ob == k.ob) + return memcmp(id + 1, k.id + 1, sizeof(int) * (OBJECT_PERSISTENT_ID_SIZE - 1)) < 0; + + return false; + } }; class EdgeMap { -public: - EdgeMap() { - } - - void clear() { - edges_.clear(); - } - - void insert(int v0, int v1) { - get_sorted_verts(v0, v1); - edges_.insert(std::pair<int, int>(v0, v1)); - } - - bool exists(int v0, int v1) { - get_sorted_verts(v0, v1); - return edges_.find(std::pair<int, int>(v0, v1)) != edges_.end(); - } - -protected: - void get_sorted_verts(int& v0, int& v1) { - if(v0 > v1) { - swap(v0, v1); - } - } - - set< std::pair<int, int> > edges_; + public: + EdgeMap() + { + } + + void clear() + { + edges_.clear(); + } + + void insert(int v0, int v1) + { + get_sorted_verts(v0, v1); + edges_.insert(std::pair<int, int>(v0, v1)); + } + + bool exists(int v0, int v1) + { + get_sorted_verts(v0, v1); + return edges_.find(std::pair<int, int>(v0, v1)) != edges_.end(); + } + + protected: + void get_sorted_verts(int &v0, int &v1) + { + if (v0 > v1) { + swap(v0, v1); + } + } + + set<std::pair<int, int>> edges_; }; CCL_NAMESPACE_END -#endif /* __BLENDER_UTIL_H__ */ +#endif /* __BLENDER_UTIL_H__ */ |