Multi-View and Stereo 3D

Official Documentation:
http://www.blender.org/manual/render/workflows/multiview.html

Implemented Features
====================
Builtin Stereo Camera
* Convergence Mode
* Interocular Distance
* Convergence Distance
* Pivot Mode

Viewport
* Cameras
* Plane
* Volume

Compositor
* View Switch Node
* Image Node Multi-View OpenEXR support

Sequencer
* Image/Movie Strips 'Use Multiview'

UV/Image Editor
* Option to see Multi-View images in Stereo-3D or its individual images
* Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images

I/O
* Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images

Scene Render Views
* Ability to have an arbitrary number of views in the scene

Missing Bits
============
First rule of Multi-View bug report: If something is not working as it should *when Views is off* this is a severe bug, do mention this in the report.

Second rule is, if something works *when Views is off* but doesn't (or crashes) when *Views is on*, this is a important bug. Do mention this in the report.

Everything else is likely small todos, and may wait until we are sure none of the above is happening.

Apart from that there are those known issues:
* Compositor Image Node poorly working for Multi-View OpenEXR
(this was working prefectly before the 'Use Multi-View' functionality)
* Selecting camera from Multi-View when looking from camera is problematic
* Animation Playback (ctrl+F11) doesn't support stereo formats
* Wrong filepath when trying to play back animated scene
* Viewport Rendering doesn't support Multi-View
* Overscan Rendering
* Fullscreen display modes need to warn the user
* Object copy should be aware of views suffix

Acknowledgments
===============
* Francesco Siddi for the help with the original feature specs and design
* Brecht Van Lommel for the original review of the code and design early on
* Blender Foundation for the Development Fund to support the project wrap up

Final patch reviewers:
* Antony Riakiotakis (psy-fi)
* Campbell Barton (ideasman42)
* Julian Eisel (Severin)
* Sergey Sharybin (nazgul)
* Thomas Dinged (dingto)

Code contributors of the original branch in github:
* Alexey Akishin
* Gabriel Caraballo
This commit is contained in:
Dalai Felinto 2015-04-06 10:40:12 -03:00
parent 74df307ca4
commit d5f1b9c222
175 changed files with 11954 additions and 2202 deletions

@ -18,7 +18,7 @@
import bpy
from bpy.types import Panel, Menu, Operator
from bpy.types import Panel, Menu, Operator, UIList
class CYCLES_MT_sampling_presets(Menu):
@ -413,6 +413,49 @@ class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel):
col.prop(rl, "use_pass_environment")
class CyclesRender_PT_views(CyclesButtonsPanel, Panel):
bl_label = "Views"
bl_context = "render_layer"
def draw_header(self, context):
rd = context.scene.render
self.layout.prop(rd, "use_multiview", text="")
def draw(self, context):
layout = self.layout
scene = context.scene
rd = scene.render
rv = rd.views.active
layout.active = rd.use_multiview
basic_stereo = (rd.views_format == 'STEREO_3D')
row = layout.row()
row.prop(rd, "views_format", expand=True)
if basic_stereo:
row = layout.row()
row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2)
row = layout.row()
row.label(text="File Suffix:")
row.prop(rv, "file_suffix", text="")
else:
row = layout.row()
row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2)
col = row.column(align=True)
col.operator("scene.render_view_add", icon='ZOOMIN', text="")
col.operator("scene.render_view_remove", icon='ZOOMOUT', text="")
row = layout.row()
row.label(text="Camera Suffix:")
row.prop(rv, "camera_suffix", text="")
class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):
bl_label = "Post Processing"
bl_options = {'DEFAULT_CLOSED'}
@ -1428,6 +1471,7 @@ def get_panels():
"DATA_PT_vertex_colors",
"DATA_PT_camera",
"DATA_PT_camera_display",
"DATA_PT_camera_stereoscopy",
"DATA_PT_camera_safe_areas",
"DATA_PT_lens",
"DATA_PT_speaker",

@ -95,7 +95,7 @@ static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings b_render
bcam->full_height = render_resolution_y(b_render);
}
static float blender_camera_focal_distance(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)
{
BL::Object b_dof_object = b_camera.dof_object();
@ -103,14 +103,16 @@ static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera)
return b_camera.dof_distance();
/* for dof object, return distance along camera Z direction */
Transform obmat = transform_clear_scale(get_transform(b_ob.matrix_world()));
BL::Array<float, 16> b_ob_matrix;
b_engine.camera_model_matrix(b_ob, b_ob_matrix);
Transform obmat = get_transform(b_ob_matrix);
Transform dofmat = get_transform(b_dof_object.matrix_world());
Transform mat = transform_inverse(obmat) * dofmat;
return fabsf(transform_get_column(&mat, 3).z);
}
static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob, bool skip_panorama = false)
static void blender_camera_from_object(BlenderCamera *bcam, BL::RenderEngine b_engine, BL::Object b_ob, bool skip_panorama = false)
{
BL::ID b_ob_data = b_ob.data();
@ -181,10 +183,10 @@ static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob, boo
bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
bcam->focaldistance = blender_camera_focal_distance(b_ob, b_camera);
bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera);
bcam->aperture_ratio = RNA_float_get(&ccamera, "aperture_ratio");
bcam->shift.x = b_camera.shift_x();
bcam->shift.x = b_engine.camera_shift_x(b_ob);
bcam->shift.y = b_camera.shift_y();
bcam->sensor_width = b_camera.sensor_width();
@ -402,8 +404,10 @@ void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override
b_ob = b_override;
if(b_ob) {
blender_camera_from_object(&bcam, b_ob);
bcam.matrix = get_transform(b_ob.matrix_world());
BL::Array<float, 16> b_ob_matrix;
blender_camera_from_object(&bcam, b_engine, b_ob);
b_engine.camera_model_matrix(b_ob, b_ob_matrix);
bcam.matrix = get_transform(b_ob_matrix);
}
/* sync */
@ -414,8 +418,9 @@ void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override
void BlenderSync::sync_camera_motion(BL::Object b_ob, float motion_time)
{
Camera *cam = scene->camera;
Transform tfm = get_transform(b_ob.matrix_world());
BL::Array<float, 16> b_ob_matrix;
b_engine.camera_model_matrix(b_ob, b_ob_matrix);
Transform tfm = get_transform(b_ob_matrix);
tfm = blender_camera_matrix(tfm, cam->type);
if(tfm != cam->matrix) {
@ -433,10 +438,10 @@ void BlenderSync::sync_camera_motion(BL::Object b_ob, float motion_time)
/* Sync 3D View Camera */
static void blender_camera_view_subset(BL::RenderSettings b_render, BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d,
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::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height, bool skip_panorama = false)
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, bool skip_panorama = false)
{
/* 3d view parameters */
bcam->nearclip = b_v3d.clip_start();
@ -449,13 +454,13 @@ static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL:
BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera();
if(b_ob) {
blender_camera_from_object(bcam, b_ob, skip_panorama);
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;
blender_camera_view_subset(b_scene.render(), b_scene, b_ob, b_v3d, b_rv3d, width, height,
blender_camera_view_subset(b_engine, b_scene.render(), b_scene, b_ob, b_v3d, b_rv3d, width, height,
&view_box, &cam_box);
bcam->pano_viewplane = view_box.make_relative_to(cam_box);
@ -493,7 +498,7 @@ static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL:
bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
}
static void blender_camera_view_subset(BL::RenderSettings b_render, BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d,
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;
@ -502,7 +507,7 @@ static void blender_camera_view_subset(BL::RenderSettings b_render, BL::Scene b_
/* get viewport viewplane */
BlenderCamera view_bcam;
blender_camera_init(&view_bcam, b_render);
blender_camera_from_view(&view_bcam, b_scene, b_v3d, b_rv3d, width, height, true);
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);
@ -510,7 +515,7 @@ static void blender_camera_view_subset(BL::RenderSettings b_render, BL::Scene b_
/* get camera viewplane */
BlenderCamera cam_bcam;
blender_camera_init(&cam_bcam, b_render);
blender_camera_from_object(&cam_bcam, b_ob, true);
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);
@ -520,7 +525,8 @@ static void blender_camera_view_subset(BL::RenderSettings b_render, BL::Scene b_
*cam_box = cam * (1.0f/cam_aspect);
}
static void blender_camera_border_subset(BL::RenderSettings b_render,
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,
@ -531,7 +537,7 @@ static void blender_camera_border_subset(BL::RenderSettings b_render,
{
/* Determine camera viewport subset. */
BoundBox2D view_box, cam_box;
blender_camera_view_subset(b_render, b_scene, b_ob, b_v3d, b_rv3d, width, height,
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. */
@ -539,7 +545,7 @@ static void blender_camera_border_subset(BL::RenderSettings b_render,
*result = cam_box.subset(border);
}
static void blender_camera_border(BlenderCamera *bcam, BL::RenderSettings b_render, BL::Scene b_scene, BL::SpaceView3D b_v3d,
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)
{
bool is_camera_view;
@ -568,7 +574,8 @@ static void blender_camera_border(BlenderCamera *bcam, BL::RenderSettings b_rend
/* Determine camera border inside the viewport. */
BoundBox2D full_border;
blender_camera_border_subset(b_render,
blender_camera_border_subset(b_engine,
b_render,
b_scene,
b_v3d,
b_rv3d,
@ -587,7 +594,8 @@ static void blender_camera_border(BlenderCamera *bcam, BL::RenderSettings b_rend
bcam->border.top = b_render.border_max_y();
/* Determine viewport subset matching camera border. */
blender_camera_border_subset(b_render,
blender_camera_border_subset(b_engine,
b_render,
b_scene,
b_v3d,
b_rv3d,
@ -602,8 +610,8 @@ void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int
{
BlenderCamera bcam;
blender_camera_init(&bcam, b_scene.render());
blender_camera_from_view(&bcam, b_scene, b_v3d, b_rv3d, width, height);
blender_camera_border(&bcam, b_scene.render(), b_scene, b_v3d, b_rv3d, width, height);
blender_camera_from_view(&bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height);
blender_camera_border(&bcam, b_engine, b_scene.render(), b_scene, b_v3d, b_rv3d, width, height);
blender_camera_sync(scene->camera, &bcam, width, height);
}

@ -331,9 +331,9 @@ static ShaderEvalType get_shader_type(const string& pass_type)
return SHADER_EVAL_BAKE;
}
static BL::RenderResult begin_render_result(BL::RenderEngine b_engine, int x, int y, int w, int h, const char *layername)
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);
return b_engine.begin_result(x, y, w, h, layername, viewname);
}
static void end_render_result(BL::RenderEngine b_engine, BL::RenderResult b_rr, bool cancel, bool do_merge_results)
@ -350,7 +350,7 @@ void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_upda
int h = params.height;
/* get render result */
BL::RenderResult b_rr = begin_render_result(b_engine, x, y, w, h, b_rlay_name.c_str());
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) {
@ -415,13 +415,14 @@ void BlenderSession::render()
/* render each layer */
BL::RenderSettings r = b_scene.render();
BL::RenderSettings::layers_iterator b_iter;
BL::RenderSettings::layers_iterator b_layer_iter;
BL::RenderResult::views_iterator b_view_iter;
for(r.layers.begin(b_iter); b_iter != r.layers.end(); ++b_iter) {
b_rlay_name = b_iter->name();
for(r.layers.begin(b_layer_iter); b_layer_iter != r.layers.end(); ++b_layer_iter) {
b_rlay_name = b_layer_iter->name();
/* temporary render result to find needed passes */
BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_rlay_name.c_str());
/* temporary render result to find needed passes and views */
BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_rlay_name.c_str(), NULL);
BL::RenderResult::layers_iterator b_single_rlay;
b_rr.layers.begin(b_single_rlay);
@ -456,31 +457,41 @@ void BlenderSession::render()
}
}
/* free result without merging */
end_render_result(b_engine, b_rr, true, false);
buffer_params.passes = passes;
scene->film->pass_alpha_threshold = b_iter->pass_alpha_threshold();
scene->film->pass_alpha_threshold = b_layer_iter->pass_alpha_threshold();
scene->film->tag_passes_update(scene, passes);
scene->film->tag_update(scene);
scene->integrator->tag_update(scene);
/* update scene */
sync->sync_camera(b_render, b_engine.camera_override(), width, height);
sync->sync_data(b_v3d, b_engine.camera_override(), &python_thread_state, b_rlay_name.c_str());
for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) {
b_rview_name = b_view_iter->name();
/* update number of samples per layer */
int samples = sync->get_layer_samples();
bool bound_samples = sync->get_layer_bound_samples();
/* set the current view */
b_engine.active_view_set(b_rview_name.c_str());
if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
session->reset(buffer_params, samples);
else
session->reset(buffer_params, session_params.samples);
/* update scene */
sync->sync_camera(b_render, b_engine.camera_override(), width, height);
sync->sync_data(b_v3d, b_engine.camera_override(), &python_thread_state, b_rlay_name.c_str());
/* render */
session->start();
session->wait();
/* update number of samples per layer */
int samples = sync->get_layer_samples();
bool bound_samples = sync->get_layer_bound_samples();
if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
session->reset(buffer_params, samples);
else
session->reset(buffer_params, session_params.samples);
/* render */
session->start();
session->wait();
if(session->progress.get_cancel())
break;
}
/* free result without merging */
end_render_result(b_engine, b_rr, true, false);
if(session->progress.get_cancel())
break;
@ -619,10 +630,12 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::Re
b_pass.rect(&pixels[0]);
}
}
/* copy combined pass */
if(buffers->get_pass_rect(PASS_COMBINED, exposure, rtile.sample, 4, &pixels[0]))
b_rlay.rect(&pixels[0]);
else {
/* copy combined pass */
BL::RenderPass b_combined_pass(b_rlay.passes.find_by_type(BL::RenderPass::type_COMBINED, b_rview_name.c_str()));
if(buffers->get_pass_rect(PASS_COMBINED, exposure, rtile.sample, 4, &pixels[0]))
b_combined_pass.rect(&pixels[0]);
}
/* tag result as updated */
b_engine.update_result(b_rr);
@ -841,6 +854,9 @@ void BlenderSession::update_status_progress()
scene += " | " + b_scene.name();
if(b_rlay_name != "")
scene += ", " + b_rlay_name;
if(b_rview_name != "")
scene += ", " + b_rview_name;
}
else {
BLI_timestr(total_time, time_str, sizeof(time_str));

@ -90,6 +90,7 @@ public:
BL::SpaceView3D b_v3d;
BL::RegionView3D b_rv3d;
string b_rlay_name;
string b_rview_name;
string last_status;
string last_error;

@ -135,6 +135,35 @@ class DATA_PT_lens(CameraButtonsPanel, Panel):
col.prop(cam, "clip_end", text="End")
class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
bl_label = "Stereoscopy"
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
render = context.scene.render
return (super().poll(context) and render.use_multiview \
and render.views_format == 'STEREO_3D')
def draw(self, context):
layout = self.layout
render = context.scene.render
st = context.camera.stereo
col = layout.column()
col.row().prop(st, "convergence_mode", expand=True)
if st.convergence_mode == 'PARALLEL':
col.prop(st, "viewport_convergence")
else:
col.prop(st, "convergence_distance")
col.prop(st, "interocular_distance")
col.label(text="Pivot:")
col.row().prop(st, "pivot", expand=True)
class DATA_PT_camera(CameraButtonsPanel, Panel):
bl_label = "Camera"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}

@ -404,6 +404,8 @@ class RENDER_PT_output(RenderButtonsPanel, Panel):
col.prop(rd, "use_render_cache")
layout.template_image_settings(image_settings, color_management=False)
if rd.use_multiview:
layout.template_image_views(image_settings)
if file_format == 'QUICKTIME':
quicktime = rd.quicktime

@ -167,5 +167,63 @@ class RENDERLAYER_PT_layer_passes(RenderLayerButtonsPanel, Panel):
self.draw_pass_type_buttons(col, rl, "refraction")
class RENDERLAYER_UL_renderviews(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
# assert(isinstance(item, bpy.types.SceneRenderView)
view = item
if self.layout_type in {'DEFAULT', 'COMPACT'}:
if view.name in {'left', 'right'}:
layout.label(view.name, icon_value=icon + (not view.use))
else:
layout.prop(view, "name", text="", index=index, icon_value=icon, emboss=False)
layout.prop(view, "use", text="", index=index)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label("", icon_value=icon + (not view.use))
class RENDERLAYER_PT_views(RenderLayerButtonsPanel, Panel):
bl_label = "Views"
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw_header(self, context):
rd = context.scene.render
self.layout.prop(rd, "use_multiview", text="")
def draw(self, context):
layout = self.layout
scene = context.scene
rd = scene.render
rv = rd.views.active
layout.active = rd.use_multiview
basic_stereo = rd.views_format == 'STEREO_3D'
row = layout.row()
row.prop(rd, "views_format", expand=True)
if basic_stereo:
row = layout.row()
row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "stereo_views", rd.views, "active_index", rows=2)
row = layout.row()
row.label(text="File Suffix:")
row.prop(rv, "file_suffix", text="")
else:
row = layout.row()
row.template_list("RENDERLAYER_UL_renderviews", "name", rd, "views", rd.views, "active_index", rows=2)
col = row.column(align=True)
col.operator("scene.render_view_add", icon='ZOOMIN', text="")
col.operator("scene.render_view_remove", icon='ZOOMOUT', text="")
row = layout.row()
row.label(text="Camera Suffix:")
row.prop(rv, "camera_suffix", text="")
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

@ -458,6 +458,10 @@ class IMAGE_HT_header(Header):
layout.prop_search(mesh.uv_textures, "active", mesh, "uv_textures", text="")
if ima:
if ima.is_stereo_3d:
row = layout.row()
row.prop(sima, "show_stereo_3d", text="")
# layers
layout.template_image_layers(ima, iuser)

@ -282,6 +282,10 @@ class INFO_MT_window(Menu):
layout.separator()
layout.operator("wm.console_toggle", icon='CONSOLE')
if context.scene.render.use_multiview:
layout.separator()
layout.operator("wm.set_stereo_3d", icon='CAMERA_STEREO')
class INFO_MT_help(Menu):
bl_label = "Help"

@ -659,6 +659,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
scene = context.scene
strip = act_strip(context)
@ -672,7 +673,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
# Current element for the filename
elem = strip.strip_elem_from_frame(context.scene.frame_current)
elem = strip.strip_elem_from_frame(scene.frame_current)
if elem:
split = layout.split(percentage=0.2)
split.label(text="File:")
@ -718,6 +719,19 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
col.prop(strip, "frame_offset_start", text="Start")
col.prop(strip, "frame_offset_end", text="End")
if scene.render.use_multiview and seq_type in {'IMAGE', 'MOVIE'}:
layout.prop(strip, "use_multiview")
col = layout.column()
col.active = strip.use_multiview
col.label(text="Views Format:")
col.row().prop(strip, "views_format", expand=True)
box = col.box()
box.active = strip.views_format == 'STEREO_3D'
box.template_image_stereo_3d(strip.stereo_3d_format)
class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
bl_label = "Sound"

@ -2936,16 +2936,50 @@ class VIEW3D_PT_view3d_display(Panel):
row.prop(region, "use_box_clip")
class VIEW3D_PT_view3d_shading(Panel):
class VIEW3D_PT_view3d_stereo(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Shading"
bl_label = "Stereoscopy"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
scene = context.scene
multiview = scene.render.use_multiview
return context.space_data and multiview
def draw(self, context):
layout = self.layout
view = context.space_data
return (view)
basic_stereo = context.scene.render.views_format == 'STEREO_3D'
col = layout.column()
col.row().prop(view, "stereo_3d_camera", expand=True)
col.label(text="Display:")
row = col.row()
row.active = basic_stereo
row.prop(view, "show_stereo_3d_cameras")
row = col.row()
row.active = basic_stereo
split = row.split()
split.prop(view, "show_stereo_3d_convergence_plane")
split = row.split()
split.prop(view, "stereo_3d_convergence_plane_alpha", text="Alpha")
split.active = view.show_stereo_3d_convergence_plane
row = col.row()
split = row.split()
split.prop(view, "show_stereo_3d_volume")
split = row.split()
split.prop(view, "stereo_3d_volume_alpha", text="Alpha")
class VIEW3D_PT_view3d_shading(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Shading"
def draw(self, context):
layout = self.layout

@ -328,6 +328,7 @@ compositor_node_categories = [
NodeItem("CompositorNodeCombYUVA"),
NodeItem("CompositorNodeSepYCCA"),
NodeItem("CompositorNodeCombYCCA"),
NodeItem("CompositorNodeSwitchView"),
]),
CompositorNodeCategory("CMP_OP_FILTER", "Filter", items=[
NodeItem("CompositorNodeBlur"),

@ -42,7 +42,7 @@ extern "C" {
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 274
#define BLENDER_SUBVERSION 3
#define BLENDER_SUBVERSION 4
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 5

@ -136,6 +136,14 @@ bool BKE_camera_view_frame_fit_to_coords(
void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings);
/* Camera multi-view API */
struct Object *BKE_camera_multiview_render(struct Scene *scene, struct Object *camera, const char *viewname);
void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Object *camera, const bool is_left, float r_viewmat[4][4]);
void BKE_camera_multiview_model_matrix(struct RenderData *rd, struct Object *camera, const char *viewname, float r_modelmat[4][4]);
float BKE_camera_multiview_shift_x(struct RenderData *rd, struct Object *camera, const char *viewname);
void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, struct Object *camera, const char *viewname);
#ifdef __cplusplus
}
#endif

@ -45,34 +45,34 @@ struct Object;
struct ImageFormatData;
struct ImagePool;
struct Main;
struct ReportList;
#define IMA_MAX_SPACE 64
void BKE_images_init(void);
void BKE_images_exit(void);
void BKE_image_free_packedfiles(struct Image *image);
void BKE_image_free_views(struct Image *image);
void BKE_image_free_buffers(struct Image *image);
/* call from library */
void BKE_image_free(struct Image *image);
void BKE_imbuf_stamp_info(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf);
void BKE_image_stamp_buf(
struct Scene *scene, struct Object *camera,
unsigned char *rect, float *rectf, int width, int height, int channels);
void BKE_image_stamp_buf(struct Scene *scene, struct Object *camera, unsigned char *rect, float *rectf, int width, int height, int channels);
bool BKE_imbuf_alpha_test(struct ImBuf *ibuf);
int BKE_imbuf_write_stamp(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
void BKE_imbuf_write_prepare(struct ImBuf *ibuf, struct ImageFormatData *imf);
int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
int BKE_imbuf_write_as(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf, const bool is_copy);
void BKE_image_path_from_imformat(
char *string, const char *base, const char *relbase, int frame,
const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames);
const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames, const char *suffix);
void BKE_image_path_from_imtype(
char *string, const char *base, const char *relbase, int frame,
const char imtype, const bool use_ext, const bool use_frames);
bool BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
bool BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype);
const char imtype, const bool use_ext, const bool use_frames, const char *suffix);
int BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype);
char BKE_image_ftype_to_imtype(const int ftype);
int BKE_image_imtype_to_ftype(const char imtype);
@ -103,6 +103,7 @@ void BKE_image_tag_time(struct Image *ima);
/* ImageUser is in Texture, in Nodes, Background Image, Image Window, .... */
/* should be used in conjunction with an ID * to Image. */
struct ImageUser;
struct RenderData;
struct RenderPass;
struct RenderResult;
@ -172,11 +173,12 @@ struct Image *BKE_image_load_exists(const char *filepath);
/* adds image, adds ibuf, generates color or pattern */
struct Image *BKE_image_add_generated(
struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4]);
struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d);
/* adds image from imbuf, owns imbuf */
struct Image *BKE_image_add_from_imbuf(struct ImBuf *ibuf);
/* for reload, refresh, pack */
void BKE_image_init_imageuser(struct Image *ima, struct ImageUser *iuser);
void BKE_image_signal(struct Image *ima, struct ImageUser *iuser, int signal);
void BKE_image_walk_all_users(const struct Main *mainp, void *customdata,
@ -184,6 +186,8 @@ void BKE_image_walk_all_users(const struct Main *mainp, void *customdata,
/* ensures an Image exists for viewing nodes or render */
struct Image *BKE_image_verify_viewer(int type, const char *name);
/* ensures the view node cache is compatible with the scene views */
void BKE_image_verify_viewer_views(const struct RenderData *rd, struct Image *ima, struct ImageUser *iuser);
/* called on frame change or before render */
void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr);
@ -195,13 +199,23 @@ void BKE_image_update_frame(const struct Main *bmain, int cfra);
/* sets index offset for multilayer files */
struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser);
/* sets index offset for multiview files */
void BKE_image_multiview_index(struct Image *ima, struct ImageUser *iuser);
/* for multilayer images as well as for render-viewer */
bool BKE_image_is_multilayer(struct Image *ima);
struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima);
void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
/* for multilayer images as well as for singlelayer */
bool BKE_image_is_openexr(struct Image *ima);
/* for multiple slot render, call this before render */
void BKE_image_backup_render(struct Scene *scene, struct Image *ima);
/* for singlelayer openexr saving */
bool BKE_image_save_openexr_multiview(struct Image *ima, struct ImBuf *ibuf, const char *filepath, const int flags);
/* goes over all textures that use images */
void BKE_image_free_all_textures(void);
@ -212,6 +226,7 @@ void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame);
void BKE_image_all_free_anim_ibufs(int except_frame);
void BKE_image_memorypack(struct Image *ima);
void BKE_image_packfiles(struct ReportList *reports, struct Image *ima, const char *basepath);
/* prints memory statistics for images */
void BKE_image_print_memlist(void);
@ -243,7 +258,8 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame);
/* Guess offset for the first frame in the sequence */
int BKE_image_sequence_guess_offset(struct Image *image);
bool BKE_image_has_anim(struct Image *image);
bool BKE_image_has_packedfile(struct Image *image);
bool BKE_image_is_animated(struct Image *image);
bool BKE_image_is_dirty(struct Image *image);
void BKE_image_file_format_set(struct Image *image, int ftype);

@ -941,6 +941,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
#define CMP_NODE_MAP_RANGE 319
#define CMP_NODE_PLANETRACKDEFORM 320
#define CMP_NODE_CORNERPIN 321
#define CMP_NODE_SWITCH_VIEW 322
/* channel toggles */
#define CMP_CHAN_RGB 1
@ -975,7 +976,8 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
/* API */
void ntreeCompositExecTree(struct Scene *scene, struct bNodeTree *ntree, struct RenderData *rd, int rendering, int do_previews,
const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings);
const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings,
const char *view_name);
void ntreeCompositTagRender(struct Scene *sce);
int ntreeCompositTagAnimated(struct bNodeTree *ntree);
void ntreeCompositTagGenerators(struct bNodeTree *ntree);

@ -70,6 +70,7 @@ void BKE_scene_free(struct Scene *sce);
struct Scene *BKE_scene_add(struct Main *bmain, const char *name);
/* base functions */
struct Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name);
struct Base *BKE_scene_base_find(struct Scene *scene, struct Object *ob);
struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob);
void BKE_scene_base_unlink(struct Scene *sce, struct Base *base);
@ -122,6 +123,9 @@ void BKE_scene_update_for_newframe_ex(struct EvaluationContext *eval_ctx, struct
struct SceneRenderLayer *BKE_scene_add_render_layer(struct Scene *sce, const char *name);
bool BKE_scene_remove_render_layer(struct Main *main, struct Scene *scene, struct SceneRenderLayer *srl);
struct SceneRenderView *BKE_scene_add_render_view(struct Scene *sce, const char *name);
bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *srv);
/* render profile */
int get_render_subsurf_level(const struct RenderData *r, int level);
int get_render_child_particle_number(const struct RenderData *r, int num);
@ -142,6 +146,23 @@ int BKE_render_num_threads(const struct RenderData *r);
double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value);
/* multiview */
bool BKE_scene_multiview_is_stereo3d(const struct RenderData *rd);
bool BKE_scene_multiview_is_render_view_active(const struct RenderData *rd, const struct SceneRenderView *srv);
bool BKE_scene_multiview_is_render_view_first(const struct RenderData *rd, const char *viewname);
bool BKE_scene_multiview_is_render_view_last(const struct RenderData *rd, const char *viewname);
size_t BKE_scene_multiview_num_views_get(const struct RenderData *rd);
struct SceneRenderView *BKE_scene_multiview_render_view_findindex(const struct RenderData *rd, const int view_id);
const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd, const int view_id);
size_t BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *viewname);
void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv, const char *filepath, char *r_filepath);
void BKE_scene_multiview_view_filepath_get(const struct RenderData *rd, const char *filepath, const char *view, char *r_filepath);
const char *BKE_scene_multiview_view_suffix_get(const struct RenderData *rd, const char *viewname);
const char *BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, const size_t view_id);
void BKE_scene_multiview_view_prefix_get(struct Scene *scene, const char *name, char *rprefix, char **rext);
void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd, const size_t width, const size_t height, size_t *r_width, size_t *r_height);
size_t BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
#ifdef __cplusplus
}
#endif

@ -41,6 +41,7 @@ struct Mask;
struct Scene;
struct Sequence;
struct SequenceModifierData;
struct Stereo3dFormat;
struct StripElem;
struct bSound;
@ -99,6 +100,7 @@ typedef struct SeqRenderData {
float motion_blur_shutter;
bool skip_cache;
bool is_proxy_render;
size_t view_id;
} SeqRenderData;
void BKE_sequencer_new_render_data(
@ -223,6 +225,7 @@ void BKE_sequencer_base_clipboard_pointers_store(struct ListBase *seqbase);
void BKE_sequencer_base_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);
void BKE_sequence_free(struct Scene *scene, struct Sequence *seq);
void BKE_sequence_free_anim(struct Sequence *seq);
const char *BKE_sequence_give_name(struct Sequence *seq);
void BKE_sequence_calc(struct Scene *scene, struct Sequence *seq);
void BKE_sequence_calc_disp(struct Scene *scene, struct Sequence *seq);
@ -235,7 +238,7 @@ struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra);
void BKE_sequencer_update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_seq, int len_change, int ibuf_change);
bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context, struct Sequence *seq, float cfra);
struct SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list);
void BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list, ListBase *queue);
void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context, short *stop, short *do_update, float *progress);
void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop);
@ -355,6 +358,10 @@ typedef struct SeqLoadInfo {
int len; /* only for image strips */
char path[1024]; /* 1024 = FILE_MAX */
/* multiview */
char views_format;
struct Stereo3dFormat *stereo3d_format;
/* return values */
char name[64];
struct Sequence *seq_sound; /* for movie's */
@ -399,7 +406,7 @@ struct Sequence *BKE_sequencer_add_sound_strip(struct bContext *C, ListBase *seq
struct Sequence *BKE_sequencer_add_movie_strip(struct bContext *C, ListBase *seqbasep, struct SeqLoadInfo *seq_load);
/* view3d draw callback, run when not in background view */
typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, char[256]);
typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, const char *, char[256]);
extern SequencerDrawView sequencer_view3d_cb;
/* copy/paste */

@ -43,16 +43,20 @@ struct ReportList;
struct Scene;
typedef struct bMovieHandle {
int (*start_movie)(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview);
int (*append_movie)(struct RenderData *rd, int start_frame, int frame, int *pixels,
int rectx, int recty, struct ReportList *reports);
void (*end_movie)(void);
int (*get_next_frame)(struct RenderData *rd, struct ReportList *reports); /* optional */
void (*get_movie_path)(char *string, struct RenderData *rd, bool preview); /* optional */
int (*start_movie)(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty,
struct ReportList *reports, bool preview, const char *suffix);
int (*append_movie)(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
int rectx, int recty, const char *suffix, struct ReportList *reports);
void (*end_movie)(void *context_v);
int (*get_next_frame)(void *context_v, struct RenderData *rd, struct ReportList *reports); /* optional */
void (*get_movie_path)(char *string, struct RenderData *rd, bool preview, const char *suffix); /* optional */
void *(*context_create)(void);
void (*context_free)(void *context_v);
} bMovieHandle;
bMovieHandle *BKE_movie_handle_get(const char imtype);
void BKE_movie_filepath_get(char *string, struct RenderData *rd, bool preview);
void BKE_movie_filepath_get(char *string, struct RenderData *rd, bool preview, const char *suffix);
void BKE_context_create(bMovieHandle *mh);
#ifdef __cplusplus
}

@ -68,11 +68,11 @@ struct RenderData;
struct ReportList;
struct Scene;
int BKE_ffmpeg_start(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview);
void BKE_ffmpeg_end(void);
int BKE_ffmpeg_append(struct RenderData *rd, int start_frame, int frame, int *pixels,
int rectx, int recty, struct ReportList *reports);
void BKE_ffmpeg_filepath_get(char *string, struct RenderData *rd, bool preview);
int BKE_ffmpeg_start(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview, const char *suffix);
void BKE_ffmpeg_end(void *context_v);
int BKE_ffmpeg_append(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
int rectx, int recty, const char *suffix, struct ReportList *reports);
void BKE_ffmpeg_filepath_get(char *string, struct RenderData *rd, bool preview, const char *suffix);
void BKE_ffmpeg_preset_set(struct RenderData *rd, int preset);
void BKE_ffmpeg_image_type_verify(struct RenderData *rd, struct ImageFormatData *imf);
@ -82,6 +82,9 @@ bool BKE_ffmpeg_alpha_channel_is_supported(struct RenderData *rd);
int BKE_ffmpeg_property_add_string(struct RenderData *rd, const char *type, const char *str);
void BKE_ffmpeg_property_del(struct RenderData *rd, void *type, void *prop_);
void *BKE_ffmpeg_context_create(void);
void BKE_ffmpeg_context_free(void *context_v);
#ifdef __cplusplus
}
#endif

@ -40,11 +40,14 @@ struct RenderData;
struct ReportList;
struct Scene;
int BKE_frameserver_start(struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview);
void BKE_frameserver_end(void);
int BKE_frameserver_append(struct RenderData *rd, int start_frame, int frame, int *pixels,
int rectx, int recty, struct ReportList *reports);
int BKE_frameserver_loop(struct RenderData *rd, struct ReportList *reports);
int BKE_frameserver_start(void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty,
struct ReportList *reports, bool preview, const char *suffix);
void BKE_frameserver_end(void *context_v);
int BKE_frameserver_append(void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
int rectx, int recty, const char*suffix, struct ReportList *reports);
int BKE_frameserver_loop(void *context_v, struct RenderData *rd, struct ReportList *reports);
void *BKE_frameserver_context_create(void);
void BKE_frameserver_context_free(void *context_v);
#ifdef __cplusplus
}

@ -423,10 +423,10 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
{
Image *ima;
ima = (Image *)id;
if (ima->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
if (BKE_image_has_packedfile(ima) == false || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) {
if (!ima->packedfile) {
if (!BKE_image_has_packedfile(ima)) {
BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
BKE_image_walk_all_users(bmain, ima, bpath_traverse_image_user_cb);
}

@ -30,16 +30,19 @@
*/
#include <stdlib.h>
#include <stddef.h>
#include "DNA_camera_types.h"
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
#include "DNA_ID.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_animsys.h"
#include "BKE_camera.h"
@ -47,6 +50,7 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "GPU_compositing.h"
@ -71,6 +75,10 @@ void *BKE_camera_add(Main *bmain, const char *name)
GPU_fx_compositor_init_dof_settings(&cam->gpu_dof);
/* stereoscopy 3d */
cam->stereo.interocular_distance = 0.065f;
cam->stereo.convergence_distance = 30.f * 0.065f;
return cam;
}
@ -695,6 +703,250 @@ bool BKE_camera_view_frame_fit_to_coords(
return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
}
/******************* multiview matrix functions ***********************/
static void camera_model_matrix(Object *camera, float r_modelmat[4][4])
{
copy_m4_m4(r_modelmat, camera->obmat);
}
static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4])
{
Camera *data = (Camera *)camera->data;
float interocular_distance, convergence_distance;
short convergence_mode, pivot;
float sizemat[4][4];
float fac = 1.0f;
float fac_signed;
interocular_distance = data->stereo.interocular_distance;
convergence_distance = data->stereo.convergence_distance;
convergence_mode = data->stereo.convergence_mode;
pivot = data->stereo.pivot;
if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
{
return camera_model_matrix(camera, r_modelmat);
}
else {
float size[3];
mat4_to_size(size, camera->obmat);
size_to_mat4(sizemat, size);
}
if (pivot == CAM_S3D_PIVOT_CENTER)
fac = 0.5f;
fac_signed = is_left ? fac : -fac;
/* rotation */
if (convergence_mode == CAM_S3D_TOE) {
float angle;
float angle_sin, angle_cos;
float toeinmat[4][4];
float rotmat[4][4];
unit_m4(rotmat);
if (pivot == CAM_S3D_PIVOT_CENTER) {
fac = -fac;
fac_signed = -fac_signed;
}
angle = atanf((interocular_distance * 0.5f) / convergence_distance) / fac;
angle_cos = cosf(angle * fac_signed);
angle_sin = sinf(angle * fac_signed);
rotmat[0][0] = angle_cos;
rotmat[2][0] = -angle_sin;
rotmat[0][2] = angle_sin;
rotmat[2][2] = angle_cos;
if (pivot == CAM_S3D_PIVOT_CENTER) {
/* set the rotation */
copy_m4_m4(toeinmat, rotmat);
/* set the translation */
toeinmat[3][0] = interocular_distance * fac_signed;
/* transform */
normalize_m4_m4(r_modelmat, camera->obmat);
mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
/* scale back to the original size */
mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
}
else { /* CAM_S3D_PIVOT_LEFT, CAM_S3D_PIVOT_RIGHT */
/* rotate perpendicular to the interocular line */
normalize_m4_m4(r_modelmat, camera->obmat);
mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
/* translate along the interocular line */
unit_m4(toeinmat);
toeinmat[3][0] = -interocular_distance * fac_signed;
mul_m4_m4m4(r_modelmat, r_modelmat, toeinmat);
/* rotate to toe-in angle */
mul_m4_m4m4(r_modelmat, r_modelmat, rotmat);
/* scale back to the original size */
mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
}
}
else {
normalize_m4_m4(r_modelmat, camera->obmat);
/* translate - no rotation in CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL */
translate_m4(r_modelmat, -interocular_distance * fac_signed, 0.0f, 0.0f);
/* scale back to the original size */
mul_m4_m4m4(r_modelmat, r_modelmat, sizemat);
}
}
/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
void BKE_camera_multiview_view_matrix(RenderData *rd, Object *camera, const bool is_left, float r_viewmat[4][4])
{
BKE_camera_multiview_model_matrix(rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat);
invert_m4(r_viewmat);
}
/* left is the default */
static bool camera_is_left(const char *viewname)
{
if (viewname && viewname[0] != '\0') {
return !STREQ(viewname, STEREO_RIGHT_NAME);
}
return true;
}
void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4])
{
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
if (!is_multiview) {
camera_model_matrix(camera, r_modelmat);
}
else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
camera_model_matrix(camera, r_modelmat);
}
else { /* SCE_VIEWS_SETUP_BASIC */
const bool is_left = camera_is_left(viewname);
camera_stereo3d_model_matrix(camera, is_left, r_modelmat);
}
normalize_m4(r_modelmat);
}
static Object *camera_multiview_advanced(Scene *scene, Object *camera, const char *suffix)
{
SceneRenderView *srv;
char name[MAX_NAME];
const char *camera_name = camera->id.name + 2;
const int len_name = strlen(camera_name);
name[0] = '\0';
for (srv = scene->r.views.first; srv; srv = srv->next) {
const int len_suffix = strlen(srv->suffix);
if (len_name < len_suffix)
continue;
if (STREQ(camera_name + (len_name - len_suffix), srv->suffix)) {
BLI_snprintf(name, sizeof(name), "%.*s%s", (len_name - len_suffix), camera_name, suffix);
break;
}
}
if (name[0] != '\0') {
Base *base = BKE_scene_base_find_by_name(scene, name);
if (base) {
return base->object;
}
}
return camera;
}
/* returns the camera to be used for render */
Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *viewname)
{
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
if (!is_multiview) {
return camera;
}
else if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
return camera;
}
else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
const char *suffix = BKE_scene_multiview_view_suffix_get(&scene->r, viewname);
return camera_multiview_advanced(scene, camera, suffix);
}
}
static float camera_stereo3d_shift_x(Object *camera, const char *viewname)
{
Camera *data = camera->data;
float shift = data->shiftx;
float interocular_distance, convergence_distance;
short convergence_mode, pivot;
bool is_left = true;
float fac = 1.0f;
float fac_signed;
if (viewname && viewname[0]) {
is_left = STREQ(viewname, STEREO_LEFT_NAME);
}
interocular_distance = data->stereo.interocular_distance;
convergence_distance = data->stereo.convergence_distance;
convergence_mode = data->stereo.convergence_mode;
pivot = data->stereo.pivot;
if (((pivot == CAM_S3D_PIVOT_LEFT) && is_left) ||
((pivot == CAM_S3D_PIVOT_RIGHT) && !is_left))
{
return shift;
}
if (pivot == CAM_S3D_PIVOT_CENTER)
fac = 0.5f;
fac_signed = is_left ? fac : -fac;
/* Note: in viewport, parallel renders as offaxis, but in render it does parallel */
if (ELEM(convergence_mode, CAM_S3D_OFFAXIS, CAM_S3D_PARALLEL)) {
shift += ((interocular_distance / data->sensor_x) * (data->lens / convergence_distance)) * fac_signed;
}
return shift;
}
float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *viewname)
{
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
Camera *data = camera->data;
if (!is_multiview) {
return data->shiftx;
}
else if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW) {
return data->shiftx;
}
else { /* SCE_VIEWS_SETUP_BASIC */
return camera_stereo3d_shift_x(camera, viewname);
}
}
void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, Object *camera, const char *viewname)
{
params->shiftx = BKE_camera_multiview_shift_x(rd, camera, viewname);
}
void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings)
{
if (camera->type == OB_CAMERA) {

File diff suppressed because it is too large Load Diff

@ -3475,6 +3475,7 @@ static void registerCompositNodes(void)
register_node_type_cmp_bokehimage();
register_node_type_cmp_bokehblur();
register_node_type_cmp_switch();
register_node_type_cmp_switch_view();
register_node_type_cmp_pixelate();
register_node_type_cmp_mask();

@ -1002,7 +1002,7 @@ static void cache_filename(char *string, const char *path, const char *relbase,
BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname);
BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true);
BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true, "");
}
/* silly functions but useful to inline when the args do a lot of indirections */

@ -128,8 +128,8 @@ int countPackedFiles(Main *bmain)
/* let's check if there are packed files... */
for (ima = bmain->image.first; ima; ima = ima->id.next)
if (ima->packedfile)
count++;
if (BKE_image_has_packedfile(ima))
count ++;
for (vf = bmain->vfont.first; vf; vf = vf->id.next)
if (vf->packedfile)
@ -232,9 +232,9 @@ void packAll(Main *bmain, ReportList *reports)
int tot = 0;
for (ima = bmain->image.first; ima; ima = ima->id.next) {
if (ima->packedfile == NULL && ima->id.lib == NULL) {
if (BKE_image_has_packedfile(ima) == false && ima->id.lib == NULL) {
if (ima->source == IMA_SRC_FILE) {
ima->packedfile = newPackedFile(reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot ++;
}
else if (BKE_image_is_animated(ima)) {
@ -564,23 +564,47 @@ int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
int unpackImage(ReportList *reports, Image *ima, int how)
{
char localname[FILE_MAX], absname[FILE_MAX];
char *newname;
int ret_value = RET_ERROR;
if (ima != NULL && ima->name[0]) {
unpack_generate_paths(ima->name, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
newname = unpackFile(reports, absname, localname, ima->packedfile, how);
if (newname != NULL) {
ret_value = RET_OK;
freePackedFile(ima->packedfile);
ima->packedfile = NULL;
BLI_strncpy(ima->name, newname, sizeof(ima->name));
MEM_freeN(newname);
BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
while (ima->packedfiles.last) {
char localname[FILE_MAX], absname[FILE_MAX];
char *newname;
ImagePackedFile *imapf = ima->packedfiles.last;
unpack_generate_paths(imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
newname = unpackFile(reports, absname, localname, imapf->packedfile, how);
if (newname != NULL) {
ImageView *iv;
ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK;
freePackedFile(imapf->packedfile);
imapf->packedfile = NULL;
/* update the new corresponding view filepath */
iv = BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath));
if (iv) {
BLI_strncpy(iv->filepath, newname, sizeof(imapf->filepath));
}
/* keep the new name in the image for non-pack specific reasons */
BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
MEM_freeN(newname);
}
else {
ret_value = RET_ERROR;
}
BLI_remlink(&ima->packedfiles, imapf);
MEM_freeN(imapf);
}
}
if (ret_value == RET_OK) {
BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
}
return(ret_value);
}
@ -636,7 +660,7 @@ void unpackAll(Main *bmain, ReportList *reports, int how)
bSound *sound;
for (ima = bmain->image.first; ima; ima = ima->id.next)
if (ima->packedfile)
if (BKE_image_has_packedfile(ima))
unpackImage(reports, ima, how);
for (vf = bmain->vfont.first; vf; vf = vf->id.next)
@ -655,7 +679,7 @@ bool BKE_pack_check(ID *id)
case ID_IM:
{
Image *ima = (Image *)id;
return ima->packedfile != NULL;
return BKE_image_has_packedfile(ima);
}
case ID_VF:
{
@ -683,7 +707,7 @@ void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how)
case ID_IM:
{
Image *ima = (Image *)id;
if (ima->packedfile) {
if (BKE_image_has_packedfile(ima)) {
unpackImage(reports, ima, how);
}
break;

@ -92,6 +92,7 @@
#include "PIL_time.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "bmesh.h"
@ -157,14 +158,16 @@ Scene *BKE_scene_copy(Scene *sce, int type)
Base *base, *obase;
if (type == SCE_COPY_EMPTY) {
ListBase lb;
ListBase rl, rv;
/* XXX. main should become an arg */
scen = BKE_scene_add(G.main, sce->id.name + 2);
lb = scen->r.layers;
rl = scen->r.layers;
rv = scen->r.views;
scen->r = sce->r;
scen->r.layers = lb;
scen->r.layers = rl;
scen->r.actlay = 0;
scen->r.views = rv;
scen->unit = sce->unit;
scen->physics_settings = sce->physics_settings;
scen->gm = sce->gm;
@ -197,6 +200,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
BLI_duplicatelist(&(scen->markers), &(sce->markers));
BLI_duplicatelist(&(scen->transform_spaces), &(sce->transform_spaces));
BLI_duplicatelist(&(scen->r.layers), &(sce->r.layers));
BLI_duplicatelist(&(scen->r.views), &(sce->r.views));
BKE_keyingsets_copy(&(scen->keyingsets), &(sce->keyingsets));
if (sce->nodetree) {
@ -390,6 +394,7 @@ void BKE_scene_free(Scene *sce)
BLI_freelistN(&sce->markers);
BLI_freelistN(&sce->transform_spaces);
BLI_freelistN(&sce->r.layers);
BLI_freelistN(&sce->r.views);
if (sce->toolsettings) {
if (sce->toolsettings->vpaint) {
@ -437,6 +442,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
ParticleEditSettings *pset;
int a;
const char *colorspace_name;
SceneRenderView *srv;
sce = BKE_libblock_alloc(bmain, ID_SCE, name);
sce->lay = sce->layact = 1;
@ -628,7 +634,16 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
/* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
BKE_scene_add_render_layer(sce, NULL);
/* multiview - stereo */
BKE_scene_add_render_view(sce, STEREO_LEFT_NAME);
srv = sce->r.views.first;
BLI_strncpy(srv->suffix, STEREO_LEFT_SUFFIX, sizeof(srv->suffix));
BKE_scene_add_render_view(sce, STEREO_RIGHT_NAME);
srv = sce->r.views.last;
BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
/* game data */
sce->gm.stereoflag = STEREO_NOSTEREO;
sce->gm.stereomode = STEREO_ANAGLYPH;
@ -701,6 +716,19 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
return sce;
}
Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
{
Base *base;
for (base = scene->base.first; base; base = base->next) {
if (STREQ(base->object->id.name + 2, name)) {
break;
}
}
return base;
}
Base *BKE_scene_base_find(Scene *scene, Object *ob)
{
return BLI_findptr(&scene->base, ob, offsetof(Base, object));
@ -1892,6 +1920,42 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *
return true;
}
/* return default view */
SceneRenderView *BKE_scene_add_render_view(Scene *sce, const char *name)
{
SceneRenderView *srv;
if (!name)
name = DATA_("RenderView");
srv = MEM_callocN(sizeof(SceneRenderView), "new render view");
BLI_strncpy(srv->name, name, sizeof(srv->name));
BLI_uniquename(&sce->r.views, srv, DATA_("RenderView"), '.', offsetof(SceneRenderView, name), sizeof(srv->name));
BLI_addtail(&sce->r.views, srv);
return srv;
}
bool BKE_scene_remove_render_view(Scene *scene, SceneRenderView *srv)
{
const int act = BLI_findindex(&scene->r.views, srv);
if (act == -1) {
return false;
}
else if (scene->r.views.first == scene->r.views.last) {
/* ensure 1 view is kept */
return false;
}
BLI_remlink(&scene->r.views, srv);
MEM_freeN(srv);
scene->r.actview = 0;
return true;
}
/* render simplification */
int get_render_subsurf_level(const RenderData *r, int lvl)
@ -2062,3 +2126,281 @@ double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, doubl
return value;
}
}
/******************** multiview *************************/
size_t BKE_scene_multiview_num_views_get(const RenderData *rd)
{
SceneRenderView *srv;
size_t totviews = 0;
if ((rd->scemode & R_MULTIVIEW) == 0)
return 1;
if (rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) {
if (BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name))) {
totviews++;
}
if (BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name))) {
totviews++;
}
}
else {
for (srv = rd->views.first; srv; srv = srv->next) {
if ((srv->viewflag & SCE_VIEW_DISABLE) == 0) {
totviews++;
}
}
}
return totviews;
}
bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
{
SceneRenderView *srv[2];
if ((rd->scemode & R_MULTIVIEW) == 0)
return false;
srv[0] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_LEFT_NAME, offsetof(SceneRenderView, name));
srv[1] = (SceneRenderView *)BLI_findstring(&rd->views, STEREO_RIGHT_NAME, offsetof(SceneRenderView, name));
return (srv[0] && ((srv[0]->viewflag & SCE_VIEW_DISABLE) == 0) &&
srv[1] && ((srv[1]->viewflag & SCE_VIEW_DISABLE) == 0));
}
/* return whether to render this SceneRenderView */
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
{
if (srv == NULL)
return false;
if ((rd->scemode & R_MULTIVIEW) == 0)
return false;
if ((srv->viewflag & SCE_VIEW_DISABLE))
return false;
if (rd->views_format == SCE_VIEWS_FORMAT_MULTIVIEW)
return true;
/* SCE_VIEWS_SETUP_BASIC */
if (STREQ(srv->name, STEREO_LEFT_NAME) ||
STREQ(srv->name, STEREO_RIGHT_NAME))
{
return true;
}
return false;
}
/* return true if viewname is the first or if the name is NULL or not found */
bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *viewname)
{
SceneRenderView *srv;
if ((rd->scemode & R_MULTIVIEW) == 0)
return true;
if ((!viewname) || (!viewname[0]))
return true;
for (srv = rd->views.first; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
return STREQ(viewname, srv->name);
}
}
return true;
}
/* return true if viewname is the last or if the name is NULL or not found */
bool BKE_scene_multiview_is_render_view_last(const RenderData *rd, const char *viewname)
{
SceneRenderView *srv;
if ((rd->scemode & R_MULTIVIEW) == 0)
return true;
if ((!viewname) || (!viewname[0]))
return true;
for (srv = rd->views.last; srv; srv = srv->prev) {
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
return STREQ(viewname, srv->name);
}
}
return true;
}
SceneRenderView *BKE_scene_multiview_render_view_findindex(const RenderData *rd, const int view_id)
{
SceneRenderView *srv;
size_t nr;
if ((rd->scemode & R_MULTIVIEW) == 0)
return NULL;
nr = 0;
for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
if (nr++ == view_id)
return srv;
}
}
return srv;
}
const char *BKE_scene_multiview_render_view_name_get(const RenderData *rd, const int view_id)
{
SceneRenderView *srv = BKE_scene_multiview_render_view_findindex(rd, view_id);
if (srv)
return srv->name;
else
return "";
}
size_t BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
{
SceneRenderView *srv;
size_t nr;
if ((!rd) || ((rd->scemode & R_MULTIVIEW) == 0))
return 0;
if ((!viewname) || (!viewname[0]))
return 0;
nr = 0;
for (srv = rd->views.first, nr = 0; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
if (STREQ(viewname, srv->name)) {
return nr;
}
else {
nr += 1;
}
}
}
return 0;
}
void BKE_scene_multiview_filepath_get(
SceneRenderView *srv, const char *filepath,
char *r_filepath)
{
BLI_strncpy(r_filepath, filepath, FILE_MAX);
BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, "");
}
/**
* When multiview is not used the filepath is as usual (e.g., ``Image.jpg``).
* When multiview is on, even if only one view is enabled the view is incorporated
* into the file name (e.g., ``Image_L.jpg``). That allows for the user to re-render
* individual views.
*/
void BKE_scene_multiview_view_filepath_get(
const RenderData *rd, const char *filepath, const char *viewname,
char *r_filepath)
{
SceneRenderView *srv;
char suffix[FILE_MAX];
srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
if (srv)
BLI_strncpy(suffix, srv->suffix, sizeof(suffix));
else
BLI_strncpy(suffix, viewname, sizeof(suffix));
BLI_strncpy(r_filepath, filepath, FILE_MAX);
BLI_path_suffix(r_filepath, FILE_MAX, suffix, "");
}
const char *BKE_scene_multiview_view_suffix_get(const RenderData *rd, const char *viewname)
{
SceneRenderView *srv;
if ((viewname == NULL) || (viewname[0] == '\0'))
return viewname;
srv = BLI_findstring(&rd->views, viewname, offsetof(SceneRenderView, name));
if (srv)
return srv->suffix;
else
return viewname;
}
const char *BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, const size_t view_id)
{
if ((rd->scemode & R_MULTIVIEW) == 0) {
return "";
}
else {
const char *viewname = BKE_scene_multiview_render_view_name_get(rd, view_id);
return BKE_scene_multiview_view_suffix_get(rd, viewname);
}
}
void BKE_scene_multiview_view_prefix_get(Scene *scene, const char *name, char *rprefix, char **rext)
{
SceneRenderView *srv;
size_t index_act;
char *suf_act;
const char delims[] = {'.', '\0'};
rprefix[0] = '\0';
/* begin of extension */
index_act = BLI_str_rpartition(name, delims, rext, &suf_act);
BLI_assert(index_act > 0);
for (srv = scene->r.views.first; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
size_t len = strlen(srv->suffix);
if (STREQLEN(*rext - len, srv->suffix, len)) {
BLI_strncpy(rprefix, name, strlen(name) - strlen(*rext) - len + 1);
break;
}
}
}
}
void BKE_scene_multiview_videos_dimensions_get(
const RenderData *rd, const size_t width, const size_t height,
size_t *r_width, size_t *r_height)
{
if ((rd->scemode & R_MULTIVIEW) &&
rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D)
{
IMB_stereo3d_write_dimensions(
rd->im_format.stereo3d_format.display_mode,
(rd->im_format.stereo3d_format.flag & S3D_SQUEEZED_FRAME) != 0,
width, height,
r_width, r_height);
}
else {
*r_width = width;
*r_height = height;
}
}
size_t BKE_scene_multiview_num_videos_get(const RenderData *rd)
{
if (BKE_imtype_is_movie(rd->im_format.imtype) == false)
return 0;
if ((rd->scemode & R_MULTIVIEW) == 0)
return 1;
if (rd->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
return 1;
}
else {
/* R_IMF_VIEWS_INDIVIDUAL */
return BKE_scene_multiview_num_views_get(rd);
}
}

@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_sequence_types.h"
#include "DNA_scene_types.h"
#include "IMB_moviecache.h"
#include "IMB_imbuf.h"
@ -41,6 +42,7 @@
#include "BLI_listbase.h"
#include "BKE_sequencer.h"
#include "BKE_scene.h"
typedef struct SeqCacheKey {
struct Sequence *seq;
@ -77,7 +79,9 @@ static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
(a->bmain != b->bmain) ||
(a->scene != b->scene) ||
(a->motion_blur_shutter != b->motion_blur_shutter) ||
(a->motion_blur_samples != b->motion_blur_samples));
(a->motion_blur_samples != b->motion_blur_samples) ||
(a->scene->r.views_format != b->scene->r.views_format) ||
(a->view_id != b->view_id));
}
static unsigned int seq_hash_render_data(const SeqRenderData *a)
@ -89,6 +93,7 @@ static unsigned int seq_hash_render_data(const SeqRenderData *a)
rval ^= ((intptr_t) a->scene) << 6;
rval ^= (int)(a->motion_blur_shutter * 100.0f) << 10;
rval ^= a->motion_blur_samples << 24;
rval ^= ((a->scene->r.views_format * 2) + a->view_id) << 32;
return rval;
}

File diff suppressed because it is too large Load Diff

@ -50,26 +50,34 @@
/* ********************** general blender movie support ***************************** */
static int start_stub(Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty),
ReportList *UNUSED(reports), bool UNUSED(preview))
static int start_stub(void *UNUSED(context_v), Scene *UNUSED(scene), RenderData *UNUSED(rd), int UNUSED(rectx), int UNUSED(recty),
ReportList *UNUSED(reports), bool UNUSED(preview), const char *UNUSED(suffix))
{ return 0; }
static void end_stub(void)
static void end_stub(void *UNUSED(context_v))
{}
static int append_stub(RenderData *UNUSED(rd), int UNUSED(start_frame), int UNUSED(frame), int *UNUSED(pixels),
int UNUSED(rectx), int UNUSED(recty), ReportList *UNUSED(reports))
static int append_stub(void *UNUSED(context_v), RenderData *UNUSED(rd), int UNUSED(start_frame), int UNUSED(frame), int *UNUSED(pixels),
int UNUSED(rectx), int UNUSED(recty), const char *UNUSED(suffix), ReportList *UNUSED(reports))
{ return 0; }
static void *context_create_stub(void)
{ return NULL; }
static void context_free_stub(void *UNUSED(context_v))
{}
#ifdef WITH_AVI
# include "AVI_avi.h"
/* callbacks */
static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview);
static void end_avi(void);
static int append_avi(RenderData *rd, int start_frame, int frame, int *pixels,
int rectx, int recty, ReportList *reports);
static void filepath_avi(char *string, RenderData *rd, bool preview);
static int start_avi(void *context_v, Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview, const char *suffix);
static void end_avi(void *context_v);
static int append_avi(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels,
int rectx, int recty, const char *suffix, ReportList *reports);
static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix);
static void *context_create_avi(void);
static void context_free_avi(void *context_v);
#endif /* WITH_AVI */
#ifdef WITH_QUICKTIME
@ -93,13 +101,17 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.end_movie = end_stub;
mh.get_next_frame = NULL;
mh.get_movie_path = NULL;
mh.context_create = context_create_stub;
mh.context_free = context_free_stub;
/* set the default handle, as builtin */
#ifdef WITH_AVI
mh.start_movie = start_avi;
mh.append_movie = append_avi;
mh.end_movie = end_avi;
mh.get_movie_path = filepath_avi;
mh.context_create = context_create_avi;
mh.context_free = context_free_avi;
#endif
/* do the platform specific handles */
@ -109,6 +121,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.append_movie = append_qt;
mh.end_movie = end_qt;
mh.get_movie_path = filepath_qt;
mh.context_create = context_create_qt;
mh.context_free = context_free_qt;
}
#endif
#ifdef WITH_FFMPEG
@ -117,6 +131,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.append_movie = BKE_ffmpeg_append;
mh.end_movie = BKE_ffmpeg_end;
mh.get_movie_path = BKE_ffmpeg_filepath_get;
mh.context_create = BKE_ffmpeg_context_create;
mh.context_free = BKE_ffmpeg_context_free;
}
#endif
#ifdef WITH_FRAMESERVER
@ -125,6 +141,8 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.append_movie = BKE_frameserver_append;
mh.end_movie = BKE_frameserver_end;
mh.get_next_frame = BKE_frameserver_loop;
mh.context_create = BKE_frameserver_context_create;
mh.context_free = BKE_frameserver_context_free;
}
#endif
@ -137,9 +155,7 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
#ifdef WITH_AVI
static AviMovie *avi = NULL;
static void filepath_avi(char *string, RenderData *rd, bool preview)
static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix)
{
int sfra, efra;
@ -170,27 +186,27 @@ static void filepath_avi(char *string, RenderData *rd, bool preview)
BLI_path_frame_range(string, sfra, efra, 4);
}
}
BLI_path_suffix(string, FILE_MAX, suffix, "");
}
static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview)
static int start_avi(void *context_v, Scene *UNUSED(scene), RenderData *rd, int rectx, int recty,
ReportList *reports, bool preview, const char *suffix)
{
int x, y;
char name[256];
AviFormat format;
int quality;
double framerate;
(void)scene; /* unused */
filepath_avi(name, rd, preview);
AviMovie *avi = context_v;
filepath_avi(name, rd, preview, suffix);
x = rectx;
y = recty;
quality = rd->im_format.quality;
framerate = (double) rd->frs_sec / (double) rd->frs_sec_base;
avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
if (rd->im_format.imtype != R_IMF_IMTYPE_AVIJPEG) format = AVI_FORMAT_AVI_RGB;
else format = AVI_FORMAT_MJPEG;
@ -216,12 +232,13 @@ static int start_avi(Scene *scene, RenderData *rd, int rectx, int recty, ReportL
return 1;
}
static int append_avi(RenderData *UNUSED(rd), int start_frame, int frame, int *pixels,
int rectx, int recty, ReportList *UNUSED(reports))
static int append_avi(void *context_v, RenderData *UNUSED(rd), int start_frame, int frame, int *pixels,
int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
{
unsigned int *rt1, *rt2, *rectot;
int x, y;
char *cp, rt;
AviMovie *avi = context_v;
if (avi == NULL)
return 0;
@ -252,22 +269,37 @@ static int append_avi(RenderData *UNUSED(rd), int start_frame, int frame, int *p
return 1;
}
static void end_avi(void)
static void end_avi(void *context_v)
{
AviMovie *avi = context_v;
if (avi == NULL) return;
AVI_close_compress(avi);
MEM_freeN(avi);
avi = NULL;
}
static void *context_create_avi(void)
{
AviMovie *avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
return avi;
}
static void context_free_avi(void *context_v)
{
AviMovie *avi = context_v;
if (avi) {
MEM_freeN(avi);
}
}
#endif /* WITH_AVI */
/* similar to BKE_image_path_from_imformat() */
void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview)
void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
{
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
if (mh->get_movie_path)
mh->get_movie_path(string, rd, preview);
mh->get_movie_path(string, rd, preview, suffix);
else
string[0] = '\0';
}

@ -61,36 +61,38 @@
#include "ffmpeg_compat.h"
static int ffmpeg_type = 0;
static int ffmpeg_codec = AV_CODEC_ID_MPEG4;
static int ffmpeg_audio_codec = AV_CODEC_ID_NONE;
static int ffmpeg_video_bitrate = 1150;
static int ffmpeg_audio_bitrate = 128;
static int ffmpeg_gop_size = 12;
static int ffmpeg_autosplit = 0;
static int ffmpeg_autosplit_count = 0;
static bool ffmpeg_preview = false;
typedef struct FFMpegContext {
int ffmpeg_type;
int ffmpeg_codec;
int ffmpeg_audio_codec;
int ffmpeg_video_bitrate;
int ffmpeg_audio_bitrate;
int ffmpeg_gop_size;
int ffmpeg_autosplit;
int ffmpeg_autosplit_count;
bool ffmpeg_preview;
static AVFormatContext *outfile = 0;
static AVStream *video_stream = 0;
static AVStream *audio_stream = 0;
static AVFrame *current_frame = 0;
static struct SwsContext *img_convert_ctx = 0;
AVFormatContext *outfile;
AVStream *video_stream;
AVStream *audio_stream;
AVFrame *current_frame;
struct SwsContext *img_convert_ctx;
static uint8_t *audio_input_buffer = 0;
static uint8_t *audio_deinterleave_buffer = 0;
static int audio_input_samples = 0;
uint8_t *audio_input_buffer;
uint8_t *audio_deinterleave_buffer;
int audio_input_samples;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
static uint8_t *audio_output_buffer = 0;
static int audio_outbuf_size = 0;
uint8_t *audio_output_buffer;
int audio_outbuf_size;
#endif
static double audio_time = 0.0f;
static bool audio_deinterleave = false;
static int audio_sample_size = 0;
double audio_time;
bool audio_deinterleave;
int audio_sample_size;
#ifdef WITH_AUDASPACE
static AUD_Device *audio_mixdown_device = 0;
AUD_Device *audio_mixdown_device;
#endif
} FFMpegContext;
#define FFMPEG_AUTOSPLIT_SIZE 2000000000
@ -99,6 +101,7 @@ static AUD_Device *audio_mixdown_device = 0;
static void ffmpeg_dict_set_int(AVDictionary **dict, const char *key, int value);
static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float value);
static void ffmpeg_set_expert_options(RenderData *rd);
static void ffmpeg_filepath_get(FFMpegContext *context, char *string, struct RenderData *rd, bool preview, const char *suffix);
/* Delete a picture buffer */
@ -117,50 +120,50 @@ static int request_float_audio_buffer(int codec_id)
}
#ifdef WITH_AUDASPACE
static int write_audio_frame(void)
static int write_audio_frame(FFMpegContext *context)
{
AVCodecContext *c = NULL;
AVPacket pkt;
AVFrame *frame = NULL;
int got_output = 0;
c = audio_stream->codec;
c = context->audio_stream->codec;
av_init_packet(&pkt);
pkt.size = 0;
pkt.data = NULL;
AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_samples);
audio_time += (double) audio_input_samples / (double) c->sample_rate;
AUD_readDevice(context->audio_mixdown_device, context->audio_input_buffer, context->audio_input_samples);
context->audio_time += (double) context->audio_input_samples / (double) c->sample_rate;
#ifdef FFMPEG_HAVE_ENCODE_AUDIO2
frame = avcodec_alloc_frame();
avcodec_get_frame_defaults(frame);
frame->pts = audio_time / av_q2d(c->time_base);
frame->nb_samples = audio_input_samples;
frame->pts = context->audio_time / av_q2d(c->time_base);
frame->nb_samples = context->audio_input_samples;
frame->format = c->sample_fmt;
#ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
frame->channel_layout = c->channel_layout;
#endif
if (audio_deinterleave) {
if (context->audio_deinterleave) {
int channel, i;
uint8_t *temp;
for (channel = 0; channel < c->channels; channel++) {
for (i = 0; i < frame->nb_samples; i++) {
memcpy(audio_deinterleave_buffer + (i + channel * frame->nb_samples) * audio_sample_size,
audio_input_buffer + (c->channels * i + channel) * audio_sample_size, audio_sample_size);
memcpy(context->audio_deinterleave_buffer + (i + channel * frame->nb_samples) * context->audio_sample_size,
context->audio_input_buffer + (c->channels * i + channel) * context->audio_sample_size, context->audio_sample_size);
}
}
temp = audio_deinterleave_buffer;
audio_deinterleave_buffer = audio_input_buffer;
audio_input_buffer = temp;
temp = context->audio_deinterleave_buffer;
context->audio_deinterleave_buffer = context->audio_input_buffer;
context->audio_input_buffer = temp;
}
avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, audio_input_buffer,
audio_input_samples * c->channels * audio_sample_size, 1);
avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, context->audio_input_buffer,
context->audio_input_samples * c->channels * context->audio_sample_size, 1);
if (avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) {
// XXX error("Error writing audio packet");
@ -172,30 +175,30 @@ static int write_audio_frame(void)
return 0;
}
#else
pkt.size = avcodec_encode_audio(c, audio_output_buffer, audio_outbuf_size, (short *) audio_input_buffer);
pkt.size = avcodec_encode_audio(c, context->audio_output_buffer, context->audio_outbuf_size, (short *) context->audio_input_buffer);
if (pkt.size < 0) {
// XXX error("Error writing audio packet");
return -1;
}
pkt.data = audio_output_buffer;
pkt.data = context->audio_output_buffer;
got_output = 1;
#endif
if (got_output) {
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, c->time_base, audio_stream->time_base);
pkt.pts = av_rescale_q(pkt.pts, c->time_base, context->audio_stream->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, c->time_base, audio_stream->time_base);
pkt.dts = av_rescale_q(pkt.dts, c->time_base, context->audio_stream->time_base);
if (pkt.duration > 0)
pkt.duration = av_rescale_q(pkt.duration, c->time_base, audio_stream->time_base);
pkt.duration = av_rescale_q(pkt.duration, c->time_base, context->audio_stream->time_base);
pkt.stream_index = audio_stream->index;
pkt.stream_index = context->audio_stream->index;
pkt.flags |= AV_PKT_FLAG_KEY;
if (av_interleaved_write_frame(outfile, &pkt) != 0) {
if (av_interleaved_write_frame(context->outfile, &pkt) != 0) {
fprintf(stderr, "Error writing audio packet!\n");
if (frame)
avcodec_free_frame(&frame);
@ -302,11 +305,11 @@ static const char **get_file_extensions(int format)
}
/* Write a frame to the output file */
static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
static int write_video_frame(FFMpegContext *context, RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
{
int got_output;
int ret, success = 1;
AVCodecContext *c = video_stream->codec;
AVCodecContext *c = context->video_stream->codec;
AVPacket packet = { 0 };
av_init_packet(&packet);
@ -321,22 +324,22 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportLis
if (ret >= 0 && got_output) {
if (packet.pts != AV_NOPTS_VALUE) {
packet.pts = av_rescale_q(packet.pts, c->time_base, video_stream->time_base);
packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame PTS: %d\n", (int)packet.pts);
}
else {
PRINT("Video Frame PTS: not set\n");
}
if (packet.dts != AV_NOPTS_VALUE) {
packet.dts = av_rescale_q(packet.dts, c->time_base, video_stream->time_base);
packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame DTS: %d\n", (int)packet.dts);
}
else {
PRINT("Video Frame DTS: not set\n");
}
packet.stream_index = video_stream->index;
ret = av_interleaved_write_frame(outfile, &packet);
packet.stream_index = context->video_stream->index;
ret = av_interleaved_write_frame(context->outfile, &packet);
success = (ret == 0);
}
else if (ret < 0) {
@ -350,11 +353,11 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame *frame, ReportLis
}
/* read and encode a frame of audio from the buffer */
static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
static AVFrame *generate_video_frame(FFMpegContext *context, uint8_t *pixels, ReportList *reports)
{
uint8_t *rendered_frame;
AVCodecContext *c = video_stream->codec;
AVCodecContext *c = context->video_stream->codec;
int width = c->width;
int height = c->height;
AVFrame *rgb_frame;
@ -367,7 +370,7 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
}
}
else {
rgb_frame = current_frame;
rgb_frame = context->current_frame;
}
rendered_frame = pixels;
@ -411,17 +414,17 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
}
if (c->pix_fmt != PIX_FMT_BGR32) {
sws_scale(img_convert_ctx, (const uint8_t *const *) rgb_frame->data,
sws_scale(context->img_convert_ctx, (const uint8_t *const *) rgb_frame->data,
rgb_frame->linesize, 0, c->height,
current_frame->data, current_frame->linesize);
context->current_frame->data, context->current_frame->linesize);
delete_picture(rgb_frame);
}
current_frame->format = PIX_FMT_BGR32;
current_frame->width = width;
current_frame->height = height;
context->current_frame->format = PIX_FMT_BGR32;
context->current_frame->width = width;
context->current_frame->height = height;
return current_frame;
return context->current_frame;
}
static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDictionary **dictionary)
@ -516,7 +519,7 @@ static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char
/* prepare a video stream for the output file */
static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContext *of,
static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of,
int rectx, int recty, char *error, int error_size)
{
AVStream *st;
@ -542,7 +545,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->height = recty;
/* FIXME: Really bad hack (tm) for NTSC support */
if (ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
if (context->ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
c->time_base.den = 2997;
c->time_base.num = 100;
}
@ -555,8 +558,8 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->time_base.num = ((double) rd->frs_sec_base) * 100000;
}
c->gop_size = ffmpeg_gop_size;
c->bit_rate = ffmpeg_video_bitrate * 1000;
c->gop_size = context->ffmpeg_gop_size;
c->bit_rate = context->ffmpeg_video_bitrate * 1000;
c->rc_max_rate = rd->ffcodecdata.rc_max_rate * 1000;
c->rc_min_rate = rd->ffcodecdata.rc_min_rate * 1000;
c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024;
@ -585,7 +588,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
c->pix_fmt = PIX_FMT_YUV422P;
}
if (ffmpeg_type == FFMPEG_XVID) {
if (context->ffmpeg_type == FFMPEG_XVID) {
/* arghhhh ... */
c->pix_fmt = PIX_FMT_YUV420P;
c->codec_tag = (('D' << 24) + ('I' << 16) + ('V' << 8) + 'X');
@ -655,14 +658,14 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
}
av_dict_free(&opts);
current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
context->current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
img_convert_ctx = sws_getContext(c->width, c->height, PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
context->img_convert_ctx = sws_getContext(c->width, c->height, PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
NULL, NULL, NULL);
return st;
}
static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
static AVStream *alloc_audio_stream(FFMpegContext *context, RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
{
AVStream *st;
AVCodecContext *c;
@ -680,7 +683,7 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
c->codec_type = AVMEDIA_TYPE_AUDIO;
c->sample_rate = rd->ffcodecdata.audio_mixrate;
c->bit_rate = ffmpeg_audio_bitrate * 1000;
c->bit_rate = context->ffmpeg_audio_bitrate * 1000;
c->sample_fmt = AV_SAMPLE_FMT_S16;
c->channels = rd->ffcodecdata.audio_channels;
@ -747,35 +750,35 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
st->codec->time_base.den = st->codec->sample_rate;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
audio_outbuf_size = FF_MIN_BUFFER_SIZE;
context->audio_outbuf_size = FF_MIN_BUFFER_SIZE;
#endif
if (c->frame_size == 0)
// used to be if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
// not sure if that is needed anymore, so let's try out if there are any
// complaints regarding some ffmpeg versions users might have
audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
context->audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
else {
audio_input_samples = c->frame_size;
context->audio_input_samples = c->frame_size;
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
if (c->frame_size * c->channels * sizeof(int16_t) * 4 > audio_outbuf_size)
audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
if (c->frame_size * c->channels * sizeof(int16_t) * 4 > context->audio_outbuf_size)
context->audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
#endif
}
audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
context->audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
context->audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
context->audio_input_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
audio_output_buffer = (uint8_t *) av_malloc(audio_outbuf_size);
context->audio_output_buffer = (uint8_t *) av_malloc(context->audio_outbuf_size);
#endif
if (audio_deinterleave)
audio_deinterleave_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
if (context->audio_deinterleave)
context->audio_deinterleave_buffer = (uint8_t *) av_malloc(context->audio_input_samples * c->channels * context->audio_sample_size);
audio_time = 0.0f;
context->audio_time = 0.0f;
return st;
}
@ -799,7 +802,7 @@ static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float va
av_dict_set(dict, key, buffer, 0);
}
static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, ReportList *reports)
static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports)
{
/* Handle to the output file */
AVFormatContext *of;
@ -808,26 +811,26 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
char name[256], error[1024];
const char **exts;
ffmpeg_type = rd->ffcodecdata.type;
ffmpeg_codec = rd->ffcodecdata.codec;
ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
ffmpeg_gop_size = rd->ffcodecdata.gop_size;
ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
context->ffmpeg_type = rd->ffcodecdata.type;
context->ffmpeg_codec = rd->ffcodecdata.codec;
context->ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
context->ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
context->ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
context->ffmpeg_gop_size = rd->ffcodecdata.gop_size;
context->ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT;
/* Determine the correct filename */
BKE_ffmpeg_filepath_get(name, rd, ffmpeg_preview);
ffmpeg_filepath_get(context, name, rd, context->ffmpeg_preview, suffix);
PRINT("Starting output to %s(ffmpeg)...\n"
" Using type=%d, codec=%d, audio_codec=%d,\n"
" video_bitrate=%d, audio_bitrate=%d,\n"
" gop_size=%d, autosplit=%d\n"
" render width=%d, render height=%d\n",
name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec,
ffmpeg_video_bitrate, ffmpeg_audio_bitrate,
ffmpeg_gop_size, ffmpeg_autosplit, rectx, recty);
name, context->ffmpeg_type, context->ffmpeg_codec, context->ffmpeg_audio_codec,
context->ffmpeg_video_bitrate, context->ffmpeg_audio_bitrate,
context->ffmpeg_gop_size, context->ffmpeg_autosplit, rectx, recty);
exts = get_file_extensions(ffmpeg_type);
exts = get_file_extensions(context->ffmpeg_type);
if (!exts) {
BKE_report(reports, RPT_ERROR, "No valid formats found");
return 0;
@ -846,7 +849,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
of->oformat = fmt;
of->packet_size = rd->ffcodecdata.mux_packet_size;
if (ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate);
}
else {
@ -857,15 +860,15 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
of->max_delay = (int)(0.7 * AV_TIME_BASE);
fmt->audio_codec = ffmpeg_audio_codec;
fmt->audio_codec = context->ffmpeg_audio_codec;
BLI_strncpy(of->filename, name, sizeof(of->filename));
/* set the codec to the user's selection */
switch (ffmpeg_type) {
switch (context->ffmpeg_type) {
case FFMPEG_AVI:
case FFMPEG_MOV:
case FFMPEG_MKV:
fmt->video_codec = ffmpeg_codec;
fmt->video_codec = context->ffmpeg_codec;
break;
case FFMPEG_OGG:
fmt->video_codec = AV_CODEC_ID_THEORA;
@ -908,9 +911,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
}
if (ffmpeg_type == FFMPEG_DV) {
if (context->ffmpeg_type == FFMPEG_DV) {
fmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
if (ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
av_dict_free(&opts);
return 0;
@ -918,9 +921,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
if (fmt->video_codec != AV_CODEC_ID_NONE) {
video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty, error, sizeof(error));
PRINT("alloc video stream %p\n", video_stream);
if (!video_stream) {
context->video_stream = alloc_video_stream(context, rd, fmt->video_codec, of, rectx, recty, error, sizeof(error));
PRINT("alloc video stream %p\n", context->video_stream);
if (!context->video_stream) {
if (error[0])
BKE_report(reports, RPT_ERROR, error);
else
@ -931,9 +934,9 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
}
if (ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of, error, sizeof(error));
if (!audio_stream) {
if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
context->audio_stream = alloc_audio_stream(context, rd, fmt->audio_codec, of, error, sizeof(error));
if (!context->audio_stream) {
if (error[0])
BKE_report(reports, RPT_ERROR, error);
else
@ -956,7 +959,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
return 0;
}
outfile = of;
context->outfile = of;
av_dump_format(of, 0, name, 1);
av_dict_free(&opts);
@ -980,11 +983,11 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
* parameter.
* </p>
*/
static void flush_ffmpeg(void)
static void flush_ffmpeg(FFMpegContext *context)
{
int ret = 0;
AVCodecContext *c = video_stream->codec;
AVCodecContext *c = context->video_stream->codec;
/* get the delayed frames */
while (1) {
int got_output;
@ -1000,28 +1003,28 @@ static void flush_ffmpeg(void)
break;
}
if (packet.pts != AV_NOPTS_VALUE) {
packet.pts = av_rescale_q(packet.pts, c->time_base, video_stream->time_base);
packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame PTS: %d\n", (int) packet.pts);
}
else {
PRINT("Video Frame PTS: not set\n");
}
if (packet.dts != AV_NOPTS_VALUE) {
packet.dts = av_rescale_q(packet.dts, c->time_base, video_stream->time_base);
packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame DTS: %d\n", (int) packet.dts);
}
else {
PRINT("Video Frame DTS: not set\n");
}
packet.stream_index = video_stream->index;
ret = av_interleaved_write_frame(outfile, &packet);
packet.stream_index = context->video_stream->index;
ret = av_interleaved_write_frame(context->outfile, &packet);
if (ret != 0) {
fprintf(stderr, "Error writing delayed frame %d\n", ret);
break;
}
}
avcodec_flush_buffers(video_stream->codec);
avcodec_flush_buffers(context->video_stream->codec);
}
/* **********************************************************************
@ -1029,7 +1032,7 @@ static void flush_ffmpeg(void)
* ********************************************************************** */
/* Get the output filename-- similar to the other output formats */
void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview)
static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData *rd, bool preview, const char *suffix)
{
char autosplit[20];
@ -1056,7 +1059,9 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview)
autosplit[0] = 0;
if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
sprintf(autosplit, "_%03d", ffmpeg_autosplit_count);
if (context) {
sprintf(autosplit, "_%03d", context->ffmpeg_autosplit_count);
}
}
if (rd->scemode & R_EXTENSION) {
@ -1086,19 +1091,28 @@ void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview)
strcat(string, autosplit);
}
BLI_path_suffix(string, FILE_MAX, suffix, "");
}
int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview)
void BKE_ffmpeg_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
{
ffmpeg_filepath_get(NULL, string, rd, preview, suffix);
}
int BKE_ffmpeg_start(void *context_v, struct Scene *scene, RenderData *rd, int rectx, int recty,
ReportList *reports, bool preview, const char *suffix)
{
int success;
FFMpegContext *context = context_v;
ffmpeg_autosplit_count = 0;
ffmpeg_preview = preview;
context->ffmpeg_autosplit_count = 0;
context->ffmpeg_preview = preview;
success = start_ffmpeg_impl(rd, rectx, recty, reports);
success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
#ifdef WITH_AUDASPACE
if (audio_stream) {
AVCodecContext *c = audio_stream->codec;
if (context->audio_stream) {
AVCodecContext *c = context->audio_stream->codec;
AUD_DeviceSpecs specs;
specs.channels = c->channels;
@ -1123,7 +1137,7 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty,
}
specs.rate = rd->ffcodecdata.audio_mixrate;
audio_mixdown_device = BKE_sound_mixdown(scene, specs, preview ? rd->psfra : rd->sfra, rd->ffcodecdata.audio_volume);
context->audio_mixdown_device = BKE_sound_mixdown(scene, specs, preview ? rd->psfra : rd->sfra, rd->ffcodecdata.audio_volume);
#ifdef FFMPEG_CODEC_TIME_BASE
c->time_base.den = specs.rate;
c->time_base.num = 1;
@ -1133,16 +1147,16 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty,
return success;
}
static void end_ffmpeg_impl(int is_autosplit);
static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit);
#ifdef WITH_AUDASPACE
static void write_audio_frames(double to_pts)
static void write_audio_frames(FFMpegContext *context, double to_pts)
{
int finished = 0;
while (audio_stream && !finished) {
if ((audio_time >= to_pts) ||
(write_audio_frame()))
while (context->audio_stream && !finished) {
if ((context->audio_time >= to_pts) ||
(write_audio_frame(context)))
{
finished = 1;
}
@ -1150,8 +1164,10 @@ static void write_audio_frames(double to_pts)
}
#endif
int BKE_ffmpeg_append(RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, ReportList *reports)
int BKE_ffmpeg_append(void *context_v, RenderData *rd, int start_frame, int frame, int *pixels,
int rectx, int recty, const char *suffix, ReportList *reports)
{
FFMpegContext *context = context_v;
AVFrame *avframe;
int success = 1;
@ -1160,111 +1176,112 @@ int BKE_ffmpeg_append(RenderData *rd, int start_frame, int frame, int *pixels, i
/* why is this done before writing the video frame and again at end_ffmpeg? */
// write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
if (video_stream) {
avframe = generate_video_frame((unsigned char *) pixels, reports);
success = (avframe && write_video_frame(rd, frame - start_frame, avframe, reports));
if (context->video_stream) {
avframe = generate_video_frame(context, (unsigned char *) pixels, reports);
success = (avframe && write_video_frame(context, rd, frame - start_frame, avframe, reports));
if (ffmpeg_autosplit) {
if (avio_tell(outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
end_ffmpeg_impl(true);
ffmpeg_autosplit_count++;
success &= start_ffmpeg_impl(rd, rectx, recty, reports);
if (context->ffmpeg_autosplit) {
if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
end_ffmpeg_impl(context, true);
context->ffmpeg_autosplit_count++;
success &= start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
}
}
}
#ifdef WITH_AUDASPACE
write_audio_frames((frame - start_frame) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
write_audio_frames(context, (frame - start_frame) / (((double)rd->frs_sec) / (double)rd->frs_sec_base));
#endif
return success;
}
static void end_ffmpeg_impl(int is_autosplit)
static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
{
unsigned int i;
PRINT("Closing ffmpeg...\n");
#if 0
if (audio_stream) { /* SEE UPPER */
write_audio_frames();
if (context->audio_stream) { /* SEE UPPER */
write_audio_frames(context);
}
#endif
#ifdef WITH_AUDASPACE
if (is_autosplit == false) {
if (audio_mixdown_device) {
AUD_closeReadDevice(audio_mixdown_device);
audio_mixdown_device = 0;
if (context->audio_mixdown_device) {
AUD_closeReadDevice(context->audio_mixdown_device);
context->audio_mixdown_device = 0;
}
}
#endif
if (video_stream && video_stream->codec) {
if (context->video_stream && context->video_stream->codec) {
PRINT("Flushing delayed frames...\n");
flush_ffmpeg();
flush_ffmpeg(context);
}
if (outfile) {
av_write_trailer(outfile);
if (context->outfile) {
av_write_trailer(context->outfile);
}
/* Close the video codec */
if (video_stream && video_stream->codec) {
avcodec_close(video_stream->codec);
PRINT("zero video stream %p\n", video_stream);
video_stream = 0;
if (context->video_stream && context->video_stream->codec) {
avcodec_close(context->video_stream->codec);
PRINT("zero video stream %p\n", context->video_stream);
context->video_stream = 0;
}
/* Close the output file */
if (outfile) {
for (i = 0; i < outfile->nb_streams; i++) {
if (&outfile->streams[i]) {
av_freep(&outfile->streams[i]);
if (context->outfile) {
for (i = 0; i < context->outfile->nb_streams; i++) {
if (&context->outfile->streams[i]) {
av_freep(&context->outfile->streams[i]);
}
}
}
/* free the temp buffer */
if (current_frame) {
delete_picture(current_frame);
current_frame = 0;
if (context->current_frame) {
delete_picture(context->current_frame);
context->current_frame = 0;
}
if (outfile && outfile->oformat) {
if (!(outfile->oformat->flags & AVFMT_NOFILE)) {
avio_close(outfile->pb);
if (context->outfile && context->outfile->oformat) {
if (!(context->outfile->oformat->flags & AVFMT_NOFILE)) {
avio_close(context->outfile->pb);
}
}
if (outfile) {
av_free(outfile);
outfile = 0;
if (context->outfile) {
av_free(context->outfile);
context->outfile = 0;
}
if (audio_input_buffer) {
av_free(audio_input_buffer);
audio_input_buffer = 0;
if (context->audio_input_buffer) {
av_free(context->audio_input_buffer);
context->audio_input_buffer = 0;
}
#ifndef FFMPEG_HAVE_ENCODE_AUDIO2
if (audio_output_buffer) {
av_free(audio_output_buffer);
audio_output_buffer = 0;
if (context->audio_output_buffer) {
av_free(context->audio_output_buffer);
context->audio_output_buffer = 0;
}
#endif
if (audio_deinterleave_buffer) {
av_free(audio_deinterleave_buffer);
audio_deinterleave_buffer = 0;
if (context->audio_deinterleave_buffer) {
av_free(context->audio_deinterleave_buffer);
context->audio_deinterleave_buffer = 0;
}
if (img_convert_ctx) {
sws_freeContext(img_convert_ctx);
img_convert_ctx = 0;
if (context->img_convert_ctx) {
sws_freeContext(context->img_convert_ctx);
context->img_convert_ctx = 0;
}
}
void BKE_ffmpeg_end(void)
void BKE_ffmpeg_end(void *context_v)
{
end_ffmpeg_impl(false);
FFMpegContext *context = context_v;
end_ffmpeg_impl(context, false);
}
/* properties */
@ -1658,4 +1675,31 @@ bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd)
return false;
}
#endif
void *BKE_ffmpeg_context_create(void)
{
FFMpegContext *context;
/* new ffmpeg data struct */
context = MEM_callocN(sizeof(FFMpegContext), "new ffmpeg context");
context->ffmpeg_codec = AV_CODEC_ID_MPEG4;
context->ffmpeg_audio_codec = AV_CODEC_ID_NONE;
context->ffmpeg_video_bitrate = 1150;
context->ffmpeg_audio_bitrate = 128;
context->ffmpeg_gop_size = 12;
context->ffmpeg_autosplit = 0;
context->ffmpeg_autosplit_count = 0;
context->ffmpeg_preview = false;
return context;
}
void BKE_ffmpeg_context_free(void *context_v)
{
FFMpegContext *context = context_v;
if (context) {
MEM_freeN(context);
}
}
#endif /* WITH_FFMPEG */

@ -66,12 +66,15 @@
#include "BKE_report.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
static int sock;
static int connsock;
static int write_ppm;
static int render_width;
static int render_height;
typedef struct FrameserverContext {
int sock;
int connsock;
int write_ppm;
int render_width;
int render_height;
} FrameserverContext;
#if defined(_WIN32)
@ -110,10 +113,11 @@ static int closesocket(int fd)
}
#endif
int BKE_frameserver_start(struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports, bool UNUSED(preview))
int BKE_frameserver_start(void *context_v, struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports, bool UNUSED(preview), const char *UNUSED(suffix))
{
struct sockaddr_in addr;
int arg = 1;
FrameserverContext *context = context_v;
(void)scene; /* unused */
@ -122,33 +126,33 @@ int BKE_frameserver_start(struct Scene *scene, RenderData *UNUSED(rd), int rectx
return 0;
}
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
if ((context->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot open socket");
return 0;
}
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
setsockopt(context->sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
addr.sin_family = AF_INET;
addr.sin_port = htons(U.frameserverport);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
if (bind(context->sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot bind to socket");
return 0;
}
if (listen(sock, SOMAXCONN) < 0) {
if (listen(context->sock, SOMAXCONN) < 0) {
shutdown_socket_system();
BKE_report(reports, RPT_ERROR, "Cannot establish listen backlog");
return 0;
}
connsock = -1;
context->connsock = -1;
render_width = rectx;
render_height = recty;
context->render_width = rectx;
context->render_height = recty;
return 1;
}
@ -177,7 +181,7 @@ static char good_bye[] =
"<body><pre>\n"
"Render stopped. Goodbye</pre></body></html>";
static int safe_write(char *s, int tosend)
static int safe_write(const int connsock, char *s, int tosend)
{
int total = tosend;
do {
@ -192,12 +196,12 @@ static int safe_write(char *s, int tosend)
return total;
}
static int safe_puts(char *s)
static int safe_puts(const int connsock, char *s)
{
return safe_write(s, strlen(s));
return safe_write(connsock, s, strlen(s));
}
static int handle_request(RenderData *rd, char *req)
static int handle_request(FrameserverContext *context, RenderData *rd, char *req)
{
char *p;
char *path;
@ -214,16 +218,16 @@ static int handle_request(RenderData *rd, char *req)
*p = 0;
if (STREQ(path, "/index.html") || STREQ(path, "/")) {
safe_puts(index_page);
if (STREQ(path, "/index.html") || strcmp(path, "/")) {
safe_puts(context->connsock, index_page);
return -1;
}
write_ppm = 0;
context->write_ppm = 0;
pathlen = strlen(path);
if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) {
write_ppm = 1;
context->write_ppm = 1;
return atoi(path + 12);
}
if (STREQ(path, "/info.txt")) {
@ -241,24 +245,24 @@ static int handle_request(RenderData *rd, char *req)
"ratescale %d\n",
rd->sfra,
rd->efra,
render_width,
render_height,
context->render_width,
context->render_height,
rd->frs_sec,
1
);
safe_puts(buf);
safe_puts(context->connsock, buf);
return -1;
}
if (STREQ(path, "/close.txt")) {
safe_puts(good_bye);
safe_puts(context->connsock, good_bye);
G.is_break = true; /* Abort render */
return -1;
}
return -1;
}
int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
int BKE_frameserver_loop(void *context_v, RenderData *rd, ReportList *UNUSED(reports))
{
fd_set readfds;
struct timeval tv;
@ -271,18 +275,20 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
#endif
char buf[4096];
if (connsock != -1) {
closesocket(connsock);
connsock = -1;
FrameserverContext *context = context_v;
if (context->connsock != -1) {
closesocket(context->connsock);
context->connsock = -1;
}
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
FD_SET(context->sock, &readfds);
rval = select(sock + 1, &readfds, NULL, NULL, &tv);
rval = select(context->sock + 1, &readfds, NULL, NULL, &tv);
if (rval < 0) {
return -1;
}
@ -293,19 +299,19 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
socklen = sizeof(addr);
if ((connsock = accept(sock, (struct sockaddr *)&addr, &socklen)) < 0) {
if ((context->connsock = accept(context->sock, (struct sockaddr *)&addr, &socklen)) < 0) {
return -1;
}
FD_ZERO(&readfds);
FD_SET(connsock, &readfds);
FD_SET(context->connsock, &readfds);
for (;;) {
/* give 10 seconds for telnet testing... */
tv.tv_sec = 10;
tv.tv_usec = 0;
rval = select(connsock + 1, &readfds, NULL, NULL, &tv);
rval = select(context->connsock + 1, &readfds, NULL, NULL, &tv);
if (rval > 0) {
break;
}
@ -319,7 +325,7 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
}
}
len = recv(connsock, buf, sizeof(buf) - 1, 0);
len = recv(context->connsock, buf, sizeof(buf) - 1, 0);
if (len < 0) {
return -1;
@ -327,13 +333,13 @@ int BKE_frameserver_loop(RenderData *rd, ReportList *UNUSED(reports))
buf[len] = 0;
return handle_request(rd, buf);
return handle_request(context, rd, buf);
}
static void serve_ppm(int *pixels, int rectx, int recty)
static void serve_ppm(FrameserverContext *context, int *pixels, int rectx, int recty)
{
unsigned char *rendered_frame;
unsigned char *row = (unsigned char *) malloc(render_width * 3);
unsigned char *row = (unsigned char *) malloc(context->render_width * 3);
int y;
char header[1024];
@ -348,7 +354,7 @@ static void serve_ppm(int *pixels, int rectx, int recty)
"255\n",
rectx, recty);
safe_puts(header);
safe_puts(context->connsock, header);
rendered_frame = (unsigned char *)pixels;
@ -364,36 +370,54 @@ static void serve_ppm(int *pixels, int rectx, int recty)
target += 3;
src += 4;
}
safe_write((char *)row, 3 * rectx);
safe_write(context->connsock, (char *)row, 3 * rectx);
}
free(row);
closesocket(connsock);
connsock = -1;
closesocket(context->connsock);
context->connsock = -1;
}
int BKE_frameserver_append(RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels,
int rectx, int recty, ReportList *UNUSED(reports))
int BKE_frameserver_append(void *context_v, RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels,
int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
{
FrameserverContext *context = context_v;
fprintf(stderr, "Serving frame: %d\n", frame);
if (write_ppm) {
serve_ppm(pixels, rectx, recty);
if (context->write_ppm) {
serve_ppm(context, pixels, rectx, recty);
}
if (connsock != -1) {
closesocket(connsock);
connsock = -1;
if (context->connsock != -1) {
closesocket(context->connsock);
context->connsock = -1;
}
return 1;
}
void BKE_frameserver_end(void)
void BKE_frameserver_end(void *context_v)
{
if (connsock != -1) {
closesocket(connsock);
connsock = -1;
FrameserverContext *context = context_v;
if (context->connsock != -1) {
closesocket(context->connsock);
context->connsock = -1;
}
closesocket(sock);
closesocket(context->sock);
shutdown_socket_system();
}
void *BKE_frameserver_context_create(void)
{
FrameserverContext *context = MEM_mallocN(sizeof(FrameserverContext), "Frameserver Context");
return context;
}
void BKE_frameserver_context_free(void *context_v)
{
FrameserverContext *context = context_v;
if (context) {
MEM_freeN(context);
}
}
#endif /* WITH_FRAMESERVER */

@ -89,6 +89,7 @@ int BLI_system_num_threads_override_get(void);
#define LOCK_MOVIECLIP 7
#define LOCK_COLORMANAGE 8
#define LOCK_FFTW 9
#define LOCK_VIEW3D 10
void BLI_lock_thread(int type);
void BLI_unlock_thread(int type);

@ -122,6 +122,7 @@ static pthread_mutex_t _nodes_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _movieclip_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _colormanage_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _fftw_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _view3d_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t mainid;
static int thread_levels = 0; /* threads can be invoked inside threads */
static int num_threads_override = 0;
@ -402,6 +403,8 @@ void BLI_lock_thread(int type)
pthread_mutex_lock(&_colormanage_lock);
else if (type == LOCK_FFTW)
pthread_mutex_lock(&_fftw_lock);
else if (type == LOCK_VIEW3D)
pthread_mutex_lock(&_view3d_lock);
}
void BLI_unlock_thread(int type)
@ -426,6 +429,8 @@ void BLI_unlock_thread(int type)
pthread_mutex_unlock(&_colormanage_lock);
else if (type == LOCK_FFTW)
pthread_mutex_unlock(&_fftw_lock);
else if (type == LOCK_VIEW3D)
pthread_mutex_unlock(&_view3d_lock);
}
/* Mutex Locks */

@ -1533,9 +1533,15 @@ void blo_make_packed_pointer_map(FileData *fd, Main *oldmain)
fd->packedmap = oldnewmap_new();
for (ima = oldmain->image.first; ima; ima = ima->id.next)
for (ima = oldmain->image.first; ima; ima = ima->id.next) {
ImagePackedFile *imapf;
if (ima->packedfile)
insert_packedmap(fd, ima->packedfile);
for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next)
if (imapf->packedfile)
insert_packedmap(fd, imapf->packedfile);
}
for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next)
if (vfont->packedfile)
@ -1568,8 +1574,13 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
entry->newp = NULL;
}
for (ima = oldmain->image.first; ima; ima = ima->id.next)
for (ima = oldmain->image.first; ima; ima = ima->id.next) {
ImagePackedFile *imapf;
ima->packedfile = newpackedadr(fd, ima->packedfile);
for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next)
imapf->packedfile = newpackedadr(fd, imapf->packedfile);
}
for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next)
vfont->packedfile = newpackedadr(fd, vfont->packedfile);
@ -3391,6 +3402,8 @@ static void lib_link_image(FileData *fd, Main *main)
static void direct_link_image(FileData *fd, Image *ima)
{
ImagePackedFile *imapf;
/* for undo system, pointers could be restored */
if (fd->imamap)
ima->cache = newimaadr(fd, ima->cache);
@ -3404,8 +3417,7 @@ static void direct_link_image(FileData *fd, Image *ima)
ima->gputexture = NULL;
ima->rr = NULL;
}
ima->anim = NULL;
ima->repbind = NULL;
/* undo system, try to restore render buffers */
@ -3419,9 +3431,18 @@ static void direct_link_image(FileData *fd, Image *ima)
memset(ima->renders, 0, sizeof(ima->renders));
ima->last_render_slot = ima->render_slot;
}
link_list(fd, &(ima->views));
link_list(fd, &(ima->packedfiles));
for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
imapf->packedfile = direct_link_packedfile(fd, imapf->packedfile);
}
ima->anims.first = ima->anims.last = NULL;
ima->packedfile = direct_link_packedfile(fd, ima->packedfile);
ima->preview = direct_link_preview_image(fd, ima->preview);
ima->stereo3d_format = newdataadr(fd, ima->stereo3d_format);
ima->ok = 1;
}
@ -5378,7 +5399,7 @@ static void lib_link_scene(FileData *fd, Main *main)
seq->scene_sound = BKE_sound_add_scene_sound_defaults(sce, seq);
}
}
seq->anim = NULL;
seq->anims.first = seq->anims.last = NULL;
lib_link_sequence_modifiers(fd, sce, &seq->modifiers);
}
@ -5610,6 +5631,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
if (seq->seq3 == NULL) seq->seq3 = seq->seq2;
seq->effectdata = newdataadr(fd, seq->effectdata);
seq->stereo3d_format = newdataadr(fd, seq->stereo3d_format);
if (seq->type & SEQ_TYPE_EFFECT)
seq->flag |= SEQ_EFFECT_NOT_LOADED;
@ -5722,6 +5744,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
link_list(fd, &(sce->markers));
link_list(fd, &(sce->transform_spaces));
link_list(fd, &(sce->r.layers));
link_list(fd, &(sce->r.views));
for (srl = sce->r.layers.first; srl; srl = srl->next) {
link_list(fd, &(srl->freestyleConfig.modules));
@ -5785,8 +5808,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
BLI_listbase_clear(&win->modalhandlers);
BLI_listbase_clear(&win->subwindows);
BLI_listbase_clear(&win->gesture);
BLI_listbase_clear(&win->drawdata);
win->drawdata = NULL;
win->drawmethod = -1;
win->drawfail = 0;
win->active = 0;
@ -5794,6 +5817,7 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
win->cursor = 0;
win->lastcursor = 0;
win->modalcursor = 0;
win->stereo3d_format = newdataadr(fd, win->stereo3d_format);
}
BLI_listbase_clear(&wm->timers);
@ -7765,7 +7789,6 @@ static void do_versions_userdef(FileData *fd, BlendFileData *bfd)
user->walk_navigation.jump_height = 0.4f; /* m */
user->walk_navigation.teleport_time = 0.2f; /* s */
}
}
static void do_versions(FileData *fd, Library *lib, Main *main)
@ -7888,7 +7911,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
link_list(fd, &user->user_keymaps);
link_list(fd, &user->addons);
link_list(fd, &user->autoexec_paths);
for (keymap=user->user_keymaps.first; keymap; keymap=keymap->next) {
keymap->modal_items= NULL;
keymap->poll = NULL;

@ -27,6 +27,7 @@
#include "BLI_utildefines.h"
#include "BLI_compiler_attrs.h"
#include "BLI_string.h"
/* for MinGW32 definition of NULL, could use BLI_blenlib.h instead too */
#include <stddef.h>
@ -48,14 +49,18 @@
#include "DNA_particle_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_actuator_types.h"
#include "DNA_camera_types.h"
#include "DNA_view3d_types.h"
#include "DNA_genfile.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@ -460,10 +465,10 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
br->mtex.random_angle = 2.0 * M_PI;
br->mask_mtex.random_angle = 2.0 * M_PI;
}
}
#undef BRUSH_RAKE
#undef BRUSH_RANDOM_ROTATION
}
/* Customizable Safe Areas */
if (!MAIN_VERSION_ATLEAST(main, 273, 2)) {
@ -724,4 +729,85 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
#undef SEQ_USE_PROXY_CUSTOM_DIR
#undef SEQ_USE_PROXY_CUSTOM_FILE
}
if (!MAIN_VERSION_ATLEAST(main, 274, 3))
{
SceneRenderView *srv;
wmWindowManager *wm;
bScreen *screen;
wmWindow *win;
Scene *scene;
Camera *cam;
Image *ima;
for (scene = main->scene.first; scene; scene = scene->id.next) {
Sequence *seq;
BKE_scene_add_render_view(scene, STEREO_LEFT_NAME);
srv = scene->r.views.first;
BLI_strncpy(srv->suffix, STEREO_LEFT_SUFFIX, sizeof(srv->suffix));
BKE_scene_add_render_view(scene, STEREO_RIGHT_NAME);
srv = scene->r.views.last;
BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
SEQ_BEGIN (scene->ed, seq)
{
seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo Display 3d Format");
}
SEQ_END
}
for (screen = main->screen.first; screen; screen = screen->id.next) {
ScrArea *sa;
for (sa = screen->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
for (sl = sa->spacedata.first; sl; sl = sl->next) {
switch (sl->spacetype) {
case SPACE_VIEW3D:
{
View3D *v3d = (View3D *)sl;
v3d->stereo3d_camera = STEREO_3D_ID;
v3d->stereo3d_flag |= V3D_S3D_DISPPLANE;
v3d->stereo3d_convergence_alpha = 0.15f;
v3d->stereo3d_volume_alpha = 0.05f;
break;
}
case SPACE_IMAGE:
{
SpaceImage *sima = (SpaceImage *) sl;
sima->iuser.flag |= IMA_SHOW_STEREO;
sima->iuser.passtype = SCE_PASS_COMBINED;
break;
}
}
}
}
}
for (cam = main->camera.first; cam; cam = cam->id.next) {
cam->stereo.interocular_distance = 0.065;
cam->stereo.convergence_distance = 30.f * 0.065;
}
for (ima = main->image.first; ima; ima = ima->id.next) {
ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo 3d Format");
if (ima->packedfile) {
ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packed File");
BLI_addtail(&ima->packedfiles, imapf);
imapf->packedfile = ima->packedfile;
BLI_strncpy(imapf->filepath, ima->name, FILE_MAX);
ima->packedfile = NULL;
}
}
for (wm = main->wm.first; wm; wm = wm->id.next) {
for (win = wm->windows.first; win; win = win->next) {
win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo Display 3d Format");
}
}
}
}

@ -2124,7 +2124,8 @@ static void write_images(WriteData *wd, ListBase *idbase)
{
Image *ima;
PackedFile * pf;
ImageView *iv;
ImagePackedFile *imapf;
ima= idbase->first;
while (ima) {
@ -2133,13 +2134,20 @@ static void write_images(WriteData *wd, ListBase *idbase)
writestruct(wd, ID_IM, "Image", 1, ima);
if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd);
if (ima->packedfile) {
pf = ima->packedfile;
writestruct(wd, DATA, "PackedFile", 1, pf);
writedata(wd, DATA, pf->size, pf->data);
for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
writestruct(wd, DATA, "ImagePackedFile", 1, imapf);
if (imapf->packedfile) {
pf = imapf->packedfile;
writestruct(wd, DATA, "PackedFile", 1, pf);
writedata(wd, DATA, pf->size, pf->data);
}
}
write_previews(wd, ima->preview);
for (iv = ima->views.first; iv; iv = iv->next)
writestruct(wd, DATA, "ImageView", 1, iv);
writestruct(wd, DATA, "Stereo3dFormat", 1, ima->stereo3d_format);
}
ima= ima->id.next;
}
@ -2340,6 +2348,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
TimeMarker *marker;
TransformOrientation *ts;
SceneRenderLayer *srl;
SceneRenderView *srv;
ToolSettings *tos;
FreestyleModuleConfig *fmc;
FreestyleLineSet *fls;
@ -2421,7 +2430,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
break;
}
}
writestruct(wd, DATA, "Stereo3dFormat", 1, seq->stereo3d_format);
strip= seq->strip;
writestruct(wd, DATA, "Strip", 1, strip);
if (seq->flag & SEQ_USE_CROP && strip->crop) {
@ -2486,6 +2497,10 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
writestruct(wd, DATA, "FreestyleLineSet", 1, fls);
}
}
/* writing MultiView to the blend file */
for (srv = sce->r.views.first; srv; srv = srv->next)
writestruct(wd, DATA, "SceneRenderView", 1, srv);
if (sce->nodetree) {
writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree);
@ -2548,8 +2563,10 @@ static void write_windowmanagers(WriteData *wd, ListBase *lb)
for (wm= lb->first; wm; wm= wm->id.next) {
writestruct(wd, ID_WM, "wmWindowManager", 1, wm);
for (win= wm->windows.first; win; win= win->next)
for (win= wm->windows.first; win; win= win->next) {
writestruct(wd, DATA, "wmWindow", 1, win);
writestruct(wd, DATA, "Stereo3dFormat", 1, win->stereo3d_format);
}
}
}

@ -74,7 +74,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
short image_source = image->source;
bool is_generated = image_source == IMA_SRC_GENERATED;
bool is_packed = image->packedfile != NULL;
bool is_packed = BKE_image_has_packedfile(image);
char export_path[FILE_MAX];
char source_path[FILE_MAX];

@ -119,6 +119,8 @@ set(SRC
nodes/COM_TimeNode.h
nodes/COM_SwitchNode.cpp
nodes/COM_SwitchNode.h
nodes/COM_SwitchViewNode.cpp
nodes/COM_SwitchViewNode.h
nodes/COM_MovieClipNode.cpp
nodes/COM_MovieClipNode.h
nodes/COM_OutputFileNode.cpp
@ -370,6 +372,8 @@ set(SRC
operations/COM_CompositorOperation.cpp
operations/COM_OutputFileOperation.h
operations/COM_OutputFileOperation.cpp
operations/COM_OutputFileMultiViewOperation.h
operations/COM_OutputFileMultiViewOperation.cpp
operations/COM_ViewerOperation.h
operations/COM_ViewerOperation.cpp
operations/COM_PreviewOperation.h

@ -316,7 +316,8 @@ extern "C" {
* generation in display space
*/
void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering,
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
const char *viewName);
/**
* @brief Deinitialize the compositor caches and allocated memory.

@ -87,6 +87,11 @@ private:
const ColorManagedViewSettings *m_viewSettings;
const ColorManagedDisplaySettings *m_displaySettings;
/**
* @brief active rendering view name
*/
const char *m_viewName;
public:
/**
* @brief constructor initializes the context with default values.
@ -180,7 +185,17 @@ public:
* @brief set has this system active openclDevices?
*/
void setHasActiveOpenCLDevices(bool hasAvtiveOpenCLDevices) { this->m_hasActiveOpenCLDevices = hasAvtiveOpenCLDevices; }
/**
* @brief get the active rendering view
*/
const char *getViewName() const { return this->m_viewName; }
/**
* @brief set the active rendering view
*/
void setViewName(const char *viewName) { this->m_viewName = viewName; }
int getChunksize() const { return this->getbNodeTree()->chunksize; }
void setFastCalculation(bool fastCalculation) {this->m_fastCalculation = fastCalculation;}

@ -101,6 +101,7 @@ extern "C" {
#include "COM_Stabilize2dNode.h"
#include "COM_SunBeamsNode.h"
#include "COM_SwitchNode.h"
#include "COM_SwitchViewNode.h"
#include "COM_TextureNode.h"
#include "COM_TimeNode.h"
#include "COM_TonemapNode.h"
@ -328,6 +329,9 @@ Node *Converter::convert(bNode *b_node)
case CMP_NODE_SWITCH:
node = new SwitchNode(b_node);
break;
case CMP_NODE_SWITCH_VIEW:
node = new SwitchViewNode(b_node);
break;
case CMP_NODE_GLARE:
node = new GlareNode(b_node);
break;

@ -43,8 +43,10 @@ extern "C" {
#endif
ExecutionSystem::ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editingtree, bool rendering, bool fastcalculation,
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings)
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
const char *viewName)
{
this->m_context.setViewName(viewName);
this->m_context.setScene(scene);
this->m_context.setbNodeTree(editingtree);
this->m_context.setPreviewHash(editingtree->previews);

@ -151,7 +151,8 @@ public:
* @param rendering [true false]
*/
ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editingtree, bool rendering, bool fastcalculation,
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
const char *viewName);
/**
* Destructor

@ -45,7 +45,8 @@ static void intern_freeCompositorCaches()
void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering,
const ColorManagedViewSettings *viewSettings,
const ColorManagedDisplaySettings *displaySettings)
const ColorManagedDisplaySettings *displaySettings,
const char *viewName)
{
/* initialize mutex, TODO this mutex init is actually not thread safe and
* should be done somewhere as part of blender startup, all the other
@ -82,7 +83,7 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende
bool twopass = (editingtree->flag & NTREE_TWO_PASS) > 0 && !rendering;
/* initialize execution system */
if (twopass) {
ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, twopass, viewSettings, displaySettings);
ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, twopass, viewSettings, displaySettings, viewName);
system->execute();
delete system;
@ -95,7 +96,7 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende
}
ExecutionSystem *system = new ExecutionSystem(rd, scene, editingtree, rendering, false,
viewSettings, displaySettings);
viewSettings, displaySettings, viewName);
system->execute();
delete system;

@ -43,6 +43,7 @@ void CompositorNode::convertToOperations(NodeConverter &converter, const Composi
CompositorOperation *compositorOperation = new CompositorOperation();
compositorOperation->setSceneName(context.getScene()->id.name);
compositorOperation->setRenderData(context.getRenderData());
compositorOperation->setViewName(context.getViewName());
compositorOperation->setbNodeTree(context.getbNodeTree());
/* alpha socket gives either 1 or a custom alpha value if "use alpha" is enabled */
compositorOperation->setUseAlphaInput(ignore_alpha || alphaSocket->isLinked());

@ -40,19 +40,19 @@ ImageNode::ImageNode(bNode *editorNode) : Node(editorNode)
}
NodeOperation *ImageNode::doMultilayerCheck(NodeConverter &converter, RenderLayer *rl, Image *image, ImageUser *user,
int framenumber, int outputsocketIndex, int passindex, DataType datatype) const
int framenumber, int outputsocketIndex, int passtype, int view, DataType datatype) const
{
NodeOutput *outputSocket = this->getOutputSocket(outputsocketIndex);
MultilayerBaseOperation *operation = NULL;
switch (datatype) {
case COM_DT_VALUE:
operation = new MultilayerValueOperation(passindex);
operation = new MultilayerValueOperation(passtype, view);
break;
case COM_DT_VECTOR:
operation = new MultilayerVectorOperation(passindex);
operation = new MultilayerVectorOperation(passtype, view);
break;
case COM_DT_COLOR:
operation = new MultilayerColorOperation(passindex);
operation = new MultilayerColorOperation(passtype, view);
break;
default:
break;
@ -96,6 +96,10 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
NodeOperation *operation = NULL;
socket = this->getOutputSocket(index);
bNodeSocket *bnodeSocket = socket->getbNodeSocket();
RenderPass *rpass = (RenderPass *)BLI_findstring(&rl->passes, bnodeSocket->identifier, offsetof(RenderPass, internal_name));
int view = (rpass ? rpass->view_id : 0);
/* Passes in the file can differ from passes stored in sockets (#36755).
* Look up the correct file pass using the socket identifier instead.
*/
@ -104,8 +108,22 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
int passindex = storage->pass_index;*/
RenderPass *rpass = (RenderPass *)BLI_findlink(&rl->passes, passindex);
#endif
int passindex;
RenderPass *rpass;
/* returns the image view to use for the current active view */
if (BLI_listbase_count_ex(&image->rr->views, 2) > 1) {
const int view_image = imageuser->view;
const bool is_allview = (view_image == 0); /* if view selected == All (0) */
if (is_allview) {
/* heuristic to match image name with scene names
* check if the view name exists in the image */
view = BLI_findstringindex(&image->rr->views, context.getViewName(), offsetof(RenderView, name));
}
else {
view = view_image - 1;
}
}
if (STREQ(bnodeSocket->identifier, "Alpha")) {
BLI_assert(combined_operation != NULL);
NodeOutput *outputSocket = this->getOutputSocket(index);
@ -118,22 +136,21 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
operation = separate_operation;
}
else {
for (rpass = (RenderPass *)rl->passes.first, passindex = 0; rpass; rpass = rpass->next, ++passindex)
if (STREQ(rpass->name, bnodeSocket->identifier))
break;
if (rpass) {
imageuser->pass = passindex;
switch (rpass->channels) {
case 1:
operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_VALUE);
operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index,
rpass->passtype, view, COM_DT_VALUE);
break;
/* using image operations for both 3 and 4 channels (RGB and RGBA respectively) */
/* XXX any way to detect actual vector images? */
case 3:
operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_VECTOR);
operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index,
rpass->passtype, view, COM_DT_VECTOR);
break;
case 4:
operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index, passindex, COM_DT_COLOR);
operation = doMultilayerCheck(converter, rl, image, imageuser, framenumber, index,
rpass->passtype, view, COM_DT_COLOR);
break;
default:
/* dummy operation is added below */
@ -168,6 +185,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
operation->setImage(image);
operation->setImageUser(imageuser);
operation->setFramenumber(framenumber);
operation->setRenderData(context.getRenderData());
operation->setViewName(context.getViewName());
converter.addOperation(operation);
if (outputStraightAlpha) {
@ -190,6 +209,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
alphaOperation->setImage(image);
alphaOperation->setImageUser(imageuser);
alphaOperation->setFramenumber(framenumber);
alphaOperation->setRenderData(context.getRenderData());
alphaOperation->setViewName(context.getViewName());
converter.addOperation(alphaOperation);
converter.mapOutputSocket(alphaImage, alphaOperation->getOutputSocket());
@ -200,6 +221,8 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
depthOperation->setImage(image);
depthOperation->setImageUser(imageuser);
depthOperation->setFramenumber(framenumber);
depthOperation->setRenderData(context.getRenderData());
depthOperation->setViewName(context.getViewName());
converter.addOperation(depthOperation);
converter.mapOutputSocket(depthImage, depthOperation->getOutputSocket());
@ -239,6 +262,7 @@ void ImageNode::convertToOperations(NodeConverter &converter, const CompositorCo
}
if (operation) {
/* not supporting multiview for this generic case */
converter.addOperation(operation);
converter.mapOutputSocket(output, operation->getOutputSocket());
}

@ -36,7 +36,7 @@ extern "C" {
class ImageNode : public Node {
private:
NodeOperation *doMultilayerCheck(NodeConverter &converter, RenderLayer *rl, Image *image, ImageUser *user,
int framenumber, int outputsocketIndex, int passindex, DataType datatype) const;
int framenumber, int outputsocketIndex, int passtype, int view, DataType datatype) const;
public:
ImageNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;

@ -23,8 +23,11 @@
#include "COM_OutputFileNode.h"
#include "COM_OutputFileOperation.h"
#include "COM_OutputFileMultiViewOperation.h"
#include "COM_ExecutionSystem.h"
#include "BKE_scene.h"
#include "BLI_path_util.h"
OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode)
@ -35,6 +38,7 @@ OutputFileNode::OutputFileNode(bNode *editorNode) : Node(editorNode)
void OutputFileNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
NodeImageMultiFile *storage = (NodeImageMultiFile *)this->getbNode()->storage;
const bool is_multiview = (context.getRenderData()->scemode & R_MULTIVIEW) != 0;
if (!context.isRendering()) {
/* only output files when rendering a sequence -
@ -46,10 +50,18 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, const Composi
if (storage->format.imtype == R_IMF_IMTYPE_MULTILAYER) {
/* single output operation for the multilayer file */
OutputOpenExrMultiLayerOperation *outputOperation = new OutputOpenExrMultiLayerOperation(
context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec);
OutputOpenExrMultiLayerOperation *outputOperation;
if (is_multiview && storage->format.views_format == R_IMF_VIEWS_MULTIVIEW) {
outputOperation = new OutputOpenExrMultiLayerMultiViewOperation(
context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec, context.getViewName());
}
else {
outputOperation = new OutputOpenExrMultiLayerOperation(
context.getRenderData(), context.getbNodeTree(), storage->base_path, storage->format.exr_codec, context.getViewName());
}
converter.addOperation(outputOperation);
int num_inputs = getNumberOfInputSockets();
bool previewAdded = false;
for (int i = 0; i < num_inputs; ++i) {
@ -76,17 +88,31 @@ void OutputFileNode::convertToOperations(NodeConverter &converter, const Composi
NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)input->getbNodeSocket()->storage;
ImageFormatData *format = (sockdata->use_node_format ? &storage->format : &sockdata->format);
char path[FILE_MAX];
/* combine file path for the input */
BLI_join_dirfile(path, FILE_MAX, storage->base_path, sockdata->path);
OutputSingleLayerOperation *outputOperation = new OutputSingleLayerOperation(
context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
context.getViewSettings(), context.getDisplaySettings());
NodeOperation *outputOperation = NULL;
if (is_multiview && format->views_format == R_IMF_VIEWS_MULTIVIEW) {
outputOperation = new OutputOpenExrSingleLayerMultiViewOperation(
context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
context.getViewSettings(), context.getDisplaySettings(), context.getViewName());
}
else if ((!is_multiview) || (format->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
outputOperation = new OutputSingleLayerOperation(
context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
context.getViewSettings(), context.getDisplaySettings(), context.getViewName());
}
else { /* R_IMF_VIEWS_STEREO_3D */
outputOperation = new OutputStereoOperation(
context.getRenderData(), context.getbNodeTree(), input->getDataType(), format, path,
sockdata->layer, context.getViewSettings(), context.getDisplaySettings(), context.getViewName());
}
converter.addOperation(outputOperation);
converter.mapInputSocket(input, outputOperation->getInputSocket(0));
if (!previewAdded) {
converter.addNodeInputPreview(input);
previewAdded = true;

@ -42,7 +42,8 @@ void RenderLayersNode::testSocketLink(NodeConverter &converter, const Compositor
operation->setScene(scene);
operation->setLayerId(layerId);
operation->setRenderData(context.getRenderData());
operation->setViewName(context.getViewName());
converter.mapOutputSocket(outputSocket, operation->getOutputSocket());
converter.addOperation(operation);

@ -22,6 +22,8 @@
#include "COM_SplitViewerNode.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_scene.h"
#include "COM_SplitOperation.h"
#include "COM_ViewerOperation.h"
@ -55,6 +57,8 @@ void SplitViewerNode::convertToOperations(NodeConverter &converter, const Compos
viewerOperation->setImageUser(imageUser);
viewerOperation->setViewSettings(context.getViewSettings());
viewerOperation->setDisplaySettings(context.getDisplaySettings());
viewerOperation->setRenderData(context.getRenderData());
viewerOperation->setViewName(context.getViewName());
/* defaults - the viewer node has these options but not exposed for split view
* we could use the split to define an area of interest on one axis at least */

@ -0,0 +1,42 @@
/*
* Copyright 2015, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor:
* Dalai Felinto
*/
#include "COM_SwitchViewNode.h"
#include "BLI_listbase.h"
SwitchViewNode::SwitchViewNode(bNode *editorNode) : Node(editorNode)
{
/* pass */
}
void SwitchViewNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
NodeOperationOutput *result;
const char *viewName = context.getViewName();
bNode *bnode = this->getbNode();
/* get the internal index of the socket with a matching name */
int nr = BLI_findstringindex(&bnode->inputs, viewName, offsetof(bNodeSocket, name));
nr = max(nr, 0);
result = converter.addInputProxy(getInputSocket(nr), false);
converter.mapOutputSocket(getOutputSocket(0), result);
}

@ -0,0 +1,37 @@
/*
* Copyright 2015, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor:
* Dalai Felinto
*/
#ifndef _COM_SwitchViewNode_h_
#define _COM_SwitchViewNode_h_
#include "COM_Node.h"
#include "COM_NodeOperation.h"
#include "DNA_node_types.h"
/**
* @brief SwitchViewNode
* @ingroup Node
*/
class SwitchViewNode : public Node {
public:
SwitchViewNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
};
#endif

@ -22,6 +22,9 @@
#include "COM_ViewerNode.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BLI_listbase.h"
#include "BKE_scene.h"
#include "COM_ViewerOperation.h"
#include "COM_ExecutionSystem.h"
@ -51,6 +54,8 @@ void ViewerNode::convertToOperations(NodeConverter &converter, const CompositorC
viewerOperation->setCenterY(editorNode->custom4);
/* alpha socket gives either 1 or a custom alpha value if "use alpha" is enabled */
viewerOperation->setUseAlphaInput(ignore_alpha || alphaSocket->isLinked());
viewerOperation->setRenderData(context.getRenderData());
viewerOperation->setViewName(context.getViewName());
viewerOperation->setViewSettings(context.getViewSettings());
viewerOperation->setDisplaySettings(context.getDisplaySettings());

@ -52,6 +52,7 @@ CompositorOperation::CompositorOperation() : NodeOperation()
this->m_active = false;
this->m_sceneName[0] = '\0';
this->m_viewName = NULL;
}
void CompositorOperation::initExecution()
@ -81,14 +82,16 @@ void CompositorOperation::deinitExecution()
RenderResult *rr = RE_AcquireResultWrite(re);
if (rr) {
if (rr->rectf != NULL) {
MEM_freeN(rr->rectf);
RenderView *rv = (RenderView *)BLI_findstring(&rr->views, this->m_viewName, offsetof(RenderView, name));
if (rv->rectf != NULL) {
MEM_freeN(rv->rectf);
}
rr->rectf = this->m_outputBuffer;
if (rr->rectz != NULL) {
MEM_freeN(rr->rectz);
rv->rectf = this->m_outputBuffer;
if (rv->rectz != NULL) {
MEM_freeN(rv->rectz);
}
rr->rectz = this->m_depthBuffer;
rv->rectz = this->m_depthBuffer;
}
else {
if (this->m_outputBuffer) {

@ -75,11 +75,17 @@ private:
* @brief operation is active for calculating final compo result
*/
bool m_active;
/**
* @brief View name, used for multiview
*/
const char *m_viewName;
public:
CompositorOperation();
const bool isActiveCompositorOutput() const { return this->m_active; }
void executeRegion(rcti *rect, unsigned int tileNumber);
void setSceneName(const char *sceneName) { BLI_strncpy(this->m_sceneName, sceneName, sizeof(this->m_sceneName)); }
void setViewName(const char *viewName) { this->m_viewName = viewName; }
void setRenderData(const RenderData *rd) { this->m_rd = rd; }
bool isOutputOperation(bool /*rendering*/) const { return this->isActiveCompositorOutput(); }
void initExecution();

@ -25,6 +25,7 @@
#include "BLI_listbase.h"
#include "DNA_image_types.h"
#include "BKE_image.h"
#include "BKE_scene.h"
#include "BLI_math.h"
extern "C" {
@ -48,6 +49,8 @@ BaseImageOperation::BaseImageOperation() : NodeOperation()
this->m_framenumber = 0;
this->m_depthBuffer = NULL;
this->m_numberOfChannels = 0;
this->m_rd = NULL;
this->m_viewName = NULL;
}
ImageOperation::ImageOperation() : BaseImageOperation()
{
@ -65,8 +68,12 @@ ImageDepthOperation::ImageDepthOperation() : BaseImageOperation()
ImBuf *BaseImageOperation::getImBuf()
{
ImBuf *ibuf;
ibuf = BKE_image_acquire_ibuf(this->m_image, this->m_imageUser, NULL);
ImageUser iuser = *this->m_imageUser;
/* local changes to the original ImageUser */
iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName);
ibuf = BKE_image_acquire_ibuf(this->m_image, &iuser, NULL);
if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
BKE_image_release_ibuf(this->m_image, ibuf, NULL);
return NULL;

@ -49,7 +49,9 @@ protected:
int m_imagewidth;
int m_framenumber;
int m_numberOfChannels;
const RenderData *m_rd;
const char *m_viewName;
BaseImageOperation();
/**
* Determine the output resolution. The resolution is retrieved from the Renderer
@ -64,7 +66,8 @@ public:
void deinitExecution();
void setImage(Image *image) { this->m_image = image; }
void setImageUser(ImageUser *imageuser) { this->m_imageUser = imageuser; }
void setRenderData(const RenderData *rd) { this->m_rd = rd; }
void setViewName(const char *viewName) { this->m_viewName = viewName; }
void setFramenumber(int framenumber) { this->m_framenumber = framenumber; }
};
class ImageOperation : public BaseImageOperation {

@ -27,18 +27,27 @@ extern "C" {
# include "IMB_imbuf_types.h"
}
MultilayerBaseOperation::MultilayerBaseOperation(int passindex) : BaseImageOperation()
MultilayerBaseOperation::MultilayerBaseOperation(int passtype, int view) : BaseImageOperation()
{
this->m_passId = passindex;
this->m_passtype = passtype;
this->m_view = view;
}
ImBuf *MultilayerBaseOperation::getImBuf()
{
RenderPass *rpass = (RenderPass *)BLI_findlink(&this->m_renderlayer->passes, this->m_passId);
if (rpass) {
this->m_imageUser->pass = m_passId;
BKE_image_multilayer_index(this->m_image->rr, this->m_imageUser);
return BaseImageOperation::getImBuf();
/* temporarily changes the view to get the right ImBuf */
int view = this->m_imageUser->view;
this->m_imageUser->view = this->m_view;
this->m_imageUser->passtype = this->m_passtype;
if (BKE_image_multilayer_index(this->m_image->rr, this->m_imageUser)) {
ImBuf *ibuf = BaseImageOperation::getImBuf();
this->m_imageUser->view = view;
return ibuf;
}
this->m_imageUser->view = view;
return NULL;
}

@ -29,7 +29,8 @@
class MultilayerBaseOperation : public BaseImageOperation {
private:
int m_passId;
int m_passtype;
int m_view;
RenderLayer *m_renderlayer;
protected:
ImBuf *getImBuf();
@ -37,13 +38,13 @@ public:
/**
* Constructor
*/
MultilayerBaseOperation(int passindex);
MultilayerBaseOperation(int passtype, int view);
void setRenderLayer(RenderLayer *renderlayer) { this->m_renderlayer = renderlayer; }
};
class MultilayerColorOperation : public MultilayerBaseOperation {
public:
MultilayerColorOperation(int passindex) : MultilayerBaseOperation(passindex) {
MultilayerColorOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) {
this->addOutputSocket(COM_DT_COLOR);
}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
@ -51,7 +52,7 @@ public:
class MultilayerValueOperation : public MultilayerBaseOperation {
public:
MultilayerValueOperation(int passindex) : MultilayerBaseOperation(passindex) {
MultilayerValueOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) {
this->addOutputSocket(COM_DT_VALUE);
}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
@ -59,7 +60,7 @@ public:
class MultilayerVectorOperation : public MultilayerBaseOperation {
public:
MultilayerVectorOperation(int passindex) : MultilayerBaseOperation(passindex) {
MultilayerVectorOperation(int passtype, int view) : MultilayerBaseOperation(passtype, view) {
this->addOutputSocket(COM_DT_VECTOR);
}
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);

@ -0,0 +1,317 @@
/*
* Copyright 2015, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor:
* Jeroen Bakker
* Monique Dewanchand
* Lukas Tönne
* Dalai Felinto
*/
#include "COM_OutputFileOperation.h"
#include "COM_OutputFileMultiViewOperation.h"
#include <string.h>
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#include "DNA_color_types.h"
#include "MEM_guardedalloc.h"
extern "C" {
#include "IMB_imbuf.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
}
/************************************ OpenEXR Singlelayer Multiview *****************************************/
OutputOpenExrSingleLayerMultiViewOperation::OutputOpenExrSingleLayerMultiViewOperation(
const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
const char *viewName)
: OutputSingleLayerOperation(rd, tree, datatype, format, path, viewSettings, displaySettings, viewName)
{
}
void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filename)
{
size_t width = this->getWidth();
size_t height = this->getHeight();
SceneRenderView *srv;
if (width != 0 && height != 0) {
void *exrhandle;
exrhandle = IMB_exr_get_handle_name(filename);
if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName))
return exrhandle;
IMB_exr_clear_channels(exrhandle);
for (srv = (SceneRenderView *)this->m_rd->views.first; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false)
continue;
IMB_exr_add_view(exrhandle, srv->name);
add_exr_channels(exrhandle, NULL, this->m_datatype, srv->name, width, NULL);
}
BLI_make_existing_file(filename);
/* prepare the file with all the channels */
if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_format->exr_codec) == 0) {
printf("Error Writing Singlelayer Multiview Openexr\n");
IMB_exr_close(exrhandle);
}
else {
IMB_exr_clear_channels(exrhandle);
return exrhandle;
}
}
return NULL;
}
void OutputOpenExrSingleLayerMultiViewOperation::deinitExecution()
{
unsigned int width = this->getWidth();
unsigned int height = this->getHeight();
if (width != 0 && height != 0) {
void *exrhandle;
Main *bmain = G.main; /* TODO, have this passed along */
char filename[FILE_MAX];
BKE_image_path_from_imtype(
filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_OPENEXR,
(this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);
exrhandle = this->get_handle(filename);
add_exr_channels(exrhandle, NULL, this->m_datatype, this->m_viewName, width, this->m_outputBuffer);
/* memory can only be freed after we write all views to the file */
this->m_outputBuffer = NULL;
this->m_imageInput = NULL;
/* ready to close the file */
if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
IMB_exr_write_channels(exrhandle);
/* free buffer memory for all the views */
free_exr_channels(exrhandle, this->m_rd, NULL, this->m_datatype);
/* remove exr handle and data */
IMB_exr_close(exrhandle);
}
}
}
/************************************ OpenEXR Multilayer Multiview *****************************************/
OutputOpenExrMultiLayerMultiViewOperation::OutputOpenExrMultiLayerMultiViewOperation(
const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName)
: OutputOpenExrMultiLayerOperation(rd, tree, path, exr_codec, viewName)
{
}
void *OutputOpenExrMultiLayerMultiViewOperation::get_handle(const char *filename)
{
unsigned int width = this->getWidth();
unsigned int height = this->getHeight();
if (width != 0 && height != 0) {
void *exrhandle;
SceneRenderView *srv;
/* get a new global handle */
exrhandle = IMB_exr_get_handle_name(filename);
if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName))
return exrhandle;
IMB_exr_clear_channels(exrhandle);
/* check renderdata for amount of views */
for (srv = (SceneRenderView *) this->m_rd->views.first; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(this->m_rd, srv) == false)
continue;
IMB_exr_add_view(exrhandle, srv->name);
for (unsigned int i = 0; i < this->m_layers.size(); ++i)
add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, srv->name, width, NULL);
}
BLI_make_existing_file(filename);
/* prepare the file with all the channels for the header */
if (IMB_exr_begin_write(exrhandle, filename, width, height, this->m_exr_codec) == 0) {
printf("Error Writing Multilayer Multiview Openexr\n");
IMB_exr_close(exrhandle);
}
else {
IMB_exr_clear_channels(exrhandle);
return exrhandle;
}
}
return NULL;
}
void OutputOpenExrMultiLayerMultiViewOperation::deinitExecution()
{
unsigned int width = this->getWidth();
unsigned int height = this->getHeight();
if (width != 0 && height != 0) {
void *exrhandle;
Main *bmain = G.main; /* TODO, have this passed along */
char filename[FILE_MAX];
BKE_image_path_from_imtype(
filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
(this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);
exrhandle = this->get_handle(filename);
for (unsigned int i = 0; i < this->m_layers.size(); ++i)
add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, this->m_viewName, width, this->m_layers[i].outputBuffer);
for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
/* memory can only be freed after we write all views to the file */
this->m_layers[i].outputBuffer = NULL;
this->m_layers[i].imageInput = NULL;
}
/* ready to close the file */
if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
IMB_exr_write_channels(exrhandle);
/* free buffer memory for all the views */
for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
free_exr_channels(exrhandle, this->m_rd, this->m_layers[i].name, this->m_layers[i].datatype);
}
IMB_exr_close(exrhandle);
}
}
}
/******************************** Stereo3D ******************************/
OutputStereoOperation::OutputStereoOperation(
const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
const char *name, const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings,
const char *viewName)
: OutputSingleLayerOperation(rd, tree, datatype, format, path, viewSettings, displaySettings, viewName)
{
BLI_strncpy(this->m_name, name, sizeof(this->m_name));
this->m_channels = get_datatype_size(datatype);
}
void *OutputStereoOperation::get_handle(const char *filename)
{
size_t width = this->getWidth();
size_t height = this->getHeight();
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
size_t i;
if (width != 0 && height != 0) {
void *exrhandle;
exrhandle = IMB_exr_get_handle_name(filename);
if (!BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName))
return exrhandle;
IMB_exr_clear_channels(exrhandle);
for (i = 0; i < 2; i++)
IMB_exr_add_view(exrhandle, names[i]);
return exrhandle;
}
return NULL;
}
void OutputStereoOperation::deinitExecution()
{
unsigned int width = this->getWidth();
unsigned int height = this->getHeight();
if (width != 0 && height != 0) {
void *exrhandle;
exrhandle = this->get_handle(this->m_path);
float *buf = this->m_outputBuffer;
/* populate single EXR channel with view data */
IMB_exr_add_channel(exrhandle, NULL, this->m_name, this->m_viewName, 1, this->m_channels * width * height, buf);
this->m_imageInput = NULL;
this->m_outputBuffer = NULL;
/* create stereo ibuf */
if (BKE_scene_multiview_is_render_view_last(this->m_rd, this->m_viewName)) {
ImBuf *ibuf[3] = {NULL};
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
Main *bmain = G.main; /* TODO, have this passed along */
char filename[FILE_MAX];
int i;
/* get rectf from EXR */
for (i = 0; i < 2; i++) {
float *rectf = IMB_exr_channel_rect(exrhandle, NULL, this->m_name, names[i]);
ibuf[i] = IMB_allocImBuf(width, height, this->m_format->planes, 0);
ibuf[i]->channels = this->m_channels;
ibuf[i]->rect_float = rectf;
ibuf[i]->mall |= IB_rectfloat;
ibuf[i]->dither = this->m_rd->dither_intensity;
/* do colormanagement in the individual views, so it doesn't need to do in the stereo */
IMB_colormanagement_imbuf_for_write(ibuf[i], true, false, this->m_viewSettings,
this->m_displaySettings, this->m_format);
IMB_prepare_write_ImBuf(IMB_isfloat(ibuf[i]), ibuf[i]);
}
/* create stereo buffer */
ibuf[2] = IMB_stereo3d_ImBuf(this->m_format, ibuf[0], ibuf[1]);
BKE_image_path_from_imformat(
filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format,
(this->m_rd->scemode & R_EXTENSION) != 0, true, NULL);
BKE_imbuf_write(ibuf[2], filename, this->m_format);
/* imbuf knows which rects are not part of ibuf */
for (i = 0; i < 3; i++)
IMB_freeImBuf(ibuf[i]);
IMB_exr_close(exrhandle);
}
}
}

@ -0,0 +1,74 @@
/*
* Copyright 2015, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor:
* Jeroen Bakker
* Monique Dewanchand
* Lukas Tönne
* Dalai Felinto
*/
#ifndef _COM_OutputFileMultiViewOperation_h
#define _COM_OutputFileMultiViewOperation_h
#include "COM_NodeOperation.h"
#include "BLI_rect.h"
#include "BLI_path_util.h"
#include "DNA_color_types.h"
#include "DNA_userdef_types.h"
#include "intern/openexr/openexr_multi.h"
class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOperation {
private:
public:
OutputOpenExrSingleLayerMultiViewOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype,
ImageFormatData *format, const char *path,
const ColorManagedViewSettings *viewSettings,
const ColorManagedDisplaySettings *displaySettings,
const char *viewName);
void *get_handle(const char *filename);
void deinitExecution();
};
/* Writes inputs into OpenEXR multilayer channels. */
class OutputOpenExrMultiLayerMultiViewOperation : public OutputOpenExrMultiLayerOperation {
private:
public:
OutputOpenExrMultiLayerMultiViewOperation(const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName);
void *get_handle(const char *filename);
void deinitExecution();
};
/**/
class OutputStereoOperation : public OutputSingleLayerOperation {
private:
char m_name[FILE_MAX];
size_t m_channels;
public:
OutputStereoOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype,
struct ImageFormatData *format, const char *path, const char *name,
const ColorManagedViewSettings *viewSettings,
const ColorManagedDisplaySettings *displaySettings, const char *viewName);
void *get_handle(const char *filename);
void deinitExecution();
};
#endif

@ -29,6 +29,7 @@
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_scene.h"
#include "DNA_color_types.h"
@ -39,7 +40,60 @@ extern "C" {
# include "IMB_imbuf_types.h"
}
static int get_datatype_size(DataType datatype)
void add_exr_channels(void *exrhandle, const char *layerName, const DataType datatype, const char *viewName, const size_t width, float *buf)
{
/* create channels */
switch (datatype) {
case COM_DT_VALUE:
IMB_exr_add_channel(exrhandle, layerName, "V", viewName, 1, width, buf ? buf : NULL);
break;
case COM_DT_VECTOR:
IMB_exr_add_channel(exrhandle, layerName, "X", viewName, 3, 3 * width, buf ? buf : NULL);
IMB_exr_add_channel(exrhandle, layerName, "Y", viewName, 3, 3 * width, buf ? buf + 1 : NULL);
IMB_exr_add_channel(exrhandle, layerName, "Z", viewName, 3, 3 * width, buf ? buf + 2 : NULL);
break;
case COM_DT_COLOR:
IMB_exr_add_channel(exrhandle, layerName, "R", viewName, 4, 4 * width, buf ? buf : NULL);
IMB_exr_add_channel(exrhandle, layerName, "G", viewName, 4, 4 * width, buf ? buf + 1 : NULL);
IMB_exr_add_channel(exrhandle, layerName, "B", viewName, 4, 4 * width, buf ? buf + 2 : NULL);
IMB_exr_add_channel(exrhandle, layerName, "A", viewName, 4, 4 * width, buf ? buf + 3 : NULL);
break;
default:
break;
}
}
void free_exr_channels(void *exrhandle, const RenderData *rd, const char *layerName, const DataType datatype)
{
SceneRenderView *srv;
/* check renderdata for amount of views */
for (srv = (SceneRenderView *) rd->views.first; srv; srv = srv->next) {
float *rect = NULL;
if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
continue;
/* the pointer is stored in the first channel of each datatype */
switch (datatype) {
case COM_DT_VALUE:
rect = IMB_exr_channel_rect(exrhandle, layerName, "V", srv->name);
break;
case COM_DT_VECTOR:
rect = IMB_exr_channel_rect(exrhandle, layerName, "X", srv->name);
break;
case COM_DT_COLOR:
rect = IMB_exr_channel_rect(exrhandle, layerName, "R", srv->name);
break;
default:
break;
}
if (rect)
MEM_freeN(rect);
}
}
int get_datatype_size(DataType datatype)
{
switch (datatype) {
case COM_DT_VALUE: return 1;
@ -94,7 +148,7 @@ static void write_buffer_rect(rcti *rect, const bNodeTree *tree,
OutputSingleLayerOperation::OutputSingleLayerOperation(
const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings)
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, const char *viewName)
{
this->m_rd = rd;
this->m_tree = tree;
@ -110,6 +164,7 @@ OutputSingleLayerOperation::OutputSingleLayerOperation(
this->m_viewSettings = viewSettings;
this->m_displaySettings = displaySettings;
this->m_viewName = viewName;
}
void OutputSingleLayerOperation::initExecution()
@ -131,6 +186,7 @@ void OutputSingleLayerOperation::deinitExecution()
ImBuf *ibuf = IMB_allocImBuf(this->getWidth(), this->getHeight(), this->m_format->planes, 0);
Main *bmain = G.main; /* TODO, have this passed along */
char filename[FILE_MAX];
const char *suffix;
ibuf->channels = size;
ibuf->rect_float = this->m_outputBuffer;
@ -140,10 +196,12 @@ void OutputSingleLayerOperation::deinitExecution()
IMB_colormanagement_imbuf_for_write(ibuf, true, false, m_viewSettings, m_displaySettings,
this->m_format);
suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName);
BKE_image_path_from_imformat(
filename, this->m_path, bmain->name, this->m_rd->cfra,
this->m_format, (this->m_rd->scemode & R_EXTENSION) != 0, true);
filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format,
(this->m_rd->scemode & R_EXTENSION) != 0, true, suffix);
if (0 == BKE_imbuf_write(ibuf, filename, this->m_format))
printf("Cannot save Node File Output to %s\n", filename);
else
@ -155,6 +213,7 @@ void OutputSingleLayerOperation::deinitExecution()
this->m_imageInput = NULL;
}
/******************************* MultiLayer *******************************/
OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bool use_layer_)
{
@ -168,13 +227,14 @@ OutputOpenExrLayer::OutputOpenExrLayer(const char *name_, DataType datatype_, bo
}
OutputOpenExrMultiLayerOperation::OutputOpenExrMultiLayerOperation(
const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec)
const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName)
{
this->m_rd = rd;
this->m_tree = tree;
BLI_strncpy(this->m_path, path, sizeof(this->m_path));
this->m_exr_codec = exr_codec;
this->m_viewName = viewName;
}
void OutputOpenExrMultiLayerOperation::add_layer(const char *name, DataType datatype, bool use_layer)
@ -210,52 +270,21 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
if (width != 0 && height != 0) {
Main *bmain = G.main; /* TODO, have this passed along */
char filename[FILE_MAX];
const char *suffix;
void *exrhandle = IMB_exr_get_handle();
suffix = BKE_scene_multiview_view_suffix_get(this->m_rd, this->m_viewName);
BKE_image_path_from_imtype(
filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
(this->m_rd->scemode & R_EXTENSION) != 0, true);
(this->m_rd->scemode & R_EXTENSION) != 0, true, suffix);
BLI_make_existing_file(filename);
for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
OutputOpenExrLayer &layer = this->m_layers[i];
if (!layer.imageInput)
continue; /* skip unconnected sockets */
char channelname[EXR_TOT_MAXNAME];
BLI_strncpy(channelname, this->m_layers[i].name, sizeof(channelname) - 2);
char *channelname_ext = channelname + strlen(channelname);
float *buf = this->m_layers[i].outputBuffer;
/* create channels */
switch (this->m_layers[i].datatype) {
case COM_DT_VALUE:
strcpy(channelname_ext, ".V");
IMB_exr_add_channel(exrhandle, 0, channelname, 1, width, buf);
break;
case COM_DT_VECTOR:
strcpy(channelname_ext, ".X");
IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf);
strcpy(channelname_ext, ".Y");
IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 1);
strcpy(channelname_ext, ".Z");
IMB_exr_add_channel(exrhandle, 0, channelname, 3, 3 * width, buf + 2);
break;
case COM_DT_COLOR:
strcpy(channelname_ext, ".R");
IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf);
strcpy(channelname_ext, ".G");
IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 1);
strcpy(channelname_ext, ".B");
IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 2);
strcpy(channelname_ext, ".A");
IMB_exr_add_channel(exrhandle, 0, channelname, 4, 4 * width, buf + 3);
break;
default:
break;
}
add_exr_channels(exrhandle, this->m_layers[i].name, this->m_layers[i].datatype, "", width, this->m_layers[i].outputBuffer);
}
/* when the filename has no permissions, this can fail */
@ -279,3 +308,4 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
}
}
}

@ -34,7 +34,7 @@
/* Writes the image to a single-layer file. */
class OutputSingleLayerOperation : public NodeOperation {
private:
protected:
const RenderData *m_rd;
const bNodeTree *m_tree;
@ -47,9 +47,11 @@ private:
const ColorManagedViewSettings *m_viewSettings;
const ColorManagedDisplaySettings *m_displaySettings;
const char *m_viewName;
public:
OutputSingleLayerOperation(const RenderData *rd, const bNodeTree *tree, DataType datatype, ImageFormatData *format, const char *path,
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings);
const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, const char *viewName);
void executeRegion(rcti *rect, unsigned int tileNumber);
bool isOutputOperation(bool /*rendering*/) const { return true; }
@ -75,7 +77,7 @@ struct OutputOpenExrLayer {
/* Writes inputs into OpenEXR multilayer channels. */
class OutputOpenExrMultiLayerOperation : public NodeOperation {
private:
protected:
typedef std::vector<OutputOpenExrLayer> LayerList;
const RenderData *m_rd;
@ -84,9 +86,10 @@ private:
char m_path[FILE_MAX];
char m_exr_codec;
LayerList m_layers;
const char *m_viewName;
public:
OutputOpenExrMultiLayerOperation(const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec);
OutputOpenExrMultiLayerOperation(const RenderData *rd, const bNodeTree *tree, const char *path, char exr_codec, const char *viewName);
void add_layer(const char *name, DataType datatype, bool use_layer);
@ -99,4 +102,8 @@ public:
bool isFileOutputOperation() const { return true; }
};
void add_exr_channels(void *exrhandle, const char *layerName, const DataType datatype, const char *viewName, const size_t width, float *buf);
void free_exr_channels(void *exrhandle, const RenderData *rd, const char *layerName, const DataType datatype);
int get_datatype_size(DataType datatype);
#endif

@ -23,6 +23,7 @@
#include "COM_RenderLayersProg.h"
#include "BLI_listbase.h"
#include "BKE_scene.h"
#include "DNA_scene_types.h"
extern "C" {
@ -57,11 +58,10 @@ void RenderLayersBaseProg::initExecution()
if (srl) {
RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
if (rl && rl->rectf) {
this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_renderpass);
if (rl) {
this->m_inputBuffer = RE_RenderLayerGetPass(rl, this->m_renderpass, this->m_viewName);
if (this->m_inputBuffer == NULL && this->m_renderpass == SCE_PASS_COMBINED) {
this->m_inputBuffer = rl->rectf;
this->m_inputBuffer = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, this->m_viewName);
}
}
}
@ -195,7 +195,7 @@ void RenderLayersBaseProg::determineResolution(unsigned int resolution[2], unsig
SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&sce->r.layers, getLayerId());
if (srl) {
RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
if (rl && rl->rectf) {
if (rl) {
resolution[0] = rl->rectx;
resolution[1] = rl->recty;
}

@ -51,7 +51,12 @@ private:
* layerId of the layer where this operation needs to get its data from
*/
short m_layerId;
/**
* viewName of the view to use (unless another view is specified by the node
*/
const char *m_viewName;
/**
* cached instance to the float buffer inside the layer
*/
@ -97,6 +102,8 @@ public:
void setRenderData(const RenderData *rd) { this->m_rd = rd; }
void setLayerId(short layerId) { this->m_layerId = layerId; }
short getLayerId() { return this->m_layerId; }
void setViewName(const char *viewName) { this->m_viewName = viewName; }
const char *getViewName() { return this->m_viewName; }
void initExecution();
void deinitExecution();
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);

@ -23,6 +23,7 @@
#include "COM_ViewerOperation.h"
#include "BLI_listbase.h"
#include "BKE_image.h"
#include "BKE_scene.h"
#include "WM_api.h"
#include "WM_types.h"
#include "PIL_time.h"
@ -57,6 +58,8 @@ ViewerOperation::ViewerOperation() : NodeOperation()
this->m_imageInput = NULL;
this->m_alphaInput = NULL;
this->m_depthInput = NULL;
this->m_rd = NULL;
this->m_viewName = NULL;
}
void ViewerOperation::initExecution()
@ -123,8 +126,18 @@ void ViewerOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/)
void ViewerOperation::initImage()
{
Image *ima = this->m_image;
ImageUser iuser = *this->m_imageUser;
void *lock;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, this->m_imageUser, &lock);
ImBuf *ibuf;
/* make sure the image has the correct number of views */
if (ima && BKE_scene_multiview_is_render_view_first(this->m_rd, this->m_viewName)) {
BKE_image_verify_viewer_views(this->m_rd, ima, this->m_imageUser);
}
/* local changes to the original ImageUser */
iuser.multi_index = BKE_scene_multiview_view_id_get(this->m_rd, this->m_viewName);
ibuf = BKE_image_acquire_ibuf(ima, &iuser, &lock);
if (!ibuf) return;
BLI_lock_thread(LOCK_DRAW_IMAGE);

@ -40,7 +40,9 @@ private:
bool m_doDepthBuffer;
ImBuf *m_ibuf;
bool m_useAlphaInput;
const RenderData *m_rd;
const char *m_viewName;
const ColorManagedViewSettings *m_viewSettings;
const ColorManagedDisplaySettings *m_displaySettings;
@ -67,6 +69,8 @@ public:
const CompositorPriority getRenderPriority() const;
bool isViewerOperation() const { return true; }
void setUseAlphaInput(bool value) { this->m_useAlphaInput = value; }
void setRenderData(const RenderData *rd) { this->m_rd = rd; }
void setViewName(const char *viewName) { this->m_viewName = viewName; }
void setViewSettings(const ColorManagedViewSettings *viewSettings) { this->m_viewSettings = viewSettings; }
void setDisplaySettings(const ColorManagedDisplaySettings *displaySettings) { this->m_displaySettings = displaySettings; }

@ -112,6 +112,7 @@ void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
bool ED_screen_stereo3d_required(struct bScreen *screen);
/* anim */
void ED_update_for_newframe(struct Main *bmain, struct Scene *scene, int mute);

@ -323,12 +323,13 @@ void ED_view3d_draw_offscreen(
struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4],
float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp,
struct GPUOffScreen *ofs,
struct GPUFX *fx, struct GPUFXSettings *fx_settings);
struct GPUFX *fx, struct GPUFXSettings *fx_settings,
const char *viewname);
struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag,
bool draw_background, int alpha_mode, char err_out[256]);
bool draw_background, int alpha_mode, const char *viewname, char err_out[256]);
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype,
bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, char err_out[256]);
bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, const char *viewname, char err_out[256]);
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip);

@ -889,6 +889,9 @@ void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *
PointerRNA *used_ptr, const char *used_propname, int active_state);
void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, int compact);
void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, int color_management);
void uiTemplateImageStereo3d(uiLayout *layout, struct PointerRNA *stereo3d_format_ptr);
void uiTemplateImageViews(uiLayout *layout, struct PointerRNA *imaptr);
void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr);
void uiTemplateImageLayers(uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser);
void uiTemplateImageInfo(uiLayout *layout, struct bContext *C, Image *ima, ImageUser *iuser);
void uiTemplateRunningJobs(uiLayout *layout, struct bContext *C);

@ -613,6 +613,7 @@ static int editsource_exec(bContext *C, wmOperator *op)
/* redraw and get active button python info */
ED_region_do_draw(C, ar);
ar->do_draw = false;
for (BLI_ghashIterator_init(&ghi, ui_editsource_info->hash);
BLI_ghashIterator_done(&ghi) == false;

@ -929,7 +929,7 @@ cage_cleanup:
BakeData *bake = &scene->r.bake;
char name[FILE_MAX];
BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false);
BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false, NULL);
if (is_automatic_name) {
BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_");

@ -55,6 +55,9 @@ void MATERIAL_OT_paste(struct wmOperatorType *ot);
void SCENE_OT_render_layer_add(struct wmOperatorType *ot);
void SCENE_OT_render_layer_remove(struct wmOperatorType *ot);
void SCENE_OT_render_view_add(struct wmOperatorType *ot);
void SCENE_OT_render_view_remove(struct wmOperatorType *ot);
#ifdef WITH_FREESTYLE
void SCENE_OT_freestyle_module_add(struct wmOperatorType *ot);
void SCENE_OT_freestyle_module_remove(struct wmOperatorType *ot);

@ -48,6 +48,7 @@
#include "DNA_userdef_types.h"
#include "BKE_blender.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
@ -116,7 +117,7 @@ typedef struct RenderJob {
} RenderJob;
/* called inside thread! */
static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect)
static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect, const char *viewname)
{
Scene *scene = rj->scene;
const float *rectf = NULL;
@ -188,11 +189,11 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
*/
/* TODO(sergey): Need to check has_combined here? */
if (iuser->pass == 0) {
size_t view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
/* find current float rect for display, first case is after composite... still weak */
if (rr->rectf)
rectf = rr->rectf;
else {
if (rr->rect32) {
rectf = RE_RenderViewGetRectf(rr, view_id);
if (rectf == NULL) {
if (RE_RenderViewGetRect32(rr, view_id)) {
/* special case, currently only happens with sequencer rendering,
* which updates the whole frame, so we can only mark display buffer
* as invalid here (sergey)
@ -201,8 +202,8 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
return;
}
else {
if (rr->renlay == NULL || rr->renlay->rectf == NULL) return;
rectf = rr->renlay->rectf;
if (rr->renlay == NULL) return;
rectf = RE_RenderLayerGetPass(rr->renlay, SCE_PASS_COMBINED, viewname);
}
}
if (rectf == NULL) return;
@ -531,6 +532,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
Image *ima = rj->image;
ImBuf *ibuf;
void *lock;
const char *viewname = RE_GetActiveRenderView(rj->re);
/* only update if we are displaying the slot being rendered */
if (ima->render_slot != ima->last_render_slot) {
@ -563,7 +565,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
ibuf->channels == 1 ||
U.image_draw_method != IMAGE_DRAW_METHOD_GLSL)
{
image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect);
image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect, viewname);
}
/* make jobs timer to send notifier */
@ -1487,7 +1489,8 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
if (re == NULL) return;
}
RE_AcquireResultImage(re, &rres);
/* Viewport render preview doesn't support multiview, view hardcoded to 0 */
RE_AcquireResultImage(re, &rres, 0);
if (rres.rectf) {
RegionView3D *rv3d = CTX_wm_region_view3d(C);

@ -39,6 +39,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_jitter.h"
#include "BLI_threads.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@ -103,11 +104,17 @@ typedef struct OGLRender {
bMovieHandle *mh;
int cfrao, nfra;
size_t totvideos;
/* quick lookup */
int view_id;
/* wm vars for timer and progress cursor */
wmWindowManager *wm;
wmWindow *win;
wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
void **movie_ctx_arr;
} OGLRender;
/* added because v3d is not always valid */
@ -121,16 +128,125 @@ static unsigned int screen_opengl_layers(OGLRender *oglrender)
}
}
static void screen_opengl_render_apply(OGLRender *oglrender)
static bool screen_opengl_is_multiview(OGLRender *oglrender)
{
View3D *v3d = oglrender->v3d;
RegionView3D *rv3d = oglrender->rv3d;
RenderData *rd = &oglrender->scene->r;
if ((rd == NULL) || ((!oglrender->is_sequencer) && ((rv3d == NULL) || (v3d == NULL))))
return false;
return (rd->scemode & R_MULTIVIEW) && ((oglrender->is_sequencer) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
}
static void screen_opengl_views_setup(OGLRender *oglrender)
{
RenderResult *rr;
RenderView *rv;
SceneRenderView *srv;
bool is_multiview;
View3D *v3d = oglrender->v3d;
RenderData *rd = &oglrender->scene->r;
rr = RE_AcquireResultWrite(oglrender->re);
is_multiview = screen_opengl_is_multiview(oglrender);
if (!is_multiview) {
/* we only have one view when multiview is off */
rv = rr->views.first;
if (rv == NULL) {
rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
BLI_addtail(&rr->views, rv);
}
while (rv->next) {
RenderView *rv_del = rv->next;
BLI_remlink(&rr->views, rv_del);
if (rv_del->rectf)
MEM_freeN(rv_del->rectf);
if (rv_del->rectz)
MEM_freeN(rv_del->rectz);
MEM_freeN(rv_del);
}
}
else {
if (!oglrender->is_sequencer)
RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d));
/* remove all the views that are not needed */
rv = rr->views.last;
while (rv) {
srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
if (rv->rectf == NULL)
rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
rv = rv->prev;
}
else {
RenderView *rv_del = rv;
rv = rv_del->prev;
BLI_remlink(&rr->views, rv_del);
if (rv_del->rectf)
MEM_freeN(rv_del->rectf);
if (rv_del->rectz)
MEM_freeN(rv_del->rectz);
MEM_freeN(rv_del);
}
}
/* create all the views that are needed */
for (srv = rd->views.first; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv) == false)
continue;
rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name));
if (rv == NULL) {
rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
BLI_addtail(&rr->views, rv);
}
}
}
for (rv = rr->views.first; rv; rv = rv->next) {
if (rv->rectf == NULL) {
rv->rectf = MEM_callocN(sizeof(float) * 4 * oglrender->sizex * oglrender->sizey, "screen_opengl_render_init rect");
}
}
BLI_lock_thread(LOCK_DRAW_IMAGE);
if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) {
oglrender->ima->flag |= IMA_IS_STEREO;
}
else {
oglrender->ima->flag &= ~IMA_IS_STEREO;
oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
}
BLI_unlock_thread(LOCK_DRAW_IMAGE);
RE_ReleaseResult(oglrender->re);
}
static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
{
Scene *scene = oglrender->scene;
ARegion *ar = oglrender->ar;
View3D *v3d = oglrender->v3d;
RegionView3D *rv3d = oglrender->rv3d;
RenderResult *rr;
Object *camera = NULL;
ImBuf *ibuf;
void *lock;
float winmat[4][4];
int sizex = oglrender->sizex;
int sizey = oglrender->sizey;
@ -138,8 +254,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
bool draw_bgpic = true;
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
unsigned char *rect = NULL;
rr = RE_AcquireResultRead(oglrender->re);
const char *viewname = RE_GetActiveRenderView(oglrender->re);
if (oglrender->is_sequencer) {
SeqRenderData context;
@ -152,9 +267,11 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
oglrender->sizex, oglrender->sizey, 100.0f,
&context);
context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);
if (ibuf) {
float *rectf;
ImBuf *linear_ibuf;
BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y));
@ -175,7 +292,8 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf);
}
memcpy(rr->rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
rectf = RE_RenderViewGetRectf(rr, oglrender->view_id);
memcpy(rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
IMB_freeImBuf(linear_ibuf);
}
@ -221,7 +339,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
/* render 3d view */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
/*int is_ortho = scene->r.mode & R_ORTHO;*/
camera = v3d->camera;
camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat);
if (camera->type == OB_CAMERA) {
Camera *cam = camera->data;
@ -248,7 +366,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, winmat,
draw_bgpic, draw_sky, is_persp,
oglrender->ofs, oglrender->fx, &fx_settings);
oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
}
else {
@ -264,7 +382,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, winmat,
draw_bgpic, draw_sky, is_persp,
oglrender->ofs, oglrender->fx, &fx_settings);
oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
for (i = 0; i < sizex * sizey * 4; i++)
@ -280,7 +398,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
ED_view3d_draw_offscreen(
scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
draw_bgpic, draw_sky, is_persp,
oglrender->ofs, oglrender->fx, &fx_settings);
oglrender->ofs, oglrender->fx, &fx_settings, viewname);
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
for (i = 0; i < sizex * sizey * 4; i++)
@ -300,7 +418,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
char err_out[256] = "unknown";
ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey,
IB_rect, OB_SOLID, false, true, true,
(draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, err_out);
(draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, viewname, err_out);
camera = scene->camera;
if (ibuf_view) {
@ -325,6 +443,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
if (rect) {
int profile_to;
float *rectf = RE_RenderViewGetRectf(rr, oglrender->view_id);
if (BKE_scene_check_color_management_enabled(scene))
profile_to = IB_PROFILE_LINEAR_RGB;
@ -333,47 +452,60 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
/* sequencer has got trickier conversion happened above
* also assume opengl's space matches byte buffer color space */
IMB_buffer_float_from_byte(rr->rectf, rect,
IMB_buffer_float_from_byte(rectf, rect,
profile_to, IB_PROFILE_SRGB, true,
oglrender->sizex, oglrender->sizey, oglrender->sizex, oglrender->sizex);
/* rr->rectf is now filled with image data */
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
BKE_image_stamp_buf(scene, camera, rect, rectf, rr->rectx, rr->recty, 4);
MEM_freeN(rect);
}
}
/* rr->rectf is now filled with image data */
static void screen_opengl_render_write(OGLRender *oglrender)
{
Scene *scene = oglrender->scene;
RenderResult *rr;
bool ok;
char name[FILE_MAX];
Object *camera = RE_GetCamera(oglrender->re);
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
BKE_image_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4);
rr = RE_AcquireResultRead(oglrender->re);
BKE_image_path_from_imformat(
name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
&scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL);
/* write images as individual images or stereo */
ok = RE_WriteRenderViewsImage(oglrender->reports, rr, scene, camera, false, name);
RE_ReleaseResultImage(oglrender->re);
if (ok) printf("OpenGL Render written to '%s'\n", name);
else printf("OpenGL Render failed to write '%s'\n", name);
}
static void screen_opengl_render_apply(OGLRender *oglrender)
{
RenderResult *rr;
RenderView *rv;
int view_id;
rr = RE_AcquireResultRead(oglrender->re);
for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
RE_SetActiveRenderView(oglrender->re, rv->name);
oglrender->view_id = view_id;
screen_opengl_render_doit(oglrender, rr);
}
RE_ReleaseResult(oglrender->re);
/* update byte from float buffer */
ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
if (ibuf) {
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
/* write file for animation */
if (oglrender->write_still) {
char name[FILE_MAX];
int ok;
if (scene->r.im_format.planes == R_IMF_CHAN_DEPTH_8) {
IMB_color_to_bw(ibuf);
}
BKE_image_path_from_imformat(
name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
&scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false);
ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, true); /* no need to stamp here */
if (ok) printf("OpenGL Render written to '%s'\n", name);
else printf("OpenGL Render failed to write '%s'\n", name);
}
if (oglrender->write_still) {
screen_opengl_render_write(oglrender);
}
BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
if (rect)
MEM_freeN(rect);
}
static bool screen_opengl_render_init(bContext *C, wmOperator *op)
@ -385,7 +517,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *prevar = CTX_wm_region(C);
RenderResult *rr;
GPUOffScreen *ofs;
OGLRender *oglrender;
int sizex, sizey;
@ -458,7 +589,6 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->sseq = CTX_wm_space_seq(C);
}
oglrender->prevsa = prevsa;
oglrender->prevar = prevar;
@ -492,15 +622,17 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* create render result */
RE_InitState(oglrender->re, NULL, &scene->r, NULL, sizex, sizey, NULL);
rr = RE_AcquireResultWrite(oglrender->re);
if (rr->rectf == NULL)
rr->rectf = MEM_callocN(sizeof(float) * 4 * sizex * sizey, "screen_opengl_render_init rect");
RE_ReleaseResult(oglrender->re);
/* create render views */
screen_opengl_views_setup(oglrender);
/* wm vars */
oglrender->wm = wm;
oglrender->win = win;
oglrender->totvideos = 0;
oglrender->mh = NULL;
oglrender->movie_ctx_arr = NULL;
return true;
}
@ -508,10 +640,19 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
{
Main *bmain = CTX_data_main(C);
Scene *scene = oglrender->scene;
size_t i;
if (oglrender->mh) {
if (BKE_imtype_is_movie(scene->r.im_format.imtype))
oglrender->mh->end_movie();
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
for (i = 0; i < oglrender->totvideos; i++) {
oglrender->mh->end_movie(oglrender->movie_ctx_arr[i]);
oglrender->mh->context_free(oglrender->movie_ctx_arr[i]);
}
}
if (oglrender->movie_ctx_arr) {
MEM_freeN(oglrender->movie_ctx_arr);
}
}
if (oglrender->timer) { /* exec will not have a timer */
@ -552,13 +693,27 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
oglrender = op->customdata;
scene = oglrender->scene;
oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
oglrender->reports = op->reports;
oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
if (!oglrender->mh->start_movie(scene, &scene->r, oglrender->sizex, oglrender->sizey, oglrender->reports, PRVRANGEON != 0)) {
screen_opengl_render_end(C, oglrender);
return 0;
size_t i, width, height;
BKE_scene_multiview_videos_dimensions_get(&scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
for (i = 0; i < oglrender->totvideos; i++) {
const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
oglrender->movie_ctx_arr[i] = oglrender->mh->context_create();
if (!oglrender->mh->start_movie(oglrender->movie_ctx_arr[i], scene, &scene->r, oglrender->sizex,
oglrender->sizey, oglrender->reports, PRVRANGEON != 0, suffix))
{
screen_opengl_render_end(C, oglrender);
return 0;
}
}
}
@ -568,18 +723,17 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
return 1;
}
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
OGLRender *oglrender = op->customdata;
Scene *scene = oglrender->scene;
ImBuf *ibuf, *ibuf_save = NULL;
void *lock;
char name[FILE_MAX];
bool ok = false;
const bool view_context = (oglrender->v3d != NULL);
Object *camera = NULL;
bool is_movie;
RenderResult *rr;
/* go to next frame */
if (CFRA < oglrender->nfra)
@ -599,7 +753,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
if (!is_movie) {
BKE_image_path_from_imformat(
name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
&scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
&scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
@ -619,89 +773,40 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
if (BKE_scene_camera_switch_update(scene)) {
oglrender->v3d->camera = scene->camera;
}
camera = oglrender->v3d->camera;
}
}
else {
BKE_scene_camera_switch_update(scene);
camera = scene->camera;
}
/* render into offscreen buffer */
screen_opengl_render_apply(oglrender);
/* save to disk */
ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
rr = RE_AcquireResultRead(oglrender->re);
if (ibuf) {
bool needs_free = false;
ibuf_save = ibuf;
if (is_movie || !BKE_imtype_requires_linear_float(scene->r.im_format.imtype)) {
ibuf_save = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &scene->view_settings,
&scene->display_settings, &scene->r.im_format);
needs_free = true;
if (is_movie) {
ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh, oglrender->sizex,
oglrender->sizey, oglrender->movie_ctx_arr, oglrender->totvideos);
if (ok) {
printf("Append frame %d", scene->r.cfra);
BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
}
/* color -> grayscale */
/* editing directly would alter the render view */
if (scene->r.im_format.planes == R_IMF_PLANES_BW) {
ImBuf *ibuf_bw = IMB_dupImBuf(ibuf_save);
IMB_color_to_bw(ibuf_bw);
if (needs_free)
IMB_freeImBuf(ibuf_save);
ibuf_save = ibuf_bw;
}
else {
ok = RE_WriteRenderViewsImage(op->reports, rr, scene, scene->camera, true, name);
if (ok) {
printf("Saved: %s", name);
BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
}
else {
/* this is lightweight & doesnt re-alloc the buffers, only do this
* to save the correct bit depth since the image is always RGBA */
ImBuf *ibuf_cpy = IMB_allocImBuf(ibuf_save->x, ibuf_save->y, scene->r.im_format.planes, 0);
ibuf_cpy->rect = ibuf_save->rect;
ibuf_cpy->rect_float = ibuf_save->rect_float;
ibuf_cpy->zbuf_float = ibuf_save->zbuf_float;
if (needs_free) {
ibuf_cpy->mall = ibuf_save->mall;
ibuf_save->mall = 0;
IMB_freeImBuf(ibuf_save);
}
ibuf_save = ibuf_cpy;
printf("Write error: cannot save %s\n", name);
BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
}
if (is_movie) {
ok = oglrender->mh->append_movie(&scene->r, PSFRA, CFRA, (int *)ibuf_save->rect,
oglrender->sizex, oglrender->sizey, oglrender->reports);
if (ok) {
printf("Append frame %d", scene->r.cfra);
BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
}
}
else {
ok = BKE_imbuf_write_stamp(scene, camera, ibuf_save, name, &scene->r.im_format);
if (ok == 0) {
printf("Write error: cannot save %s\n", name);
BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
}
else {
printf("Saved: %s", name);
BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
}
}
if (needs_free)
IMB_freeImBuf(ibuf_save);
}
BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
RE_ReleaseResult(oglrender->re);
/* movie stats prints have no line break */
printf("\n");

@ -58,6 +58,9 @@ void ED_operatortypes_render(void)
WM_operatortype_append(SCENE_OT_render_layer_add);
WM_operatortype_append(SCENE_OT_render_layer_remove);
WM_operatortype_append(SCENE_OT_render_view_add);
WM_operatortype_append(SCENE_OT_render_view_remove);
#ifdef WITH_FREESTYLE
WM_operatortype_append(SCENE_OT_freestyle_module_add);
WM_operatortype_append(SCENE_OT_freestyle_module_remove);

@ -548,7 +548,9 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
/* test if something rendered ok */
re = RE_GetRender(name);
RE_AcquireResultImage(re, &rres);
/* material preview only needs monoscopy (view 0) */
RE_AcquireResultImage(re, &rres, 0);
if (rres.rectf) {
@ -561,9 +563,11 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect");
float fx = rect->xmin + offx;
float fy = rect->ymin;
/* material preview only needs monoscopy (view 0) */
if (re)
RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte);
RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte, 0);
glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte);
MEM_freeN(rect_byte);

@ -605,6 +605,70 @@ void SCENE_OT_render_layer_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
/********************** render view operators *********************/
static int render_view_remove_poll(bContext *C)
{
Scene *scene = CTX_data_scene(C);
/* don't allow user to remove "left" and "right" views */
return scene->r.actview > 1;
}
static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
BKE_scene_add_render_view(scene, NULL);
scene->r.actview = BLI_listbase_count(&scene->r.views) - 1;
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
}
void SCENE_OT_render_view_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Render View";
ot->idname = "SCENE_OT_render_view_add";
ot->description = "Add a render view";
/* api callbacks */
ot->exec = render_view_add_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview);
if (!BKE_scene_remove_render_view(scene, rv))
return OPERATOR_CANCELLED;
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
}
void SCENE_OT_render_view_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Render View";
ot->idname = "SCENE_OT_render_view_remove";
ot->description = "Remove the selected render view";
/* api callbacks */
ot->exec = render_view_remove_exec;
ot->poll = render_view_remove_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
#ifdef WITH_FREESTYLE
static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportList *reports)

@ -493,7 +493,6 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
glDisable(GL_BLEND);
#endif
ar->do_draw = 0;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
UI_blocklist_free_inactive(C, &ar->uiblocks);

@ -59,6 +59,7 @@
#include "ED_screen.h"
#include "ED_screen_types.h"
#include "ED_clip.h"
#include "ED_node.h"
#include "ED_render.h"
#include "UI_interface.h"
@ -2122,4 +2123,85 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
}
/*
* return true if any active area requires to see in 3D
*/
bool ED_screen_stereo3d_required(bScreen *screen)
{
ScrArea *sa;
Scene *sce = screen->scene;
const bool is_multiview = (sce->r.scemode & R_MULTIVIEW) != 0;
for (sa = screen->areabase.first; sa; sa = sa->next) {
switch (sa->spacetype) {
case SPACE_VIEW3D:
{
View3D *v3d;
if (!is_multiview)
continue;
v3d = sa->spacedata.first;
if (v3d->camera && v3d->stereo3d_camera == STEREO_3D_ID) {
ARegion *ar;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->regiondata && ar->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = ar->regiondata;
if (rv3d->persp == RV3D_CAMOB) {
return true;
}
}
}
}
break;
}
case SPACE_IMAGE:
{
SpaceImage *sima;
/* images should always show in stereo, even if
* the file doesn't have views enabled */
sima = sa->spacedata.first;
if (sima->image && (sima->image->flag & IMA_IS_STEREO) &&
(sima->iuser.flag & IMA_SHOW_STEREO))
{
return true;
}
break;
}
case SPACE_NODE:
{
SpaceNode *snode;
if (!is_multiview)
continue;
snode = sa->spacedata.first;
if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
return true;
}
break;
}
case SPACE_SEQ:
{
SpaceSeq *sseq;
if (!is_multiview)
continue;
sseq = sa->spacedata.first;
if (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
return true;
}
if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
return true;
}
break;
}
}
}
return false;
}

@ -990,6 +990,7 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
rect.ymax = rect.ymin + BLI_rcti_size_y(&rect) / U.pixelsize;
newwin = WM_window_open(C, &rect);
*newwin->stereo3d_format = *win->stereo3d_format;
/* allocs new screen and adds to newly created window, using window size */
newsc = ED_screen_add(newwin, CTX_data_scene(C), sc->id.name + 2);

@ -303,6 +303,7 @@ typedef struct ScreenshotJob {
const short *stop;
const short *do_update;
ReportList reports;
void *movie_ctx;
} ScreenshotJob;
@ -312,7 +313,10 @@ static void screenshot_freejob(void *sjv)
if (sj->dumprect)
MEM_freeN(sj->dumprect);
if (sj->movie_ctx)
MEM_freeN(sj->movie_ctx);
MEM_freeN(sj);
}
@ -337,20 +341,21 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
{
ScreenshotJob *sj = sjv;
RenderData rd = sj->scene->r;
bMovieHandle *mh = BKE_movie_handle_get(sj->scene->r.im_format.imtype);
bMovieHandle *mh = NULL;
/* we need this as local variables for renderdata */
rd.frs_sec = U.scrcastfps;
rd.frs_sec_base = 1.0f;
if (BKE_imtype_is_movie(rd.im_format.imtype)) {
if (!mh->start_movie(sj->scene, &rd, sj->dumpsx, sj->dumpsy, &sj->reports, false)) {
mh = BKE_movie_handle_get(sj->scene->r.im_format.imtype);
sj->movie_ctx = mh->context_create();
if (!mh->start_movie(sj->movie_ctx, sj->scene, &rd, sj->dumpsx, sj->dumpsy, &sj->reports, false, "")) {
printf("screencast job stopped\n");
return;
}
}
else
mh = NULL;
sj->stop = stop;
sj->do_update = do_update;
@ -362,8 +367,8 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
if (sj->dumprect) {
if (mh) {
if (mh->append_movie(&rd, rd.sfra, rd.cfra, (int *)sj->dumprect,
sj->dumpsx, sj->dumpsy, &sj->reports))
if (mh->append_movie(sj->movie_ctx, &rd, rd.sfra, rd.cfra, (int *)sj->dumprect,
sj->dumpsx, sj->dumpsy, "", &sj->reports))
{
BKE_reportf(&sj->reports, RPT_INFO, "Appended frame: %d", rd.cfra);
printf("Appended frame %d\n", rd.cfra);
@ -379,7 +384,7 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
BKE_image_path_from_imformat(
name, rd.pic, sj->bmain->name, rd.cfra,
&rd.im_format, (rd.scemode & R_EXTENSION) != 0, true);
&rd.im_format, (rd.scemode & R_EXTENSION) != 0, true, NULL);
ibuf->rect = sj->dumprect;
ok = BKE_imbuf_write(ibuf, name, &rd.im_format);
@ -410,8 +415,10 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
PIL_sleep_ms(U.scrcastwait);
}
if (mh)
mh->end_movie();
if (mh) {
mh->end_movie(sj->movie_ctx);
mh->context_free(sj->movie_ctx);
}
BKE_report(&sj->reports, RPT_INFO, "Screencast job stopped");
}

@ -499,7 +499,7 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
int w = imapaintpartial.x2 - imapaintpartial.x1;
int h = imapaintpartial.y2 - imapaintpartial.y1;
/* Testing with partial update in uv editor too */
GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h); //!texpaint);
GPU_paint_update_image(image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h); //!texpaint);
}
}

@ -1109,7 +1109,7 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
if (ima == NULL) {
return 0;
}
else if (ima->packedfile && ima->rr) {
else if (BKE_image_has_packedfile(ima) && ima->rr) {
s->warnpackedfile = ima->id.name + 2;
return 0;
}

@ -5233,7 +5233,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
if (w > maxsize) w = maxsize;
if (h > maxsize) h = maxsize;
ibuf = ED_view3d_draw_offscreen_imbuf(scene, CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, false, R_ALPHAPREMUL, err_out);
ibuf = ED_view3d_draw_offscreen_imbuf(scene, CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, false, R_ALPHAPREMUL, NULL, err_out);
if (!ibuf) {
/* Mostly happens when OpenGL offscreen buffer was failed to create, */
/* but could be other reasons. Should be handled in the future. nazgul */
@ -5444,7 +5444,7 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain)
RNA_string_get(op->ptr, "name", imagename);
}
ima = BKE_image_add_generated(bmain, width, height, imagename, alpha ? 32 : 24, use_float,
gen_type, color);
gen_type, color, false);
return ima;
}

@ -44,6 +44,7 @@
#include "BKE_image.h"
#include "BKE_node.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
#include "RE_pipeline.h"
@ -82,9 +83,9 @@ static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf,
else {
if (ima->source == IMA_SRC_MOVIE) {
ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Movie"), len - ofs);
if (ima->anim)
if (BKE_image_has_anim(ima))
ofs += BLI_snprintf(str + ofs, len - ofs, IFACE_(" %d frs"),
IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN));
IMB_anim_get_duration(((ImageAnim *)ima->anims.first)->anim, IMB_TC_RECORD_RUN));
}
else {
ofs += BLI_strncpy_rlen(str, IFACE_("Image"), len - ofs);
@ -311,10 +312,10 @@ static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *
static const char *ui_imageuser_layer_fake_name(RenderResult *rr)
{
if (rr->rectf) {
if (RE_RenderViewGetRectf(rr, 0)) {
return IFACE_("Composite");
}
else if (rr->rect32) {
else if (RE_RenderViewGetRect32(rr, 0)) {
return IFACE_("Sequence");
}
else {
@ -375,7 +376,7 @@ final:
static const char *ui_imageuser_pass_fake_name(RenderLayer *rl)
{
if (rl == NULL || rl->rectf) {
if (rl == NULL) {
return IFACE_("Combined");
}
else {
@ -383,9 +384,9 @@ static const char *ui_imageuser_pass_fake_name(RenderLayer *rl)
}
}
static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *ptrpair_p)
static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
void **rnd_data = ptrpair_p;
void **rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
Image *image = rnd_data[0];
ImageUser *iuser = rnd_data[1];
@ -398,6 +399,7 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *
RenderPass *rpass;
const char *fake_name;
int nr;
int passflag = 0;
/* may have been freed since drawing */
rr = BKE_image_acquire_renderresult(scene, image);
@ -419,15 +421,22 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *
fake_name = ui_imageuser_pass_fake_name(rl);
if (fake_name) {
BLI_strncpy(rpass_fake.name, fake_name, sizeof(rpass_fake.name));
BLI_strncpy(rpass_fake.internal_name, fake_name, sizeof(rpass_fake.internal_name));
nr += 1;
}
/* rendered results don't have a Combined pass */
for (rpass = rl ? rl->passes.last : NULL; rpass; rpass = rpass->prev, nr--) {
/* just show one pass of each kind */
if (passflag & rpass->passtype)
continue;
passflag |= rpass->passtype;
final:
uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->name), 0, 0,
UI_UNIT_X * 5, UI_UNIT_X, &iuser->pass, (float) nr, 0.0, 0, -1, "");
uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rpass->internal_name), 0, 0,
UI_UNIT_X * 5, UI_UNIT_X, &iuser->passtype, (float) rpass->passtype, 0.0, 0, -1, "");
}
if (fake_name) {
@ -441,21 +450,81 @@ final:
BKE_image_release_renderresult(scene, image);
}
/**************************** view menus *****************************/
static void ui_imageuser_view_menu_rr(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
void **rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
Image *image = rnd_data[0];
ImageUser *iuser = rnd_data[1];
RenderResult *rr;
RenderView *rview;
int nr;
Scene *scene = iuser->scene;
/* may have been freed since drawing */
rr = BKE_image_acquire_renderresult(scene, image);
if (UNLIKELY(rr == NULL)) {
return;
}
UI_block_layout_set_current(block, layout);
uiLayoutColumn(layout, false);
uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("View"),
0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
uiItemS(layout);
nr = (rr ? BLI_listbase_count(&rr->views) : 0) - 1;
for (rview = rr ? rr->views.last : NULL; rview; rview = rview->prev, nr--) {
uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(rview->name), 0, 0,
UI_UNIT_X * 5, UI_UNIT_X, &iuser->view, (float) nr, 0.0, 0, -1, "");
}
BKE_image_release_renderresult(scene, image);
}
static void ui_imageuser_view_menu_multiview(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
void **rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
Image *image = rnd_data[0];
ImageUser *iuser = rnd_data[1];
int nr;
ImageView *iv;
UI_block_layout_set_current(block, layout);
uiLayoutColumn(layout, false);
uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("View"),
0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
uiItemS(layout);
nr = BLI_listbase_count(&image->views) - 1;
for (iv = image->views.last; iv; iv = iv->prev, nr--) {
uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, IFACE_(iv->name), 0, 0,
UI_UNIT_X * 5, UI_UNIT_X, &iuser->view, (float) nr, 0.0, 0, -1, "");
}
}
/* 5 layer button callbacks... */
static void image_multi_cb(bContext *C, void *rr_v, void *iuser_v)
{
ImageUser *iuser = iuser_v;
BKE_image_multilayer_index(rr_v, iuser);
BKE_image_multilayer_index(rr_v, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
}
static void image_multi_inclay_cb(bContext *C, void *rr_v, void *iuser_v)
{
RenderResult *rr = rr_v;
ImageUser *iuser = iuser_v;
int tot = BLI_listbase_count(&rr->layers);
if (rr->rectf || rr->rect32)
if (RE_HasFakeLayer(rr))
tot++; /* fake compo/sequencer layer */
if (iuser->layer < tot - 1) {
@ -483,7 +552,7 @@ static void image_multi_incpass_cb(bContext *C, void *rr_v, void *iuser_v)
if (rl) {
int tot = BLI_listbase_count(&rl->passes);
if (rr->rectf || rr->rect32)
if (RE_HasFakeLayer(rr))
tot++; /* fake compo/sequencer layer */
if (iuser->pass < tot - 1) {
@ -504,6 +573,16 @@ static void image_multi_decpass_cb(bContext *C, void *rr_v, void *iuser_v)
}
}
/* 5 view button callbacks... */
static void image_multiview_cb(bContext *C, void *ima_v, void *iuser_v)
{
Image *ima = ima_v;
ImageUser *iuser = iuser_v;
BKE_image_multiview_index(ima, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
}
#if 0
static void image_freecache_cb(bContext *C, void *ima_v, void *unused)
{
@ -523,13 +602,14 @@ static void image_user_change(bContext *C, void *iuser_v, void *unused)
static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w, short *render_slot)
{
static void *rnd_pt[3]; /* XXX, workaround */
static void *rnd_pt[4]; /* XXX, workaround */
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but;
RenderLayer *rl = NULL;
int wmenu1, wmenu2, wmenu3;
int wmenu1, wmenu2, wmenu3, wmenu4;
const char *fake_name;
const char *display_name;
const char *display_name = "";
const bool show_stereo = (iuser->flag & IMA_SHOW_STEREO);
uiLayoutRow(layout, true);
@ -537,6 +617,7 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
wmenu1 = (2 * w) / 5;
wmenu2 = (3 * w) / 5;
wmenu3 = (3 * w) / 6;
wmenu4 = (3 * w) / 6;
rnd_pt[0] = image;
rnd_pt[1] = iuser;
@ -558,6 +639,7 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
if (rr) {
RenderPass *rpass;
RenderView *rview;
int rpass_index;
/* layer */
@ -566,20 +648,50 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
rl = BLI_findlink(&rr->layers, rpass_index);
rnd_pt[2] = SET_INT_IN_POINTER(rpass_index);
display_name = rl ? rl->name : (fake_name ? fake_name : "");
but = uiDefMenuBut(block, ui_imageuser_layer_menu, rnd_pt, display_name, 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer"));
UI_but_func_set(but, image_multi_cb, rr, iuser);
UI_but_type_set_menu_from_pulldown(but);
if (RE_layers_have_name(rr)) {
display_name = rl ? rl->name : (fake_name ? fake_name : "");
but = uiDefMenuBut(block, ui_imageuser_layer_menu, rnd_pt, display_name, 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer"));
UI_but_func_set(but, image_multi_cb, rr, iuser);
UI_but_type_set_menu_from_pulldown(but);
}
/* pass */
fake_name = ui_imageuser_pass_fake_name(rl);
rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL);
display_name = rpass ? rpass->name : (fake_name ? fake_name : "");
display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : "");
but = uiDefMenuBut(block, ui_imageuser_pass_menu, rnd_pt, display_name, 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass"));
UI_but_func_set(but, image_multi_cb, rr, iuser);
UI_but_type_set_menu_from_pulldown(but);
/* view */
if (BLI_listbase_count_ex(&rr->views, 2) > 1 && !show_stereo) {
rview = BLI_findlink(&rr->views, iuser->view);
display_name = rview ? rview->name : "";
but = uiDefMenuBut(block, ui_imageuser_view_menu_rr, rnd_pt, display_name, 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View"));
UI_but_func_set(but, image_multi_cb, rr, iuser);
UI_but_type_set_menu_from_pulldown(but);
}
}
/* stereo image */
else if (((image->flag & IMA_IS_STEREO) && (!show_stereo)) ||
((image->flag & IMA_IS_MULTIVIEW) && ((image->flag & IMA_IS_STEREO) == 0)))
{
ImageView *iv;
int nr = 0;
for (iv = image->views.first; iv; iv = iv->next) {
if (nr++ == iuser->view) {
display_name = iv->name;
break;
}
}
but = uiDefMenuBut(block, ui_imageuser_view_menu_multiview, rnd_pt, display_name, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View"));
UI_but_func_set(but, image_multiview_cb, image, iuser);
UI_but_type_set_menu_from_pulldown(but);
}
}
@ -734,13 +846,13 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
if (ima->source != IMA_SRC_GENERATED) {
row = uiLayoutRow(layout, true);
if (ima->packedfile)
if (BKE_image_has_packedfile(ima))
uiItemO(row, "", ICON_PACKAGE, "image.unpack");
else
uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
row = uiLayoutRow(row, true);
uiLayoutSetEnabled(row, ima->packedfile == NULL);
uiLayoutSetEnabled(row, BKE_image_has_packedfile(ima) == false);
uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
}
@ -792,6 +904,17 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
uiItemR(row, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE);
}
if ((scene->r.scemode & R_MULTIVIEW) != 0) {
uiItemS(layout);
col = uiLayoutColumn(layout, false);
uiItemR(col, &imaptr, "use_multiview", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(&imaptr, "use_multiview"));
uiTemplateImageViews(col, &imaptr);
}
if (ima->source == IMA_SRC_MOVIE) {
col = uiLayoutColumn(layout, false);
uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE);
@ -962,6 +1085,101 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man
}
}
void uiTemplateImageStereo3d(uiLayout *layout, PointerRNA *stereo3d_format_ptr)
{
Stereo3dFormat *stereo3d_format = stereo3d_format_ptr->data;
uiLayout *col;
col = uiLayoutColumn(layout, false);
uiItemR(col, stereo3d_format_ptr, "display_mode", 0, NULL, ICON_NONE);
switch (stereo3d_format->display_mode) {
case S3D_DISPLAY_ANAGLYPH:
{
uiItemR(col, stereo3d_format_ptr, "anaglyph_type", 0, NULL, ICON_NONE);
break;
}
case S3D_DISPLAY_INTERLACE:
{
uiItemR(col, stereo3d_format_ptr, "interlace_type", 0, NULL, ICON_NONE);
uiItemR(col, stereo3d_format_ptr, "use_interlace_swap", 0, NULL, ICON_NONE);
break;
}
case S3D_DISPLAY_SIDEBYSIDE:
{
uiItemR(col, stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE);
/* fall-through */
}
case S3D_DISPLAY_TOPBOTTOM:
{
uiItemR(col, stereo3d_format_ptr, "use_squeezed_frame", 0, NULL, ICON_NONE);
break;
}
}
}
static void uiTemplateViewsFormat(uiLayout *layout, PointerRNA *ptr, PointerRNA *stereo3d_format_ptr)
{
uiLayout *col, *box;
col = uiLayoutColumn(layout, false);
uiItemL(col, IFACE_("Views Format:"), ICON_NONE);
uiItemR(uiLayoutRow(col, false), ptr, "views_format", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
if (stereo3d_format_ptr) {
box = uiLayoutBox(col);
uiLayoutSetActive(box, RNA_enum_get(ptr, "views_format") == R_IMF_VIEWS_STEREO_3D);
uiTemplateImageStereo3d(box, stereo3d_format_ptr);
}
}
void uiTemplateImageViews(uiLayout *layout, PointerRNA *imaptr)
{
Image *ima = imaptr->data;
if (ima->type != IMA_TYPE_MULTILAYER) {
PropertyRNA *prop;
PointerRNA stereo3d_format_ptr;
prop = RNA_struct_find_property(imaptr, "stereo_3d_format");
stereo3d_format_ptr = RNA_property_pointer_get(imaptr, prop);
uiTemplateViewsFormat(layout, imaptr, &stereo3d_format_ptr);
}
else {
uiTemplateViewsFormat(layout, imaptr, NULL);
}
}
void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr)
{
ImageFormatData *imf = imfptr->data;
uiLayout *col;
if (ptr) {
uiItemR(layout, ptr, "use_multiview", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_multiview"));
}
else {
col = uiLayoutColumn(layout, false);
}
if (imf->imtype != R_IMF_IMTYPE_MULTILAYER) {
PropertyRNA *prop;
PointerRNA stereo3d_format_ptr;
prop = RNA_struct_find_property(imfptr, "stereo_3d_format");
stereo3d_format_ptr = RNA_property_pointer_get(imfptr, prop);
uiTemplateViewsFormat(col, imfptr, &stereo3d_format_ptr);
}
else {
uiTemplateViewsFormat(col, imfptr, NULL);
}
}
void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser)
{
Scene *scene = CTX_data_scene(C);

@ -783,7 +783,7 @@ void draw_image_main(const bContext *C, ARegion *ar)
Image *ima;
ImBuf *ibuf;
float zoomx, zoomy;
bool show_viewer, show_render, show_paint;
bool show_viewer, show_render, show_paint, show_stereo3d, show_multilayer;
void *lock;
/* XXX can we do this in refresh? */
@ -813,6 +813,8 @@ void draw_image_main(const bContext *C, ARegion *ar)
show_viewer = (ima && ima->source == IMA_SRC_VIEWER) != 0;
show_render = (show_viewer && ima->type == IMA_TYPE_R_RESULT) != 0;
show_paint = (ima && (sima->mode == SI_MODE_PAINT) && (show_viewer == false) && (show_render == false));
show_stereo3d = (ima && (ima->flag & IMA_IS_STEREO) && (sima->iuser.flag & IMA_SHOW_STEREO));
show_multilayer = ima && BKE_image_is_multilayer(ima);
if (show_viewer) {
/* use locked draw for drawing viewer image buffer since the compositor
@ -823,6 +825,14 @@ void draw_image_main(const bContext *C, ARegion *ar)
BLI_lock_thread(LOCK_DRAW_IMAGE);
}
if (show_stereo3d) {
if (show_multilayer)
/* update multiindex and pass for the current eye */
BKE_image_multilayer_index(ima->rr, &sima->iuser);
else
BKE_image_multiview_index(ima, &sima->iuser);
}
ibuf = ED_space_image_acquire_buffer(sima, &lock);
/* draw the image or grid */

@ -30,14 +30,21 @@
#include <stddef.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#ifndef WIN32
# include <unistd.h>
#else
# include <io.h>
#endif
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_string_utf8.h"
#include "BLF_translation.h"
@ -60,6 +67,7 @@
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_sound.h"
#include "BKE_scene.h"
#include "GPU_draw.h"
#include "GPU_buffers.h"
@ -68,6 +76,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_moviecache.h"
#include "intern/openexr/openexr_multi.h"
#include "RE_pipeline.h"
@ -936,6 +945,7 @@ static void image_filesel(bContext *C, wmOperator *op, const char *path)
typedef struct ImageOpenData {
PropertyPointerRNA pprop;
ImageUser *iuser;
ImageFormatData im_format;
} ImageOpenData;
typedef struct ImageFrame {
@ -946,7 +956,6 @@ typedef struct ImageFrame {
static void image_open_init(bContext *C, wmOperator *op)
{
ImageOpenData *iod;
op->customdata = iod = MEM_callocN(sizeof(ImageOpenData), __func__);
iod->iuser = CTX_data_pointer_get_type(C, "image_user", &RNA_ImageUser).data;
UI_context_active_but_prop_get_templateID(C, &iod->pprop.ptr, &iod->pprop.prop);
@ -1048,7 +1057,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
ImageUser *iuser = NULL;
ImageOpenData *iod;
ImageOpenData *iod = op->customdata;
PointerRNA idptr;
Image *ima = NULL;
char path[FILE_MAX];
@ -1085,6 +1094,21 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (!op->customdata)
image_open_init(C, op);
/* handle multiview images */
if (RNA_boolean_get(op->ptr, "use_multiview")) {
ImageFormatData *imf = &iod->im_format;
ima->flag |= IMA_USE_VIEWS;
ima->views_format = imf->views_format;
*ima->stereo3d_format = imf->stereo3d_format;
}
else {
ima->flag &= ~IMA_USE_VIEWS;
ima->flag &= ~IMA_IS_STEREO;
ima->flag &= ~IMA_IS_MULTIVIEW;
BKE_image_free_views(ima);
}
/* only image path after save, never ibuf */
if (is_relative_path) {
if (!exists) {
@ -1128,6 +1152,8 @@ static int image_open_exec(bContext *C, wmOperator *op)
iuser->framenr = 1;
iuser->offset = frame_ofs - 1;
iuser->fie_ima = 2;
iuser->scene = scene;
BKE_image_init_imageuser(ima, iuser);
}
/* XXX unpackImage frees image buffers */
@ -1146,7 +1172,8 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */
const char *path = U.textudir;
Image *ima = NULL;
Scene *scene = CTX_data_scene(C);
PropertyRNA *prop;
if (sima) {
ima = sima->image;
}
@ -1185,11 +1212,44 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
image_open_init(C, op);
/* show multiview save options only if scene has multiviews */
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
image_filesel(C, op, path);
return OPERATOR_RUNNING_MODAL;
}
static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
return !(STREQ(prop_id, "filepath") ||
STREQ(prop_id, "directory") ||
STREQ(prop_id, "filename")
);
}
static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
ImageOpenData *iod = op->customdata;
ImageFormatData *imf = &iod->im_format;
PointerRNA imf_ptr, ptr;
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(layout, &ptr, image_open_draw_check_prop, '\0');
/* image template */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
/* multiview template */
if (RNA_boolean_get(op->ptr, "show_multiview"))
uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
}
/* called by other space types too */
void IMAGE_OT_open(wmOperatorType *ot)
{
@ -1202,6 +1262,7 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot->exec = image_open_exec;
ot->invoke = image_open_invoke;
ot->cancel = image_open_cancel;
ot->ui = image_open_draw;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@ -1233,10 +1294,10 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
}
if (!ima || !iuser || !ima->anim)
if (!ima || !iuser || !BKE_image_has_anim(ima))
return OPERATOR_CANCELLED;
iuser->frames = IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN);
iuser->frames = IMB_anim_get_duration(((ImageAnim *) ima->anims.first)->anim, IMB_TC_RECORD_RUN);
BKE_image_user_frame_calc(iuser, scene->r.cfra, 0);
return OPERATOR_FINISHED;
@ -1433,6 +1494,10 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
}
}
/* use the multiview image settings as the default */
simopts->im_format.stereo3d_format = *ima->stereo3d_format;
simopts->im_format.views_format = ima->views_format;
/* color management */
BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings);
BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings);
@ -1468,30 +1533,131 @@ static void save_image_options_to_op(SaveImageOptions *simopts, wmOperator *op)
RNA_string_set(op->ptr, "filepath", simopts->filepath);
}
/* returns the pass index for the view_id */
static int get_multiview_pass_id(RenderResult *rr, ImageUser *iuser, const int view_id)
{
RenderLayer *rl;
RenderPass *rpass;
int passtype;
short rl_index = 0, rp_index;
if (rr == NULL || iuser == NULL)
return 0;
if (BLI_listbase_count_ex(&rr->views, 2) < 2)
return iuser->pass;
if (RE_HasFakeLayer(rr))
rl_index ++; /* fake compo/sequencer layer */
rl = BLI_findlink(&rr->layers, rl_index);
if (!rl) return iuser->pass;
rpass = BLI_findlink(&rl->passes, iuser->pass);
passtype = rpass->passtype;
rp_index = 0;
for (rpass = rl->passes.first; rpass; rpass = rpass->next, rp_index++) {
if (rpass->passtype == passtype &&
rpass->view_id == view_id)
{
return rp_index;
}
}
return iuser->pass;
}
static void save_image_post(wmOperator *op, ImBuf *ibuf, Image *ima, int ok, int save_copy, const char *relbase, int relative, int do_newpath, const char *filepath)
{
if (ok) {
if (!save_copy) {
if (do_newpath) {
BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
BLI_strncpy(ima->name, filepath, sizeof(ima->name));
}
ibuf->userflags &= ~IB_BITMAPDIRTY;
/* change type? */
if (ima->type == IMA_TYPE_R_RESULT) {
ima->type = IMA_TYPE_IMAGE;
/* workaround to ensure the render result buffer is no longer used
* by this image, otherwise can crash when a new render result is
* created. */
if (ibuf->rect && !(ibuf->mall & IB_rect))
imb_freerectImBuf(ibuf);
if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
imb_freerectfloatImBuf(ibuf);
if (ibuf->zbuf && !(ibuf->mall & IB_zbuf))
IMB_freezbufImBuf(ibuf);
if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
IMB_freezbuffloatImBuf(ibuf);
}
if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
ima->source = IMA_SRC_FILE;
ima->type = IMA_TYPE_IMAGE;
}
/* only image path, never ibuf */
if (relative) {
BLI_path_rel(ima->name, relbase); /* only after saving */
}
IMB_colormanagment_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
}
}
else {
BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", filepath);
}
}
static void save_imbuf_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
{
if (colormanaged_ibuf != ibuf) {
/* This guys might be modified by image buffer write functions,
* need to copy them back from color managed image buffer to an
* original one, so file type of image is being properly updated.
*/
ibuf->ftype = colormanaged_ibuf->ftype;
ibuf->planes = colormanaged_ibuf->planes;
IMB_freeImBuf(colormanaged_ibuf);
}
}
/**
* \return success.
* \note ``ima->name`` and ``ibuf->name`` should end up the same.
* \note for multiview the first ``ibuf`` is important to get the settings.
*/
static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveImageOptions *simopts, bool do_newpath)
{
Image *ima = ED_space_image(sima);
void *lock;
ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock);
Scene *scene;
RenderResult *rr = NULL;
bool ok = false;
WM_cursor_wait(1);
if (ibuf) {
ImBuf *colormanaged_ibuf;
ImBuf *colormanaged_ibuf = NULL;
const char *relbase = ID_BLEND_PATH(CTX_data_main(C), &ima->id);
const bool relative = (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path"));
const bool save_copy = (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy"));
const bool save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render"));
ImageFormatData *imf = &simopts->im_format;
const bool is_multilayer = imf->imtype == R_IMF_IMTYPE_MULTILAYER;
bool is_mono;
/* old global to ensure a 2nd save goes to same dir */
BLI_strncpy(G.ima, simopts->filepath, sizeof(G.ima));
WM_cursor_wait(1);
if (ima->type == IMA_TYPE_R_RESULT) {
/* enforce user setting for RGB or RGBA, but skip BW */
if (simopts->im_format.planes == R_IMF_PLANES_RGBA) {
@ -1512,83 +1678,197 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
}
}
colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
/* we need renderresult for exr and rendered multiview */
scene = CTX_data_scene(C);
rr = BKE_image_acquire_renderresult(scene, ima);
is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : (ima->flag & IMA_IS_MULTIVIEW) == 0;
if (simopts->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
Scene *scene = CTX_data_scene(C);
RenderResult *rr = BKE_image_acquire_renderresult(scene, ima);
if (rr) {
ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, simopts->im_format.exr_codec);
/* error handling */
if (!rr) {
if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
goto cleanup;
}
}
else {
if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
if ((ima->flag & IMA_IS_STEREO) == 0) {
BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
goto cleanup;
}
/* it shouldn't ever happen*/
if ((BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)) == NULL) ||
(BLI_findstring(&rr->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)) == NULL))
{
BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
goto cleanup;
}
}
}
/* fancy multiview OpenEXR */
if ((imf->imtype == R_IMF_IMTYPE_MULTILAYER) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) {
ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, true, NULL);
save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
ED_space_image_release_buffer(sima, ibuf, lock);
}
else if ((imf->imtype == R_IMF_IMTYPE_OPENEXR) && (imf->views_format == R_IMF_VIEWS_MULTIVIEW)) {
/* treat special Openexr case separetely (this is the singlelayer multiview OpenEXR */
BKE_imbuf_write_prepare(ibuf, imf);
ok = BKE_image_save_openexr_multiview(ima, ibuf, simopts->filepath, (IB_rect | IB_zbuf | IB_zbuffloat | IB_multiview));
ED_space_image_release_buffer(sima, ibuf, lock);
}
/* regular mono pipeline */
else if (is_mono) {
if (is_multilayer) {
ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL);
}
else {
BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, imf, save_copy);
save_imbuf_post(ibuf, colormanaged_ibuf);
}
BKE_image_release_renderresult(scene, ima);
}
else {
ok = BKE_imbuf_write_as(colormanaged_ibuf, simopts->filepath, &simopts->im_format, save_copy);
save_image_post(op, ibuf, ima, ok, (is_multilayer ? true : save_copy), relbase, relative, do_newpath, simopts->filepath);
ED_space_image_release_buffer(sima, ibuf, lock);
}
/* individual multiview images */
else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
size_t i;
unsigned char planes = ibuf->planes;
const size_t totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
if (ok) {
if (!save_copy) {
if (do_newpath) {
BLI_strncpy(ibuf->name, simopts->filepath, sizeof(ibuf->name));
BLI_strncpy(ima->name, simopts->filepath, sizeof(ima->name));
if (!is_multilayer) {
ED_space_image_release_buffer(sima, ibuf, lock);
}
for (i = 0; i < totviews; i++) {
char filepath[FILE_MAX];
bool ok_view = false;
const char *view = rr ? ((RenderView *) BLI_findlink(&rr->views, i))->name :
((ImageView *) BLI_findlink(&ima->views, i))->name;
if (is_multilayer) {
BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
ok_view = RE_WriteRenderResult(op->reports, rr, filepath, imf, false, view);
save_image_post(op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
}
else {
/* copy iuser to get the correct ibuf for this view */
ImageUser iuser = sima->iuser;
iuser.view = i;
iuser.flag &= ~IMA_SHOW_STEREO;
ibuf->userflags &= ~IB_BITMAPDIRTY;
if (rr) {
iuser.pass = get_multiview_pass_id(rr, &sima->iuser, i);
BKE_image_multilayer_index(rr, &iuser);
}
else {
BKE_image_multiview_index(ima, &iuser);
}
/* change type? */
if (ima->type == IMA_TYPE_R_RESULT) {
ima->type = IMA_TYPE_IMAGE;
ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
ibuf->planes = planes;
/* workaround to ensure the render result buffer is no longer used
* by this image, otherwise can crash when a new render result is
* created. */
if (ibuf->rect && !(ibuf->mall & IB_rect))
imb_freerectImBuf(ibuf);
if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
imb_freerectfloatImBuf(ibuf);
if (ibuf->zbuf && !(ibuf->mall & IB_zbuf))
IMB_freezbufImBuf(ibuf);
if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
IMB_freezbuffloatImBuf(ibuf);
}
if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
ima->source = IMA_SRC_FILE;
ima->type = IMA_TYPE_IMAGE;
BKE_scene_multiview_view_filepath_get(&scene->r, simopts->filepath, view, filepath);
colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &simopts->im_format, save_copy);
save_imbuf_post(ibuf, colormanaged_ibuf);
save_image_post(op, ibuf, ima, ok_view, true, relbase, relative, do_newpath, filepath);
BKE_image_release_ibuf(sima->image, ibuf, lock);
}
ok &= ok_view;
}
/* only image path, never ibuf */
if (relative) {
BLI_path_rel(ima->name, relbase); /* only after saving */
}
IMB_colormanagment_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
if (is_multilayer) {
ED_space_image_release_buffer(sima, ibuf, lock);
}
}
else {
BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", simopts->filepath);
}
/* stereo (multiview) images */
else if (simopts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
ok = RE_WriteRenderResult(op->reports, rr, simopts->filepath, imf, false, NULL);
save_image_post(op, ibuf, ima, ok, true, relbase, relative, do_newpath, simopts->filepath);
ED_space_image_release_buffer(sima, ibuf, lock);
}
else {
ImBuf *ibuf_stereo[2] = {NULL};
unsigned char planes = ibuf->planes;
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
int i;
/* we need to get the specific per-view buffers */
ED_space_image_release_buffer(sima, ibuf, lock);
for (i = 0; i < 2; i ++) {
ImageUser iuser = sima->iuser;
iuser.flag &= ~IMA_SHOW_STEREO;
if (rr) {
int id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
iuser.pass = get_multiview_pass_id(rr, &sima->iuser, id);
iuser.view = id;
BKE_image_multilayer_index(rr, &iuser);
}
else {
iuser.view = i;
BKE_image_multiview_index(ima, &iuser);
}
ibuf = BKE_image_acquire_ibuf(sima->image, &iuser, &lock);
if (ibuf == NULL) {
BKE_report(op->reports, RPT_ERROR, "Did not write, unexpected error when saving stereo image");
goto cleanup;
}
ibuf->planes = planes;
/* color manage the ImBuf leaving it ready for saving */
colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true,
&imf->view_settings, &imf->display_settings, imf);
BKE_imbuf_write_prepare(colormanaged_ibuf, imf);
IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf);
/* duplicate buffer to prevent locker issue when using render result */
ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
save_imbuf_post(ibuf, colormanaged_ibuf);
BKE_image_release_ibuf(sima->image, ibuf, lock);
}
ibuf = IMB_stereo3d_ImBuf(imf, ibuf_stereo[0], ibuf_stereo[1]);
/* save via traditional path */
ok = BKE_imbuf_write_as(ibuf, simopts->filepath, imf, save_copy);
IMB_freeImBuf(ibuf);
for (i = 0; i < 2; i ++) {
IMB_freeImBuf(ibuf_stereo[i]);
}
}
}
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, sima->image);
WM_cursor_wait(0);
if (colormanaged_ibuf != ibuf) {
/* This guys might be modified by image buffer write functions,
* need to copy them back from color managed image buffer to an
* original one, so file type of image is being properly updated.
*/
ibuf->ftype = colormanaged_ibuf->ftype;
ibuf->planes = colormanaged_ibuf->planes;
IMB_freeImBuf(colormanaged_ibuf);
}
}
else {
cleanup:
ED_space_image_release_buffer(sima, ibuf, lock);
}
ED_space_image_release_buffer(sima, ibuf, lock);
if (rr) {
BKE_image_release_renderresult(scene, ima);
}
WM_cursor_wait(0);
return ok;
}
@ -1636,6 +1916,7 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
Image *ima = ED_space_image(sima);
Scene *scene = CTX_data_scene(C);
SaveImageOptions simopts;
PropertyRNA *prop;
const bool save_as_render = ((ima->source == IMA_SRC_VIEWER) || (ima->flag & IMA_VIEW_AS_RENDER));
if (RNA_struct_property_is_set(op->ptr, "filepath"))
@ -1657,6 +1938,12 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
op->customdata = MEM_mallocN(sizeof(simopts.im_format), __func__);
memcpy(op->customdata, &simopts.im_format, sizeof(simopts.im_format));
/* show multiview save options only if image has multiviews */
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
prop = RNA_struct_find_property(op->ptr, "use_multiview");
RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
image_filesel(C, op, simopts.filepath);
return OPERATOR_RUNNING_MODAL;
@ -1683,15 +1970,20 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
ImageFormatData *imf = op->customdata;
PointerRNA ptr;
PointerRNA imf_ptr, ptr;
const bool is_multiview = RNA_boolean_get(op->ptr, "use_multiview");
/* image template */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &ptr);
uiTemplateImageSettings(layout, &ptr, false);
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
uiTemplateImageSettings(layout, &imf_ptr, false);
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, '\0');
/* multiview template */
if (is_multiview)
uiTemplateImageFormatViews(layout, &imf_ptr, NULL);
}
static int image_save_as_poll(bContext *C)
@ -1714,8 +2006,6 @@ static int image_save_as_poll(bContext *C)
void IMAGE_OT_save_as(wmOperatorType *ot)
{
// PropertyRNA *prop;
/* identifiers */
ot->name = "Save As Image";
ot->idname = "IMAGE_OT_save_as";
@ -1932,6 +2222,7 @@ static int image_new_exec(bContext *C, wmOperator *op)
float color[4];
int width, height, floatbuf, gen_type, alpha;
int gen_context;
int stereo3d;
/* retrieve state */
sima = CTX_wm_space_image(C);
@ -1952,11 +2243,12 @@ static int image_new_exec(bContext *C, wmOperator *op)
RNA_float_get_array(op->ptr, "color", color);
alpha = RNA_boolean_get(op->ptr, "alpha");
gen_context = RNA_enum_get(op->ptr, "gen_context");
stereo3d = RNA_boolean_get(op->ptr, "use_stereo_3d");
if (!alpha)
color[3] = 1.0f;
ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color);
ima = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, floatbuf, gen_type, color, stereo3d);
if (!ima)
return OPERATOR_CANCELLED;
@ -2036,6 +2328,53 @@ static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
}
static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *split, *col[2];
uiLayout *layout = op->layout;
PointerRNA ptr;
#if 0
Scene *scene = CTX_data_scene(C);
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
#endif
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
/* copy of WM_operator_props_dialog_popup() layout */
split = uiLayoutSplit(layout, 0.5f, false);
col[0] = uiLayoutColumn(split, false);
col[1] = uiLayoutColumn(split, false);
uiItemL(col[0], IFACE_("Name"), ICON_NONE);
uiItemR(col[1], &ptr, "name", 0, "", ICON_NONE);
uiItemL(col[0], IFACE_("Width"), ICON_NONE);
uiItemR(col[1], &ptr, "width", 0, "", ICON_NONE);
uiItemL(col[0], IFACE_("Height"), ICON_NONE);
uiItemR(col[1], &ptr, "height", 0, "", ICON_NONE);
uiItemL(col[0], IFACE_("Color"), ICON_NONE);
uiItemR(col[1], &ptr, "color", 0, "", ICON_NONE);
uiItemL(col[0], "", ICON_NONE);
uiItemR(col[1], &ptr, "alpha", 0, NULL, ICON_NONE);
uiItemL(col[0], IFACE_("Generated Type"), ICON_NONE);
uiItemR(col[1], &ptr, "generated_type", 0, "", ICON_NONE);
uiItemL(col[0], "", ICON_NONE);
uiItemR(col[1], &ptr, "float", 0, NULL, ICON_NONE);
#if 0
if (is_multiview) {
uiItemL(col[0], "", ICON_NONE);
uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
}
#endif
}
void IMAGE_OT_new(wmOperatorType *ot)
{
PropertyRNA *prop;
@ -2056,6 +2395,7 @@ void IMAGE_OT_new(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_new_exec;
ot->invoke = image_new_invoke;
ot->ui = image_new_draw;
/* flags */
ot->flag = OPTYPE_UNDO;
@ -2075,7 +2415,8 @@ void IMAGE_OT_new(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
prop = RNA_def_enum(ot->srna, "gen_context", gen_context_items, 0, "Gen Context", "Generation context");
RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_boolean(ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views");
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
#undef IMA_DEF_NAME
@ -2200,7 +2541,7 @@ static bool image_pack_test(bContext *C, wmOperator *op)
if (!ima)
return 0;
if (!as_png && ima->packedfile)
if (!as_png && BKE_image_has_packedfile(ima))
return 0;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@ -2229,7 +2570,7 @@ static int image_pack_exec(bContext *C, wmOperator *op)
if (as_png)
BKE_image_memorypack(ima);
else
ima->packedfile = newPackedFile(op->reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
BKE_image_packfiles(op->reports, ima, ID_BLEND_PATH(bmain, &ima->id));
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
@ -2301,7 +2642,7 @@ static int image_unpack_exec(bContext *C, wmOperator *op)
if (!ima) ima = CTX_data_edit_image(C);
}
if (!ima || !ima->packedfile)
if (!ima || !BKE_image_has_packedfile(ima))
return OPERATOR_CANCELLED;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@ -2329,7 +2670,7 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
if (RNA_struct_property_is_set(op->ptr, "id"))
return image_unpack_exec(C, op);
if (!ima || !ima->packedfile)
if (!ima || !BKE_image_has_packedfile(ima))
return OPERATOR_CANCELLED;
if (ima->source == IMA_SRC_SEQUENCE || ima->source == IMA_SRC_MOVIE) {
@ -2340,7 +2681,7 @@ static int image_unpack_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
if (G.fileflags & G_AUTOPACK)
BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save");
unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, ima->name, "textures", ima->packedfile);
unpack_menu(C, "IMAGE_OT_unpack", ima->id.name + 2, ima->name, "textures", BKE_image_has_packedfile(ima) ? ((ImagePackedFile *)ima->packedfiles.first)->packedfile : NULL);
return OPERATOR_FINISHED;
}

@ -156,7 +156,8 @@ static SpaceLink *image_new(const bContext *UNUSED(C))
simage->iuser.ok = true;
simage->iuser.fie_ima = 2;
simage->iuser.frames = 100;
simage->iuser.flag = IMA_SHOW_STEREO;
scopes_new(&simage->scopes);
simage->sample_line_hist.height = 100;

@ -703,7 +703,9 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr,
uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE);
}
if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER) {
if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
RNA_boolean_get(ptr, "has_layers"))
{
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE);
}
@ -1214,6 +1216,24 @@ static void node_shader_set_butfunc(bNodeType *ntype)
/* ****************** BUTTON CALLBACKS FOR COMPOSITE NODES ***************** */
static void node_buts_image_views(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr,
PointerRNA *imaptr)
{
uiLayout *col;
if (!imaptr->data)
return;
col = uiLayoutColumn(layout, false);
if (RNA_boolean_get(ptr, "has_views")) {
if (RNA_enum_get(ptr, "view") == 0)
uiItemR(col, ptr, "view", 0, NULL, ICON_CAMERA_STEREO);
else
uiItemR(col, ptr, "view", 0, NULL, ICON_SCENE);
}
}
static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
bNode *node = ptr->data;
@ -1227,6 +1247,8 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
imaptr = RNA_pointer_get(ptr, "image");
node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr);
node_buts_image_views(layout, C, ptr, &imaptr);
}
static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@ -1717,8 +1739,8 @@ static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), Po
static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
if (multilayer)
uiItemL(layout, IFACE_("Path:"), ICON_NONE);
else
@ -1727,15 +1749,22 @@ static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C)
}
static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
PointerRNA imfptr = RNA_pointer_get(ptr, "format");
PointerRNA active_input_ptr, op_ptr;
uiLayout *row, *col;
int active_index;
int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
node_composit_buts_file_output(layout, C, ptr);
uiTemplateImageSettings(layout, &imfptr, false);
/* disable stereo output for multilayer, too much work for something that no one will use */
/* if someone asks for that we can implement it */
if (is_multiview)
uiTemplateImageFormatViews(layout, &imfptr, NULL);
uiItemS(layout);
uiItemO(layout, IFACE_("Add Input"), ICON_ZOOMIN, "NODE_OT_output_file_add_socket");
@ -1797,6 +1826,9 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format") == false);
uiTemplateImageSettings(col, &imfptr, false);
if (is_multiview)
uiTemplateImageFormatViews(layout, &imfptr, NULL);
}
}
}
@ -2090,6 +2122,18 @@ static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), Poi
uiItemR(layout, ptr, "check", 0, NULL, ICON_NONE);
}
static void node_composit_buts_switch_view_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
{
PointerRNA op_ptr;
wmOperatorType *ot = WM_operatortype_find("NODE_OT_switch_view_update", 1);
BLI_assert(ot != 0);
WM_operator_properties_create_ptr(&op_ptr, ot);
uiItemFullO_ptr(layout, ot, "Update Views", ICON_FILE_REFRESH, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
}
static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *row;
@ -2587,6 +2631,9 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_SWITCH:
ntype->draw_buttons = node_composit_buts_switch;
break;
case CMP_NODE_SWITCH_VIEW:
ntype->draw_buttons_ex = node_composit_buts_switch_view_ex;
break;
case CMP_NODE_MASK_BOX:
ntype->draw_buttons = node_composit_buts_boxmask;
ntype->draw_backdrop = node_composit_backdrop_boxmask;
@ -2959,6 +3006,7 @@ static void node_file_output_socket_draw(bContext *C, uiLayout *layout, PointerR
imfptr = RNA_pointer_get(node_ptr, "format");
imtype = RNA_enum_get(&imfptr, "file_format");
if (imtype == R_IMF_IMTYPE_MULTILAYER) {
NodeImageMultiFileSocket *input = sock->storage;
RNA_pointer_create(&ntree->id, &RNA_NodeOutputFileSlotLayer, input, &inputptr);

@ -212,13 +212,13 @@ static void compo_progressjob(void *cjv, float progress)
*(cj->progress) = progress;
}
/* only this runs inside thread */
static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress)
{
CompoJob *cj = cjv;
bNodeTree *ntree = cj->localtree;
Scene *scene = cj->scene;
SceneRenderView *srv;
if (scene->use_nodes == false)
return;
@ -238,7 +238,11 @@ static void compo_startjob(void *cjv, short *stop, short *do_update, float *prog
// XXX BIF_store_spare();
/* 1 is do_previews */
ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings);
for (srv = scene->r.views.first; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) continue;
ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings, srv->name);
}
ntree->test_break = NULL;
ntree->stats_draw = NULL;
@ -1660,6 +1664,54 @@ void NODE_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ****************** Switch View ******************* */
static int node_switch_view_poll(bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
if (snode && snode->edittree)
return true;
return false;
}
static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node, *next;
for (node = snode->edittree->nodes.first; node; node = next) {
next = node->next;
if (node->flag & SELECT) {
/* call the update function from the Switch View node */
node->update = NODE_UPDATE_OPERATOR;
}
}
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
snode_notify(C, snode);
snode_dag_update(C, snode);
return OPERATOR_FINISHED;
}
void NODE_OT_switch_view_update(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Update Views";
ot->description = "Update views of selected node";
ot->idname = "NODE_OT_switch_view_update";
/* api callbacks */
ot->exec = node_switch_view_exec;
ot->poll = node_switch_view_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ****************** Delete with reconnect ******************* */
static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
{

@ -200,6 +200,8 @@ void NODE_OT_output_file_add_socket(struct wmOperatorType *ot);
void NODE_OT_output_file_remove_active_socket(struct wmOperatorType *ot);
void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot);
void NODE_OT_switch_view_update (struct wmOperatorType *ot);
/* Note: clipboard_cut is a simple macro of copy + delete */
void NODE_OT_clipboard_copy(struct wmOperatorType *ot);
void NODE_OT_clipboard_paste(struct wmOperatorType *ot);

@ -123,6 +123,8 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_viewer_border);
WM_operatortype_append(NODE_OT_clear_viewer_border);
WM_operatortype_append(NODE_OT_switch_view_update);
WM_operatortype_append(NODE_OT_tree_socket_add);
WM_operatortype_append(NODE_OT_tree_socket_remove);
WM_operatortype_append(NODE_OT_tree_socket_move);

@ -60,6 +60,7 @@
#include "ED_screen.h"
#include "ED_sequencer.h"
#include "UI_interface.h"
#include "BKE_sound.h"
@ -70,6 +71,10 @@
/* own include */
#include "sequencer_intern.h"
typedef struct SequencerAddData {
ImageFormatData im_format;
} SequencerAddData;
/* Generic functions, reused by add strip operators */
/* avoid passing multiple args and be more verbose */
@ -222,6 +227,19 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, wmOperator *op)
}
RNA_PROP_END;
}
if ((prop = RNA_struct_find_property(op->ptr, "use_multiview")) && RNA_property_boolean_get(op->ptr, prop)) {
if (op->customdata) {
SequencerAddData *sad = op->customdata;
ImageFormatData *imf = &sad->im_format;
seq_load->views_format = imf->views_format;
seq_load->flag |= SEQ_USE_VIEWS;
/* operator custom data is always released after the SeqLoadInfo, no need to handle the memory here */
seq_load->stereo3d_format = &imf->stereo3d_format;
}
}
}
/**
@ -573,6 +591,9 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
return OPERATOR_CANCELLED;
}
if (op->customdata)
MEM_freeN(op->customdata);
BKE_sequencer_sort(scene);
BKE_sequencer_update_muting(ed);
@ -581,15 +602,40 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
return OPERATOR_FINISHED;
}
/* add sequencer operators */
static void sequencer_add_init(bContext *UNUSED(C), wmOperator *op)
{
op->customdata = MEM_callocN(sizeof(SequencerAddData), __func__);
}
static void sequencer_add_cancel(bContext *UNUSED(C), wmOperator *op)
{
if (op->customdata)
MEM_freeN(op->customdata);
op->customdata = NULL;
}
static bool sequencer_add_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
return !(STREQ(prop_id, "filepath") ||
STREQ(prop_id, "directory") ||
STREQ(prop_id, "filename")
);
}
/* add movie operator */
static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
{
return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_movie_strip);
}
static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
PropertyRNA *prop;
Scene *scene = CTX_data_scene(C);
/* This is for drag and drop */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath"))
@ -599,13 +645,37 @@ static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const w
}
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIE);
sequencer_add_init(C, op);
/* show multiview save options only if scene has multiviews */
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
//return sequencer_add_movie_strip_exec(C, op);
}
static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
SequencerAddData *sad = op->customdata;
ImageFormatData *imf = &sad->im_format;
PointerRNA imf_ptr, ptr;
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(layout, &ptr, sequencer_add_draw_check_prop, '\0');
/* image template */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
/* multiview template */
if (RNA_boolean_get(op->ptr, "show_multiview"))
uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
}
void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
{
@ -618,9 +688,11 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = sequencer_add_movie_strip_invoke;
ot->exec = sequencer_add_movie_strip_exec;
ot->cancel = sequencer_add_cancel;
ot->ui = sequencer_add_draw;
ot->poll = ED_operator_sequencer_active_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@ -735,6 +807,9 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
sequencer_add_apply_overlap(C, op, seq);
if (op->customdata)
MEM_freeN(op->customdata);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -742,6 +817,9 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
PropertyRNA *prop;
Scene *scene = CTX_data_scene(C);
/* drag drop has set the names */
if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) {
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME | SEQPROP_NOPATHS, SEQ_TYPE_IMAGE);
@ -750,6 +828,12 @@ static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const w
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME, SEQ_TYPE_IMAGE);
sequencer_add_init(C, op);
/* show multiview save options only if scene has multiviews */
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
}
@ -766,6 +850,8 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
/* api callbacks */
ot->invoke = sequencer_add_image_strip_invoke;
ot->exec = sequencer_add_image_strip_exec;
ot->cancel = sequencer_add_cancel;
ot->ui = sequencer_add_draw;
ot->poll = ED_operator_sequencer_active_editable;

@ -50,6 +50,7 @@
#include "BKE_main.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
#include "BKE_scene.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
@ -860,7 +861,7 @@ void ED_sequencer_special_preview_clear(void)
sequencer_special_update_set(NULL);
}
ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs)
ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname)
{
SeqRenderData context;
ImBuf *ibuf;
@ -888,6 +889,7 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int
bmain->eval_ctx, bmain, scene,
rectx, recty, proxy_size,
&context);
context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
/* sequencer could start rendering, in this case we need to be sure it wouldn't be canceled
* by Esc pressed somewhere in the past
@ -994,6 +996,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
const bool is_imbuf = ED_space_sequencer_check_show_imbuf(sseq);
int format, type;
bool glsl_used = false;
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
if (G.is_rendering == false && (scene->r.seq_flag & R_SEQ_GL_PREV) == 0) {
/* stop all running jobs, except screen one. currently previews frustrate Render
@ -1023,8 +1026,9 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
return;
}
ibuf = sequencer_ibuf_get(bmain, scene, sseq, cfra, frame_ofs);
/* for now we only support Left/Right */
ibuf = sequencer_ibuf_get(bmain, scene, sseq, cfra, frame_ofs, names[sseq->multiview_eye]);
if (ibuf == NULL)
return;

@ -180,8 +180,6 @@ static void seq_proxy_build_job(const bContext *C)
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
ScrArea *sa = CTX_wm_area(C);
struct SeqIndexBuildContext *context;
LinkData *link;
Sequence *seq;
GSet *file_list;
@ -209,9 +207,7 @@ static void seq_proxy_build_job(const bContext *C)
SEQP_BEGIN (ed, seq)
{
if ((seq->flag & SELECT)) {
context = BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list);
link = BLI_genericNodeN(context);
BLI_addtail(&pj->queue, link);
BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list, &pj->queue);
}
}
SEQ_END
@ -3442,12 +3438,18 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
SEQP_BEGIN(ed, seq)
{
if ((seq->flag & SELECT)) {
struct SeqIndexBuildContext *context;
ListBase queue = {NULL, NULL};
LinkData *link;
short stop = 0, do_update;
float progress;
context = BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list);
BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress);
BKE_sequencer_proxy_rebuild_finish(context, 0);
BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list, &queue);
for (link = queue.first; link; link = link->next) {
struct SeqIndexBuildContext *context = link->data;
BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress);
BKE_sequencer_proxy_rebuild_finish(context, 0);
}
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
}
}

@ -62,7 +62,7 @@ void sequencer_special_update_set(Sequence *seq);
/* UNUSED */
// void seq_reset_imageofs(struct SpaceSeq *sseq);
struct ImBuf *sequencer_ibuf_get(struct Main *bmain, struct Scene *scene, struct SpaceSeq *sseq, int cfra, int frame_ofs);
struct ImBuf *sequencer_ibuf_get(struct Main *bmain, struct Scene *scene, struct SpaceSeq *sseq, int cfra, int frame_ofs, const char *viewname);
/* sequencer_edit.c */
struct View2D;

@ -94,7 +94,7 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
Scene *scene = CTX_data_scene(C);
SpaceSeq *sseq = (SpaceSeq *) CTX_wm_space_data(C);
ARegion *ar = CTX_wm_region(C);
ImBuf *ibuf = sequencer_ibuf_get(bmain, scene, sseq, CFRA, 0);
ImBuf *ibuf = sequencer_ibuf_get(bmain, scene, sseq, CFRA, 0, NULL);
ImageSampleInfo *info = op->customdata;
float fx, fy;

Some files were not shown because too many files have changed in this diff Show More