svn merge ^/trunk/blender -r55700:55776
This commit is contained in:
		@@ -1292,18 +1292,14 @@ elseif(WIN32)
 | 
				
			|||||||
		if(WITH_OPENCOLLADA)
 | 
							if(WITH_OPENCOLLADA)
 | 
				
			||||||
			set(OPENCOLLADA ${LIBDIR}/opencollada)
 | 
								set(OPENCOLLADA ${LIBDIR}/opencollada)
 | 
				
			||||||
			set(OPENCOLLADA_INCLUDE_DIRS
 | 
								set(OPENCOLLADA_INCLUDE_DIRS
 | 
				
			||||||
				${OPENCOLLADA}/include/COLLADAStreamWriter
 | 
									${OPENCOLLADA}/include/opencollada/COLLADAStreamWriter
 | 
				
			||||||
				${OPENCOLLADA}/include/COLLADABaseUtils
 | 
									${OPENCOLLADA}/include/opencollada/COLLADABaseUtils
 | 
				
			||||||
				${OPENCOLLADA}/include/COLLADAFramework
 | 
									${OPENCOLLADA}/include/opencollada/COLLADAFramework
 | 
				
			||||||
				${OPENCOLLADA}/include/COLLADASaxFrameworkLoader
 | 
									${OPENCOLLADA}/include/opencollada/COLLADASaxFrameworkLoader
 | 
				
			||||||
				${OPENCOLLADA}/include/GeneratedSaxParser
 | 
									${OPENCOLLADA}/include/opencollada/GeneratedSaxParser
 | 
				
			||||||
			)
 | 
								)
 | 
				
			||||||
			set(OPENCOLLADA_LIBPATH ${OPENCOLLADA}/lib/opencollada)
 | 
								set(OPENCOLLADA_LIBPATH ${OPENCOLLADA}/lib/opencollada)
 | 
				
			||||||
			if(WITH_MINGW64)
 | 
								set(OPENCOLLADA_LIBRARIES OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver buffer ftoa xml)
 | 
				
			||||||
				set(OPENCOLLADA_LIBRARIES OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver pcre buffer ftoa xml)
 | 
					 | 
				
			||||||
			else()
 | 
					 | 
				
			||||||
				set(OPENCOLLADA_LIBRARIES OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver expat pcre buffer ftoa)
 | 
					 | 
				
			||||||
			endif()
 | 
					 | 
				
			||||||
			set(PCRE_LIBRARIES pcre)
 | 
								set(PCRE_LIBRARIES pcre)
 | 
				
			||||||
		endif()
 | 
							endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1416,8 +1412,8 @@ elseif(WIN32)
 | 
				
			|||||||
				LLVMX86Disassembler LLVMX86Info
 | 
									LLVMX86Disassembler LLVMX86Info
 | 
				
			||||||
				LLVMX86Utils LLVMipa
 | 
									LLVMX86Utils LLVMipa
 | 
				
			||||||
				LLVMipo LLVMCore)
 | 
									LLVMipo LLVMCore)
 | 
				
			||||||
				#imagehelp is needed by LLVM 3.1 on MinGW, check lib\Support\Windows\Signals.inc
 | 
								#imagehelp is needed by LLVM 3.1 on MinGW, check lib\Support\Windows\Signals.inc
 | 
				
			||||||
				set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS} -limagehlp")
 | 
								set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS} -limagehlp")
 | 
				
			||||||
			set(LLVM_STATIC YES)
 | 
								set(LLVM_STATIC YES)
 | 
				
			||||||
		endif()
 | 
							endif()
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,7 +88,7 @@ int AUD_FFMPEGReader::decode(AVPacket& packet, AUD_Buffer& buffer)
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				memcpy(((data_t*)buffer.getBuffer()) + buf_pos, frame->data[1], data_size);
 | 
									memcpy(((data_t*)buffer.getBuffer()) + buf_pos, frame->data[0], data_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			buf_pos += data_size;
 | 
								buf_pos += data_size;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -205,6 +205,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
 | 
				
			|||||||
                default=1,
 | 
					                default=1,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cls.subsurface_samples = IntProperty(
 | 
				
			||||||
 | 
					                name="Subsurface Samples",
 | 
				
			||||||
 | 
					                description="Number of subsurface scattering samples to render for each AA sample",
 | 
				
			||||||
 | 
					                min=1, max=10000,
 | 
				
			||||||
 | 
					                default=1,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        cls.no_caustics = BoolProperty(
 | 
					        cls.no_caustics = BoolProperty(
 | 
				
			||||||
                name="No Caustics",
 | 
					                name="No Caustics",
 | 
				
			||||||
                description="Leave out caustics, resulting in a darker image with less noise",
 | 
					                description="Leave out caustics, resulting in a darker image with less noise",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -83,6 +83,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
 | 
				
			|||||||
            sub.prop(cscene, "transmission_samples", text="Transmission")
 | 
					            sub.prop(cscene, "transmission_samples", text="Transmission")
 | 
				
			||||||
            sub.prop(cscene, "ao_samples", text="AO")
 | 
					            sub.prop(cscene, "ao_samples", text="AO")
 | 
				
			||||||
            sub.prop(cscene, "mesh_light_samples", text="Mesh Light")
 | 
					            sub.prop(cscene, "mesh_light_samples", text="Mesh Light")
 | 
				
			||||||
 | 
					            sub.prop(cscene, "subsurface_samples", text="Subsurface")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel):
 | 
					class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -252,7 +252,6 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
 | 
				
			|||||||
	else if (b_node.is_a(&RNA_ShaderNodeNormal)) {
 | 
						else if (b_node.is_a(&RNA_ShaderNodeNormal)) {
 | 
				
			||||||
		BL::Node::outputs_iterator out_it;
 | 
							BL::Node::outputs_iterator out_it;
 | 
				
			||||||
		b_node.outputs.begin(out_it);
 | 
							b_node.outputs.begin(out_it);
 | 
				
			||||||
		BL::NodeSocket vec_sock(*out_it);
 | 
					 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		NormalNode *norm = new NormalNode();
 | 
							NormalNode *norm = new NormalNode();
 | 
				
			||||||
		norm->direction = get_node_output_vector(b_node, "Normal");
 | 
							norm->direction = get_node_output_vector(b_node, "Normal");
 | 
				
			||||||
@@ -302,6 +301,9 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
 | 
				
			|||||||
	else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
 | 
						else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
 | 
				
			||||||
		node = new DiffuseBsdfNode();
 | 
							node = new DiffuseBsdfNode();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						else if (b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) {
 | 
				
			||||||
 | 
							node = new SubsurfaceScatteringNode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
 | 
						else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
 | 
				
			||||||
		BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
 | 
							BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
 | 
				
			||||||
		GlossyBsdfNode *glossy = new GlossyBsdfNode();
 | 
							GlossyBsdfNode *glossy = new GlossyBsdfNode();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,6 @@
 | 
				
			|||||||
#include "background.h"
 | 
					#include "background.h"
 | 
				
			||||||
#include "camera.h"
 | 
					#include "camera.h"
 | 
				
			||||||
#include "film.h"
 | 
					#include "film.h"
 | 
				
			||||||
#include "../render/filter.h"
 | 
					 | 
				
			||||||
#include "graph.h"
 | 
					#include "graph.h"
 | 
				
			||||||
#include "integrator.h"
 | 
					#include "integrator.h"
 | 
				
			||||||
#include "light.h"
 | 
					#include "light.h"
 | 
				
			||||||
@@ -197,6 +196,7 @@ void BlenderSync::sync_integrator()
 | 
				
			|||||||
	integrator->transmission_samples = get_int(cscene, "transmission_samples");
 | 
						integrator->transmission_samples = get_int(cscene, "transmission_samples");
 | 
				
			||||||
	integrator->ao_samples = get_int(cscene, "ao_samples");
 | 
						integrator->ao_samples = get_int(cscene, "ao_samples");
 | 
				
			||||||
	integrator->mesh_light_samples = get_int(cscene, "mesh_light_samples");
 | 
						integrator->mesh_light_samples = get_int(cscene, "mesh_light_samples");
 | 
				
			||||||
 | 
						integrator->subsurface_samples = get_int(cscene, "subsurface_samples");
 | 
				
			||||||
	integrator->progressive = get_boolean(cscene, "progressive");
 | 
						integrator->progressive = get_boolean(cscene, "progressive");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(integrator->modified(previntegrator))
 | 
						if(integrator->modified(previntegrator))
 | 
				
			||||||
@@ -213,18 +213,11 @@ void BlenderSync::sync_film()
 | 
				
			|||||||
	Film prevfilm = *film;
 | 
						Film prevfilm = *film;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	film->exposure = get_float(cscene, "film_exposure");
 | 
						film->exposure = get_float(cscene, "film_exposure");
 | 
				
			||||||
 | 
						film->filter_type = (FilterType)RNA_enum_get(&cscene, "filter_type");
 | 
				
			||||||
 | 
						film->filter_width = (film->filter_type == FILTER_BOX)? 1.0f: get_float(cscene, "filter_width");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(film->modified(prevfilm))
 | 
						if(film->modified(prevfilm))
 | 
				
			||||||
		film->tag_update(scene);
 | 
							film->tag_update(scene);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	Filter *filter = scene->filter;
 | 
					 | 
				
			||||||
	Filter prevfilter = *filter;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	filter->filter_type = (FilterType)RNA_enum_get(&cscene, "filter_type");
 | 
					 | 
				
			||||||
	filter->filter_width = (filter->filter_type == FILTER_BOX)? 1.0f: get_float(cscene, "filter_width");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(filter->modified(prevfilter))
 | 
					 | 
				
			||||||
		filter->tag_update(scene);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Render Layer */
 | 
					/* Render Layer */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -216,6 +216,14 @@ public:
 | 
				
			|||||||
		return mem;
 | 
							return mem;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void copy_at(T *ptr, size_t offset, size_t size)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if(size > 0) {
 | 
				
			||||||
 | 
								size_t mem_size = size*data_elements*datatype_size(data_type);
 | 
				
			||||||
 | 
								memcpy(&data[0] + offset, ptr, mem_size);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void reference(T *ptr, size_t width, size_t height = 0)
 | 
						void reference(T *ptr, size_t width, size_t height = 0)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		data.clear();
 | 
							data.clear();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@ set(SRC_HEADERS
 | 
				
			|||||||
	kernel_projection.h
 | 
						kernel_projection.h
 | 
				
			||||||
	kernel_random.h
 | 
						kernel_random.h
 | 
				
			||||||
	kernel_shader.h
 | 
						kernel_shader.h
 | 
				
			||||||
 | 
						kernel_subsurface.h
 | 
				
			||||||
	kernel_textures.h
 | 
						kernel_textures.h
 | 
				
			||||||
	kernel_triangle.h
 | 
						kernel_triangle.h
 | 
				
			||||||
	kernel_types.h
 | 
						kernel_types.h
 | 
				
			||||||
@@ -62,6 +63,7 @@ set(SRC_CLOSURE_HEADERS
 | 
				
			|||||||
	closure/bsdf_util.h
 | 
						closure/bsdf_util.h
 | 
				
			||||||
	closure/bsdf_ward.h
 | 
						closure/bsdf_ward.h
 | 
				
			||||||
	closure/bsdf_westin.h
 | 
						closure/bsdf_westin.h
 | 
				
			||||||
 | 
						closure/bssrdf.h
 | 
				
			||||||
	closure/emissive.h
 | 
						closure/emissive.h
 | 
				
			||||||
	closure/volume.h
 | 
						closure/volume.h
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,7 @@
 | 
				
			|||||||
#include "../closure/bsdf_ward.h"
 | 
					#include "../closure/bsdf_ward.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#include "../closure/bsdf_westin.h"
 | 
					#include "../closure/bsdf_westin.h"
 | 
				
			||||||
 | 
					#include "../closure/bssrdf.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CCL_NAMESPACE_BEGIN
 | 
					CCL_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										154
									
								
								intern/cycles/kernel/closure/bssrdf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								intern/cycles/kernel/closure/bssrdf.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,154 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2013, 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __KERNEL_BSSRDF_H__
 | 
				
			||||||
 | 
					#define __KERNEL_BSSRDF_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device int bssrdf_setup(ShaderClosure *sc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if(sc->data0 < BSSRDF_MIN_RADIUS) {
 | 
				
			||||||
 | 
							/* revert to diffuse BSDF if radius too small */
 | 
				
			||||||
 | 
							sc->data0 = 0.0f;
 | 
				
			||||||
 | 
							sc->data1 = 0.0f;
 | 
				
			||||||
 | 
							return bsdf_diffuse_setup(sc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							/* radius + IOR params */
 | 
				
			||||||
 | 
							sc->data0 = max(sc->data0, 0.0f);
 | 
				
			||||||
 | 
							sc->data1 = max(sc->data1, 1.0f);
 | 
				
			||||||
 | 
							sc->type = CLOSURE_BSSRDF_ID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Simple Cubic BSSRDF falloff */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device float bssrdf_cubic(float ld, float r)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if(ld == 0.0f)
 | 
				
			||||||
 | 
							return (r == 0.0f)? 1.0f: 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return powf(ld - min(r, ld), 3.0f) * 4.0f/powf(ld, 4.0f);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Original BSSRDF fallof function */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct BSSRDFParams {
 | 
				
			||||||
 | 
						float eta;		/* index of refraction */
 | 
				
			||||||
 | 
						float sigma_t_; /* reduced extinction coefficient */
 | 
				
			||||||
 | 
						float sigma_tr;	/* effective extinction coefficient */
 | 
				
			||||||
 | 
						float Fdr;		/* diffuse fresnel reflectance */
 | 
				
			||||||
 | 
						float D;		/* diffusion constant */
 | 
				
			||||||
 | 
						float A;
 | 
				
			||||||
 | 
						float alpha_;	/* reduced albedo */
 | 
				
			||||||
 | 
						float zr;		/* distance of virtual lightsource above surface */
 | 
				
			||||||
 | 
						float zv;		/* distance of virtual lightsource below surface */
 | 
				
			||||||
 | 
						float ld;		/* mean free path */
 | 
				
			||||||
 | 
						float ro;		/* diffuse reflectance */
 | 
				
			||||||
 | 
					} BSSRDFParams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device float bssrdf_reduced_albedo_Rd(float alpha_, float A, float ro)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						float sq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sq = sqrt(3.0f*(1.0f - alpha_));
 | 
				
			||||||
 | 
						return (alpha_/2.0f)*(1.0f + expf((-4.0f/3.0f)*A*sq))*expf(-sq) - ro;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device float bssrdf_compute_reduced_albedo(float A, float ro)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const float tolerance = 1e-8;
 | 
				
			||||||
 | 
						const int max_iteration_count = 20;
 | 
				
			||||||
 | 
						float d, fsub, xn_1 = 0.0f, xn = 1.0f, fxn, fxn_1;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* use secant method to compute reduced albedo using Rd function inverse
 | 
				
			||||||
 | 
						 * with a given reflectance */
 | 
				
			||||||
 | 
						fxn = bssrdf_reduced_albedo_Rd(xn, A, ro);
 | 
				
			||||||
 | 
						fxn_1 = bssrdf_reduced_albedo_Rd(xn_1, A, ro);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i= 0; i < max_iteration_count; i++) {
 | 
				
			||||||
 | 
							fsub = (fxn - fxn_1);
 | 
				
			||||||
 | 
							if (fabsf(fsub) < tolerance)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							d = ((xn - xn_1)/fsub)*fxn;
 | 
				
			||||||
 | 
							if (fabsf(d) < tolerance)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							xn_1 = xn;
 | 
				
			||||||
 | 
							fxn_1 = fxn;
 | 
				
			||||||
 | 
							xn = xn - d;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (xn > 1.0f) xn = 1.0f;
 | 
				
			||||||
 | 
							if (xn_1 > 1.0f) xn_1 = 1.0f;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							fxn = bssrdf_reduced_albedo_Rd(xn, A, ro);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* avoid division by zero later */
 | 
				
			||||||
 | 
						if (xn <= 0.0f)
 | 
				
			||||||
 | 
							xn = 0.00001f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return xn;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device void bssrdf_setup_params(BSSRDFParams *ss, float refl, float radius, float ior)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ss->eta = ior;
 | 
				
			||||||
 | 
						ss->Fdr = -1.440f/ior*ior + 0.710f/ior + 0.668f + 0.0636f*ior;
 | 
				
			||||||
 | 
						ss->A = (1.0f + ss->Fdr)/(1.0f - ss->Fdr);
 | 
				
			||||||
 | 
						ss->ld = radius;
 | 
				
			||||||
 | 
						ss->ro = min(refl, 0.999f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ss->alpha_ = bssrdf_compute_reduced_albedo(ss->A, ss->ro);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ss->sigma_tr = 1.0f/ss->ld;
 | 
				
			||||||
 | 
						ss->sigma_t_ = ss->sigma_tr/sqrtf(3.0f*(1.0f - ss->alpha_));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ss->D = 1.0f/(3.0f*ss->sigma_t_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ss->zr = 1.0f/ss->sigma_t_;
 | 
				
			||||||
 | 
						ss->zv = ss->zr + 4.0f*ss->A*ss->D;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* exponential falloff function */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device float bssrdf_original(const BSSRDFParams *ss, float r)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if(ss->ld == 0.0f)
 | 
				
			||||||
 | 
							return (r == 0.0f)? 1.0f: 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float rr = r*r;
 | 
				
			||||||
 | 
						float sr, sv, Rdr, Rdv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sr = sqrt(rr + ss->zr*ss->zr);
 | 
				
			||||||
 | 
						sv = sqrt(rr + ss->zv*ss->zv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Rdr = ss->zr*(1.0f + ss->sigma_tr*sr)*expf(-ss->sigma_tr*sr)/(sr*sr*sr);
 | 
				
			||||||
 | 
						Rdv = ss->zv*(1.0f + ss->sigma_tr*sv)*expf(-ss->sigma_tr*sv)/(sv*sv*sv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ss->alpha_*(1.0f/(4.0f*(float)M_PI))*(Rdr + Rdv);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __KERNEL_BSSRDF_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -923,6 +923,330 @@ __device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const ui
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Special ray intersection routines for subsurface scattering. In that case we
 | 
				
			||||||
 | 
					 * only want to intersect with primitives in the same object, and if case of
 | 
				
			||||||
 | 
					 * multiple hits we pick a single random primitive as the intersection point. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device_inline void bvh_triangle_intersect_subsurface(KernelGlobals *kg, Intersection *isect,
 | 
				
			||||||
 | 
						float3 P, float3 idir, int object, int triAddr, float tmax, int *num_hits, float subsurface_random)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* compute and check intersection t-value */
 | 
				
			||||||
 | 
						float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
 | 
				
			||||||
 | 
						float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
 | 
				
			||||||
 | 
						float3 dir = 1.0f/idir;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
 | 
				
			||||||
 | 
						float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z);
 | 
				
			||||||
 | 
						float t = Oz * invDz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(t > 0.0f && t < tmax) {
 | 
				
			||||||
 | 
							/* compute and check barycentric u */
 | 
				
			||||||
 | 
							float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z;
 | 
				
			||||||
 | 
							float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z;
 | 
				
			||||||
 | 
							float u = Ox + t*Dx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(u >= 0.0f) {
 | 
				
			||||||
 | 
								/* compute and check barycentric v */
 | 
				
			||||||
 | 
								float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
 | 
				
			||||||
 | 
								float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z;
 | 
				
			||||||
 | 
								float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z;
 | 
				
			||||||
 | 
								float v = Oy + t*Dy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(v >= 0.0f && u + v <= 1.0f) {
 | 
				
			||||||
 | 
									(*num_hits)++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(subsurface_random * (*num_hits) <= 1.0f) {
 | 
				
			||||||
 | 
										/* record intersection */
 | 
				
			||||||
 | 
										isect->prim = triAddr;
 | 
				
			||||||
 | 
										isect->object = object;
 | 
				
			||||||
 | 
										isect->u = u;
 | 
				
			||||||
 | 
										isect->v = v;
 | 
				
			||||||
 | 
										isect->t = t;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device_inline int bvh_intersect_subsurface(KernelGlobals *kg, const Ray *ray, Intersection *isect, int subsurface_object, float subsurface_random)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* traversal stack in CUDA thread-local memory */
 | 
				
			||||||
 | 
						int traversalStack[BVH_STACK_SIZE];
 | 
				
			||||||
 | 
						traversalStack[0] = ENTRYPOINT_SENTINEL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* traversal variables in registers */
 | 
				
			||||||
 | 
						int stackPtr = 0;
 | 
				
			||||||
 | 
						int nodeAddr = kernel_data.bvh.root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* ray parameters in registers */
 | 
				
			||||||
 | 
						const float tmax = ray->t;
 | 
				
			||||||
 | 
						float3 P = ray->P;
 | 
				
			||||||
 | 
						float3 idir = bvh_inverse_direction(ray->D);
 | 
				
			||||||
 | 
						int object = ~0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int num_hits = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isect->t = tmax;
 | 
				
			||||||
 | 
						isect->object = ~0;
 | 
				
			||||||
 | 
						isect->prim = ~0;
 | 
				
			||||||
 | 
						isect->u = 0.0f;
 | 
				
			||||||
 | 
						isect->v = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* traversal loop */
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							do
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								/* traverse internal nodes */
 | 
				
			||||||
 | 
								while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									bool traverseChild0, traverseChild1, closestChild1;
 | 
				
			||||||
 | 
									int nodeAddrChild1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									bvh_node_intersect(kg, &traverseChild0, &traverseChild1,
 | 
				
			||||||
 | 
										&closestChild1, &nodeAddr, &nodeAddrChild1,
 | 
				
			||||||
 | 
										P, idir, isect->t, ~0, nodeAddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(traverseChild0 != traverseChild1) {
 | 
				
			||||||
 | 
										/* one child was intersected */
 | 
				
			||||||
 | 
										if(traverseChild1) {
 | 
				
			||||||
 | 
											nodeAddr = nodeAddrChild1;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else {
 | 
				
			||||||
 | 
										if(!traverseChild0) {
 | 
				
			||||||
 | 
											/* neither child was intersected */
 | 
				
			||||||
 | 
											nodeAddr = traversalStack[stackPtr];
 | 
				
			||||||
 | 
											--stackPtr;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else {
 | 
				
			||||||
 | 
											/* both children were intersected, push the farther one */
 | 
				
			||||||
 | 
											if(closestChild1) {
 | 
				
			||||||
 | 
												int tmp = nodeAddr;
 | 
				
			||||||
 | 
												nodeAddr = nodeAddrChild1;
 | 
				
			||||||
 | 
												nodeAddrChild1 = tmp;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											++stackPtr;
 | 
				
			||||||
 | 
											traversalStack[stackPtr] = nodeAddrChild1;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* if node is leaf, fetch triangle list */
 | 
				
			||||||
 | 
								if(nodeAddr < 0) {
 | 
				
			||||||
 | 
									float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1));
 | 
				
			||||||
 | 
									int primAddr = __float_as_int(leaf.x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __INSTANCING__
 | 
				
			||||||
 | 
									if(primAddr >= 0) {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
										int primAddr2 = __float_as_int(leaf.y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/* pop */
 | 
				
			||||||
 | 
										nodeAddr = traversalStack[stackPtr];
 | 
				
			||||||
 | 
										--stackPtr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/* primitive intersection */
 | 
				
			||||||
 | 
										while(primAddr < primAddr2) {
 | 
				
			||||||
 | 
											/* only primitives from the same object */
 | 
				
			||||||
 | 
											uint tri_object = (object == ~0)? kernel_tex_fetch(__prim_object, primAddr): object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											if(tri_object == subsurface_object) {
 | 
				
			||||||
 | 
												/* intersect ray against primitive */
 | 
				
			||||||
 | 
					#ifdef __HAIR__
 | 
				
			||||||
 | 
												uint segment = kernel_tex_fetch(__prim_segment, primAddr);
 | 
				
			||||||
 | 
												if(segment == ~0) /* ignore hair for sss */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
													bvh_triangle_intersect_subsurface(kg, isect, P, idir, object, primAddr, tmax, &num_hits, subsurface_random);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											primAddr++;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					#ifdef __INSTANCING__
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else {
 | 
				
			||||||
 | 
										/* instance push */
 | 
				
			||||||
 | 
										if(subsurface_object == kernel_tex_fetch(__prim_object, -primAddr-1)) {
 | 
				
			||||||
 | 
											object = subsurface_object;
 | 
				
			||||||
 | 
											bvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											++stackPtr;
 | 
				
			||||||
 | 
											traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											nodeAddr = kernel_tex_fetch(__object_node, object);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else {
 | 
				
			||||||
 | 
											/* pop */
 | 
				
			||||||
 | 
											nodeAddr = traversalStack[stackPtr];
 | 
				
			||||||
 | 
											--stackPtr;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} while(nodeAddr != ENTRYPOINT_SENTINEL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __INSTANCING__
 | 
				
			||||||
 | 
							if(stackPtr >= 0) {
 | 
				
			||||||
 | 
								kernel_assert(object != ~0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* instance pop */
 | 
				
			||||||
 | 
								bvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax);
 | 
				
			||||||
 | 
								object = ~0;
 | 
				
			||||||
 | 
								nodeAddr = traversalStack[stackPtr];
 | 
				
			||||||
 | 
								--stackPtr;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						} while(nodeAddr != ENTRYPOINT_SENTINEL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return num_hits;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __OBJECT_MOTION__
 | 
				
			||||||
 | 
					__device bool bvh_intersect_motion_subsurface(KernelGlobals *kg, const Ray *ray, Intersection *isect, int subsurface_object, float subsurface_random)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* traversal stack in CUDA thread-local memory */
 | 
				
			||||||
 | 
						int traversalStack[BVH_STACK_SIZE];
 | 
				
			||||||
 | 
						traversalStack[0] = ENTRYPOINT_SENTINEL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* traversal variables in registers */
 | 
				
			||||||
 | 
						int stackPtr = 0;
 | 
				
			||||||
 | 
						int nodeAddr = kernel_data.bvh.root;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* ray parameters in registers */
 | 
				
			||||||
 | 
						const float tmax = ray->t;
 | 
				
			||||||
 | 
						float3 P = ray->P;
 | 
				
			||||||
 | 
						float3 idir = bvh_inverse_direction(ray->D);
 | 
				
			||||||
 | 
						int object = ~0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int num_hits = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Transform ob_tfm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isect->t = tmax;
 | 
				
			||||||
 | 
						isect->object = ~0;
 | 
				
			||||||
 | 
						isect->prim = ~0;
 | 
				
			||||||
 | 
						isect->u = 0.0f;
 | 
				
			||||||
 | 
						isect->v = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* traversal loop */
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							do
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								/* traverse internal nodes */
 | 
				
			||||||
 | 
								while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									bool traverseChild0, traverseChild1, closestChild1;
 | 
				
			||||||
 | 
									int nodeAddrChild1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									bvh_node_intersect(kg, &traverseChild0, &traverseChild1,
 | 
				
			||||||
 | 
										&closestChild1, &nodeAddr, &nodeAddrChild1,
 | 
				
			||||||
 | 
										P, idir, isect->t, ~0, nodeAddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(traverseChild0 != traverseChild1) {
 | 
				
			||||||
 | 
										/* one child was intersected */
 | 
				
			||||||
 | 
										if(traverseChild1) {
 | 
				
			||||||
 | 
											nodeAddr = nodeAddrChild1;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else {
 | 
				
			||||||
 | 
										if(!traverseChild0) {
 | 
				
			||||||
 | 
											/* neither child was intersected */
 | 
				
			||||||
 | 
											nodeAddr = traversalStack[stackPtr];
 | 
				
			||||||
 | 
											--stackPtr;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else {
 | 
				
			||||||
 | 
											/* both children were intersected, push the farther one */
 | 
				
			||||||
 | 
											if(closestChild1) {
 | 
				
			||||||
 | 
												int tmp = nodeAddr;
 | 
				
			||||||
 | 
												nodeAddr = nodeAddrChild1;
 | 
				
			||||||
 | 
												nodeAddrChild1 = tmp;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											++stackPtr;
 | 
				
			||||||
 | 
											traversalStack[stackPtr] = nodeAddrChild1;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* if node is leaf, fetch triangle list */
 | 
				
			||||||
 | 
								if(nodeAddr < 0) {
 | 
				
			||||||
 | 
									float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1));
 | 
				
			||||||
 | 
									int primAddr = __float_as_int(leaf.x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(primAddr >= 0) {
 | 
				
			||||||
 | 
										int primAddr2 = __float_as_int(leaf.y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/* pop */
 | 
				
			||||||
 | 
										nodeAddr = traversalStack[stackPtr];
 | 
				
			||||||
 | 
										--stackPtr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/* primitive intersection */
 | 
				
			||||||
 | 
										while(primAddr < primAddr2) {
 | 
				
			||||||
 | 
											/* only primitives from the same object */
 | 
				
			||||||
 | 
											uint tri_object = (object == ~0)? kernel_tex_fetch(__prim_object, primAddr): object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											if(tri_object == subsurface_object) {
 | 
				
			||||||
 | 
												/* intersect ray against primitive */
 | 
				
			||||||
 | 
					#ifdef __HAIR__
 | 
				
			||||||
 | 
												uint segment = kernel_tex_fetch(__prim_segment, primAddr);
 | 
				
			||||||
 | 
												if(segment == ~0) /* ignore hair for sss */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
													bvh_triangle_intersect_subsurface(kg, isect, P, idir, object, primAddr, tmax, &num_hits, subsurface_random);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											primAddr++;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else {
 | 
				
			||||||
 | 
										/* instance push */
 | 
				
			||||||
 | 
										if(subsurface_object == kernel_tex_fetch(__prim_object, -primAddr-1)) {
 | 
				
			||||||
 | 
											object = subsurface_object;
 | 
				
			||||||
 | 
											object = kernel_tex_fetch(__prim_object, -primAddr-1);
 | 
				
			||||||
 | 
											bvh_instance_motion_push(kg, object, ray, &P, &idir, &isect->t, &ob_tfm, tmax);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											++stackPtr;
 | 
				
			||||||
 | 
											traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											nodeAddr = kernel_tex_fetch(__object_node, object);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else {
 | 
				
			||||||
 | 
											/* pop */
 | 
				
			||||||
 | 
											nodeAddr = traversalStack[stackPtr];
 | 
				
			||||||
 | 
											--stackPtr;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} while(nodeAddr != ENTRYPOINT_SENTINEL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(stackPtr >= 0) {
 | 
				
			||||||
 | 
								kernel_assert(object != ~0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* instance pop */
 | 
				
			||||||
 | 
								bvh_instance_motion_pop(kg, object, ray, &P, &idir, &isect->t, &ob_tfm, tmax);
 | 
				
			||||||
 | 
								object = ~0;
 | 
				
			||||||
 | 
								nodeAddr = traversalStack[stackPtr];
 | 
				
			||||||
 | 
								--stackPtr;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} while(nodeAddr != ENTRYPOINT_SENTINEL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return num_hits;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device_inline int scene_intersect_subsurface(KernelGlobals *kg, const Ray *ray, Intersection *isect, int subsurface_object, float subsurface_random)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef __OBJECT_MOTION__
 | 
				
			||||||
 | 
						if(kernel_data.bvh.have_motion)
 | 
				
			||||||
 | 
							return bvh_intersect_motion_subsurface(kg, ray, isect, subsurface_object, subsurface_random);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return bvh_intersect_subsurface(kg, ray, isect, subsurface_object, subsurface_random);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						return bvh_intersect_subsurface(kg, ray, isect, subsurface_object, subsurface_random);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Ray offset to avoid self intersection */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__device_inline float3 ray_offset(float3 P, float3 Ng)
 | 
					__device_inline float3 ray_offset(float3 P, float3 Ng)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef __INTERSECTION_REFINE__
 | 
					#ifdef __INTERSECTION_REFINE__
 | 
				
			||||||
@@ -971,6 +1295,10 @@ __device_inline float3 ray_offset(float3 P, float3 Ng)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Refine triangle intersection to more precise hit point. For rays that travel
 | 
				
			||||||
 | 
					 * far the precision is often not so good, this reintersects the primitive from
 | 
				
			||||||
 | 
					 * a closer distance. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray)
 | 
					__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	float3 P = ray->P;
 | 
						float3 P = ray->P;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,7 +53,7 @@ __device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/* compute point on plane of focus */
 | 
							/* compute point on plane of focus */
 | 
				
			||||||
		float ft = kernel_data.cam.focaldistance/ray->D.z;
 | 
							float ft = kernel_data.cam.focaldistance/ray->D.z;
 | 
				
			||||||
		float3 Pfocus = ray->P + ray->D*ft;
 | 
							float3 Pfocus = ray->D*ft;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* update ray for effect of lens */
 | 
							/* update ray for effect of lens */
 | 
				
			||||||
		ray->P = make_float3(lensuv.x, lensuv.y, 0.0f);
 | 
							ray->P = make_float3(lensuv.x, lensuv.y, 0.0f);
 | 
				
			||||||
@@ -112,11 +112,13 @@ __device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, floa
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/* compute point on plane of focus */
 | 
							/* compute point on plane of focus */
 | 
				
			||||||
		float ft = kernel_data.cam.focaldistance/ray->D.z;
 | 
							float ft = kernel_data.cam.focaldistance/ray->D.z;
 | 
				
			||||||
		float3 Pfocus = ray->P + ray->D*ft;
 | 
							float3 Pfocus = ray->D*ft;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* update ray for effect of lens */
 | 
							/* update ray for effect of lens */
 | 
				
			||||||
		ray->P = make_float3(lensuv.x, lensuv.y, 0.0f);
 | 
							ray->P = make_float3(lensuv.x, lensuv.y, 0.0f);
 | 
				
			||||||
		ray->D = normalize(Pfocus - ray->P);
 | 
							ray->D = normalize(Pfocus - ray->P);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ray->P += Pcamera;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* transform ray from camera to world */
 | 
						/* transform ray from camera to world */
 | 
				
			||||||
@@ -224,8 +226,9 @@ __device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, flo
 | 
				
			|||||||
	float lens_u, float lens_v, float time, Ray *ray)
 | 
						float lens_u, float lens_v, float time, Ray *ray)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* pixel filter */
 | 
						/* pixel filter */
 | 
				
			||||||
	float raster_x = x + kernel_tex_interp(__filter_table, filter_u, FILTER_TABLE_SIZE);
 | 
						int filter_table_offset = kernel_data.film.filter_table_offset;
 | 
				
			||||||
	float raster_y = y + kernel_tex_interp(__filter_table, filter_v, FILTER_TABLE_SIZE);
 | 
						float raster_x = x + lookup_table_read(kg, filter_u, filter_table_offset, FILTER_TABLE_SIZE);
 | 
				
			||||||
 | 
						float raster_y = y + lookup_table_read(kg, filter_v, filter_table_offset, FILTER_TABLE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __CAMERA_MOTION__
 | 
					#ifdef __CAMERA_MOTION__
 | 
				
			||||||
	/* motion blur */
 | 
						/* motion blur */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,19 +57,6 @@ template<typename T> struct texture  {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float interp(float x, int size)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		kernel_assert(size == width);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		x = clamp(x, 0.0f, 1.0f)*width;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		int index = min((int)x, width-1);
 | 
					 | 
				
			||||||
		int nindex = min(index+1, width-1);
 | 
					 | 
				
			||||||
		float t = x - index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return (1.0f - t)*data[index] + t*data[nindex];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	T *data;
 | 
						T *data;
 | 
				
			||||||
	int width;
 | 
						int width;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -157,7 +144,7 @@ typedef texture_image<uchar4> texture_image_uchar4;
 | 
				
			|||||||
#define kernel_tex_fetch(tex, index) (kg->tex.fetch(index))
 | 
					#define kernel_tex_fetch(tex, index) (kg->tex.fetch(index))
 | 
				
			||||||
#define kernel_tex_fetch_m128(tex, index) (kg->tex.fetch_m128(index))
 | 
					#define kernel_tex_fetch_m128(tex, index) (kg->tex.fetch_m128(index))
 | 
				
			||||||
#define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index))
 | 
					#define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index))
 | 
				
			||||||
#define kernel_tex_interp(tex, t, size) (kg->tex.interp(t, size))
 | 
					#define kernel_tex_lookup(tex, t, offset, size) (kg->tex.lookup(t, offset, size))
 | 
				
			||||||
#define kernel_tex_image_interp(tex, x, y) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp(x, y) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp(x, y))
 | 
					#define kernel_tex_image_interp(tex, x, y) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp(x, y) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp(x, y))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define kernel_data (kg->__data)
 | 
					#define kernel_data (kg->__data)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,7 +58,6 @@ typedef texture<uchar4, 2, cudaReadModeNormalizedFloat> texture_image_uchar4;
 | 
				
			|||||||
/* Macros to handle different memory storage on different devices */
 | 
					/* Macros to handle different memory storage on different devices */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define kernel_tex_fetch(t, index) tex1Dfetch(t, index)
 | 
					#define kernel_tex_fetch(t, index) tex1Dfetch(t, index)
 | 
				
			||||||
#define kernel_tex_interp(t, x, size) tex1D(t, x)
 | 
					 | 
				
			||||||
#define kernel_tex_image_interp(t, x, y) tex2D(t, x, y)
 | 
					#define kernel_tex_image_interp(t, x, y) tex2D(t, x, y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define kernel_data __data
 | 
					#define kernel_data __data
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,18 +45,6 @@
 | 
				
			|||||||
/* no assert in opencl */
 | 
					/* no assert in opencl */
 | 
				
			||||||
#define kernel_assert(cond)
 | 
					#define kernel_assert(cond)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* manual implementation of interpolated 1D lookup */
 | 
					 | 
				
			||||||
__device float kernel_tex_interp_(__global float *data, int width, float x)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	x = clamp(x, 0.0f, 1.0f)*width;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	int index = min((int)x, width-1);
 | 
					 | 
				
			||||||
	int nindex = min(index+1, width-1);
 | 
					 | 
				
			||||||
	float t = x - index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return (1.0f - t)*data[index] + t*data[nindex];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* make_type definitions with opencl style element initializers */
 | 
					/* make_type definitions with opencl style element initializers */
 | 
				
			||||||
#ifdef make_float2
 | 
					#ifdef make_float2
 | 
				
			||||||
#undef make_float2
 | 
					#undef make_float2
 | 
				
			||||||
@@ -114,7 +102,7 @@ __device float kernel_tex_interp_(__global float *data, int width, float x)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* data lookup defines */
 | 
					/* data lookup defines */
 | 
				
			||||||
#define kernel_data (*kg->data)
 | 
					#define kernel_data (*kg->data)
 | 
				
			||||||
#define kernel_tex_interp(t, x, size) kernel_tex_interp_(kg->t, size, x)
 | 
					#define kernel_tex_lookup(t, x, offset, size) kernel_tex_lookup_(kg->t, offset, size, x)
 | 
				
			||||||
#define kernel_tex_fetch(t, index) kg->t[index]
 | 
					#define kernel_tex_fetch(t, index) kg->t[index]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* define NULL */
 | 
					/* define NULL */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,8 +66,6 @@ __device void kernel_shader_evaluate(KernelGlobals *kg, uint4 *input, float4 *ou
 | 
				
			|||||||
		out = shader_eval_background(kg, &sd, flag, SHADER_CONTEXT_MAIN);
 | 
							out = shader_eval_background(kg, &sd, flag, SHADER_CONTEXT_MAIN);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	shader_release(kg, &sd);
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	/* write output */
 | 
						/* write output */
 | 
				
			||||||
	output[i] = make_float4(out.x, out.y, out.z, 0.0f);
 | 
						output[i] = make_float4(out.x, out.y, out.z, 0.0f);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,8 +69,6 @@ __device_noinline float3 direct_emissive_eval(KernelGlobals *kg, float rando,
 | 
				
			|||||||
	
 | 
						
 | 
				
			||||||
	eval *= ls->eval_fac;
 | 
						eval *= ls->eval_fac;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	shader_release(kg, &sd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return eval;
 | 
						return eval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -207,7 +205,6 @@ __device_noinline float3 indirect_background(KernelGlobals *kg, Ray *ray, int pa
 | 
				
			|||||||
	ShaderData sd;
 | 
						ShaderData sd;
 | 
				
			||||||
	shader_setup_from_background(kg, &sd, ray);
 | 
						shader_setup_from_background(kg, &sd, ray);
 | 
				
			||||||
	float3 L = shader_eval_background(kg, &sd, path_flag, SHADER_CONTEXT_EMISSION);
 | 
						float3 L = shader_eval_background(kg, &sd, path_flag, SHADER_CONTEXT_EMISSION);
 | 
				
			||||||
	shader_release(kg, &sd);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __BACKGROUND_MIS__
 | 
					#ifdef __BACKGROUND_MIS__
 | 
				
			||||||
	/* check if background light exists or if we should skip pdf */
 | 
						/* check if background light exists or if we should skip pdf */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,5 +88,39 @@ typedef struct KernelGlobals {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Interpolated lookup table access */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device float lookup_table_read(KernelGlobals *kg, float x, int offset, int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						x = clamp(x, 0.0f, 1.0f)*(size-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int index = min((int)x, size-1);
 | 
				
			||||||
 | 
						int nindex = min(index+1, size-1);
 | 
				
			||||||
 | 
						float t = x - index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float data0 = kernel_tex_fetch(__lookup_table, index + offset);
 | 
				
			||||||
 | 
						if(t == 0.0f)
 | 
				
			||||||
 | 
							return data0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float data1 = kernel_tex_fetch(__lookup_table, nindex + offset);
 | 
				
			||||||
 | 
						return (1.0f - t)*data0 + t*data1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device float lookup_table_read_2D(KernelGlobals *kg, float x, float y, int offset, int xsize, int ysize)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						y = clamp(y, 0.0f, 1.0f)*(ysize-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int index = min((int)y, ysize-1);
 | 
				
			||||||
 | 
						int nindex = min(index+1, ysize-1);
 | 
				
			||||||
 | 
						float t = y - index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float data0 = lookup_table_read(kg, x, offset + xsize*index, xsize);
 | 
				
			||||||
 | 
						if(t == 0.0f)
 | 
				
			||||||
 | 
							return data0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float data1 = lookup_table_read(kg, x, offset + xsize*nindex, xsize);
 | 
				
			||||||
 | 
						return (1.0f - t)*data0 + t*data1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CCL_NAMESPACE_END
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,10 @@
 | 
				
			|||||||
#include "kernel_random.h"
 | 
					#include "kernel_random.h"
 | 
				
			||||||
#include "kernel_passes.h"
 | 
					#include "kernel_passes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __SUBSURFACE__
 | 
				
			||||||
 | 
					#include "kernel_subsurface.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CCL_NAMESPACE_BEGIN
 | 
					CCL_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct PathState {
 | 
					typedef struct PathState {
 | 
				
			||||||
@@ -149,7 +153,7 @@ __device_inline float path_state_terminate_probability(KernelGlobals *kg, PathSt
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* probalistic termination */
 | 
						/* probalistic termination */
 | 
				
			||||||
	return average(throughput);
 | 
						return average(throughput); /* todo: try using max here */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, float3 *shadow)
 | 
					__device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, float3 *shadow)
 | 
				
			||||||
@@ -212,8 +216,6 @@ __device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ra
 | 
				
			|||||||
				if(ray->t != FLT_MAX)
 | 
									if(ray->t != FLT_MAX)
 | 
				
			||||||
					ray->D = normalize_len(Pend - ray->P, &ray->t);
 | 
										ray->D = normalize_len(Pend - ray->P, &ray->t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				shader_release(kg, &sd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				bounce++;
 | 
									bounce++;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -323,10 +325,8 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
 | 
				
			|||||||
				L_transparent += average(holdout_weight*throughput);
 | 
									L_transparent += average(holdout_weight*throughput);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(sd.flag & SD_HOLDOUT_MASK) {
 | 
								if(sd.flag & SD_HOLDOUT_MASK)
 | 
				
			||||||
				shader_release(kg, &sd);
 | 
					 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -345,13 +345,29 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
 | 
				
			|||||||
		float probability = path_state_terminate_probability(kg, &state, throughput);
 | 
							float probability = path_state_terminate_probability(kg, &state, throughput);
 | 
				
			||||||
		float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
 | 
							float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(terminate >= probability) {
 | 
							if(terminate >= probability)
 | 
				
			||||||
			shader_release(kg, &sd);
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		throughput /= probability;
 | 
							throughput /= probability;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __SUBSURFACE__
 | 
				
			||||||
 | 
							/* bssrdf scatter to a different location on the same object, replacing
 | 
				
			||||||
 | 
							 * the closures with a diffuse BSDF */
 | 
				
			||||||
 | 
							if(sd.flag & SD_BSSRDF) {
 | 
				
			||||||
 | 
								float bssrdf_probability;
 | 
				
			||||||
 | 
								ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* modify throughput for picking bssrdf or bsdf */
 | 
				
			||||||
 | 
								throughput *= bssrdf_probability;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* do bssrdf scatter step if we picked a bssrdf closure */
 | 
				
			||||||
 | 
								if(sc) {
 | 
				
			||||||
 | 
									uint lcg_state = lcg_init(rbsdf);
 | 
				
			||||||
 | 
									subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __AO__
 | 
					#ifdef __AO__
 | 
				
			||||||
		/* ambient occlusion */
 | 
							/* ambient occlusion */
 | 
				
			||||||
		if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
 | 
							if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
 | 
				
			||||||
@@ -415,10 +431,8 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* no BSDF? we can stop here */
 | 
							/* no BSDF? we can stop here */
 | 
				
			||||||
		if(!(sd.flag & SD_BSDF)) {
 | 
							if(!(sd.flag & SD_BSDF))
 | 
				
			||||||
			shader_release(kg, &sd);
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* sample BSDF */
 | 
							/* sample BSDF */
 | 
				
			||||||
		float bsdf_pdf;
 | 
							float bsdf_pdf;
 | 
				
			||||||
@@ -432,8 +446,6 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
 | 
				
			|||||||
		label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
 | 
							label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
 | 
				
			||||||
			&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
 | 
								&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		shader_release(kg, &sd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
 | 
							if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -481,7 +493,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
 | 
				
			|||||||
#ifdef __NON_PROGRESSIVE__
 | 
					#ifdef __NON_PROGRESSIVE__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer,
 | 
					__device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer,
 | 
				
			||||||
	float3 throughput, float throughput_normalize,
 | 
						float3 throughput, float num_samples_adjust,
 | 
				
			||||||
	float min_ray_pdf, float ray_pdf, PathState state, int rng_offset, PathRadiance *L)
 | 
						float min_ray_pdf, float ray_pdf, PathState state, int rng_offset, PathRadiance *L)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef __LAMP_MIS__
 | 
					#ifdef __LAMP_MIS__
 | 
				
			||||||
@@ -554,16 +566,32 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
 | 
				
			|||||||
		/* path termination. this is a strange place to put the termination, it's
 | 
							/* path termination. this is a strange place to put the termination, it's
 | 
				
			||||||
		 * mainly due to the mixed in MIS that we use. gives too many unneeded
 | 
							 * mainly due to the mixed in MIS that we use. gives too many unneeded
 | 
				
			||||||
		 * shader evaluations, only need emission if we are going to terminate */
 | 
							 * shader evaluations, only need emission if we are going to terminate */
 | 
				
			||||||
		float probability = path_state_terminate_probability(kg, &state, throughput*throughput_normalize);
 | 
							float probability = path_state_terminate_probability(kg, &state, throughput*num_samples_adjust);
 | 
				
			||||||
		float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
 | 
							float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(terminate >= probability) {
 | 
							if(terminate >= probability)
 | 
				
			||||||
			shader_release(kg, &sd);
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		throughput /= probability;
 | 
							throughput /= probability;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __SUBSURFACE__
 | 
				
			||||||
 | 
							/* bssrdf scatter to a different location on the same object, replacing
 | 
				
			||||||
 | 
							 * the closures with a diffuse BSDF */
 | 
				
			||||||
 | 
							if(sd.flag & SD_BSSRDF) {
 | 
				
			||||||
 | 
								float bssrdf_probability;
 | 
				
			||||||
 | 
								ShaderClosure *sc = subsurface_scatter_pick_closure(kg, &sd, &bssrdf_probability);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* modify throughput for picking bssrdf or bsdf */
 | 
				
			||||||
 | 
								throughput *= bssrdf_probability;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* do bssrdf scatter step if we picked a bssrdf closure */
 | 
				
			||||||
 | 
								if(sc) {
 | 
				
			||||||
 | 
									uint lcg_state = lcg_init(rbsdf);
 | 
				
			||||||
 | 
									subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __AO__
 | 
					#ifdef __AO__
 | 
				
			||||||
		/* ambient occlusion */
 | 
							/* ambient occlusion */
 | 
				
			||||||
		if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
 | 
							if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
 | 
				
			||||||
@@ -628,10 +656,8 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* no BSDF? we can stop here */
 | 
							/* no BSDF? we can stop here */
 | 
				
			||||||
		if(!(sd.flag & SD_BSDF)) {
 | 
							if(!(sd.flag & SD_BSDF))
 | 
				
			||||||
			shader_release(kg, &sd);
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* sample BSDF */
 | 
							/* sample BSDF */
 | 
				
			||||||
		float bsdf_pdf;
 | 
							float bsdf_pdf;
 | 
				
			||||||
@@ -645,8 +671,6 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
 | 
				
			|||||||
		label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
 | 
							label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
 | 
				
			||||||
			&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
 | 
								&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		shader_release(kg, &sd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
 | 
							if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -676,6 +700,193 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device_noinline void kernel_path_non_progressive_lighting(KernelGlobals *kg, RNG *rng, int sample,
 | 
				
			||||||
 | 
						ShaderData *sd, float3 throughput, float num_samples_adjust,
 | 
				
			||||||
 | 
						float min_ray_pdf, float ray_pdf, PathState state,
 | 
				
			||||||
 | 
						int rng_offset, PathRadiance *L, __global float *buffer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef __AO__
 | 
				
			||||||
 | 
						/* ambient occlusion */
 | 
				
			||||||
 | 
						if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) {
 | 
				
			||||||
 | 
							int num_samples = ceil(kernel_data.integrator.ao_samples*num_samples_adjust);
 | 
				
			||||||
 | 
							float num_samples_inv = num_samples_adjust/num_samples;
 | 
				
			||||||
 | 
							float ao_factor = kernel_data.background.ao_factor;
 | 
				
			||||||
 | 
							float3 ao_N;
 | 
				
			||||||
 | 
							float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for(int j = 0; j < num_samples; j++) {
 | 
				
			||||||
 | 
								/* todo: solve correlation */
 | 
				
			||||||
 | 
								float bsdf_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_U);
 | 
				
			||||||
 | 
								float bsdf_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_V);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								float3 ao_D;
 | 
				
			||||||
 | 
								float ao_pdf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
 | 
				
			||||||
 | 
									Ray light_ray;
 | 
				
			||||||
 | 
									float3 ao_shadow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									light_ray.P = ray_offset(sd->P, sd->Ng);
 | 
				
			||||||
 | 
									light_ray.D = ao_D;
 | 
				
			||||||
 | 
									light_ray.t = kernel_data.background.ao_distance;
 | 
				
			||||||
 | 
					#ifdef __OBJECT_MOTION__
 | 
				
			||||||
 | 
									light_ray.time = sd->time;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow))
 | 
				
			||||||
 | 
										path_radiance_accum_ao(L, throughput*num_samples_inv, ao_bsdf, ao_shadow, state.bounce);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __EMISSION__
 | 
				
			||||||
 | 
						/* sample illumination from lights to find path contribution */
 | 
				
			||||||
 | 
						if(sd->flag & SD_BSDF_HAS_EVAL) {
 | 
				
			||||||
 | 
							Ray light_ray;
 | 
				
			||||||
 | 
							BsdfEval L_light;
 | 
				
			||||||
 | 
							bool is_lamp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __OBJECT_MOTION__
 | 
				
			||||||
 | 
							light_ray.time = sd->time;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* lamp sampling */
 | 
				
			||||||
 | 
							for(int i = 0; i < kernel_data.integrator.num_all_lights; i++) {
 | 
				
			||||||
 | 
								int num_samples = ceil(num_samples_adjust*light_select_num_samples(kg, i));
 | 
				
			||||||
 | 
								float num_samples_inv = num_samples_adjust/(num_samples*kernel_data.integrator.num_all_lights);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(kernel_data.integrator.pdf_triangles != 0.0f)
 | 
				
			||||||
 | 
									num_samples_inv *= 0.5f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for(int j = 0; j < num_samples; j++) {
 | 
				
			||||||
 | 
									float light_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_U);
 | 
				
			||||||
 | 
									float light_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_V);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(direct_emission(kg, sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
 | 
				
			||||||
 | 
										/* trace shadow ray */
 | 
				
			||||||
 | 
										float3 shadow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
 | 
				
			||||||
 | 
											/* accumulate */
 | 
				
			||||||
 | 
											path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state.bounce, is_lamp);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* mesh light sampling */
 | 
				
			||||||
 | 
							if(kernel_data.integrator.pdf_triangles != 0.0f) {
 | 
				
			||||||
 | 
								int num_samples = ceil(num_samples_adjust*kernel_data.integrator.mesh_light_samples);
 | 
				
			||||||
 | 
								float num_samples_inv = num_samples_adjust/num_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(kernel_data.integrator.num_all_lights)
 | 
				
			||||||
 | 
									num_samples_inv *= 0.5f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for(int j = 0; j < num_samples; j++) {
 | 
				
			||||||
 | 
									float light_t = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT);
 | 
				
			||||||
 | 
									float light_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_U);
 | 
				
			||||||
 | 
									float light_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_V);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* only sample triangle lights */
 | 
				
			||||||
 | 
									if(kernel_data.integrator.num_all_lights)
 | 
				
			||||||
 | 
										light_t = 0.5f*light_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(direct_emission(kg, sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
 | 
				
			||||||
 | 
										/* trace shadow ray */
 | 
				
			||||||
 | 
										float3 shadow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
 | 
				
			||||||
 | 
											/* accumulate */
 | 
				
			||||||
 | 
											path_radiance_accum_light(L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state.bounce, is_lamp);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(int i = 0; i< sd->num_closure; i++) {
 | 
				
			||||||
 | 
							const ShaderClosure *sc = &sd->closure[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(!CLOSURE_IS_BSDF(sc->type))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							/* transparency is not handled here, but in outer loop */
 | 
				
			||||||
 | 
							if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int num_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
 | 
				
			||||||
 | 
								num_samples = kernel_data.integrator.diffuse_samples;
 | 
				
			||||||
 | 
							else if(CLOSURE_IS_BSDF_GLOSSY(sc->type))
 | 
				
			||||||
 | 
								num_samples = kernel_data.integrator.glossy_samples;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								num_samples = kernel_data.integrator.transmission_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							num_samples = ceil(num_samples_adjust*num_samples);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							float num_samples_inv = num_samples_adjust/num_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for(int j = 0; j < num_samples; j++) {
 | 
				
			||||||
 | 
								/* sample BSDF */
 | 
				
			||||||
 | 
								float bsdf_pdf;
 | 
				
			||||||
 | 
								BsdfEval bsdf_eval;
 | 
				
			||||||
 | 
								float3 bsdf_omega_in;
 | 
				
			||||||
 | 
								differential3 bsdf_domega_in;
 | 
				
			||||||
 | 
								float bsdf_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_U);
 | 
				
			||||||
 | 
								float bsdf_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_V);
 | 
				
			||||||
 | 
								int label;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								label = shader_bsdf_sample_closure(kg, sd, sc, bsdf_u, bsdf_v, &bsdf_eval,
 | 
				
			||||||
 | 
									&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* modify throughput */
 | 
				
			||||||
 | 
								float3 tp = throughput;
 | 
				
			||||||
 | 
								path_radiance_bsdf_bounce(L, &tp, &bsdf_eval, bsdf_pdf, state.bounce, label);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* set labels */
 | 
				
			||||||
 | 
								float min_ray_pdf = FLT_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(!(label & LABEL_TRANSPARENT))
 | 
				
			||||||
 | 
									min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* modify path state */
 | 
				
			||||||
 | 
								PathState ps = state;
 | 
				
			||||||
 | 
								path_state_next(kg, &ps, label);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* setup ray */
 | 
				
			||||||
 | 
								Ray bsdf_ray;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								bsdf_ray.P = ray_offset(sd->P, (label & LABEL_TRANSMIT)? -sd->Ng: sd->Ng);
 | 
				
			||||||
 | 
								bsdf_ray.D = bsdf_omega_in;
 | 
				
			||||||
 | 
								bsdf_ray.t = FLT_MAX;
 | 
				
			||||||
 | 
					#ifdef __RAY_DIFFERENTIALS__
 | 
				
			||||||
 | 
								bsdf_ray.dP = sd->dP;
 | 
				
			||||||
 | 
								bsdf_ray.dD = bsdf_domega_in;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef __OBJECT_MOTION__
 | 
				
			||||||
 | 
								bsdf_ray.time = sd->time;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								kernel_path_indirect(kg, rng, sample*num_samples + j, bsdf_ray, buffer,
 | 
				
			||||||
 | 
									tp*num_samples_inv, num_samples,
 | 
				
			||||||
 | 
									min_ray_pdf, bsdf_pdf, ps, rng_offset+PRNG_BOUNCE_NUM, L);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* for render passes, sum and reset indirect light pass variables
 | 
				
			||||||
 | 
								 * for the next samples */
 | 
				
			||||||
 | 
								path_radiance_sum_indirect(L);
 | 
				
			||||||
 | 
								path_radiance_reset_indirect(L);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer)
 | 
					__device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* initialize */
 | 
						/* initialize */
 | 
				
			||||||
@@ -740,10 +951,8 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
 | 
				
			|||||||
				L_transparent += average(holdout_weight*throughput);
 | 
									L_transparent += average(holdout_weight*throughput);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(sd.flag & SD_HOLDOUT_MASK) {
 | 
								if(sd.flag & SD_HOLDOUT_MASK)
 | 
				
			||||||
				shader_release(kg, &sd);
 | 
					 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -763,195 +972,47 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
 | 
				
			|||||||
			float probability = path_state_terminate_probability(kg, &state, throughput);
 | 
								float probability = path_state_terminate_probability(kg, &state, throughput);
 | 
				
			||||||
			float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
 | 
								float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(terminate >= probability) {
 | 
								if(terminate >= probability)
 | 
				
			||||||
				shader_release(kg, &sd);
 | 
					 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			throughput /= probability;
 | 
								throughput /= probability;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __AO__
 | 
					#ifdef __SUBSURFACE__
 | 
				
			||||||
		/* ambient occlusion */
 | 
							/* bssrdf scatter to a different location on the same object */
 | 
				
			||||||
		if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
 | 
							if(sd.flag & SD_BSSRDF) {
 | 
				
			||||||
			int num_samples = kernel_data.integrator.ao_samples;
 | 
								for(int i = 0; i< sd.num_closure; i++) {
 | 
				
			||||||
			float num_samples_inv = 1.0f/num_samples;
 | 
									ShaderClosure *sc = &sd.closure[i];
 | 
				
			||||||
			float ao_factor = kernel_data.background.ao_factor;
 | 
					 | 
				
			||||||
			float3 ao_N;
 | 
					 | 
				
			||||||
			float3 ao_bsdf = shader_bsdf_ao(kg, &sd, ao_factor, &ao_N);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for(int j = 0; j < num_samples; j++) {
 | 
									if(!CLOSURE_IS_BSSRDF(sc->type))
 | 
				
			||||||
				/* todo: solve correlation */
 | 
					 | 
				
			||||||
				float bsdf_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_U);
 | 
					 | 
				
			||||||
				float bsdf_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_V);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				float3 ao_D;
 | 
					 | 
				
			||||||
				float ao_pdf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
 | 
					 | 
				
			||||||
					Ray light_ray;
 | 
					 | 
				
			||||||
					float3 ao_shadow;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					light_ray.P = ray_offset(sd.P, sd.Ng);
 | 
					 | 
				
			||||||
					light_ray.D = ao_D;
 | 
					 | 
				
			||||||
					light_ray.t = kernel_data.background.ao_distance;
 | 
					 | 
				
			||||||
#ifdef __OBJECT_MOTION__
 | 
					 | 
				
			||||||
					light_ray.time = sd.time;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow))
 | 
					 | 
				
			||||||
						path_radiance_accum_ao(&L, throughput*num_samples_inv, ao_bsdf, ao_shadow, state.bounce);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __EMISSION__
 | 
					 | 
				
			||||||
		/* sample illumination from lights to find path contribution */
 | 
					 | 
				
			||||||
		if(sd.flag & SD_BSDF_HAS_EVAL) {
 | 
					 | 
				
			||||||
			Ray light_ray;
 | 
					 | 
				
			||||||
			BsdfEval L_light;
 | 
					 | 
				
			||||||
			bool is_lamp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __OBJECT_MOTION__
 | 
					 | 
				
			||||||
			light_ray.time = sd.time;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/* lamp sampling */
 | 
					 | 
				
			||||||
			for(int i = 0; i < kernel_data.integrator.num_all_lights; i++) {
 | 
					 | 
				
			||||||
				int num_samples = light_select_num_samples(kg, i);
 | 
					 | 
				
			||||||
				float num_samples_inv = 1.0f/(num_samples*kernel_data.integrator.num_all_lights);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if(kernel_data.integrator.pdf_triangles != 0.0f)
 | 
					 | 
				
			||||||
					num_samples_inv *= 0.5f;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				for(int j = 0; j < num_samples; j++) {
 | 
					 | 
				
			||||||
					float light_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_U);
 | 
					 | 
				
			||||||
					float light_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_V);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if(direct_emission(kg, &sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
 | 
					 | 
				
			||||||
						/* trace shadow ray */
 | 
					 | 
				
			||||||
						float3 shadow;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
 | 
					 | 
				
			||||||
							/* accumulate */
 | 
					 | 
				
			||||||
							path_radiance_accum_light(&L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state.bounce, is_lamp);
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/* mesh light sampling */
 | 
					 | 
				
			||||||
			if(kernel_data.integrator.pdf_triangles != 0.0f) {
 | 
					 | 
				
			||||||
				int num_samples = kernel_data.integrator.mesh_light_samples;
 | 
					 | 
				
			||||||
				float num_samples_inv = 1.0f/num_samples;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if(kernel_data.integrator.num_all_lights)
 | 
					 | 
				
			||||||
					num_samples_inv *= 0.5f;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				for(int j = 0; j < num_samples; j++) {
 | 
					 | 
				
			||||||
					float light_t = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT);
 | 
					 | 
				
			||||||
					float light_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_U);
 | 
					 | 
				
			||||||
					float light_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_V);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					/* only sample triangle lights */
 | 
					 | 
				
			||||||
					if(kernel_data.integrator.num_all_lights)
 | 
					 | 
				
			||||||
						light_t = 0.5f*light_t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if(direct_emission(kg, &sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
 | 
					 | 
				
			||||||
						/* trace shadow ray */
 | 
					 | 
				
			||||||
						float3 shadow;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
						if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
 | 
					 | 
				
			||||||
							/* accumulate */
 | 
					 | 
				
			||||||
							path_radiance_accum_light(&L, throughput*num_samples_inv, &L_light, shadow, num_samples_inv, state.bounce, is_lamp);
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for(int i = 0; i< sd.num_closure; i++) {
 | 
					 | 
				
			||||||
			const ShaderClosure *sc = &sd.closure[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(!CLOSURE_IS_BSDF(sc->type))
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			/* transparency is not handled here, but in outer loop */
 | 
					 | 
				
			||||||
			if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID)
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			int num_samples;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
 | 
					 | 
				
			||||||
				num_samples = kernel_data.integrator.diffuse_samples;
 | 
					 | 
				
			||||||
			else if(CLOSURE_IS_BSDF_GLOSSY(sc->type))
 | 
					 | 
				
			||||||
				num_samples = kernel_data.integrator.glossy_samples;
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				num_samples = kernel_data.integrator.transmission_samples;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			float num_samples_inv = 1.0f/num_samples;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			for(int j = 0; j < num_samples; j++) {
 | 
					 | 
				
			||||||
				/* sample BSDF */
 | 
					 | 
				
			||||||
				float bsdf_pdf;
 | 
					 | 
				
			||||||
				BsdfEval bsdf_eval;
 | 
					 | 
				
			||||||
				float3 bsdf_omega_in;
 | 
					 | 
				
			||||||
				differential3 bsdf_domega_in;
 | 
					 | 
				
			||||||
				float bsdf_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_U);
 | 
					 | 
				
			||||||
				float bsdf_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_V);
 | 
					 | 
				
			||||||
				int label;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				label = shader_bsdf_sample_closure(kg, &sd, sc, bsdf_u, bsdf_v, &bsdf_eval,
 | 
					 | 
				
			||||||
					&bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
 | 
					 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				/* modify throughput */
 | 
									/* set up random number generator */
 | 
				
			||||||
				float3 tp = throughput;
 | 
									uint lcg_state = lcg_init(rbsdf);
 | 
				
			||||||
				path_radiance_bsdf_bounce(&L, &tp, &bsdf_eval, bsdf_pdf, state.bounce, label);
 | 
									int num_samples = kernel_data.integrator.subsurface_samples;
 | 
				
			||||||
 | 
									float num_samples_inv = 1.0f/num_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				/* set labels */
 | 
									/* do subsurface scatter step with copy of shader data, this will
 | 
				
			||||||
				float min_ray_pdf = FLT_MAX;
 | 
									 * replace the BSSRDF with a diffuse BSDF closure */
 | 
				
			||||||
 | 
									for(int j = 0; j < num_samples; j++) {
 | 
				
			||||||
 | 
										ShaderData bssrdf_sd = sd;
 | 
				
			||||||
 | 
										subsurface_scatter_step(kg, &bssrdf_sd, state.flag, sc, &lcg_state, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if(!(label & LABEL_TRANSPARENT))
 | 
										/* compute lighting with the BSDF closure */
 | 
				
			||||||
					min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf);
 | 
										kernel_path_non_progressive_lighting(kg, rng, sample*num_samples + j,
 | 
				
			||||||
 | 
											&bssrdf_sd, throughput, num_samples_inv,
 | 
				
			||||||
				/* modify path state */
 | 
											ray_pdf, ray_pdf, state, rng_offset, &L, buffer);
 | 
				
			||||||
				PathState ps = state;
 | 
									}
 | 
				
			||||||
				path_state_next(kg, &ps, label);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				/* setup ray */
 | 
					 | 
				
			||||||
				Ray bsdf_ray;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				bsdf_ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);
 | 
					 | 
				
			||||||
				bsdf_ray.D = bsdf_omega_in;
 | 
					 | 
				
			||||||
				bsdf_ray.t = FLT_MAX;
 | 
					 | 
				
			||||||
#ifdef __RAY_DIFFERENTIALS__
 | 
					 | 
				
			||||||
				bsdf_ray.dP = sd.dP;
 | 
					 | 
				
			||||||
				bsdf_ray.dD = bsdf_domega_in;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef __OBJECT_MOTION__
 | 
					 | 
				
			||||||
				bsdf_ray.time = sd.time;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				kernel_path_indirect(kg, rng, sample*num_samples + j, bsdf_ray, buffer,
 | 
					 | 
				
			||||||
					tp*num_samples_inv, num_samples,
 | 
					 | 
				
			||||||
					min_ray_pdf, bsdf_pdf, ps, rng_offset+PRNG_BOUNCE_NUM, &L);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				/* for render passes, sum and reset indirect light pass variables
 | 
					 | 
				
			||||||
				 * for the next samples */
 | 
					 | 
				
			||||||
				path_radiance_sum_indirect(&L);
 | 
					 | 
				
			||||||
				path_radiance_reset_indirect(&L);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* lighting */
 | 
				
			||||||
 | 
							kernel_path_non_progressive_lighting(kg, rng, sample, &sd, throughput,
 | 
				
			||||||
 | 
								1.0f, ray_pdf, ray_pdf, state, rng_offset, &L, buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* continue in case of transparency */
 | 
							/* continue in case of transparency */
 | 
				
			||||||
		throughput *= shader_bsdf_transparency(kg, &sd);
 | 
							throughput *= shader_bsdf_transparency(kg, &sd);
 | 
				
			||||||
		shader_release(kg, &sd);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(is_zero(throughput))
 | 
							if(is_zero(throughput))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -200,5 +200,19 @@ __device void path_rng_end(KernelGlobals *kg, __global uint *rng_state, RNG rng)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device float lcg_step(uint *rng)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* implicit mod 2^32 */
 | 
				
			||||||
 | 
						*rng = (1103515245*(*rng) + 12345);
 | 
				
			||||||
 | 
						return (float)*rng * (1.0f/(float)0xFFFFFFFF);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device uint lcg_init(float seed)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint rng = __float_as_int(seed);
 | 
				
			||||||
 | 
						lcg_step(&rng);
 | 
				
			||||||
 | 
						return rng;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CCL_NAMESPACE_END
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -158,6 +158,103 @@ __device_noinline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ShaderData setup from BSSRDF scatter */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __SUBSURFACE__
 | 
				
			||||||
 | 
					__device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderData *sd,
 | 
				
			||||||
 | 
						const Intersection *isect, const Ray *ray)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bool backfacing = sd->flag & SD_BACKFACING;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* object, matrices, time, ray_length stay the same */
 | 
				
			||||||
 | 
						sd->flag = kernel_tex_fetch(__object_flag, sd->object);
 | 
				
			||||||
 | 
						sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __HAIR__
 | 
				
			||||||
 | 
						if(kernel_tex_fetch(__prim_segment, isect->prim) != ~0) {
 | 
				
			||||||
 | 
							/* Strand Shader setting*/
 | 
				
			||||||
 | 
							float4 curvedata = kernel_tex_fetch(__curves, sd->prim);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sd->shader = __float_as_int(curvedata.z);
 | 
				
			||||||
 | 
							sd->segment = isect->segment;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							float tcorr = isect->t;
 | 
				
			||||||
 | 
							if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_POSTINTERSECTCORRECTION)
 | 
				
			||||||
 | 
								tcorr = (isect->u < 0)? tcorr + sqrtf(isect->v) : tcorr - sqrtf(isect->v);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sd->P = bvh_curve_refine(kg, sd, isect, ray, tcorr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							/* fetch triangle data */
 | 
				
			||||||
 | 
							float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim);
 | 
				
			||||||
 | 
							float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
 | 
				
			||||||
 | 
							sd->shader = __float_as_int(Ns.w);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __HAIR__
 | 
				
			||||||
 | 
							sd->segment = ~0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __UV__
 | 
				
			||||||
 | 
							sd->u = isect->u;
 | 
				
			||||||
 | 
							sd->v = isect->v;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* vectors */
 | 
				
			||||||
 | 
							sd->P = bvh_triangle_refine(kg, sd, isect, ray);
 | 
				
			||||||
 | 
							sd->Ng = Ng;
 | 
				
			||||||
 | 
							sd->N = Ng;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							/* smooth normal */
 | 
				
			||||||
 | 
							if(sd->shader & SHADER_SMOOTH_NORMAL)
 | 
				
			||||||
 | 
								sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __DPDU__
 | 
				
			||||||
 | 
							/* dPdu/dPdv */
 | 
				
			||||||
 | 
							triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __HAIR__
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __INSTANCING__
 | 
				
			||||||
 | 
						if(isect->object != ~0) {
 | 
				
			||||||
 | 
							/* instance transform */
 | 
				
			||||||
 | 
							object_normal_transform(kg, sd, &sd->N);
 | 
				
			||||||
 | 
							object_normal_transform(kg, sd, &sd->Ng);
 | 
				
			||||||
 | 
					#ifdef __DPDU__
 | 
				
			||||||
 | 
							object_dir_transform(kg, sd, &sd->dPdu);
 | 
				
			||||||
 | 
							object_dir_transform(kg, sd, &sd->dPdv);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* backfacing test */
 | 
				
			||||||
 | 
						if(backfacing) {
 | 
				
			||||||
 | 
							sd->flag |= SD_BACKFACING;
 | 
				
			||||||
 | 
							sd->Ng = -sd->Ng;
 | 
				
			||||||
 | 
							sd->N = -sd->N;
 | 
				
			||||||
 | 
					#ifdef __DPDU__
 | 
				
			||||||
 | 
							sd->dPdu = -sd->dPdu;
 | 
				
			||||||
 | 
							sd->dPdv = -sd->dPdv;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* should not get used in principle as the shading will only use a diffuse
 | 
				
			||||||
 | 
						 * BSDF, but the shader might still access it */
 | 
				
			||||||
 | 
						sd->I = sd->N;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __RAY_DIFFERENTIALS__
 | 
				
			||||||
 | 
						/* differentials */
 | 
				
			||||||
 | 
						differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng);
 | 
				
			||||||
 | 
						/* don't modify dP and dI */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ShaderData setup from position sampled on mesh */
 | 
					/* ShaderData setup from position sampled on mesh */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__device_noinline void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
 | 
					__device_noinline void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
 | 
				
			||||||
@@ -283,11 +380,9 @@ __device_noinline void shader_setup_from_sample(KernelGlobals *kg, ShaderData *s
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* ShaderData setup for displacement */
 | 
					/* ShaderData setup for displacement */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__device_noinline void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
 | 
					__device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
 | 
				
			||||||
	int object, int prim, float u, float v)
 | 
						int object, int prim, float u, float v)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Note: no OSLShader::init call here, this is done in shader_setup_from_sample! */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	float3 P, Ng, I = make_float3(0.0f, 0.0f, 0.0f);
 | 
						float3 P, Ng, I = make_float3(0.0f, 0.0f, 0.0f);
 | 
				
			||||||
	int shader;
 | 
						int shader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -418,7 +513,7 @@ __device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
 | 
				
			|||||||
			const ShaderClosure *sc = &sd->closure[sampled];
 | 
								const ShaderClosure *sc = &sd->closure[sampled];
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
			if(CLOSURE_IS_BSDF(sc->type)) {
 | 
								if(CLOSURE_IS_BSDF(sc->type)) {
 | 
				
			||||||
				sum += sd->closure[sampled].sample_weight;
 | 
									sum += sc->sample_weight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if(r <= sum)
 | 
									if(r <= sum)
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
@@ -811,7 +906,7 @@ __device void shader_merge_closures(KernelGlobals *kg, ShaderData *sd)
 | 
				
			|||||||
			ShaderClosure *scj = &sd->closure[j];
 | 
								ShaderClosure *scj = &sd->closure[j];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __OSL__
 | 
					#ifdef __OSL__
 | 
				
			||||||
			if(!sci->prim && sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
 | 
								if(!sci->prim && !scj->prim && sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
			if(sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
 | 
								if(sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -823,18 +918,12 @@ __device void shader_merge_closures(KernelGlobals *kg, ShaderData *sd)
 | 
				
			|||||||
					memmove(scj, scj+1, size*sizeof(ShaderClosure));
 | 
										memmove(scj, scj+1, size*sizeof(ShaderClosure));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				sd->num_closure--;
 | 
									sd->num_closure--;
 | 
				
			||||||
 | 
									j--;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Free ShaderData */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
__device void shader_release(KernelGlobals *kg, ShaderData *sd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	/* nothing to do currently */
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CCL_NAMESPACE_END
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										241
									
								
								intern/cycles/kernel/kernel_subsurface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								intern/cycles/kernel/kernel_subsurface.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,241 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2013, 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BSSRDF_MULTI_EVAL
 | 
				
			||||||
 | 
					#define BSSRDF_SKIP_NO_HIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device float bssrdf_sample_distance(KernelGlobals *kg, float radius, float refl, float u)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int table_offset = kernel_data.bssrdf.table_offset;
 | 
				
			||||||
 | 
						float r = lookup_table_read_2D(kg, u, refl, table_offset, BSSRDF_RADIUS_TABLE_SIZE, BSSRDF_REFL_TABLE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return r*radius;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef BSSRDF_MULTI_EVAL
 | 
				
			||||||
 | 
					__device float bssrdf_pdf(KernelGlobals *kg, float radius, float refl, float r)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if(r >= radius)
 | 
				
			||||||
 | 
							return 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* todo: when we use the real BSSRDF this will need to be divided by the maximum
 | 
				
			||||||
 | 
						 * radius instead of the average radius */
 | 
				
			||||||
 | 
						float t = r/radius;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int table_offset = kernel_data.bssrdf.table_offset + BSSRDF_PDF_TABLE_OFFSET;
 | 
				
			||||||
 | 
						float pdf = lookup_table_read_2D(kg, t, refl, table_offset, BSSRDF_RADIUS_TABLE_SIZE, BSSRDF_REFL_TABLE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pdf /= radius;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pdf;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__device ShaderClosure *subsurface_scatter_pick_closure(KernelGlobals *kg, ShaderData *sd, float *probability)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* sum sample weights of bssrdf and bsdf */
 | 
				
			||||||
 | 
						float bsdf_sum = 0.0f;
 | 
				
			||||||
 | 
						float bssrdf_sum = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(int i = 0; i < sd->num_closure; i++) {
 | 
				
			||||||
 | 
							ShaderClosure *sc = &sd->closure[i];
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(CLOSURE_IS_BSDF(sc->type))
 | 
				
			||||||
 | 
								bsdf_sum += sc->sample_weight;
 | 
				
			||||||
 | 
							else if(CLOSURE_IS_BSSRDF(sc->type))
 | 
				
			||||||
 | 
								bssrdf_sum += sc->sample_weight;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* use bsdf or bssrdf? */
 | 
				
			||||||
 | 
						float r = sd->randb_closure*(bsdf_sum + bssrdf_sum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(r < bsdf_sum) {
 | 
				
			||||||
 | 
							/* use bsdf, and adjust randb so we can reuse it for picking a bsdf */
 | 
				
			||||||
 | 
							sd->randb_closure = r/bsdf_sum;
 | 
				
			||||||
 | 
							*probability = (bsdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/bsdf_sum: 1.0f;
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* use bssrdf */
 | 
				
			||||||
 | 
						r -= bsdf_sum;
 | 
				
			||||||
 | 
						sd->randb_closure = 0.0f; /* not needed anymore */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float sum = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(int i = 0; i < sd->num_closure; i++) {
 | 
				
			||||||
 | 
							ShaderClosure *sc = &sd->closure[i];
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(CLOSURE_IS_BSSRDF(sc->type)) {
 | 
				
			||||||
 | 
								sum += sc->sample_weight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(r <= sum) {
 | 
				
			||||||
 | 
					#ifdef BSSRDF_MULTI_EVAL
 | 
				
			||||||
 | 
									*probability = (bssrdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/bssrdf_sum: 1.0f;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
									*probability = (bssrdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/sc->sample_weight: 1.0f;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
									return sc;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* should never happen */
 | 
				
			||||||
 | 
						*probability = 1.0f;
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef BSSRDF_MULTI_EVAL
 | 
				
			||||||
 | 
					__device float3 subsurface_scatter_multi_eval(KernelGlobals *kg, ShaderData *sd, bool hit, float refl, float *r, int num_r, bool all)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* compute pdf */
 | 
				
			||||||
 | 
						float3 eval_sum = make_float3(0.0f, 0.0f, 0.0f);
 | 
				
			||||||
 | 
						float pdf_sum = 0.0f;
 | 
				
			||||||
 | 
						float sample_weight_sum = 0.0f;
 | 
				
			||||||
 | 
						int num_bssrdf = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(int i = 0; i < sd->num_closure; i++) {
 | 
				
			||||||
 | 
							ShaderClosure *sc = &sd->closure[i];
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(CLOSURE_IS_BSSRDF(sc->type)) {
 | 
				
			||||||
 | 
								float sample_weight = (all)? 1.0f: sc->sample_weight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* compute pdf */
 | 
				
			||||||
 | 
								float pdf = 1.0f;
 | 
				
			||||||
 | 
								for(int i = 0; i < num_r; i++)
 | 
				
			||||||
 | 
									pdf *= bssrdf_pdf(kg, sc->data0, refl, r[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								eval_sum += sc->weight*pdf;
 | 
				
			||||||
 | 
								pdf_sum += sample_weight*pdf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								sample_weight_sum += sample_weight;
 | 
				
			||||||
 | 
								num_bssrdf++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float inv_pdf_sum;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if(pdf_sum > 0.0f) {
 | 
				
			||||||
 | 
							/* in case of non-progressive integrate we sample all bssrdf's once,
 | 
				
			||||||
 | 
							 * for progressive we pick one, so adjust pdf for that */
 | 
				
			||||||
 | 
							if(all)
 | 
				
			||||||
 | 
								inv_pdf_sum = 1.0f/pdf_sum;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								inv_pdf_sum = sample_weight_sum/pdf_sum;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							inv_pdf_sum = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float3 weight = eval_sum * inv_pdf_sum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return weight;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* replace closures with a single diffuse bsdf closure after scatter step */
 | 
				
			||||||
 | 
					__device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, float3 weight)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ShaderClosure *sc = &sd->closure[0];
 | 
				
			||||||
 | 
						sd->num_closure = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sc->weight = weight;
 | 
				
			||||||
 | 
						sc->sample_weight = 1.0f;
 | 
				
			||||||
 | 
						sc->data0 = 0.0f;
 | 
				
			||||||
 | 
						sc->data1 = 0.0f;
 | 
				
			||||||
 | 
						sc->N = sd->N;
 | 
				
			||||||
 | 
						sd->flag &= ~SD_CLOSURE_FLAGS;
 | 
				
			||||||
 | 
						sd->flag |= bsdf_diffuse_setup(sc);
 | 
				
			||||||
 | 
						sd->randb_closure = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* todo: evaluate shading to get blurred textures and bump mapping */
 | 
				
			||||||
 | 
						/* shader_eval_surface(kg, sd, 0.0f, state_flag, SHADER_CONTEXT_SSS); */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* subsurface scattering step, from a point on the surface to another nearby point on the same object */
 | 
				
			||||||
 | 
					__device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, int state_flag, ShaderClosure *sc, uint *lcg_state, bool all)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						float radius = sc->data0;
 | 
				
			||||||
 | 
						float refl = max(average(sc->weight)*3.0f, 0.0f);
 | 
				
			||||||
 | 
						float r = 0.0f;
 | 
				
			||||||
 | 
						bool hit = false;
 | 
				
			||||||
 | 
						float3 weight = make_float3(1.0f, 1.0f, 1.0f);
 | 
				
			||||||
 | 
					#ifdef BSSRDF_MULTI_EVAL
 | 
				
			||||||
 | 
						float r_attempts[BSSRDF_MAX_ATTEMPTS];
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						int num_attempts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* attempt to find a hit a given number of times before giving up */
 | 
				
			||||||
 | 
						for(num_attempts = 0; num_attempts < kernel_data.bssrdf.num_attempts; num_attempts++) {
 | 
				
			||||||
 | 
							/* random numbers for sampling */
 | 
				
			||||||
 | 
							float u1 = lcg_step(lcg_state);
 | 
				
			||||||
 | 
							float u2 = lcg_step(lcg_state);
 | 
				
			||||||
 | 
							float u3 = lcg_step(lcg_state);
 | 
				
			||||||
 | 
							float u4 = lcg_step(lcg_state);
 | 
				
			||||||
 | 
							float u5 = lcg_step(lcg_state);
 | 
				
			||||||
 | 
							float u6 = lcg_step(lcg_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							r = bssrdf_sample_distance(kg, radius, refl, u5);
 | 
				
			||||||
 | 
					#ifdef BSSRDF_MULTI_EVAL
 | 
				
			||||||
 | 
							r_attempts[num_attempts] = r;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							float3 p1 = sd->P + sample_uniform_sphere(u1, u2)*r;
 | 
				
			||||||
 | 
							float3 p2 = sd->P + sample_uniform_sphere(u3, u4)*r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* create ray */
 | 
				
			||||||
 | 
							Ray ray;
 | 
				
			||||||
 | 
							ray.P = p1;
 | 
				
			||||||
 | 
							ray.D = normalize_len(p2 - p1, &ray.t);
 | 
				
			||||||
 | 
							ray.dP = sd->dP;
 | 
				
			||||||
 | 
							ray.dD.dx = make_float3(0.0f, 0.0f, 0.0f);
 | 
				
			||||||
 | 
							ray.dD.dy = make_float3(0.0f, 0.0f, 0.0f);
 | 
				
			||||||
 | 
							ray.time = sd->time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* intersect with the same object. if multiple intersections are
 | 
				
			||||||
 | 
							 * found it will randomly pick one of them */
 | 
				
			||||||
 | 
							Intersection isect;
 | 
				
			||||||
 | 
							if(scene_intersect_subsurface(kg, &ray, &isect, sd->object, u6) == 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* setup new shading point */
 | 
				
			||||||
 | 
							shader_setup_from_subsurface(kg, sd, &isect, &ray);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hit = true;
 | 
				
			||||||
 | 
							num_attempts++;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* evaluate subsurface scattering closures */
 | 
				
			||||||
 | 
					#ifdef BSSRDF_MULTI_EVAL
 | 
				
			||||||
 | 
						weight *= subsurface_scatter_multi_eval(kg, sd, hit, refl, r_attempts, num_attempts, all);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						weight *= sc->weight;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef BSSRDF_SKIP_NO_HIT
 | 
				
			||||||
 | 
						if(!hit)
 | 
				
			||||||
 | 
							weight = make_float3(0.0f, 0.0f, 0.0f);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* replace closures with a single diffuse BSDF */
 | 
				
			||||||
 | 
						subsurface_scatter_setup_diffuse_bsdf(sd, weight);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -66,8 +66,8 @@ KERNEL_TEX(uint4, texture_uint4, __svm_nodes)
 | 
				
			|||||||
KERNEL_TEX(uint, texture_uint, __shader_flag)
 | 
					KERNEL_TEX(uint, texture_uint, __shader_flag)
 | 
				
			||||||
KERNEL_TEX(uint, texture_uint, __object_flag)
 | 
					KERNEL_TEX(uint, texture_uint, __object_flag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* camera/film */
 | 
					/* lookup tables */
 | 
				
			||||||
KERNEL_TEX(float, texture_float, __filter_table)
 | 
					KERNEL_TEX(float, texture_float, __lookup_table)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* sobol */
 | 
					/* sobol */
 | 
				
			||||||
KERNEL_TEX(uint, texture_uint, __sobol_directions)
 | 
					KERNEL_TEX(uint, texture_uint, __sobol_directions)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,13 @@ CCL_NAMESPACE_BEGIN
 | 
				
			|||||||
#define PARTICLE_SIZE 		5
 | 
					#define PARTICLE_SIZE 		5
 | 
				
			||||||
#define TIME_INVALID		FLT_MAX
 | 
					#define TIME_INVALID		FLT_MAX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BSSRDF_RADIUS_TABLE_SIZE	1024
 | 
				
			||||||
 | 
					#define BSSRDF_REFL_TABLE_SIZE		256
 | 
				
			||||||
 | 
					#define BSSRDF_PDF_TABLE_OFFSET		(BSSRDF_RADIUS_TABLE_SIZE*BSSRDF_REFL_TABLE_SIZE)
 | 
				
			||||||
 | 
					#define BSSRDF_LOOKUP_TABLE_SIZE	(BSSRDF_RADIUS_TABLE_SIZE*BSSRDF_REFL_TABLE_SIZE*2)
 | 
				
			||||||
 | 
					#define BSSRDF_MIN_RADIUS			1e-8f
 | 
				
			||||||
 | 
					#define BSSRDF_MAX_ATTEMPTS			8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TEX_NUM_FLOAT_IMAGES	5
 | 
					#define TEX_NUM_FLOAT_IMAGES	5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* device capabilities */
 | 
					/* device capabilities */
 | 
				
			||||||
@@ -48,6 +55,7 @@ CCL_NAMESPACE_BEGIN
 | 
				
			|||||||
#ifdef WITH_OSL
 | 
					#ifdef WITH_OSL
 | 
				
			||||||
#define __OSL__
 | 
					#define __OSL__
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#define __SUBSURFACE__
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __KERNEL_CUDA__
 | 
					#ifdef __KERNEL_CUDA__
 | 
				
			||||||
@@ -423,7 +431,8 @@ typedef enum ShaderContext {
 | 
				
			|||||||
	SHADER_CONTEXT_INDIRECT = 1,
 | 
						SHADER_CONTEXT_INDIRECT = 1,
 | 
				
			||||||
	SHADER_CONTEXT_EMISSION = 2,
 | 
						SHADER_CONTEXT_EMISSION = 2,
 | 
				
			||||||
	SHADER_CONTEXT_SHADOW = 3,
 | 
						SHADER_CONTEXT_SHADOW = 3,
 | 
				
			||||||
	SHADER_CONTEXT_NUM = 4
 | 
						SHADER_CONTEXT_SSS = 4,
 | 
				
			||||||
 | 
						SHADER_CONTEXT_NUM = 5
 | 
				
			||||||
} ShaderContext;
 | 
					} ShaderContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Shader Data
 | 
					/* Shader Data
 | 
				
			||||||
@@ -438,20 +447,23 @@ enum ShaderDataFlag {
 | 
				
			|||||||
	SD_BSDF = 4,			/* have bsdf closure? */
 | 
						SD_BSDF = 4,			/* have bsdf closure? */
 | 
				
			||||||
	SD_BSDF_HAS_EVAL = 8,	/* have non-singular bsdf closure? */
 | 
						SD_BSDF_HAS_EVAL = 8,	/* have non-singular bsdf closure? */
 | 
				
			||||||
	SD_BSDF_GLOSSY = 16,	/* have glossy bsdf */
 | 
						SD_BSDF_GLOSSY = 16,	/* have glossy bsdf */
 | 
				
			||||||
	SD_HOLDOUT = 32,		/* have holdout closure? */
 | 
						SD_BSSRDF = 32,			/* have bssrdf */
 | 
				
			||||||
	SD_VOLUME = 64,			/* have volume closure? */
 | 
						SD_HOLDOUT = 64,		/* have holdout closure? */
 | 
				
			||||||
	SD_AO = 128,			/* have ao closure? */
 | 
						SD_VOLUME = 128,		/* have volume closure? */
 | 
				
			||||||
 | 
						SD_AO = 256,			/* have ao closure? */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY|SD_BSSRDF|SD_HOLDOUT|SD_VOLUME|SD_AO),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* shader flags */
 | 
						/* shader flags */
 | 
				
			||||||
	SD_SAMPLE_AS_LIGHT = 256,			/* direct light sample */
 | 
						SD_SAMPLE_AS_LIGHT = 512,			/* direct light sample */
 | 
				
			||||||
	SD_HAS_SURFACE_TRANSPARENT = 512,	/* has surface transparency */
 | 
						SD_HAS_SURFACE_TRANSPARENT = 1024,	/* has surface transparency */
 | 
				
			||||||
	SD_HAS_VOLUME = 1024,				/* has volume shader */
 | 
						SD_HAS_VOLUME = 2048,				/* has volume shader */
 | 
				
			||||||
	SD_HOMOGENEOUS_VOLUME = 2048,		/* has homogeneous volume */
 | 
						SD_HOMOGENEOUS_VOLUME = 4096,		/* has homogeneous volume */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* object flags */
 | 
						/* object flags */
 | 
				
			||||||
	SD_HOLDOUT_MASK = 4096,				/* holdout for camera rays */
 | 
						SD_HOLDOUT_MASK = 8192,				/* holdout for camera rays */
 | 
				
			||||||
	SD_OBJECT_MOTION = 8192,			/* has object motion blur */
 | 
						SD_OBJECT_MOTION = 16384,			/* has object motion blur */
 | 
				
			||||||
	SD_TRANSFORM_APPLIED = 16384 		/* vertices have transform applied */
 | 
						SD_TRANSFORM_APPLIED = 32768 		/* vertices have transform applied */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct ShaderData {
 | 
					typedef struct ShaderData {
 | 
				
			||||||
@@ -611,8 +623,9 @@ typedef struct KernelFilm {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	int pass_shadow;
 | 
						int pass_shadow;
 | 
				
			||||||
	float pass_shadow_scale;
 | 
						float pass_shadow_scale;
 | 
				
			||||||
	int pass_pad1;
 | 
					
 | 
				
			||||||
	int pass_pad2;
 | 
						int filter_table_offset;
 | 
				
			||||||
 | 
						int filter_pad;
 | 
				
			||||||
} KernelFilm;
 | 
					} KernelFilm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct KernelBackground {
 | 
					typedef struct KernelBackground {
 | 
				
			||||||
@@ -680,6 +693,9 @@ typedef struct KernelIntegrator {
 | 
				
			|||||||
	int ao_samples;
 | 
						int ao_samples;
 | 
				
			||||||
	int mesh_light_samples;
 | 
						int mesh_light_samples;
 | 
				
			||||||
	int use_lamp_mis;
 | 
						int use_lamp_mis;
 | 
				
			||||||
 | 
						int subsurface_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int pad1, pad2, pad3;
 | 
				
			||||||
} KernelIntegrator;
 | 
					} KernelIntegrator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct KernelBVH {
 | 
					typedef struct KernelBVH {
 | 
				
			||||||
@@ -711,9 +727,14 @@ typedef struct KernelCurves {
 | 
				
			|||||||
	float encasing_ratio;
 | 
						float encasing_ratio;
 | 
				
			||||||
	int curveflags;
 | 
						int curveflags;
 | 
				
			||||||
	int subdivisions;
 | 
						int subdivisions;
 | 
				
			||||||
 | 
					 | 
				
			||||||
} KernelCurves;
 | 
					} KernelCurves;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct KernelBSSRDF {
 | 
				
			||||||
 | 
						int table_offset;
 | 
				
			||||||
 | 
						int num_attempts;
 | 
				
			||||||
 | 
						int pad1, pad2;
 | 
				
			||||||
 | 
					} KernelBSSRDF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct KernelData {
 | 
					typedef struct KernelData {
 | 
				
			||||||
	KernelCamera cam;
 | 
						KernelCamera cam;
 | 
				
			||||||
	KernelFilm film;
 | 
						KernelFilm film;
 | 
				
			||||||
@@ -722,6 +743,7 @@ typedef struct KernelData {
 | 
				
			|||||||
	KernelIntegrator integrator;
 | 
						KernelIntegrator integrator;
 | 
				
			||||||
	KernelBVH bvh;
 | 
						KernelBVH bvh;
 | 
				
			||||||
	KernelCurves curve_kernel_data;
 | 
						KernelCurves curve_kernel_data;
 | 
				
			||||||
 | 
						KernelBSSRDF bssrdf;
 | 
				
			||||||
} KernelData;
 | 
					} KernelData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CCL_NAMESPACE_END
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,12 +18,14 @@ set(SRC
 | 
				
			|||||||
	bsdf_phong_ramp.cpp
 | 
						bsdf_phong_ramp.cpp
 | 
				
			||||||
	bsdf_toon.cpp
 | 
						bsdf_toon.cpp
 | 
				
			||||||
	emissive.cpp
 | 
						emissive.cpp
 | 
				
			||||||
 | 
						osl_bssrdf.cpp
 | 
				
			||||||
	osl_closures.cpp
 | 
						osl_closures.cpp
 | 
				
			||||||
	osl_services.cpp
 | 
						osl_services.cpp
 | 
				
			||||||
	osl_shader.cpp
 | 
						osl_shader.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(HEADER_SRC
 | 
					set(HEADER_SRC
 | 
				
			||||||
 | 
						osl_bssrdf.h
 | 
				
			||||||
	osl_closures.h
 | 
						osl_closures.h
 | 
				
			||||||
	osl_globals.h
 | 
						osl_globals.h
 | 
				
			||||||
	osl_services.h
 | 
						osl_services.h
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										90
									
								
								intern/cycles/kernel/osl/osl_bssrdf.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								intern/cycles/kernel/osl/osl_bssrdf.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Adapted from Open Shading Language with this license:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
 | 
				
			||||||
 | 
					 * All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Modifications Copyright 2011, Blender Foundation.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					 * met:
 | 
				
			||||||
 | 
					 * * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 *   notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 * * Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 *   notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					 *   documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					 * * Neither the name of Sony Pictures Imageworks nor the names of its
 | 
				
			||||||
 | 
					 *   contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					 *   this software without specific prior written permission.
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <OpenImageIO/fmath.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <OSL/genclosure.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "osl_bssrdf.h"
 | 
				
			||||||
 | 
					#include "osl_closures.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "kernel_types.h"
 | 
				
			||||||
 | 
					#include "kernel_montecarlo.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "closure/bsdf_diffuse.h"
 | 
				
			||||||
 | 
					#include "closure/bssrdf.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace OSL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BSSRDFClosure : public CBSSRDFClosure {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						size_t memsize() const { return sizeof(*this); }
 | 
				
			||||||
 | 
						const char *name() const { return "bssrdf_cubic"; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void setup()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							sc.prim = NULL;
 | 
				
			||||||
 | 
							sc.data0 = fabsf(average(radius));
 | 
				
			||||||
 | 
							sc.data1 = 1.3f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							m_shaderdata_flag = bssrdf_setup(&sc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool mergeable(const ClosurePrimitive *other) const
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void print_on(std::ostream &out) const
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							out << name() << " ((" << sc.N[0] << ", " << sc.N[1] << ", " << sc.N[2] << "))";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ClosureParam *closure_bssrdf_params()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static ClosureParam params[] = {
 | 
				
			||||||
 | 
							CLOSURE_FLOAT3_PARAM(BSSRDFClosure, sc.N),
 | 
				
			||||||
 | 
							CLOSURE_FLOAT3_PARAM(BSSRDFClosure, radius),
 | 
				
			||||||
 | 
							//CLOSURE_FLOAT_PARAM(BSSRDFClosure, sc.data1),
 | 
				
			||||||
 | 
						    CLOSURE_STRING_KEYPARAM("label"),
 | 
				
			||||||
 | 
						    CLOSURE_FINISH_PARAM(BSSRDFClosure)
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						return params;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CLOSURE_PREPARE(closure_bssrdf_prepare, BSSRDFClosure)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										65
									
								
								intern/cycles/kernel/osl/osl_bssrdf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								intern/cycles/kernel/osl/osl_bssrdf.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Adapted from Open Shading Language with this license:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
 | 
				
			||||||
 | 
					 * All Rights Reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Modifications Copyright 2011, Blender Foundation.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					 * met:
 | 
				
			||||||
 | 
					 * * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 *   notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 * * Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 *   notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					 *   documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					 * * Neither the name of Sony Pictures Imageworks nor the names of its
 | 
				
			||||||
 | 
					 *   contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					 *   this software without specific prior written permission.
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __OSL_BSSRDF_H__
 | 
				
			||||||
 | 
					#define __OSL_BSSRDF_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <OSL/oslclosure.h>
 | 
				
			||||||
 | 
					#include <OSL/oslexec.h>
 | 
				
			||||||
 | 
					#include <OSL/genclosure.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "kernel_types.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "util_types.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CBSSRDFClosure : public OSL::ClosurePrimitive {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						ShaderClosure sc;
 | 
				
			||||||
 | 
						float3 radius;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CBSSRDFClosure() : OSL::ClosurePrimitive(BSSRDF),
 | 
				
			||||||
 | 
						  m_shaderdata_flag(0) { }
 | 
				
			||||||
 | 
						~CBSSRDFClosure() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int scattering() const { return LABEL_DIFFUSE; }
 | 
				
			||||||
 | 
						int shaderdata_flag() const { return m_shaderdata_flag; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						int m_shaderdata_flag;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __OSL_BSSRDF_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -201,6 +201,8 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
 | 
				
			|||||||
		closure_bsdf_diffuse_toon_params(), closure_bsdf_diffuse_toon_prepare);
 | 
							closure_bsdf_diffuse_toon_params(), closure_bsdf_diffuse_toon_prepare);
 | 
				
			||||||
	register_closure(ss, "specular_toon", id++,
 | 
						register_closure(ss, "specular_toon", id++,
 | 
				
			||||||
		closure_bsdf_specular_toon_params(), closure_bsdf_specular_toon_prepare);
 | 
							closure_bsdf_specular_toon_params(), closure_bsdf_specular_toon_prepare);
 | 
				
			||||||
 | 
						register_closure(ss, "bssrdf_cubic", id++,
 | 
				
			||||||
 | 
							closure_bssrdf_params(), closure_bssrdf_prepare);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CCL_NAMESPACE_END
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,6 +51,7 @@ OSL::ClosureParam *closure_bsdf_diffuse_ramp_params();
 | 
				
			|||||||
OSL::ClosureParam *closure_bsdf_phong_ramp_params();
 | 
					OSL::ClosureParam *closure_bsdf_phong_ramp_params();
 | 
				
			||||||
OSL::ClosureParam *closure_bsdf_diffuse_toon_params();
 | 
					OSL::ClosureParam *closure_bsdf_diffuse_toon_params();
 | 
				
			||||||
OSL::ClosureParam *closure_bsdf_specular_toon_params();
 | 
					OSL::ClosureParam *closure_bsdf_specular_toon_params();
 | 
				
			||||||
 | 
					OSL::ClosureParam *closure_bssrdf_params();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
 | 
					void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
 | 
				
			||||||
void closure_background_prepare(OSL::RendererServices *, int id, void *data);
 | 
					void closure_background_prepare(OSL::RendererServices *, int id, void *data);
 | 
				
			||||||
@@ -60,6 +61,7 @@ void closure_bsdf_diffuse_ramp_prepare(OSL::RendererServices *, int id, void *da
 | 
				
			|||||||
void closure_bsdf_phong_ramp_prepare(OSL::RendererServices *, int id, void *data);
 | 
					void closure_bsdf_phong_ramp_prepare(OSL::RendererServices *, int id, void *data);
 | 
				
			||||||
void closure_bsdf_diffuse_toon_prepare(OSL::RendererServices *, int id, void *data);
 | 
					void closure_bsdf_diffuse_toon_prepare(OSL::RendererServices *, int id, void *data);
 | 
				
			||||||
void closure_bsdf_specular_toon_prepare(OSL::RendererServices *, int id, void *data);
 | 
					void closure_bsdf_specular_toon_prepare(OSL::RendererServices *, int id, void *data);
 | 
				
			||||||
 | 
					void closure_bssrdf_prepare(OSL::RendererServices *, int id, void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	AmbientOcclusion = 100
 | 
						AmbientOcclusion = 100
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@
 | 
				
			|||||||
#include "kernel_globals.h"
 | 
					#include "kernel_globals.h"
 | 
				
			||||||
#include "kernel_object.h"
 | 
					#include "kernel_object.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "osl_bssrdf.h"
 | 
				
			||||||
#include "osl_closures.h"
 | 
					#include "osl_closures.h"
 | 
				
			||||||
#include "osl_globals.h"
 | 
					#include "osl_globals.h"
 | 
				
			||||||
#include "osl_services.h"
 | 
					#include "osl_services.h"
 | 
				
			||||||
@@ -201,7 +202,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				case OSL::ClosurePrimitive::Holdout:
 | 
									case OSL::ClosurePrimitive::Holdout: {
 | 
				
			||||||
					sc.sample_weight = 0.0f;
 | 
										sc.sample_weight = 0.0f;
 | 
				
			||||||
					sc.type = CLOSURE_HOLDOUT_ID;
 | 
										sc.type = CLOSURE_HOLDOUT_ID;
 | 
				
			||||||
					sc.prim = NULL;
 | 
										sc.prim = NULL;
 | 
				
			||||||
@@ -211,7 +212,43 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
 | 
				
			|||||||
						sd->flag |= SD_HOLDOUT;
 | 
											sd->flag |= SD_HOLDOUT;
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case OSL::ClosurePrimitive::BSSRDF:
 | 
									}
 | 
				
			||||||
 | 
									case OSL::ClosurePrimitive::BSSRDF: {
 | 
				
			||||||
 | 
										CBSSRDFClosure *bssrdf = (CBSSRDFClosure *)prim;
 | 
				
			||||||
 | 
										float sample_weight = fabsf(average(weight));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if(sample_weight > 1e-5f && sd->num_closure+2 < MAX_CLOSURE) {
 | 
				
			||||||
 | 
											sc.sample_weight = sample_weight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											sc.type = bssrdf->sc.type;
 | 
				
			||||||
 | 
											sc.N = bssrdf->sc.N;
 | 
				
			||||||
 | 
											sc.data1 = bssrdf->sc.data1;
 | 
				
			||||||
 | 
											sc.prim = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											/* create one closure for each color channel */
 | 
				
			||||||
 | 
											if(fabsf(weight.x) > 0.0f) {
 | 
				
			||||||
 | 
												sc.weight = make_float3(weight.x, 0.0f, 0.0f);
 | 
				
			||||||
 | 
												sc.data0 = bssrdf->radius.x;
 | 
				
			||||||
 | 
												sd->closure[sd->num_closure++] = sc;
 | 
				
			||||||
 | 
												sd->flag |= bssrdf->shaderdata_flag();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											if(fabsf(weight.y) > 0.0f) {
 | 
				
			||||||
 | 
												sc.weight = make_float3(0.0f, weight.y, 0.0f);
 | 
				
			||||||
 | 
												sc.data0 = bssrdf->radius.y;
 | 
				
			||||||
 | 
												sd->closure[sd->num_closure++] = sc;
 | 
				
			||||||
 | 
												sd->flag |= bssrdf->shaderdata_flag();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											if(fabsf(weight.z) > 0.0f) {
 | 
				
			||||||
 | 
												sc.weight = make_float3(0.0f, 0.0f, weight.z);
 | 
				
			||||||
 | 
												sc.data0 = bssrdf->radius.z;
 | 
				
			||||||
 | 
												sd->closure[sd->num_closure++] = sc;
 | 
				
			||||||
 | 
												sd->flag |= bssrdf->shaderdata_flag();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				case OSL::ClosurePrimitive::Debug:
 | 
									case OSL::ClosurePrimitive::Debug:
 | 
				
			||||||
					break; /* not implemented */
 | 
										break; /* not implemented */
 | 
				
			||||||
				case OSL::ClosurePrimitive::Background:
 | 
									case OSL::ClosurePrimitive::Background:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,6 +55,7 @@ set(SRC_OSL
 | 
				
			|||||||
	node_separate_rgb.osl
 | 
						node_separate_rgb.osl
 | 
				
			||||||
	node_set_normal.osl
 | 
						node_set_normal.osl
 | 
				
			||||||
	node_sky_texture.osl
 | 
						node_sky_texture.osl
 | 
				
			||||||
 | 
						node_subsurface_scattering.osl
 | 
				
			||||||
	node_tangent.osl
 | 
						node_tangent.osl
 | 
				
			||||||
	node_texture_coordinate.osl
 | 
						node_texture_coordinate.osl
 | 
				
			||||||
	node_translucent_bsdf.osl
 | 
						node_translucent_bsdf.osl
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										33
									
								
								intern/cycles/kernel/shaders/node_subsurface_scattering.osl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								intern/cycles/kernel/shaders/node_subsurface_scattering.osl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2011, 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "stdosl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					shader node_subsurface_scattering(
 | 
				
			||||||
 | 
						color Color = 0.8,
 | 
				
			||||||
 | 
						float Scale = 1.0,
 | 
				
			||||||
 | 
						vector Radius = vector(0.1, 0.1, 0.1),
 | 
				
			||||||
 | 
						float IOR = 1.3,
 | 
				
			||||||
 | 
						normal Normal = N,
 | 
				
			||||||
 | 
						output closure color BSSRDF = 0)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						float eta = max(IOR, 1.0 + 1e-5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BSSRDF = Color * bssrdf_cubic(N, Scale * Radius);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -461,6 +461,7 @@ closure color emission() BUILTIN;
 | 
				
			|||||||
closure color background() BUILTIN;
 | 
					closure color background() BUILTIN;
 | 
				
			||||||
closure color holdout() BUILTIN;
 | 
					closure color holdout() BUILTIN;
 | 
				
			||||||
closure color ambient_occlusion() BUILTIN;
 | 
					closure color ambient_occlusion() BUILTIN;
 | 
				
			||||||
 | 
					closure color bssrdf_cubic(normal N, vector radius) BUILTIN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Renderer state
 | 
					// Renderer state
 | 
				
			||||||
int raytype (string typename) BUILTIN;
 | 
					int raytype (string typename) BUILTIN;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@ __device void svm_node_glass_setup(ShaderData *sd, ShaderClosure *sc, int type,
 | 
				
			|||||||
	if(type == CLOSURE_BSDF_SHARP_GLASS_ID) {
 | 
						if(type == CLOSURE_BSDF_SHARP_GLASS_ID) {
 | 
				
			||||||
		if(refract) {
 | 
							if(refract) {
 | 
				
			||||||
			sc->data0 = eta;
 | 
								sc->data0 = eta;
 | 
				
			||||||
 | 
								sc->data1 = 0.0f;
 | 
				
			||||||
			sd->flag |= bsdf_refraction_setup(sc);
 | 
								sd->flag |= bsdf_refraction_setup(sc);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
@@ -58,6 +59,9 @@ __device_inline ShaderClosure *svm_node_closure_get_non_bsdf(ShaderData *sd, Clo
 | 
				
			|||||||
	if(sd->num_closure < MAX_CLOSURE) {
 | 
						if(sd->num_closure < MAX_CLOSURE) {
 | 
				
			||||||
		sc->weight *= mix_weight;
 | 
							sc->weight *= mix_weight;
 | 
				
			||||||
		sc->type = type;
 | 
							sc->type = type;
 | 
				
			||||||
 | 
					#ifdef __OSL__
 | 
				
			||||||
 | 
							sc->prim = NULL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		sd->num_closure++;
 | 
							sd->num_closure++;
 | 
				
			||||||
		return sc;
 | 
							return sc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -79,6 +83,9 @@ __device_inline ShaderClosure *svm_node_closure_get_bsdf(ShaderData *sd, float m
 | 
				
			|||||||
		sc->weight = weight;
 | 
							sc->weight = weight;
 | 
				
			||||||
		sc->sample_weight = sample_weight;
 | 
							sc->sample_weight = sample_weight;
 | 
				
			||||||
		sd->num_closure++;
 | 
							sd->num_closure++;
 | 
				
			||||||
 | 
					#ifdef __OSL__
 | 
				
			||||||
 | 
							sc->prim = NULL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		return sc;
 | 
							return sc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -125,10 +132,13 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
 | 
				
			|||||||
				float roughness = param1;
 | 
									float roughness = param1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if(roughness == 0.0f) {
 | 
									if(roughness == 0.0f) {
 | 
				
			||||||
 | 
										sc->data0 = 0.0f;
 | 
				
			||||||
 | 
										sc->data1 = 0.0f;
 | 
				
			||||||
					sd->flag |= bsdf_diffuse_setup(sc);
 | 
										sd->flag |= bsdf_diffuse_setup(sc);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				else {
 | 
									else {
 | 
				
			||||||
					sc->data0 = roughness;
 | 
										sc->data0 = roughness;
 | 
				
			||||||
 | 
										sc->data1 = 0.0f;
 | 
				
			||||||
					sd->flag |= bsdf_oren_nayar_setup(sc);
 | 
										sd->flag |= bsdf_oren_nayar_setup(sc);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -138,6 +148,8 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
 | 
				
			|||||||
			ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
 | 
								ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(sc) {
 | 
								if(sc) {
 | 
				
			||||||
 | 
									sc->data0 = 0.0f;
 | 
				
			||||||
 | 
									sc->data1 = 0.0f;
 | 
				
			||||||
				sc->N = N;
 | 
									sc->N = N;
 | 
				
			||||||
				sd->flag |= bsdf_translucent_setup(sc);
 | 
									sd->flag |= bsdf_translucent_setup(sc);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -147,6 +159,8 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
 | 
				
			|||||||
			ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
 | 
								ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(sc) {
 | 
								if(sc) {
 | 
				
			||||||
 | 
									sc->data0 = 0.0f;
 | 
				
			||||||
 | 
									sc->data1 = 0.0f;
 | 
				
			||||||
				sc->N = N;
 | 
									sc->N = N;
 | 
				
			||||||
				sd->flag |= bsdf_transparent_setup(sc);
 | 
									sd->flag |= bsdf_transparent_setup(sc);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -164,6 +178,7 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
 | 
				
			|||||||
			if(sc) {
 | 
								if(sc) {
 | 
				
			||||||
				sc->N = N;
 | 
									sc->N = N;
 | 
				
			||||||
				sc->data0 = param1;
 | 
									sc->data0 = param1;
 | 
				
			||||||
 | 
									sc->data1 = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				/* setup bsdf */
 | 
									/* setup bsdf */
 | 
				
			||||||
				if(type == CLOSURE_BSDF_REFLECTION_ID)
 | 
									if(type == CLOSURE_BSDF_REFLECTION_ID)
 | 
				
			||||||
@@ -302,10 +317,73 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				/* sigma */
 | 
									/* sigma */
 | 
				
			||||||
				sc->data0 = clamp(param1, 0.0f, 1.0f);
 | 
									sc->data0 = clamp(param1, 0.0f, 1.0f);
 | 
				
			||||||
 | 
									sc->data1 = 0.0f;
 | 
				
			||||||
				sd->flag |= bsdf_ashikhmin_velvet_setup(sc);
 | 
									sd->flag |= bsdf_ashikhmin_velvet_setup(sc);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					#ifdef __SUBSURFACE__
 | 
				
			||||||
 | 
							case CLOSURE_BSSRDF_ID: {
 | 
				
			||||||
 | 
								ShaderClosure *sc = &sd->closure[sd->num_closure];
 | 
				
			||||||
 | 
								float3 weight = sc->weight * mix_weight;
 | 
				
			||||||
 | 
								float sample_weight = fabsf(average(weight));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(sample_weight > 1e-5f && sd->num_closure+2 < MAX_CLOSURE) {
 | 
				
			||||||
 | 
									/* radius * scale */
 | 
				
			||||||
 | 
									float3 radius = stack_load_float3(stack, data_node.w)*param1;
 | 
				
			||||||
 | 
									/* index of refraction */
 | 
				
			||||||
 | 
									float eta = fmaxf(param2, 1.0f + 1e-5f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* create one closure per color channel */
 | 
				
			||||||
 | 
									if(fabsf(weight.x) > 0.0f) {
 | 
				
			||||||
 | 
										sc->weight = make_float3(weight.x, 0.0f, 0.0f);
 | 
				
			||||||
 | 
										sc->sample_weight = sample_weight;
 | 
				
			||||||
 | 
										sc->data0 = radius.x;
 | 
				
			||||||
 | 
										sc->data1 = eta;
 | 
				
			||||||
 | 
					#ifdef __OSL__
 | 
				
			||||||
 | 
										sc->prim = NULL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
										sc->N = N;
 | 
				
			||||||
 | 
										sd->flag |= bssrdf_setup(sc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										sd->num_closure++;
 | 
				
			||||||
 | 
										sc++;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(fabsf(weight.y) > 0.0f) {
 | 
				
			||||||
 | 
										sc->weight = make_float3(0.0f, weight.y, 0.0f);
 | 
				
			||||||
 | 
										sc->sample_weight = sample_weight;
 | 
				
			||||||
 | 
										sc->data0 = radius.y;
 | 
				
			||||||
 | 
										sc->data1 = eta;
 | 
				
			||||||
 | 
					#ifdef __OSL__
 | 
				
			||||||
 | 
										sc->prim = NULL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
										sc->N = N;
 | 
				
			||||||
 | 
										sd->flag |= bssrdf_setup(sc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										sd->num_closure++;
 | 
				
			||||||
 | 
										sc++;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(fabsf(weight.z) > 0.0f) {
 | 
				
			||||||
 | 
										sc->weight = make_float3(0.0f, 0.0f, weight.z);
 | 
				
			||||||
 | 
										sc->sample_weight = sample_weight;
 | 
				
			||||||
 | 
										sc->data0 = radius.z;
 | 
				
			||||||
 | 
										sc->data1 = eta;
 | 
				
			||||||
 | 
					#ifdef __OSL__
 | 
				
			||||||
 | 
										sc->prim = NULL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
										sc->N = N;
 | 
				
			||||||
 | 
										sd->flag |= bssrdf_setup(sc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										sd->num_closure++;
 | 
				
			||||||
 | 
										sc++;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -346,12 +346,11 @@ typedef enum ClosureType {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	CLOSURE_BSDF_TRANSPARENT_ID,
 | 
						CLOSURE_BSDF_TRANSPARENT_ID,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CLOSURE_BSSRDF_CUBIC_ID,
 | 
						CLOSURE_BSSRDF_ID,
 | 
				
			||||||
	CLOSURE_EMISSION_ID,
 | 
						CLOSURE_EMISSION_ID,
 | 
				
			||||||
	CLOSURE_DEBUG_ID,
 | 
						CLOSURE_DEBUG_ID,
 | 
				
			||||||
	CLOSURE_BACKGROUND_ID,
 | 
						CLOSURE_BACKGROUND_ID,
 | 
				
			||||||
	CLOSURE_HOLDOUT_ID,
 | 
						CLOSURE_HOLDOUT_ID,
 | 
				
			||||||
	CLOSURE_SUBSURFACE_ID,
 | 
					 | 
				
			||||||
	CLOSURE_AMBIENT_OCCLUSION_ID,
 | 
						CLOSURE_AMBIENT_OCCLUSION_ID,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CLOSURE_VOLUME_ID,
 | 
						CLOSURE_VOLUME_ID,
 | 
				
			||||||
@@ -366,6 +365,7 @@ typedef enum ClosureType {
 | 
				
			|||||||
#define CLOSURE_IS_BSDF_DIFFUSE(type) (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_OREN_NAYAR_ID)
 | 
					#define CLOSURE_IS_BSDF_DIFFUSE(type) (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_OREN_NAYAR_ID)
 | 
				
			||||||
#define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_GLOSSY_ID && type <= CLOSURE_BSDF_PHONG_RAMP_ID)
 | 
					#define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_GLOSSY_ID && type <= CLOSURE_BSDF_PHONG_RAMP_ID)
 | 
				
			||||||
#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID)
 | 
					#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID)
 | 
				
			||||||
 | 
					#define CLOSURE_IS_BSSRDF(type) (type == CLOSURE_BSSRDF_ID)
 | 
				
			||||||
#define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_ISOTROPIC_ID)
 | 
					#define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_ISOTROPIC_ID)
 | 
				
			||||||
#define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID)
 | 
					#define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID)
 | 
				
			||||||
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
 | 
					#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,10 +17,10 @@ set(SRC
 | 
				
			|||||||
	attribute.cpp
 | 
						attribute.cpp
 | 
				
			||||||
	background.cpp
 | 
						background.cpp
 | 
				
			||||||
	buffers.cpp
 | 
						buffers.cpp
 | 
				
			||||||
 | 
						bssrdf.cpp
 | 
				
			||||||
	camera.cpp
 | 
						camera.cpp
 | 
				
			||||||
	film.cpp
 | 
						film.cpp
 | 
				
			||||||
	# film_response.cpp (code unused)
 | 
						# film_response.cpp (code unused)
 | 
				
			||||||
	filter.cpp
 | 
					 | 
				
			||||||
	graph.cpp
 | 
						graph.cpp
 | 
				
			||||||
	image.cpp
 | 
						image.cpp
 | 
				
			||||||
	integrator.cpp
 | 
						integrator.cpp
 | 
				
			||||||
@@ -37,6 +37,7 @@ set(SRC
 | 
				
			|||||||
	shader.cpp
 | 
						shader.cpp
 | 
				
			||||||
	sobol.cpp
 | 
						sobol.cpp
 | 
				
			||||||
	svm.cpp
 | 
						svm.cpp
 | 
				
			||||||
 | 
						tables.cpp
 | 
				
			||||||
	tile.cpp
 | 
						tile.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,10 +45,10 @@ set(SRC_HEADERS
 | 
				
			|||||||
	attribute.h
 | 
						attribute.h
 | 
				
			||||||
	background.h
 | 
						background.h
 | 
				
			||||||
	buffers.h
 | 
						buffers.h
 | 
				
			||||||
 | 
						bssrdf.h
 | 
				
			||||||
	camera.h
 | 
						camera.h
 | 
				
			||||||
	film.h
 | 
						film.h
 | 
				
			||||||
	# film_response.h (code unused)
 | 
						# film_response.h (code unused)
 | 
				
			||||||
	filter.h
 | 
					 | 
				
			||||||
	graph.h
 | 
						graph.h
 | 
				
			||||||
	image.h
 | 
						image.h
 | 
				
			||||||
	integrator.h
 | 
						integrator.h
 | 
				
			||||||
@@ -63,6 +64,7 @@ set(SRC_HEADERS
 | 
				
			|||||||
	shader.h
 | 
						shader.h
 | 
				
			||||||
	sobol.h
 | 
						sobol.h
 | 
				
			||||||
	svm.h
 | 
						svm.h
 | 
				
			||||||
 | 
						tables.h
 | 
				
			||||||
	tile.h
 | 
						tile.h
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										141
									
								
								intern/cycles/render/bssrdf.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								intern/cycles/render/bssrdf.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2011, 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "bssrdf.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "util_algorithm.h"
 | 
				
			||||||
 | 
					#include "util_math.h"
 | 
				
			||||||
 | 
					#include "util_types.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "kernel_types.h"
 | 
				
			||||||
 | 
					#include "kernel_montecarlo.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "closure/bsdf_diffuse.h"
 | 
				
			||||||
 | 
					#include "closure/bssrdf.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Cumulative density function utilities */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static float cdf_lookup_inverse(const vector<float>& table, float2 range, float x)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int index = upper_bound(table.begin(), table.end(), x) - table.begin();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(index == 0)
 | 
				
			||||||
 | 
							return range[0];
 | 
				
			||||||
 | 
						else if(index == table.size())
 | 
				
			||||||
 | 
							return range[1];
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							index--;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						float t = (x - table[index])/(table[index+1] - table[index]);
 | 
				
			||||||
 | 
						float y = ((index + t)/(table.size() - 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return y*(range[1] - range[0]) + range[0];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cdf_invert(vector<float>& to, float2 to_range, const vector<float>& from, float2 from_range)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						float step = 1.0f/(float)(to.size() - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(int i = 0; i < to.size(); i++) {
 | 
				
			||||||
 | 
							float x = (i*step)*(from_range[1] - from_range[0]) + from_range[0];
 | 
				
			||||||
 | 
							to[i] = cdf_lookup_inverse(from, to_range, x);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* BSSRDF */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static float bssrdf_lookup_table_max_radius(const BSSRDFParams *ss)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* todo: adjust when we use the real BSSRDF */
 | 
				
			||||||
 | 
						return ss->ld;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void bssrdf_lookup_table_create(const BSSRDFParams *ss, vector<float>& sample_table, vector<float>& pdf_table)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const int size = BSSRDF_RADIUS_TABLE_SIZE;
 | 
				
			||||||
 | 
						vector<float> cdf(size);
 | 
				
			||||||
 | 
						vector<float> pdf(size);
 | 
				
			||||||
 | 
						float step = 1.0f/(float)(size - 1);
 | 
				
			||||||
 | 
						float max_radius = bssrdf_lookup_table_max_radius(ss);
 | 
				
			||||||
 | 
						float pdf_sum = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* compute the probability density function */
 | 
				
			||||||
 | 
						for(int i = 0; i < pdf.size(); i++) {
 | 
				
			||||||
 | 
							float x = (i*step)*max_radius;
 | 
				
			||||||
 | 
							pdf[i] = bssrdf_cubic(ss->ld, x);
 | 
				
			||||||
 | 
							pdf_sum += pdf[i];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* adjust for area covered by each distance */
 | 
				
			||||||
 | 
						for(int i = 0; i < pdf.size(); i++) {
 | 
				
			||||||
 | 
							float x = (i*step)*max_radius;
 | 
				
			||||||
 | 
							pdf[i] *= 2*M_PI_F*x;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* normalize pdf, we multiply in reflectance later */
 | 
				
			||||||
 | 
						if(pdf_sum > 0.0f)
 | 
				
			||||||
 | 
							for(int i = 0; i < pdf.size(); i++)
 | 
				
			||||||
 | 
								pdf[i] /= pdf_sum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* sum to account for sampling which uses overlapping sphere */
 | 
				
			||||||
 | 
						for(int i = pdf.size() - 2; i >= 0; i--)
 | 
				
			||||||
 | 
							pdf[i] = pdf[i] + pdf[i+1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* compute the cumulative density function */
 | 
				
			||||||
 | 
						cdf[0] = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(int i = 1; i < size; i++)
 | 
				
			||||||
 | 
							cdf[i] = cdf[i-1] + 0.5f*(pdf[i-1] + pdf[i])*step*max_radius;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/* invert cumulative density function for importance sampling */
 | 
				
			||||||
 | 
						float2 cdf_range = make_float2(0.0f, cdf[size - 1]);
 | 
				
			||||||
 | 
						float2 table_range = make_float2(0.0f, max_radius);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cdf_invert(sample_table, table_range, cdf, cdf_range);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* copy pdf table */
 | 
				
			||||||
 | 
						for(int i = 0; i < pdf.size(); i++)
 | 
				
			||||||
 | 
							pdf_table[i] = pdf[i];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void bssrdf_table_build(vector<float>& table)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						vector<float> sample_table(BSSRDF_RADIUS_TABLE_SIZE);
 | 
				
			||||||
 | 
						vector<float> pdf_table(BSSRDF_RADIUS_TABLE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						table.resize(BSSRDF_LOOKUP_TABLE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* create a 2D lookup table, for reflection x sample radius */
 | 
				
			||||||
 | 
						for(int i = 0; i < BSSRDF_REFL_TABLE_SIZE; i++) {
 | 
				
			||||||
 | 
							float refl = (float)i/(float)(BSSRDF_REFL_TABLE_SIZE-1);
 | 
				
			||||||
 | 
							float ior = 1.3f;
 | 
				
			||||||
 | 
							float radius = 1.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							BSSRDFParams ss;
 | 
				
			||||||
 | 
							bssrdf_setup_params(&ss, refl, radius, ior);
 | 
				
			||||||
 | 
							bssrdf_lookup_table_create(&ss, sample_table, pdf_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memcpy(&table[i*BSSRDF_RADIUS_TABLE_SIZE], &sample_table[0], BSSRDF_RADIUS_TABLE_SIZE*sizeof(float));
 | 
				
			||||||
 | 
							memcpy(&table[BSSRDF_PDF_TABLE_OFFSET + i*BSSRDF_RADIUS_TABLE_SIZE], &pdf_table[0], BSSRDF_RADIUS_TABLE_SIZE*sizeof(float));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										31
									
								
								intern/cycles/render/bssrdf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								intern/cycles/render/bssrdf.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2011, 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __BSSRDF_H__
 | 
				
			||||||
 | 
					#define __BSSRDF_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "util_vector.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void bssrdf_table_build(vector<float>& table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __BSSRDF_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -22,9 +22,12 @@
 | 
				
			|||||||
#include "integrator.h"
 | 
					#include "integrator.h"
 | 
				
			||||||
#include "mesh.h"
 | 
					#include "mesh.h"
 | 
				
			||||||
#include "scene.h"
 | 
					#include "scene.h"
 | 
				
			||||||
 | 
					#include "tables.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "util_algorithm.h"
 | 
					#include "util_algorithm.h"
 | 
				
			||||||
 | 
					#include "util_debug.h"
 | 
				
			||||||
#include "util_foreach.h"
 | 
					#include "util_foreach.h"
 | 
				
			||||||
 | 
					#include "util_math.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CCL_NAMESPACE_BEGIN
 | 
					CCL_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -171,12 +174,84 @@ bool Pass::contains(const vector<Pass>& passes, PassType type)
 | 
				
			|||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Pixel Filter */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static float filter_func_box(float v, float width)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (float)1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static float filter_func_gaussian(float v, float width)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						v *= (float)2/width;
 | 
				
			||||||
 | 
						return (float)expf((float)-2*v*v);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static vector<float> filter_table(FilterType type, float width)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const int filter_table_size = FILTER_TABLE_SIZE-1;
 | 
				
			||||||
 | 
						vector<float> filter_table_cdf(filter_table_size+1);
 | 
				
			||||||
 | 
						vector<float> filter_table(filter_table_size+1);
 | 
				
			||||||
 | 
						float (*filter_func)(float, float) = NULL;
 | 
				
			||||||
 | 
						int i, half_size = filter_table_size/2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch(type) {
 | 
				
			||||||
 | 
							case FILTER_BOX:
 | 
				
			||||||
 | 
								filter_func = filter_func_box;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case FILTER_GAUSSIAN:
 | 
				
			||||||
 | 
								filter_func = filter_func_gaussian;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								assert(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* compute cumulative distribution function */
 | 
				
			||||||
 | 
						filter_table_cdf[0] = 0.0f;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						for(i = 0; i < filter_table_size; i++) {
 | 
				
			||||||
 | 
							float x = i*width*0.5f/(filter_table_size-1);
 | 
				
			||||||
 | 
							float y = filter_func(x, width);
 | 
				
			||||||
 | 
							filter_table_cdf[i+1] += filter_table_cdf[i] + fabsf(y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(i = 0; i <= filter_table_size; i++)
 | 
				
			||||||
 | 
							filter_table_cdf[i] /= filter_table_cdf[filter_table_size];
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/* create importance sampling table */
 | 
				
			||||||
 | 
						for(i = 0; i <= half_size; i++) {
 | 
				
			||||||
 | 
							float x = i/(float)half_size;
 | 
				
			||||||
 | 
							int index = upper_bound(filter_table_cdf.begin(), filter_table_cdf.end(), x) - filter_table_cdf.begin();
 | 
				
			||||||
 | 
							float t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(index < filter_table_size+1) {
 | 
				
			||||||
 | 
								t = (x - filter_table_cdf[index])/(filter_table_cdf[index+1] - filter_table_cdf[index]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								t = 0.0f;
 | 
				
			||||||
 | 
								index = filter_table_size;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							float y = ((index + t)/(filter_table_size))*width;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							filter_table[half_size+i] = 0.5f*(1.0f + y);
 | 
				
			||||||
 | 
							filter_table[half_size-i] = 0.5f*(1.0f - y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return filter_table;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Film */
 | 
					/* Film */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Film::Film()
 | 
					Film::Film()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	exposure = 0.8f;
 | 
						exposure = 0.8f;
 | 
				
			||||||
	Pass::add(PASS_COMBINED, passes);
 | 
						Pass::add(PASS_COMBINED, passes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						filter_type = FILTER_BOX;
 | 
				
			||||||
 | 
						filter_width = 1.0f;
 | 
				
			||||||
 | 
						filter_table_offset = TABLE_OFFSET_INVALID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	need_update = true;
 | 
						need_update = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -184,10 +259,12 @@ Film::~Film()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Film::device_update(Device *device, DeviceScene *dscene)
 | 
					void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if(!need_update)
 | 
						if(!need_update)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						device_free(device, dscene, scene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	KernelFilm *kfilm = &dscene->data.film;
 | 
						KernelFilm *kfilm = &dscene->data.film;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -284,17 +361,28 @@ void Film::device_update(Device *device, DeviceScene *dscene)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	kfilm->pass_stride = align_up(kfilm->pass_stride, 4);
 | 
						kfilm->pass_stride = align_up(kfilm->pass_stride, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* update filter table */
 | 
				
			||||||
 | 
						vector<float> table = filter_table(filter_type, filter_width);
 | 
				
			||||||
 | 
						filter_table_offset = scene->lookup_tables->add_table(dscene, table);
 | 
				
			||||||
 | 
						kfilm->filter_table_offset = (int)filter_table_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	need_update = false;
 | 
						need_update = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Film::device_free(Device *device, DeviceScene *dscene)
 | 
					void Film::device_free(Device *device, DeviceScene *dscene, Scene *scene)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if(filter_table_offset != TABLE_OFFSET_INVALID) {
 | 
				
			||||||
 | 
							scene->lookup_tables->remove_table(filter_table_offset);
 | 
				
			||||||
 | 
							filter_table_offset = TABLE_OFFSET_INVALID;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool Film::modified(const Film& film)
 | 
					bool Film::modified(const Film& film)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return !(exposure == film.exposure
 | 
						return !(exposure == film.exposure
 | 
				
			||||||
		&& Pass::equals(passes, film.passes));
 | 
							&& Pass::equals(passes, film.passes)
 | 
				
			||||||
 | 
							&& filter_type == film.filter_type
 | 
				
			||||||
 | 
							&& filter_width == film.filter_width);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Film::tag_passes_update(Scene *scene, const vector<Pass>& passes_)
 | 
					void Film::tag_passes_update(Scene *scene, const vector<Pass>& passes_)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,11 @@ class Device;
 | 
				
			|||||||
class DeviceScene;
 | 
					class DeviceScene;
 | 
				
			||||||
class Scene;
 | 
					class Scene;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum FilterType {
 | 
				
			||||||
 | 
						FILTER_BOX,
 | 
				
			||||||
 | 
						FILTER_GAUSSIAN
 | 
				
			||||||
 | 
					} FilterType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Pass {
 | 
					class Pass {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	PassType type;
 | 
						PassType type;
 | 
				
			||||||
@@ -47,13 +52,18 @@ class Film {
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
	float exposure;
 | 
						float exposure;
 | 
				
			||||||
	vector<Pass> passes;
 | 
						vector<Pass> passes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FilterType filter_type;
 | 
				
			||||||
 | 
						float filter_width;
 | 
				
			||||||
 | 
						size_t filter_table_offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool need_update;
 | 
						bool need_update;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Film();
 | 
						Film();
 | 
				
			||||||
	~Film();
 | 
						~Film();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void device_update(Device *device, DeviceScene *dscene);
 | 
						void device_update(Device *device, DeviceScene *dscene, Scene *scene);
 | 
				
			||||||
	void device_free(Device *device, DeviceScene *dscene);
 | 
						void device_free(Device *device, DeviceScene *dscene, Scene *scene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool modified(const Film& film);
 | 
						bool modified(const Film& film);
 | 
				
			||||||
	void tag_passes_update(Scene *scene, const vector<Pass>& passes_);
 | 
						void tag_passes_update(Scene *scene, const vector<Pass>& passes_);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,142 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright 2011, 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.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "camera.h"
 | 
					 | 
				
			||||||
#include "device.h"
 | 
					 | 
				
			||||||
#include "filter.h"
 | 
					 | 
				
			||||||
#include "scene.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "kernel_types.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "util_algorithm.h"
 | 
					 | 
				
			||||||
#include "util_debug.h"
 | 
					 | 
				
			||||||
#include "util_math.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CCL_NAMESPACE_BEGIN
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Filter::Filter()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	filter_type = FILTER_BOX;
 | 
					 | 
				
			||||||
	filter_width = 1.0f;
 | 
					 | 
				
			||||||
	need_update = true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Filter::~Filter()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static float filter_func_box(float v, float width)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return (float)1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static float filter_func_gaussian(float v, float width)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	v *= (float)2/width;
 | 
					 | 
				
			||||||
	return (float)expf((float)-2*v*v);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static vector<float> filter_table(FilterType type, float width)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const int filter_table_size = FILTER_TABLE_SIZE-1;
 | 
					 | 
				
			||||||
	vector<float> filter_table_cdf(filter_table_size+1);
 | 
					 | 
				
			||||||
	vector<float> filter_table(filter_table_size+1);
 | 
					 | 
				
			||||||
	float (*filter_func)(float, float) = NULL;
 | 
					 | 
				
			||||||
	int i, half_size = filter_table_size/2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch(type) {
 | 
					 | 
				
			||||||
		case FILTER_BOX:
 | 
					 | 
				
			||||||
			filter_func = filter_func_box;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case FILTER_GAUSSIAN:
 | 
					 | 
				
			||||||
			filter_func = filter_func_gaussian;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			assert(0);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* compute cumulative distribution function */
 | 
					 | 
				
			||||||
	filter_table_cdf[0] = 0.0f;
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	for(i = 0; i < filter_table_size; i++) {
 | 
					 | 
				
			||||||
		float x = i*width*0.5f/(filter_table_size-1);
 | 
					 | 
				
			||||||
		float y = filter_func(x, width);
 | 
					 | 
				
			||||||
		filter_table_cdf[i+1] += filter_table_cdf[i] + fabsf(y);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for(i = 0; i <= filter_table_size; i++)
 | 
					 | 
				
			||||||
		filter_table_cdf[i] /= filter_table_cdf[filter_table_size];
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	/* create importance sampling table */
 | 
					 | 
				
			||||||
	for(i = 0; i <= half_size; i++) {
 | 
					 | 
				
			||||||
		float x = i/(float)half_size;
 | 
					 | 
				
			||||||
		int index = upper_bound(filter_table_cdf.begin(), filter_table_cdf.end(), x) - filter_table_cdf.begin();
 | 
					 | 
				
			||||||
		float t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if(index < filter_table_size+1) {
 | 
					 | 
				
			||||||
			t = (x - filter_table_cdf[index])/(filter_table_cdf[index+1] - filter_table_cdf[index]);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		else {
 | 
					 | 
				
			||||||
			t = 0.0f;
 | 
					 | 
				
			||||||
			index = filter_table_size;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		float y = ((index + t)/(filter_table_size))*width;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		filter_table[half_size+i] = 0.5f*(1.0f + y);
 | 
					 | 
				
			||||||
		filter_table[half_size-i] = 0.5f*(1.0f - y);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return filter_table;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Filter::device_update(Device *device, DeviceScene *dscene)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if(!need_update)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	device_free(device, dscene);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* update __filter_table */
 | 
					 | 
				
			||||||
	vector<float> table = filter_table(filter_type, filter_width);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dscene->filter_table.copy(&table[0], table.size());
 | 
					 | 
				
			||||||
	device->tex_alloc("__filter_table", dscene->filter_table, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	need_update = false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Filter::device_free(Device *device, DeviceScene *dscene)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	device->tex_free(dscene->filter_table);
 | 
					 | 
				
			||||||
	dscene->filter_table.clear();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool Filter::modified(const Filter& filter)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return !(filter_type == filter.filter_type &&
 | 
					 | 
				
			||||||
		filter_width == filter.filter_width);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Filter::tag_update(Scene *scene)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	need_update = true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CCL_NAMESPACE_END
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -187,6 +187,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	virtual bool has_surface_emission() { return false; }
 | 
						virtual bool has_surface_emission() { return false; }
 | 
				
			||||||
	virtual bool has_surface_transparent() { return false; }
 | 
						virtual bool has_surface_transparent() { return false; }
 | 
				
			||||||
 | 
						virtual bool has_surface_bssrdf() { return false; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vector<ShaderInput*> inputs;
 | 
						vector<ShaderInput*> inputs;
 | 
				
			||||||
	vector<ShaderOutput*> outputs;
 | 
						vector<ShaderOutput*> outputs;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,6 +54,7 @@ Integrator::Integrator()
 | 
				
			|||||||
	transmission_samples = 1;
 | 
						transmission_samples = 1;
 | 
				
			||||||
	ao_samples = 1;
 | 
						ao_samples = 1;
 | 
				
			||||||
	mesh_light_samples = 1;
 | 
						mesh_light_samples = 1;
 | 
				
			||||||
 | 
						subsurface_samples = 1;
 | 
				
			||||||
	progressive = true;
 | 
						progressive = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	need_update = true;
 | 
						need_update = true;
 | 
				
			||||||
@@ -108,6 +109,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
 | 
				
			|||||||
	kintegrator->transmission_samples = transmission_samples;
 | 
						kintegrator->transmission_samples = transmission_samples;
 | 
				
			||||||
	kintegrator->ao_samples = ao_samples;
 | 
						kintegrator->ao_samples = ao_samples;
 | 
				
			||||||
	kintegrator->mesh_light_samples = mesh_light_samples;
 | 
						kintegrator->mesh_light_samples = mesh_light_samples;
 | 
				
			||||||
 | 
						kintegrator->subsurface_samples = subsurface_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* sobol directions table */
 | 
						/* sobol directions table */
 | 
				
			||||||
	int max_samples = 1;
 | 
						int max_samples = 1;
 | 
				
			||||||
@@ -163,6 +165,7 @@ bool Integrator::modified(const Integrator& integrator)
 | 
				
			|||||||
		transmission_samples == integrator.transmission_samples &&
 | 
							transmission_samples == integrator.transmission_samples &&
 | 
				
			||||||
		ao_samples == integrator.ao_samples &&
 | 
							ao_samples == integrator.ao_samples &&
 | 
				
			||||||
		mesh_light_samples == integrator.mesh_light_samples &&
 | 
							mesh_light_samples == integrator.mesh_light_samples &&
 | 
				
			||||||
 | 
							subsurface_samples == integrator.subsurface_samples &&
 | 
				
			||||||
		motion_blur == integrator.motion_blur);
 | 
							motion_blur == integrator.motion_blur);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,6 +54,7 @@ public:
 | 
				
			|||||||
	int transmission_samples;
 | 
						int transmission_samples;
 | 
				
			||||||
	int ao_samples;
 | 
						int ao_samples;
 | 
				
			||||||
	int mesh_light_samples;
 | 
						int mesh_light_samples;
 | 
				
			||||||
 | 
						int subsurface_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool progressive;
 | 
						bool progressive;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1262,16 +1262,19 @@ void ProxyNode::compile(OSLCompiler& compiler)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* BSDF Closure */
 | 
					/* BSDF Closure */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BsdfNode::BsdfNode()
 | 
					BsdfNode::BsdfNode(bool scattering_)
 | 
				
			||||||
: ShaderNode("bsdf")
 | 
					: ShaderNode("subsurface_scattering"), scattering(scattering_)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	closure = ccl::CLOSURE_BSDF_DIFFUSE_ID;
 | 
						closure = ccl::CLOSURE_BSSRDF_ID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
 | 
						add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
 | 
				
			||||||
	add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
 | 
						add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
 | 
				
			||||||
	add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
 | 
						add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	add_output("BSDF", SHADER_SOCKET_CLOSURE);
 | 
						if(scattering)
 | 
				
			||||||
 | 
							add_output("BSSRDF", SHADER_SOCKET_CLOSURE);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							add_output("BSDF", SHADER_SOCKET_CLOSURE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3)
 | 
					void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3)
 | 
				
			||||||
@@ -1313,7 +1316,8 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *
 | 
				
			|||||||
			(param3)? param3->stack_offset: SVM_STACK_INVALID);
 | 
								(param3)? param3->stack_offset: SVM_STACK_INVALID);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		compiler.add_node(NODE_CLOSURE_BSDF, normal_in->stack_offset);
 | 
							compiler.add_node(NODE_CLOSURE_BSDF, normal_in->stack_offset, SVM_STACK_INVALID,
 | 
				
			||||||
 | 
								(param3)? param3->stack_offset: SVM_STACK_INVALID);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1548,6 +1552,29 @@ void TransparentBsdfNode::compile(OSLCompiler& compiler)
 | 
				
			|||||||
	compiler.add(this, "node_transparent_bsdf");
 | 
						compiler.add(this, "node_transparent_bsdf");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Subsurface Scattering Closure */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SubsurfaceScatteringNode::SubsurfaceScatteringNode()
 | 
				
			||||||
 | 
					: BsdfNode(true)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						name = "subsurface_scattering";
 | 
				
			||||||
 | 
						closure = CLOSURE_BSSRDF_ID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						add_input("Scale", SHADER_SOCKET_FLOAT, 0.01f);
 | 
				
			||||||
 | 
						add_input("Radius", SHADER_SOCKET_VECTOR, make_float3(0.1f, 0.1f, 0.1f));
 | 
				
			||||||
 | 
						add_input("IOR", SHADER_SOCKET_FLOAT, 1.3f);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SubsurfaceScatteringNode::compile(SVMCompiler& compiler)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						BsdfNode::compile(compiler, input("Scale"), input("IOR"), input("Radius"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SubsurfaceScatteringNode::compile(OSLCompiler& compiler)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						compiler.add(this, "node_subsurface_scattering");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Emissive Closure */
 | 
					/* Emissive Closure */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EmissionNode::EmissionNode()
 | 
					EmissionNode::EmissionNode()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -198,11 +198,13 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class BsdfNode : public ShaderNode {
 | 
					class BsdfNode : public ShaderNode {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	SHADER_NODE_CLASS(BsdfNode)
 | 
						BsdfNode(bool scattering = false);
 | 
				
			||||||
 | 
						SHADER_NODE_BASE_CLASS(BsdfNode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL);
 | 
						void compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3 = NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ClosureType closure;
 | 
						ClosureType closure;
 | 
				
			||||||
 | 
						bool scattering;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class WardBsdfNode : public BsdfNode {
 | 
					class WardBsdfNode : public BsdfNode {
 | 
				
			||||||
@@ -257,6 +259,12 @@ public:
 | 
				
			|||||||
	static ShaderEnum distribution_enum;
 | 
						static ShaderEnum distribution_enum;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SubsurfaceScatteringNode : public BsdfNode {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						SHADER_NODE_CLASS(SubsurfaceScatteringNode)
 | 
				
			||||||
 | 
						bool has_surface_bssrdf() { return true; }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class EmissionNode : public ShaderNode {
 | 
					class EmissionNode : public ShaderNode {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	SHADER_NODE_CLASS(EmissionNode)
 | 
						SHADER_NODE_CLASS(EmissionNode)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,7 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
 | 
				
			|||||||
	if(!need_update)
 | 
						if(!need_update)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	device_free(device, dscene);
 | 
						device_free(device, dscene, scene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* determine which shaders are in use */
 | 
						/* determine which shaders are in use */
 | 
				
			||||||
	device_update_shaders_used(scene);
 | 
						device_update_shaders_used(scene);
 | 
				
			||||||
@@ -114,11 +114,11 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
 | 
				
			|||||||
	device_update_common(device, dscene, scene, progress);
 | 
						device_update_common(device, dscene, scene, progress);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OSLShaderManager::device_free(Device *device, DeviceScene *dscene)
 | 
					void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	OSLGlobals *og = (OSLGlobals*)device->osl_memory();
 | 
						OSLGlobals *og = (OSLGlobals*)device->osl_memory();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	device_free_common(device, dscene);
 | 
						device_free_common(device, dscene, scene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* clear shader engine */
 | 
						/* clear shader engine */
 | 
				
			||||||
	og->use = false;
 | 
						og->use = false;
 | 
				
			||||||
@@ -328,6 +328,7 @@ const char *OSLShaderManager::shader_load_bytecode(const string& hash, const str
 | 
				
			|||||||
	OSLShaderInfo info;
 | 
						OSLShaderInfo info;
 | 
				
			||||||
	info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
 | 
						info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
 | 
				
			||||||
	info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
 | 
						info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
 | 
				
			||||||
 | 
						info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos);
 | 
				
			||||||
	loaded_shaders[hash] = info;
 | 
						loaded_shaders[hash] = info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return loaded_shaders.find(hash)->first.c_str();
 | 
						return loaded_shaders.find(hash)->first.c_str();
 | 
				
			||||||
@@ -511,6 +512,8 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
 | 
				
			|||||||
			current_shader->has_surface_emission = true;
 | 
								current_shader->has_surface_emission = true;
 | 
				
			||||||
		if(info->has_surface_transparent)
 | 
							if(info->has_surface_transparent)
 | 
				
			||||||
			current_shader->has_surface_transparent = true;
 | 
								current_shader->has_surface_transparent = true;
 | 
				
			||||||
 | 
							if(info->has_surface_bssrdf)
 | 
				
			||||||
 | 
								current_shader->has_surface_bssrdf = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -671,6 +674,8 @@ void OSLCompiler::generate_nodes(const set<ShaderNode*>& nodes)
 | 
				
			|||||||
						current_shader->has_surface_emission = true;
 | 
											current_shader->has_surface_emission = true;
 | 
				
			||||||
					if(node->has_surface_transparent())
 | 
										if(node->has_surface_transparent())
 | 
				
			||||||
						current_shader->has_surface_transparent = true;
 | 
											current_shader->has_surface_transparent = true;
 | 
				
			||||||
 | 
										if(node->has_surface_bssrdf())
 | 
				
			||||||
 | 
											current_shader->has_surface_bssrdf = true;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				else
 | 
									else
 | 
				
			||||||
					nodes_done = false;
 | 
										nodes_done = false;
 | 
				
			||||||
@@ -736,6 +741,7 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
 | 
				
			|||||||
		shader->has_surface = false;
 | 
							shader->has_surface = false;
 | 
				
			||||||
		shader->has_surface_emission = false;
 | 
							shader->has_surface_emission = false;
 | 
				
			||||||
		shader->has_surface_transparent = false;
 | 
							shader->has_surface_transparent = false;
 | 
				
			||||||
 | 
							shader->has_surface_bssrdf = false;
 | 
				
			||||||
		shader->has_volume = false;
 | 
							shader->has_volume = false;
 | 
				
			||||||
		shader->has_displacement = false;
 | 
							shader->has_displacement = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,11 +50,13 @@ class ShaderOutput;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct OSLShaderInfo {
 | 
					struct OSLShaderInfo {
 | 
				
			||||||
	OSLShaderInfo()
 | 
						OSLShaderInfo()
 | 
				
			||||||
	: has_surface_emission(false), has_surface_transparent(false)
 | 
						: has_surface_emission(false), has_surface_transparent(false),
 | 
				
			||||||
 | 
						  has_surface_bssrdf(false)
 | 
				
			||||||
	{}
 | 
						{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool has_surface_emission;
 | 
						bool has_surface_emission;
 | 
				
			||||||
	bool has_surface_transparent;
 | 
						bool has_surface_transparent;
 | 
				
			||||||
 | 
						bool has_surface_bssrdf;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Shader Manage */
 | 
					/* Shader Manage */
 | 
				
			||||||
@@ -69,7 +71,7 @@ public:
 | 
				
			|||||||
	bool use_osl() { return true; }
 | 
						bool use_osl() { return true; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
 | 
						void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
 | 
				
			||||||
	void device_free(Device *device, DeviceScene *dscene);
 | 
						void device_free(Device *device, DeviceScene *dscene, Scene *scene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* osl compile and query */
 | 
						/* osl compile and query */
 | 
				
			||||||
	static bool osl_compile(const string& inputfile, const string& outputfile);
 | 
						static bool osl_compile(const string& inputfile, const string& outputfile);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,19 +20,19 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "background.h"
 | 
					#include "background.h"
 | 
				
			||||||
#include "camera.h"
 | 
					#include "camera.h"
 | 
				
			||||||
 | 
					#include "curves.h"
 | 
				
			||||||
#include "device.h"
 | 
					#include "device.h"
 | 
				
			||||||
#include "film.h"
 | 
					#include "film.h"
 | 
				
			||||||
#include "filter.h"
 | 
					 | 
				
			||||||
#include "integrator.h"
 | 
					#include "integrator.h"
 | 
				
			||||||
#include "light.h"
 | 
					#include "light.h"
 | 
				
			||||||
#include "shader.h"
 | 
					 | 
				
			||||||
#include "mesh.h"
 | 
					#include "mesh.h"
 | 
				
			||||||
#include "object.h"
 | 
					#include "object.h"
 | 
				
			||||||
#include "particles.h"
 | 
					 | 
				
			||||||
#include "curves.h"
 | 
					 | 
				
			||||||
#include "scene.h"
 | 
					 | 
				
			||||||
#include "svm.h"
 | 
					 | 
				
			||||||
#include "osl.h"
 | 
					#include "osl.h"
 | 
				
			||||||
 | 
					#include "particles.h"
 | 
				
			||||||
 | 
					#include "scene.h"
 | 
				
			||||||
 | 
					#include "shader.h"
 | 
				
			||||||
 | 
					#include "svm.h"
 | 
				
			||||||
 | 
					#include "tables.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "util_foreach.h"
 | 
					#include "util_foreach.h"
 | 
				
			||||||
#include "util_progress.h"
 | 
					#include "util_progress.h"
 | 
				
			||||||
@@ -46,7 +46,7 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
 | 
				
			|||||||
	memset(&dscene.data, 0, sizeof(dscene.data));
 | 
						memset(&dscene.data, 0, sizeof(dscene.data));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	camera = new Camera();
 | 
						camera = new Camera();
 | 
				
			||||||
	filter = new Filter();
 | 
						lookup_tables = new LookupTables();
 | 
				
			||||||
	film = new Film();
 | 
						film = new Film();
 | 
				
			||||||
	background = new Background();
 | 
						background = new Background();
 | 
				
			||||||
	light_manager = new LightManager();
 | 
						light_manager = new LightManager();
 | 
				
			||||||
@@ -93,14 +93,13 @@ void Scene::free_memory(bool final)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if(device) {
 | 
						if(device) {
 | 
				
			||||||
		camera->device_free(device, &dscene);
 | 
							camera->device_free(device, &dscene);
 | 
				
			||||||
		filter->device_free(device, &dscene);
 | 
							film->device_free(device, &dscene, this);
 | 
				
			||||||
		film->device_free(device, &dscene);
 | 
					 | 
				
			||||||
		background->device_free(device, &dscene);
 | 
							background->device_free(device, &dscene);
 | 
				
			||||||
		integrator->device_free(device, &dscene);
 | 
							integrator->device_free(device, &dscene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		object_manager->device_free(device, &dscene);
 | 
							object_manager->device_free(device, &dscene);
 | 
				
			||||||
		mesh_manager->device_free(device, &dscene);
 | 
							mesh_manager->device_free(device, &dscene);
 | 
				
			||||||
		shader_manager->device_free(device, &dscene);
 | 
							shader_manager->device_free(device, &dscene, this);
 | 
				
			||||||
		light_manager->device_free(device, &dscene);
 | 
							light_manager->device_free(device, &dscene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		particle_system_manager->device_free(device, &dscene);
 | 
							particle_system_manager->device_free(device, &dscene);
 | 
				
			||||||
@@ -108,10 +107,12 @@ void Scene::free_memory(bool final)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if(!params.persistent_data || final)
 | 
							if(!params.persistent_data || final)
 | 
				
			||||||
			image_manager->device_free(device, &dscene);
 | 
								image_manager->device_free(device, &dscene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							lookup_tables->device_free(device, &dscene);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(final) {
 | 
						if(final) {
 | 
				
			||||||
		delete filter;
 | 
							delete lookup_tables;
 | 
				
			||||||
		delete camera;
 | 
							delete camera;
 | 
				
			||||||
		delete film;
 | 
							delete film;
 | 
				
			||||||
		delete background;
 | 
							delete background;
 | 
				
			||||||
@@ -188,13 +189,8 @@ void Scene::device_update(Device *device_, Progress& progress)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if(progress.get_cancel()) return;
 | 
						if(progress.get_cancel()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	progress.set_status("Updating Filter");
 | 
					 | 
				
			||||||
	filter->device_update(device, &dscene);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(progress.get_cancel()) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	progress.set_status("Updating Film");
 | 
						progress.set_status("Updating Film");
 | 
				
			||||||
	film->device_update(device, &dscene);
 | 
						film->device_update(device, &dscene, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(progress.get_cancel()) return;
 | 
						if(progress.get_cancel()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -203,6 +199,11 @@ void Scene::device_update(Device *device_, Progress& progress)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if(progress.get_cancel()) return;
 | 
						if(progress.get_cancel()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						progress.set_status("Updating Lookup Tables");
 | 
				
			||||||
 | 
						lookup_tables->device_update(device, &dscene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(progress.get_cancel()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	progress.set_status("Updating Device", "Writing constant memory");
 | 
						progress.set_status("Updating Device", "Writing constant memory");
 | 
				
			||||||
	device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
 | 
						device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -247,7 +248,7 @@ bool Scene::need_reset()
 | 
				
			|||||||
		|| object_manager->need_update
 | 
							|| object_manager->need_update
 | 
				
			||||||
		|| mesh_manager->need_update
 | 
							|| mesh_manager->need_update
 | 
				
			||||||
		|| light_manager->need_update
 | 
							|| light_manager->need_update
 | 
				
			||||||
		|| filter->need_update
 | 
							|| lookup_tables->need_update
 | 
				
			||||||
		|| integrator->need_update
 | 
							|| integrator->need_update
 | 
				
			||||||
		|| shader_manager->need_update
 | 
							|| shader_manager->need_update
 | 
				
			||||||
		|| particle_system_manager->need_update
 | 
							|| particle_system_manager->need_update
 | 
				
			||||||
@@ -261,7 +262,6 @@ void Scene::reset()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* ensure all objects are updated */
 | 
						/* ensure all objects are updated */
 | 
				
			||||||
	camera->tag_update();
 | 
						camera->tag_update();
 | 
				
			||||||
	filter->tag_update(this);
 | 
					 | 
				
			||||||
	film->tag_update(this);
 | 
						film->tag_update(this);
 | 
				
			||||||
	background->tag_update(this);
 | 
						background->tag_update(this);
 | 
				
			||||||
	integrator->tag_update(this);
 | 
						integrator->tag_update(this);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,10 +39,10 @@ class Camera;
 | 
				
			|||||||
class Device;
 | 
					class Device;
 | 
				
			||||||
class DeviceInfo;
 | 
					class DeviceInfo;
 | 
				
			||||||
class Film;
 | 
					class Film;
 | 
				
			||||||
class Filter;
 | 
					 | 
				
			||||||
class Integrator;
 | 
					class Integrator;
 | 
				
			||||||
class Light;
 | 
					class Light;
 | 
				
			||||||
class LightManager;
 | 
					class LightManager;
 | 
				
			||||||
 | 
					class LookupTables;
 | 
				
			||||||
class Mesh;
 | 
					class Mesh;
 | 
				
			||||||
class MeshManager;
 | 
					class MeshManager;
 | 
				
			||||||
class Object;
 | 
					class Object;
 | 
				
			||||||
@@ -99,8 +99,8 @@ public:
 | 
				
			|||||||
	device_vector<uint> shader_flag;
 | 
						device_vector<uint> shader_flag;
 | 
				
			||||||
	device_vector<uint> object_flag;
 | 
						device_vector<uint> object_flag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* filter */
 | 
						/* lookup tables */
 | 
				
			||||||
	device_vector<float> filter_table;
 | 
						device_vector<float> lookup_table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* integrator */
 | 
						/* integrator */
 | 
				
			||||||
	device_vector<uint> sobol_directions;
 | 
						device_vector<uint> sobol_directions;
 | 
				
			||||||
@@ -155,7 +155,7 @@ class Scene {
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
	/* data */
 | 
						/* data */
 | 
				
			||||||
	Camera *camera;
 | 
						Camera *camera;
 | 
				
			||||||
	Filter *filter;
 | 
						LookupTables *lookup_tables;
 | 
				
			||||||
	Film *film;
 | 
						Film *film;
 | 
				
			||||||
	Background *background;
 | 
						Background *background;
 | 
				
			||||||
	Integrator *integrator;
 | 
						Integrator *integrator;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@
 | 
				
			|||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
					 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "bssrdf.h"
 | 
				
			||||||
#include "device.h"
 | 
					#include "device.h"
 | 
				
			||||||
#include "graph.h"
 | 
					#include "graph.h"
 | 
				
			||||||
#include "light.h"
 | 
					#include "light.h"
 | 
				
			||||||
@@ -25,6 +26,7 @@
 | 
				
			|||||||
#include "scene.h"
 | 
					#include "scene.h"
 | 
				
			||||||
#include "shader.h"
 | 
					#include "shader.h"
 | 
				
			||||||
#include "svm.h"
 | 
					#include "svm.h"
 | 
				
			||||||
 | 
					#include "tables.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "util_foreach.h"
 | 
					#include "util_foreach.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,6 +48,7 @@ Shader::Shader()
 | 
				
			|||||||
	has_surface = false;
 | 
						has_surface = false;
 | 
				
			||||||
	has_surface_transparent = false;
 | 
						has_surface_transparent = false;
 | 
				
			||||||
	has_surface_emission = false;
 | 
						has_surface_emission = false;
 | 
				
			||||||
 | 
						has_surface_bssrdf = false;
 | 
				
			||||||
	has_volume = false;
 | 
						has_volume = false;
 | 
				
			||||||
	has_displacement = false;
 | 
						has_displacement = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -115,6 +118,7 @@ void Shader::tag_used(Scene *scene)
 | 
				
			|||||||
ShaderManager::ShaderManager()
 | 
					ShaderManager::ShaderManager()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	need_update = true;
 | 
						need_update = true;
 | 
				
			||||||
 | 
						bssrdf_table_offset = TABLE_OFFSET_INVALID;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ShaderManager::~ShaderManager()
 | 
					ShaderManager::~ShaderManager()
 | 
				
			||||||
@@ -196,7 +200,8 @@ void ShaderManager::device_update_shaders_used(Scene *scene)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
 | 
					void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	device_free_common(device, dscene);
 | 
						device->tex_free(dscene->shader_flag);
 | 
				
			||||||
 | 
						dscene->shader_flag.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(scene->shaders.size() == 0)
 | 
						if(scene->shaders.size() == 0)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@@ -204,6 +209,7 @@ void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Sc
 | 
				
			|||||||
	uint shader_flag_size = scene->shaders.size()*4;
 | 
						uint shader_flag_size = scene->shaders.size()*4;
 | 
				
			||||||
	uint *shader_flag = dscene->shader_flag.resize(shader_flag_size);
 | 
						uint *shader_flag = dscene->shader_flag.resize(shader_flag_size);
 | 
				
			||||||
	uint i = 0;
 | 
						uint i = 0;
 | 
				
			||||||
 | 
						bool has_surface_bssrdf = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach(Shader *shader, scene->shaders) {
 | 
						foreach(Shader *shader, scene->shaders) {
 | 
				
			||||||
		uint flag = 0;
 | 
							uint flag = 0;
 | 
				
			||||||
@@ -216,6 +222,8 @@ void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Sc
 | 
				
			|||||||
			flag |= SD_HAS_VOLUME;
 | 
								flag |= SD_HAS_VOLUME;
 | 
				
			||||||
		if(shader->homogeneous_volume)
 | 
							if(shader->homogeneous_volume)
 | 
				
			||||||
			flag |= SD_HOMOGENEOUS_VOLUME;
 | 
								flag |= SD_HOMOGENEOUS_VOLUME;
 | 
				
			||||||
 | 
							if(shader->has_surface_bssrdf)
 | 
				
			||||||
 | 
								has_surface_bssrdf = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		shader_flag[i++] = flag;
 | 
							shader_flag[i++] = flag;
 | 
				
			||||||
		shader_flag[i++] = shader->pass_id;
 | 
							shader_flag[i++] = shader->pass_id;
 | 
				
			||||||
@@ -224,10 +232,32 @@ void ShaderManager::device_update_common(Device *device, DeviceScene *dscene, Sc
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	device->tex_alloc("__shader_flag", dscene->shader_flag);
 | 
						device->tex_alloc("__shader_flag", dscene->shader_flag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* bssrdf lookup table */
 | 
				
			||||||
 | 
						KernelBSSRDF *kbssrdf = &dscene->data.bssrdf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(has_surface_bssrdf && bssrdf_table_offset == TABLE_OFFSET_INVALID) {
 | 
				
			||||||
 | 
							vector<float> table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bssrdf_table_build(table);
 | 
				
			||||||
 | 
							bssrdf_table_offset = scene->lookup_tables->add_table(dscene, table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							kbssrdf->table_offset = (int)bssrdf_table_offset;
 | 
				
			||||||
 | 
							kbssrdf->num_attempts = BSSRDF_MAX_ATTEMPTS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if(!has_surface_bssrdf && bssrdf_table_offset != TABLE_OFFSET_INVALID) {
 | 
				
			||||||
 | 
							scene->lookup_tables->remove_table(bssrdf_table_offset);
 | 
				
			||||||
 | 
							bssrdf_table_offset = TABLE_OFFSET_INVALID;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ShaderManager::device_free_common(Device *device, DeviceScene *dscene)
 | 
					void ShaderManager::device_free_common(Device *device, DeviceScene *dscene, Scene *scene)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if(bssrdf_table_offset != TABLE_OFFSET_INVALID) {
 | 
				
			||||||
 | 
							scene->lookup_tables->remove_table(bssrdf_table_offset);
 | 
				
			||||||
 | 
							bssrdf_table_offset = TABLE_OFFSET_INVALID;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	device->tex_free(dscene->shader_flag);
 | 
						device->tex_free(dscene->shader_flag);
 | 
				
			||||||
	dscene->shader_flag.clear();
 | 
						dscene->shader_flag.clear();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,6 +75,7 @@ public:
 | 
				
			|||||||
	bool has_surface_transparent;
 | 
						bool has_surface_transparent;
 | 
				
			||||||
	bool has_volume;
 | 
						bool has_volume;
 | 
				
			||||||
	bool has_displacement;
 | 
						bool has_displacement;
 | 
				
			||||||
 | 
						bool has_surface_bssrdf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* requested mesh attributes */
 | 
						/* requested mesh attributes */
 | 
				
			||||||
	AttributeRequestSet attributes;
 | 
						AttributeRequestSet attributes;
 | 
				
			||||||
@@ -116,11 +117,11 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* device update */
 | 
						/* device update */
 | 
				
			||||||
	virtual void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) = 0;
 | 
						virtual void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) = 0;
 | 
				
			||||||
	virtual void device_free(Device *device, DeviceScene *dscene) = 0;
 | 
						virtual void device_free(Device *device, DeviceScene *dscene, Scene *scene) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void device_update_shaders_used(Scene *scene);
 | 
						void device_update_shaders_used(Scene *scene);
 | 
				
			||||||
	void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
 | 
						void device_update_common(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
 | 
				
			||||||
	void device_free_common(Device *device, DeviceScene *dscene);
 | 
						void device_free_common(Device *device, DeviceScene *dscene, Scene *scene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* get globally unique id for a type of attribute */
 | 
						/* get globally unique id for a type of attribute */
 | 
				
			||||||
	uint get_attribute_id(ustring name);
 | 
						uint get_attribute_id(ustring name);
 | 
				
			||||||
@@ -138,6 +139,8 @@ protected:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap;
 | 
						typedef unordered_map<ustring, uint, ustringHash> AttributeIDMap;
 | 
				
			||||||
	AttributeIDMap unique_attribute_id;
 | 
						AttributeIDMap unique_attribute_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t bssrdf_table_offset;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CCL_NAMESPACE_END
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,7 +50,7 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* test if we need to update */
 | 
						/* test if we need to update */
 | 
				
			||||||
	device_free(device, dscene);
 | 
						device_free(device, dscene, scene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* determine which shaders are in use */
 | 
						/* determine which shaders are in use */
 | 
				
			||||||
	device_update_shaders_used(scene);
 | 
						device_update_shaders_used(scene);
 | 
				
			||||||
@@ -99,9 +99,9 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
 | 
				
			|||||||
	need_update = false;
 | 
						need_update = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SVMShaderManager::device_free(Device *device, DeviceScene *dscene)
 | 
					void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	device_free_common(device, dscene);
 | 
						device_free_common(device, dscene, scene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	device->tex_free(dscene->svm_nodes);
 | 
						device->tex_free(dscene->svm_nodes);
 | 
				
			||||||
	dscene->svm_nodes.clear();
 | 
						dscene->svm_nodes.clear();
 | 
				
			||||||
@@ -486,6 +486,8 @@ void SVMCompiler::generate_closure(ShaderNode *node, set<ShaderNode*>& done)
 | 
				
			|||||||
			current_shader->has_surface_emission = true;
 | 
								current_shader->has_surface_emission = true;
 | 
				
			||||||
		if(node->has_surface_transparent())
 | 
							if(node->has_surface_transparent())
 | 
				
			||||||
			current_shader->has_surface_transparent = true;
 | 
								current_shader->has_surface_transparent = true;
 | 
				
			||||||
 | 
							if(node->has_surface_bssrdf())
 | 
				
			||||||
 | 
								current_shader->has_surface_bssrdf = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* end node is added outside of this */
 | 
							/* end node is added outside of this */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -546,6 +548,8 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& don
 | 
				
			|||||||
			current_shader->has_surface_emission = true;
 | 
								current_shader->has_surface_emission = true;
 | 
				
			||||||
		if(node->has_surface_transparent())
 | 
							if(node->has_surface_transparent())
 | 
				
			||||||
			current_shader->has_surface_transparent = true;
 | 
								current_shader->has_surface_transparent = true;
 | 
				
			||||||
 | 
							if(node->has_surface_bssrdf())
 | 
				
			||||||
 | 
								current_shader->has_surface_bssrdf = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	done.insert(node);
 | 
						done.insert(node);
 | 
				
			||||||
@@ -654,6 +658,7 @@ void SVMCompiler::compile(Shader *shader, vector<int4>& global_svm_nodes, int in
 | 
				
			|||||||
	shader->has_surface = false;
 | 
						shader->has_surface = false;
 | 
				
			||||||
	shader->has_surface_emission = false;
 | 
						shader->has_surface_emission = false;
 | 
				
			||||||
	shader->has_surface_transparent = false;
 | 
						shader->has_surface_transparent = false;
 | 
				
			||||||
 | 
						shader->has_surface_bssrdf = false;
 | 
				
			||||||
	shader->has_volume = false;
 | 
						shader->has_volume = false;
 | 
				
			||||||
	shader->has_displacement = false;
 | 
						shader->has_displacement = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,7 +48,7 @@ public:
 | 
				
			|||||||
	void reset(Scene *scene);
 | 
						void reset(Scene *scene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
 | 
						void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
 | 
				
			||||||
	void device_free(Device *device, DeviceScene *dscene);
 | 
						void device_free(Device *device, DeviceScene *dscene, Scene *scene);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Graph Compiler */
 | 
					/* Graph Compiler */
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										110
									
								
								intern/cycles/render/tables.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								intern/cycles/render/tables.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2011, 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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "device.h"
 | 
				
			||||||
 | 
					#include "scene.h"
 | 
				
			||||||
 | 
					#include "tables.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "util_debug.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Lookup Tables */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LookupTables::LookupTables()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						need_update = true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LookupTables::~LookupTables()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						assert(lookup_tables.size() == 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LookupTables::device_update(Device *device, DeviceScene *dscene)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if(!need_update)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						device->tex_alloc("__lookup_table", dscene->lookup_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						need_update = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LookupTables::device_free(Device *device, DeviceScene *dscene)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						device->tex_free(dscene->lookup_table);
 | 
				
			||||||
 | 
						dscene->lookup_table.clear();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static size_t round_up_to_multiple(size_t size, size_t chunk)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ((size + chunk - 1)/chunk) * chunk;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t LookupTables::add_table(DeviceScene *dscene, vector<float>& data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						assert(data.size() > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						need_update = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Table new_table;
 | 
				
			||||||
 | 
						new_table.offset = 0;
 | 
				
			||||||
 | 
						new_table.size = round_up_to_multiple(data.size(), TABLE_CHUNK_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* find space to put lookup table */
 | 
				
			||||||
 | 
						list<Table>::iterator table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(table = lookup_tables.begin(); table != lookup_tables.end(); table++) {
 | 
				
			||||||
 | 
							if(new_table.offset + new_table.size <= table->offset) {
 | 
				
			||||||
 | 
								lookup_tables.insert(table, new_table);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								new_table.offset = table->offset + table->size;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(table == lookup_tables.end()) {
 | 
				
			||||||
 | 
							/* add at the end */
 | 
				
			||||||
 | 
							lookup_tables.push_back(new_table);
 | 
				
			||||||
 | 
							dscene->lookup_table.resize(new_table.offset + new_table.size);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* copy table data and return offset */
 | 
				
			||||||
 | 
						dscene->lookup_table.copy_at(&data[0], new_table.offset, data.size());
 | 
				
			||||||
 | 
						return new_table.offset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LookupTables::remove_table(size_t offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						need_update = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list<Table>::iterator table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(table = lookup_tables.begin(); table != lookup_tables.end(); table++) {
 | 
				
			||||||
 | 
							if(table->offset == offset) {
 | 
				
			||||||
 | 
								lookup_tables.erase(table);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert(table != lookup_tables.end());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -16,8 +16,10 @@
 | 
				
			|||||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
					 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef __FILTER_H__
 | 
					#ifndef __TABLES_H__
 | 
				
			||||||
#define __FILTER_H__
 | 
					#define __TABLES_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <util_list.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CCL_NAMESPACE_BEGIN
 | 
					CCL_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,29 +27,30 @@ class Device;
 | 
				
			|||||||
class DeviceScene;
 | 
					class DeviceScene;
 | 
				
			||||||
class Scene;
 | 
					class Scene;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum FilterType {
 | 
					enum { TABLE_CHUNK_SIZE = 256 };
 | 
				
			||||||
	FILTER_BOX,
 | 
					enum { TABLE_OFFSET_INVALID = -1 };
 | 
				
			||||||
	FILTER_GAUSSIAN
 | 
					 | 
				
			||||||
} FilterType;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Filter {
 | 
					class LookupTables {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	/* pixel filter */
 | 
						struct Table {
 | 
				
			||||||
	FilterType filter_type;
 | 
							size_t offset;
 | 
				
			||||||
	float filter_width;
 | 
							size_t size;
 | 
				
			||||||
	bool need_update;
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Filter();
 | 
						bool need_update;
 | 
				
			||||||
	~Filter();
 | 
						list<Table> lookup_tables;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LookupTables();
 | 
				
			||||||
 | 
						~LookupTables();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void device_update(Device *device, DeviceScene *dscene);
 | 
						void device_update(Device *device, DeviceScene *dscene);
 | 
				
			||||||
	void device_free(Device *device, DeviceScene *dscene);
 | 
						void device_free(Device *device, DeviceScene *dscene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool modified(const Filter& filter);
 | 
						size_t add_table(DeviceScene *dscene, vector<float>& data);
 | 
				
			||||||
	void tag_update(Scene *scene);
 | 
						void remove_table(size_t offset);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CCL_NAMESPACE_END
 | 
					CCL_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __FILTER_H__ */
 | 
					#endif /* __TABLES_H__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1151,14 +1151,7 @@ __device float safe_logf(float a, float b)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
__device float safe_divide(float a, float b)
 | 
					__device float safe_divide(float a, float b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	float result;
 | 
						return (b != 0.0f)? a/b: 0.0f;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(b == 0.0f)
 | 
					 | 
				
			||||||
		result = 0.0f;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		result = a/b;
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Ray Intersection */
 | 
					/* Ray Intersection */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -171,6 +171,20 @@ void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if ((LIBAVCODEC_VERSION_MAJOR < 54) || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR < 28))
 | 
				
			||||||
 | 
					static inline
 | 
				
			||||||
 | 
					void avcodec_free_frame(AVFrame **frame)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* don't need to do anything with old AVFrame
 | 
				
			||||||
 | 
						 * since it does not have malloced members */
 | 
				
			||||||
 | 
						(void)frame;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if ((LIBAVCODEC_VERSION_MAJOR > 54) || (LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 13))
 | 
				
			||||||
 | 
					#define FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef FFMPEG_HAVE_AVIO
 | 
					#ifndef FFMPEG_HAVE_AVIO
 | 
				
			||||||
#define AVIO_FLAG_WRITE URL_WRONLY
 | 
					#define AVIO_FLAG_WRITE URL_WRONLY
 | 
				
			||||||
#define avio_open url_fopen
 | 
					#define avio_open url_fopen
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -454,7 +454,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
 | 
				
			|||||||
	GHOST_TDrawingContextType type,
 | 
						GHOST_TDrawingContextType type,
 | 
				
			||||||
	const bool stereoVisual, const GHOST_TUns16 numOfAASamples
 | 
						const bool stereoVisual, const GHOST_TUns16 numOfAASamples
 | 
				
			||||||
) :
 | 
					) :
 | 
				
			||||||
	GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone, stereoVisual, numOfAASamples),
 | 
						GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone, stereoVisual, false, numOfAASamples),
 | 
				
			||||||
	m_customCursor(0)
 | 
						m_customCursor(0)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[40];
 | 
						NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[40];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,7 +53,7 @@ public:
 | 
				
			|||||||
	    const bool stereoVisual,
 | 
						    const bool stereoVisual,
 | 
				
			||||||
	    const GHOST_TUns16 numOfAASamples
 | 
						    const GHOST_TUns16 numOfAASamples
 | 
				
			||||||
	    ) :
 | 
						    ) :
 | 
				
			||||||
		GHOST_Window(width, height, state, type, stereoVisual, numOfAASamples),
 | 
							GHOST_Window(width, height, state, type, stereoVisual, false, numOfAASamples),
 | 
				
			||||||
		m_system(system)
 | 
							m_system(system)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		setTitle(title);
 | 
							setTitle(title);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -130,7 +130,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(
 | 
				
			|||||||
    int msPixelFormat)
 | 
					    int msPixelFormat)
 | 
				
			||||||
	:
 | 
						:
 | 
				
			||||||
	GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone,
 | 
						GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone,
 | 
				
			||||||
	             stereoVisual, numOfAASamples),
 | 
						             stereoVisual, false, numOfAASamples),
 | 
				
			||||||
	m_system(system),
 | 
						m_system(system),
 | 
				
			||||||
	m_hDC(0),
 | 
						m_hDC(0),
 | 
				
			||||||
	m_hGlRc(0),
 | 
						m_hGlRc(0),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,6 +44,7 @@ set(SRC
 | 
				
			|||||||
if(WITH_OPENCOLORIO)
 | 
					if(WITH_OPENCOLORIO)
 | 
				
			||||||
	add_definitions(
 | 
						add_definitions(
 | 
				
			||||||
		-DWITH_OCIO
 | 
							-DWITH_OCIO
 | 
				
			||||||
 | 
							-DGLEW_STATIC
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list(APPEND INC_SYS
 | 
						list(APPEND INC_SYS
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@ Import('env')
 | 
				
			|||||||
sources = env.Glob('*.cc')
 | 
					sources = env.Glob('*.cc')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
incs = '. ../guardedalloc ../../source/blender/blenlib'
 | 
					incs = '. ../guardedalloc ../../source/blender/blenlib'
 | 
				
			||||||
defs = []
 | 
					defs = [ 'GLEW_STATIC' ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if env['WITH_BF_OCIO']:
 | 
					if env['WITH_BF_OCIO']:
 | 
				
			||||||
    defs.append('WITH_OCIO')
 | 
					    defs.append('WITH_OCIO')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -381,8 +381,9 @@ void FallbackImpl::matrixTransformScale(float * , float * , const float *)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor)
 | 
					bool FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FallbackImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
 | 
					void FallbackImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -283,9 +283,9 @@ void OCIO_matrixTransformScale(float * m44, float * offset4, const float *scale4
 | 
				
			|||||||
	impl->matrixTransformScale(m44, offset4, scale4f);
 | 
						impl->matrixTransformScale(m44, offset4, scale4f);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor)
 | 
					int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, int predivide)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	impl->setupGLSLDraw(state_r, processor);
 | 
						return (int) impl->setupGLSLDraw(state_r, processor, (bool) predivide);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state)
 | 
					void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -121,7 +121,7 @@ void OCIO_matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void OCIO_matrixTransformScale(float * m44, float * offset4, const float * scale4);
 | 
					void OCIO_matrixTransformScale(float * m44, float * offset4, const float * scale4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor);
 | 
					int OCIO_setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, int predivide);
 | 
				
			||||||
void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state);
 | 
					void OCIO_finishGLSLDraw(struct OCIO_GLSLDrawState *state);
 | 
				
			||||||
void OCIO_freeOGLState(struct OCIO_GLSLDrawState *state);
 | 
					void OCIO_freeOGLState(struct OCIO_GLSLDrawState *state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -551,228 +551,3 @@ void OCIOImpl::matrixTransformScale(float * m44, float * offset4, const float *s
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	MatrixTransform::Scale(m44, offset4, scale4f);
 | 
						MatrixTransform::Scale(m44, offset4, scale4f);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
/* **** OpenGL drawing routines using GLSL for color space transform ***** */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Some of the GLSL transform related functions below are adopted from
 | 
					 | 
				
			||||||
 * ociodisplay utility of OpenColorIO project which are originally
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct OCIO_GLSLDrawState {
 | 
					 | 
				
			||||||
	bool lut3d_texture_allocated;  /* boolean flag indicating whether
 | 
					 | 
				
			||||||
									* lut texture is allocated
 | 
					 | 
				
			||||||
									*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	GLuint lut3d_texture;  /* OGL texture ID for 3D LUT */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	float *lut3d;  /* 3D LUT table */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Cache */
 | 
					 | 
				
			||||||
	std::string lut3dcacheid;
 | 
					 | 
				
			||||||
	std::string shadercacheid;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* GLSL stuff */
 | 
					 | 
				
			||||||
	GLuint fragShader;
 | 
					 | 
				
			||||||
	GLuint program;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Previous OpenGL state. */
 | 
					 | 
				
			||||||
	GLint last_texture, last_texture_unit;
 | 
					 | 
				
			||||||
} OCIO_GLSLDrawState;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const char * g_fragShaderText = ""
 | 
					 | 
				
			||||||
"\n"
 | 
					 | 
				
			||||||
"uniform sampler2D tex1;\n"
 | 
					 | 
				
			||||||
"uniform sampler3D tex2;\n"
 | 
					 | 
				
			||||||
"\n"
 | 
					 | 
				
			||||||
"void main()\n"
 | 
					 | 
				
			||||||
"{\n"
 | 
					 | 
				
			||||||
"    vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n"
 | 
					 | 
				
			||||||
"    gl_FragColor = OCIODisplay(col, tex2);\n"
 | 
					 | 
				
			||||||
"}\n";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GLuint compileShaderText(GLenum shaderType, const char *text)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	GLuint shader;
 | 
					 | 
				
			||||||
	GLint stat;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	shader = glCreateShader(shaderType);
 | 
					 | 
				
			||||||
	glShaderSource(shader, 1, (const GLchar **) &text, NULL);
 | 
					 | 
				
			||||||
	glCompileShader(shader);
 | 
					 | 
				
			||||||
	glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!stat) {
 | 
					 | 
				
			||||||
		GLchar log[1000];
 | 
					 | 
				
			||||||
		GLsizei len;
 | 
					 | 
				
			||||||
		glGetShaderInfoLog(shader, 1000, &len, log);
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return shader;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static GLuint linkShaders(GLuint fragShader)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (!fragShader)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	GLuint program = glCreateProgram();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (fragShader)
 | 
					 | 
				
			||||||
		glAttachShader(program, fragShader);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	glLinkProgram(program);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* check link */
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		GLint stat;
 | 
					 | 
				
			||||||
		glGetProgramiv(program, GL_LINK_STATUS, &stat);
 | 
					 | 
				
			||||||
		if (!stat) {
 | 
					 | 
				
			||||||
			GLchar log[1000];
 | 
					 | 
				
			||||||
			GLsizei len;
 | 
					 | 
				
			||||||
			glGetProgramInfoLog(program, 1000, &len, log);
 | 
					 | 
				
			||||||
			fprintf(stderr, "Shader link error:\n%s\n", log);
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return program;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static OCIO_GLSLDrawState *allocateOpenGLState(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	OCIO_GLSLDrawState *state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Allocate memory for state. */
 | 
					 | 
				
			||||||
	state = (OCIO_GLSLDrawState *) MEM_callocN(sizeof(OCIO_GLSLDrawState),
 | 
					 | 
				
			||||||
	                                             "OCIO OpenGL State struct");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Call constructors on new memory. */
 | 
					 | 
				
			||||||
	new (&state->lut3dcacheid) std::string("");
 | 
					 | 
				
			||||||
	new (&state->shadercacheid) std::string("");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return state;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Ensure LUT texture and array are allocated */
 | 
					 | 
				
			||||||
static void ensureLUT3DAllocated(OCIO_GLSLDrawState *state)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int num_3d_entries = 3 * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE * LUT3D_EDGE_SIZE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state->lut3d_texture_allocated)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	glGenTextures(1, &state->lut3d_texture);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	state->lut3d = (float *) MEM_callocN(sizeof(float) * num_3d_entries, "OCIO GPU 3D LUT");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    glActiveTexture(GL_TEXTURE1);
 | 
					 | 
				
			||||||
	glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
 | 
					 | 
				
			||||||
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
					 | 
				
			||||||
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
					 | 
				
			||||||
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 | 
					 | 
				
			||||||
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 | 
					 | 
				
			||||||
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
 | 
					 | 
				
			||||||
	glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB,
 | 
					 | 
				
			||||||
	             LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
 | 
					 | 
				
			||||||
	             0, GL_RGB,GL_FLOAT, &state->lut3d);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	state->lut3d_texture_allocated = true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Setup OpenGL contexts for a transform defined by processor using GLSL
 | 
					 | 
				
			||||||
 * All LUT allocating baking and shader compilation happens here.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Once this function is called, callee could start drawing images
 | 
					 | 
				
			||||||
 * using regular 2D texture.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * When all drawing is finished, finishGLSLDraw shall be called to
 | 
					 | 
				
			||||||
 * restore OpenGL context to it's pre-GLSL draw state.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Create state if needed. */
 | 
					 | 
				
			||||||
	OCIO_GLSLDrawState *state;
 | 
					 | 
				
			||||||
	if (!*state_r)
 | 
					 | 
				
			||||||
		*state_r = allocateOpenGLState();
 | 
					 | 
				
			||||||
	state = *state_r;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	glGetIntegerv(GL_TEXTURE_2D, &state->last_texture);
 | 
					 | 
				
			||||||
	glGetIntegerv(GL_ACTIVE_TEXTURE, &state->last_texture_unit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ensureLUT3DAllocated(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Step 1: Create a GPU Shader Description */
 | 
					 | 
				
			||||||
	GpuShaderDesc shaderDesc;
 | 
					 | 
				
			||||||
	shaderDesc.setLanguage(GPU_LANGUAGE_GLSL_1_0);
 | 
					 | 
				
			||||||
	shaderDesc.setFunctionName("OCIODisplay");
 | 
					 | 
				
			||||||
	shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Step 2: Compute the 3D LUT */
 | 
					 | 
				
			||||||
	std::string lut3dCacheID = ocio_processor->getGpuLut3DCacheID(shaderDesc);
 | 
					 | 
				
			||||||
	if (lut3dCacheID != state->lut3dcacheid) {
 | 
					 | 
				
			||||||
		state->lut3dcacheid = lut3dCacheID;
 | 
					 | 
				
			||||||
		ocio_processor->getGpuLut3D(state->lut3d, shaderDesc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		glActiveTexture(GL_TEXTURE1);
 | 
					 | 
				
			||||||
		glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
 | 
					 | 
				
			||||||
		glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0,
 | 
					 | 
				
			||||||
		                LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
 | 
					 | 
				
			||||||
		                GL_RGB, GL_FLOAT, state->lut3d);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Step 3: Compute the Shader */
 | 
					 | 
				
			||||||
	std::string shaderCacheID = ocio_processor->getGpuShaderTextCacheID(shaderDesc);
 | 
					 | 
				
			||||||
	if (state->program == 0 || shaderCacheID != state->shadercacheid) {
 | 
					 | 
				
			||||||
		state->shadercacheid = shaderCacheID;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::ostringstream os;
 | 
					 | 
				
			||||||
		os << ocio_processor->getGpuShaderText(shaderDesc) << "\n";
 | 
					 | 
				
			||||||
		os << g_fragShaderText;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (state->fragShader)
 | 
					 | 
				
			||||||
			glDeleteShader(state->fragShader);
 | 
					 | 
				
			||||||
		state->fragShader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (state->program)
 | 
					 | 
				
			||||||
			glDeleteProgram(state->program);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		state->program = linkShaders(state->fragShader);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	glActiveTexture(GL_TEXTURE1);
 | 
					 | 
				
			||||||
	glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	glActiveTexture(GL_TEXTURE0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    glUseProgram(state->program);
 | 
					 | 
				
			||||||
    glUniform1i(glGetUniformLocation(state->program, "tex1"), 0);
 | 
					 | 
				
			||||||
    glUniform1i(glGetUniformLocation(state->program, "tex2"), 1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	glActiveTexture(state->last_texture_unit);
 | 
					 | 
				
			||||||
	glBindTexture(GL_TEXTURE_2D, state->last_texture);
 | 
					 | 
				
			||||||
	glUseProgram(0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	using std::string;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state->lut3d_texture_allocated)
 | 
					 | 
				
			||||||
		glDeleteTextures(1, &state->lut3d_texture);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state->lut3d)
 | 
					 | 
				
			||||||
		MEM_freeN(state->lut3d);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	state->lut3dcacheid.~string();
 | 
					 | 
				
			||||||
	state->shadercacheid.~string();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	MEM_freeN(state);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -96,7 +96,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	virtual void matrixTransformScale(float * m44, float * offset4, const float * scale4) = 0;
 | 
						virtual void matrixTransformScale(float * m44, float * offset4, const float * scale4) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual void setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor) = 0;
 | 
						virtual bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide) = 0;
 | 
				
			||||||
	virtual void finishGLSLDraw(struct OCIO_GLSLDrawState *state) = 0;
 | 
						virtual void finishGLSLDraw(struct OCIO_GLSLDrawState *state) = 0;
 | 
				
			||||||
	virtual void freeGLState(struct OCIO_GLSLDrawState *state_r) = 0;
 | 
						virtual void freeGLState(struct OCIO_GLSLDrawState *state_r) = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -169,7 +169,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	void matrixTransformScale(float * m44, float * offset4, const float * scale4);
 | 
						void matrixTransformScale(float * m44, float * offset4, const float * scale4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor);
 | 
						bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide);
 | 
				
			||||||
	void finishGLSLDraw(struct OCIO_GLSLDrawState *state);
 | 
						void finishGLSLDraw(struct OCIO_GLSLDrawState *state);
 | 
				
			||||||
	void freeGLState(struct OCIO_GLSLDrawState *state_r);
 | 
						void freeGLState(struct OCIO_GLSLDrawState *state_r);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -243,7 +243,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	void matrixTransformScale(float * m44, float * offset4, const float * scale4);
 | 
						void matrixTransformScale(float * m44, float * offset4, const float * scale4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor);
 | 
						bool setupGLSLDraw(struct OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide);
 | 
				
			||||||
	void finishGLSLDraw(struct OCIO_GLSLDrawState *state);
 | 
						void finishGLSLDraw(struct OCIO_GLSLDrawState *state);
 | 
				
			||||||
	void freeGLState(struct OCIO_GLSLDrawState *state_r);
 | 
						void freeGLState(struct OCIO_GLSLDrawState *state_r);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,15 +77,33 @@ typedef struct OCIO_GLSLDrawState {
 | 
				
			|||||||
	GLint last_texture, last_texture_unit;
 | 
						GLint last_texture, last_texture_unit;
 | 
				
			||||||
} OCIO_GLSLDrawState;
 | 
					} OCIO_GLSLDrawState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char * g_fragShaderText = ""
 | 
					/* Hardcoded to do alpha predivide before color space conversion */
 | 
				
			||||||
 | 
					static const char *g_fragShaderText = ""
 | 
				
			||||||
"\n"
 | 
					"\n"
 | 
				
			||||||
"uniform sampler2D tex1;\n"
 | 
					"uniform sampler2D tex1;\n"
 | 
				
			||||||
"uniform sampler3D tex2;\n"
 | 
					"uniform sampler3D tex2;\n"
 | 
				
			||||||
 | 
					"uniform bool predivide;\n"
 | 
				
			||||||
"\n"
 | 
					"\n"
 | 
				
			||||||
"void main()\n"
 | 
					"void main()\n"
 | 
				
			||||||
"{\n"
 | 
					"{\n"
 | 
				
			||||||
"    vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n"
 | 
					"    vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n"
 | 
				
			||||||
"    gl_FragColor = OCIODisplay(col, tex2);\n"
 | 
					"    if (predivide == false || col[3] == 1.0f || col[3] == 0.0f) {\n"
 | 
				
			||||||
 | 
					"      gl_FragColor = OCIODisplay(col, tex2);\n"
 | 
				
			||||||
 | 
					"    } else {\n"
 | 
				
			||||||
 | 
					"      float alpha = col[3];\n"
 | 
				
			||||||
 | 
					"      float inv_alpha = 1.0f / alpha;\n"
 | 
				
			||||||
 | 
					"\n"
 | 
				
			||||||
 | 
					"      col[0] *= inv_alpha;\n"
 | 
				
			||||||
 | 
					"      col[1] *= inv_alpha;\n"
 | 
				
			||||||
 | 
					"      col[2] *= inv_alpha;\n"
 | 
				
			||||||
 | 
					"\n"
 | 
				
			||||||
 | 
					"      gl_FragColor = OCIODisplay(col, tex2);\n"
 | 
				
			||||||
 | 
					"\n"
 | 
				
			||||||
 | 
					"      col[0] *= alpha;\n"
 | 
				
			||||||
 | 
					"      col[1] *= alpha;\n"
 | 
				
			||||||
 | 
					"      col[2] *= alpha;\n"
 | 
				
			||||||
 | 
					"    }\n"
 | 
				
			||||||
 | 
					"\n"
 | 
				
			||||||
"}\n";
 | 
					"}\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static GLuint compileShaderText(GLenum shaderType, const char *text)
 | 
					static GLuint compileShaderText(GLenum shaderType, const char *text)
 | 
				
			||||||
@@ -187,7 +205,7 @@ static void ensureLUT3DAllocated(OCIO_GLSLDrawState *state)
 | 
				
			|||||||
 * When all drawing is finished, finishGLSLDraw shall be called to
 | 
					 * When all drawing is finished, finishGLSLDraw shall be called to
 | 
				
			||||||
 * restore OpenGL context to it's pre-GLSL draw state.
 | 
					 * restore OpenGL context to it's pre-GLSL draw state.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor)
 | 
					bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRcPtr *processor, bool predivide)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor;
 | 
						ConstProcessorRcPtr ocio_processor = *(ConstProcessorRcPtr *) processor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -232,22 +250,36 @@ void OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (state->fragShader)
 | 
							if (state->fragShader)
 | 
				
			||||||
			glDeleteShader(state->fragShader);
 | 
								glDeleteShader(state->fragShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		state->fragShader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
 | 
							state->fragShader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (state->program)
 | 
							if (state->fragShader) {
 | 
				
			||||||
			glDeleteProgram(state->program);
 | 
								if (state->program)
 | 
				
			||||||
 | 
									glDeleteProgram(state->program);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		state->program = linkShaders(state->fragShader);
 | 
								state->program = linkShaders(state->fragShader);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glActiveTexture(GL_TEXTURE1);
 | 
						if (state->program) {
 | 
				
			||||||
	glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
 | 
							glActiveTexture(GL_TEXTURE1);
 | 
				
			||||||
 | 
							glBindTexture(GL_TEXTURE_3D, state->lut3d_texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glActiveTexture(GL_TEXTURE0);
 | 
							glActiveTexture(GL_TEXTURE0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glUseProgram(state->program);
 | 
							glUseProgram(state->program);
 | 
				
			||||||
	glUniform1i(glGetUniformLocation(state->program, "tex1"), 0);
 | 
							glUniform1i(glGetUniformLocation(state->program, "tex1"), 0);
 | 
				
			||||||
	glUniform1i(glGetUniformLocation(state->program, "tex2"), 1);
 | 
							glUniform1i(glGetUniformLocation(state->program, "tex2"), 1);
 | 
				
			||||||
 | 
							glUniform1i(glGetUniformLocation(state->program, "predivide"), predivide);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							glActiveTexture(state->last_texture_unit);
 | 
				
			||||||
 | 
							glBindTexture(GL_TEXTURE_2D, state->last_texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
 | 
					void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state)
 | 
				
			||||||
@@ -267,6 +299,12 @@ void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state)
 | 
				
			|||||||
	if (state->lut3d)
 | 
						if (state->lut3d)
 | 
				
			||||||
		MEM_freeN(state->lut3d);
 | 
							MEM_freeN(state->lut3d);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (state->program)
 | 
				
			||||||
 | 
							glDeleteProgram(state->program);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (state->fragShader)
 | 
				
			||||||
 | 
							glDeleteShader(state->fragShader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	state->lut3dcacheid.~string();
 | 
						state->lut3dcacheid.~string();
 | 
				
			||||||
	state->shadercacheid.~string();
 | 
						state->shadercacheid.~string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,7 +66,7 @@ colorspaces:
 | 
				
			|||||||
      Rec. 709 (Full Range), Blender native linear space
 | 
					      Rec. 709 (Full Range), Blender native linear space
 | 
				
			||||||
    isdata: false
 | 
					    isdata: false
 | 
				
			||||||
    allocation: lg2
 | 
					    allocation: lg2
 | 
				
			||||||
    allocationvars: [-8.5, 5]
 | 
					    allocationvars: [-15, 6]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - !<ColorSpace>
 | 
					  - !<ColorSpace>
 | 
				
			||||||
    name: Raw
 | 
					    name: Raw
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -296,6 +296,7 @@ class SpellChecker():
 | 
				
			|||||||
        "spacebar",
 | 
					        "spacebar",
 | 
				
			||||||
        "tooltip", "tooltips",
 | 
					        "tooltip", "tooltips",
 | 
				
			||||||
        "trackpad",
 | 
					        "trackpad",
 | 
				
			||||||
 | 
					        "tuple",
 | 
				
			||||||
        "unicode",
 | 
					        "unicode",
 | 
				
			||||||
        "viewport", "viewports",
 | 
					        "viewport", "viewports",
 | 
				
			||||||
        "viscoelastic",
 | 
					        "viscoelastic",
 | 
				
			||||||
@@ -437,6 +438,7 @@ class SpellChecker():
 | 
				
			|||||||
        "ascii",
 | 
					        "ascii",
 | 
				
			||||||
        "atrac",
 | 
					        "atrac",
 | 
				
			||||||
        "bsdf",
 | 
					        "bsdf",
 | 
				
			||||||
 | 
					        "bssrdf",
 | 
				
			||||||
        "bw",
 | 
					        "bw",
 | 
				
			||||||
        "ccd",
 | 
					        "ccd",
 | 
				
			||||||
        "cmd",
 | 
					        "cmd",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -204,36 +204,40 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
 | 
				
			|||||||
    def draw(self, context):
 | 
					    def draw(self, context):
 | 
				
			||||||
        layout = self.layout
 | 
					        layout = self.layout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ob = context.object
 | 
					        obj = context.object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        split = layout.split()
 | 
					        split = layout.split()
 | 
				
			||||||
        col = split.column()
 | 
					        col = split.column()
 | 
				
			||||||
        col.prop(ob, "draw_type", text="Type")
 | 
					        col.prop(obj, "draw_type", text="Type")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        col = split.column()
 | 
					        col = split.column()
 | 
				
			||||||
        row = col.row()
 | 
					        row = col.row()
 | 
				
			||||||
        row.prop(ob, "show_bounds", text="Bounds")
 | 
					        row.prop(obj, "show_bounds", text="Bounds")
 | 
				
			||||||
        sub = row.row()
 | 
					        sub = row.row()
 | 
				
			||||||
        sub.active = ob.show_bounds
 | 
					        sub.active = obj.show_bounds
 | 
				
			||||||
        sub.prop(ob, "draw_bounds_type", text="")
 | 
					        sub.prop(obj, "draw_bounds_type", text="")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        split = layout.split()
 | 
					        split = layout.split()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        col = split.column()
 | 
					        col = split.column()
 | 
				
			||||||
        col.prop(ob, "show_name", text="Name")
 | 
					        col.prop(obj, "show_name", text="Name")
 | 
				
			||||||
        col.prop(ob, "show_axis", text="Axis")
 | 
					        col.prop(obj, "show_axis", text="Axis")
 | 
				
			||||||
        if ob.type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT'}:
 | 
					        
 | 
				
			||||||
 | 
					        obj_type = obj.type
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if obj_type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT'}:
 | 
				
			||||||
            # Makes no sense for cameras, armtures, etc.!
 | 
					            # Makes no sense for cameras, armtures, etc.!
 | 
				
			||||||
            col.prop(ob, "show_wire", text="Wire")
 | 
					            col.prop(obj, "show_wire", text="Wire")
 | 
				
			||||||
            # Only useful with object having faces/materials...
 | 
					            # Only useful with object having faces/materials...
 | 
				
			||||||
            col.prop(ob, "color", text="Object Color")
 | 
					            col.prop(obj, "color", text="Object Color")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        col = split.column()
 | 
					        col = split.column()
 | 
				
			||||||
        col.prop(ob, "show_texture_space", text="Texture Space")
 | 
					        col.prop(obj, "show_texture_space", text="Texture Space")
 | 
				
			||||||
        col.prop(ob, "show_x_ray", text="X-Ray")
 | 
					        col.prop(obj, "show_x_ray", text="X-Ray")
 | 
				
			||||||
        if ob.type == 'MESH':
 | 
					        if obj_type == 'MESH' or (obj_type == 'EMPTY' and obj.empty_draw_type == 'IMAGE'):
 | 
				
			||||||
            col.prop(ob, "show_transparent", text="Transparency")
 | 
					            col.prop(obj, "show_transparent", text="Transparency")
 | 
				
			||||||
            col.prop(ob, "show_all_edges")
 | 
					        if obj_type == 'MESH':
 | 
				
			||||||
 | 
					            col.prop(obj, "show_all_edges")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class OBJECT_PT_duplication(ObjectButtonsPanel, Panel):
 | 
					class OBJECT_PT_duplication(ObjectButtonsPanel, Panel):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -886,6 +886,7 @@ class CLIP_PT_tools_clip(CLIP_PT_clip_view_panel, Panel):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        layout.operator("clip.set_viewport_background")
 | 
					        layout.operator("clip.set_viewport_background")
 | 
				
			||||||
        layout.operator("clip.setup_tracking_scene")
 | 
					        layout.operator("clip.setup_tracking_scene")
 | 
				
			||||||
 | 
					        layout.operator("clip.prefetch")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CLIP_MT_view(Menu):
 | 
					class CLIP_MT_view(Menu):
 | 
				
			||||||
@@ -945,6 +946,7 @@ class CLIP_MT_clip(Menu):
 | 
				
			|||||||
        layout.operator("clip.open")
 | 
					        layout.operator("clip.open")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if clip:
 | 
					        if clip:
 | 
				
			||||||
 | 
					            layout.operator("clip.prefetch")
 | 
				
			||||||
            layout.operator("clip.reload")
 | 
					            layout.operator("clip.reload")
 | 
				
			||||||
            layout.menu("CLIP_MT_proxy")
 | 
					            layout.menu("CLIP_MT_proxy")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -151,10 +151,17 @@ class NODE_MT_select(Menu):
 | 
				
			|||||||
        layout.operator("node.select_all", text="Inverse").action = 'INVERT'
 | 
					        layout.operator("node.select_all", text="Inverse").action = 'INVERT'
 | 
				
			||||||
        layout.operator("node.select_linked_from")
 | 
					        layout.operator("node.select_linked_from")
 | 
				
			||||||
        layout.operator("node.select_linked_to")
 | 
					        layout.operator("node.select_linked_to")
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					        layout.separator()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        layout.operator("node.select_same_type")
 | 
					        layout.operator("node.select_same_type")
 | 
				
			||||||
        layout.operator("node.select_same_type_step").prev = True
 | 
					        layout.operator("node.select_same_type_step").prev = True
 | 
				
			||||||
        layout.operator("node.select_same_type_step").prev = False
 | 
					        layout.operator("node.select_same_type_step").prev = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        layout.separator()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        layout.operator("node.find_node")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NODE_MT_node(Menu):
 | 
					class NODE_MT_node(Menu):
 | 
				
			||||||
    bl_label = "Node"
 | 
					    bl_label = "Node"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -247,6 +247,7 @@ struct DerivedMesh {
 | 
				
			|||||||
	void *(*getVertDataArray)(DerivedMesh *dm, int type);
 | 
						void *(*getVertDataArray)(DerivedMesh *dm, int type);
 | 
				
			||||||
	void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
 | 
						void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
 | 
				
			||||||
	void *(*getTessFaceDataArray)(DerivedMesh *dm, int type);
 | 
						void *(*getTessFaceDataArray)(DerivedMesh *dm, int type);
 | 
				
			||||||
 | 
						void *(*getLoopDataArray)(DerivedMesh *dm, int type);
 | 
				
			||||||
	void *(*getPolyDataArray)(DerivedMesh *dm, int type);
 | 
						void *(*getPolyDataArray)(DerivedMesh *dm, int type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Retrieves the base CustomData structures for
 | 
						/** Retrieves the base CustomData structures for
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,18 +41,17 @@ struct Object;
 | 
				
			|||||||
struct bAction;
 | 
					struct bAction;
 | 
				
			||||||
struct Scene;
 | 
					struct Scene;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void        BKE_group_free(struct Group *group);
 | 
					void          BKE_group_free(struct Group *group);
 | 
				
			||||||
void        BKE_group_unlink(struct Group *group);
 | 
					void          BKE_group_unlink(struct Group *group);
 | 
				
			||||||
struct Group *add_group(struct Main *bmain, const char *name);
 | 
					struct Group *BKE_group_add(struct Main *bmain, const char *name);
 | 
				
			||||||
struct Group *BKE_group_copy(struct Group *group);
 | 
					struct Group *BKE_group_copy(struct Group *group);
 | 
				
			||||||
int         add_to_group(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
 | 
					bool          BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
 | 
				
			||||||
int         rem_from_group(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
 | 
					bool          BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
 | 
				
			||||||
struct Group *find_group(struct Object *ob, struct Group *group);
 | 
					struct Group *BKE_group_object_find(struct Group *group, struct Object *ob);
 | 
				
			||||||
int         object_in_group(struct Object *ob, struct Group *group);
 | 
					bool          BKE_group_object_exists(struct Group *group, struct Object *ob);
 | 
				
			||||||
int         group_is_animated(struct Object *parent, struct Group *group);
 | 
					bool          BKE_group_is_animated(struct Group *group, struct Object *parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void        group_tag_recalc(struct Group *group);
 | 
					void          BKE_group_tag_recalc(struct Group *group);
 | 
				
			||||||
void        group_handle_recalc_and_update(struct Scene *scene, struct Object *parent, struct Group *group);
 | 
					void          BKE_group_handle_recalc_and_update(struct Scene *scene, struct Object *parent, struct Group *group);
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  /* __BKE_GROUP_H__ */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,10 +107,12 @@ __attribute__((nonnull))
 | 
				
			|||||||
;
 | 
					;
 | 
				
			||||||
void clear_id_newpoins(void);
 | 
					void clear_id_newpoins(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
void IDnames_to_pupstring(const char **str, const char *title, const char *extraops,
 | 
					void IDnames_to_pupstring(const char **str, const char *title, const char *extraops,
 | 
				
			||||||
                          struct ListBase *lb, struct ID *link, short *nr);
 | 
					                          struct ListBase *lb, struct ID *link, short *nr);
 | 
				
			||||||
void IMAnames_to_pupstring(const char **str, const char *title, const char *extraops,
 | 
					void IMAnames_to_pupstring(const char **str, const char *title, const char *extraops,
 | 
				
			||||||
                           struct ListBase *lb, struct ID *link, short *nr);
 | 
					                           struct ListBase *lb, struct ID *link, short *nr);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void flag_listbase_ids(ListBase *lb, short flag, short value);
 | 
					void flag_listbase_ids(ListBase *lb, short flag, short value);
 | 
				
			||||||
void flag_all_listbases_ids(short flag, short value);
 | 
					void flag_all_listbases_ids(short flag, short value);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,7 +59,8 @@ struct Material *give_node_material(struct Material *ma); /* returns node materi
 | 
				
			|||||||
void BKE_material_make_local(struct Material *ma);
 | 
					void BKE_material_make_local(struct Material *ma);
 | 
				
			||||||
void extern_local_matarar(struct Material **matar, short totcol);
 | 
					void extern_local_matarar(struct Material **matar, short totcol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void automatname(struct Material *);
 | 
					/* UNUSED */
 | 
				
			||||||
 | 
					// void automatname(struct Material *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* material slots */
 | 
					/* material slots */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,7 @@ void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
 | 
					struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
 | 
				
			||||||
void BKE_movieclip_reload(struct MovieClip *clip);
 | 
					void BKE_movieclip_reload(struct MovieClip *clip);
 | 
				
			||||||
 | 
					void BKE_movieclip_clear_cache(struct MovieClip *clip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ImBuf *BKE_movieclip_get_ibuf(struct MovieClip *clip, struct MovieClipUser *user);
 | 
					struct ImBuf *BKE_movieclip_get_ibuf(struct MovieClip *clip, struct MovieClipUser *user);
 | 
				
			||||||
struct ImBuf *BKE_movieclip_get_postprocessed_ibuf(struct MovieClip *clip, struct MovieClipUser *user, int postprocess_flag);
 | 
					struct ImBuf *BKE_movieclip_get_postprocessed_ibuf(struct MovieClip *clip, struct MovieClipUser *user, int postprocess_flag);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -444,9 +444,6 @@ const char *	nodeStaticSocketInterfaceType(int type, int subtype);
 | 
				
			|||||||
	BLI_ghashIterator_free(__node_socket_type_iter__); \
 | 
						BLI_ghashIterator_free(__node_socket_type_iter__); \
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void			nodeMakeDynamicType(struct bNode *node);
 | 
					 | 
				
			||||||
int				nodeDynamicUnlinkText(struct ID *txtid);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct bNodeSocket *nodeFindSocket(struct bNode *node, int in_out, const char *identifier);
 | 
					struct bNodeSocket *nodeFindSocket(struct bNode *node, int in_out, const char *identifier);
 | 
				
			||||||
struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, const char *idname,
 | 
					struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree, struct bNode *node, int in_out, const char *idname,
 | 
				
			||||||
                                  const char *identifier, const char *name);
 | 
					                                  const char *identifier, const char *name);
 | 
				
			||||||
@@ -575,9 +572,6 @@ void            BKE_node_preview_set_pixel(struct bNodePreview *preview, const f
 | 
				
			|||||||
/* ************** NODE TYPE ACCESS *************** */
 | 
					/* ************** NODE TYPE ACCESS *************** */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char     *nodeLabel(struct bNode *node);
 | 
					const char     *nodeLabel(struct bNode *node);
 | 
				
			||||||
struct bNodeTree *nodeGroupEditGet(struct bNode *node);
 | 
					 | 
				
			||||||
struct bNodeTree *nodeGroupEditSet(struct bNode *node, int edit);
 | 
					 | 
				
			||||||
void            nodeGroupEditClear(struct bNode *node);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int				nodeGroupPoll(struct bNodeTree *nodetree, struct bNodeTree *grouptree);
 | 
					int				nodeGroupPoll(struct bNodeTree *nodetree, struct bNodeTree *grouptree);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -752,6 +746,7 @@ struct ShadeResult;
 | 
				
			|||||||
#define SH_NODE_TANGENT					174
 | 
					#define SH_NODE_TANGENT					174
 | 
				
			||||||
#define SH_NODE_NORMAL_MAP				175
 | 
					#define SH_NODE_NORMAL_MAP				175
 | 
				
			||||||
#define SH_NODE_HAIR_INFO				176
 | 
					#define SH_NODE_HAIR_INFO				176
 | 
				
			||||||
 | 
					#define SH_NODE_SUBSURFACE_SCATTERING	177
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* custom defines options for Material node */
 | 
					/* custom defines options for Material node */
 | 
				
			||||||
#define SH_NODE_MAT_DIFF   1
 | 
					#define SH_NODE_MAT_DIFF   1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -255,7 +255,8 @@ struct ParticleSystem *psys_get_current(struct Object *ob);
 | 
				
			|||||||
/* for rna */
 | 
					/* for rna */
 | 
				
			||||||
short psys_get_current_num(struct Object *ob);
 | 
					short psys_get_current_num(struct Object *ob);
 | 
				
			||||||
void psys_set_current_num(Object *ob, int index);
 | 
					void psys_set_current_num(Object *ob, int index);
 | 
				
			||||||
struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys);
 | 
					/* UNUSED */
 | 
				
			||||||
 | 
					// struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Object *psys_get_lattice(struct ParticleSimulationData *sim);
 | 
					struct Object *psys_get_lattice(struct ParticleSimulationData *sim);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,6 @@ void smokeModifier_reset_turbulence(struct SmokeModifierData *smd);
 | 
				
			|||||||
void smokeModifier_createType(struct SmokeModifierData *smd);
 | 
					void smokeModifier_createType(struct SmokeModifierData *smd);
 | 
				
			||||||
void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData *tsmd);
 | 
					void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData *tsmd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
long long smoke_get_mem_req(int xres, int yres, int zres, int amplify);
 | 
					 | 
				
			||||||
float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
 | 
					float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
 | 
				
			||||||
int smoke_get_data_flags(struct SmokeDomainSettings *sds);
 | 
					int smoke_get_data_flags(struct SmokeDomainSettings *sds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,8 @@ struct MTex *add_mtex_id(struct ID *id, int slot);
 | 
				
			|||||||
struct Tex *BKE_texture_copy(struct Tex *tex);
 | 
					struct Tex *BKE_texture_copy(struct Tex *tex);
 | 
				
			||||||
struct Tex *localize_texture(struct Tex *tex);
 | 
					struct Tex *localize_texture(struct Tex *tex);
 | 
				
			||||||
void BKE_texture_make_local(struct Tex *tex);
 | 
					void BKE_texture_make_local(struct Tex *tex);
 | 
				
			||||||
void autotexname(struct Tex *tex);
 | 
					/* UNUSED */
 | 
				
			||||||
 | 
					// void autotexname(struct Tex *tex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Tex *give_current_object_texture(struct Object *ob);
 | 
					struct Tex *give_current_object_texture(struct Object *ob);
 | 
				
			||||||
struct Tex *give_current_material_texture(struct Material *ma);
 | 
					struct Tex *give_current_material_texture(struct Material *ma);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,7 +124,6 @@ void push_queue(DagNodeQueue *queue, DagNode *node);
 | 
				
			|||||||
void push_stack(DagNodeQueue *queue, DagNode *node);
 | 
					void push_stack(DagNodeQueue *queue, DagNode *node);
 | 
				
			||||||
DagNode *pop_queue(DagNodeQueue *queue);
 | 
					DagNode *pop_queue(DagNodeQueue *queue);
 | 
				
			||||||
DagNode *get_top_node_queue(DagNodeQueue *queue);
 | 
					DagNode *get_top_node_queue(DagNodeQueue *queue);
 | 
				
			||||||
int queue_count(DagNodeQueue *queue);
 | 
					 | 
				
			||||||
void queue_delete(DagNodeQueue *queue);
 | 
					void queue_delete(DagNodeQueue *queue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Dag management
 | 
					// Dag management
 | 
				
			||||||
@@ -137,9 +136,6 @@ DagNode *dag_get_node(DagForest *forest, void *fob);
 | 
				
			|||||||
DagNode *dag_get_sub_node(DagForest *forest, void *fob);
 | 
					DagNode *dag_get_sub_node(DagForest *forest, void *fob);
 | 
				
			||||||
void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name);
 | 
					void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DagNodeQueue *graph_dfs(void);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void set_node_xy(DagNode *node, float x, float y);
 | 
					 | 
				
			||||||
void graph_print_queue(DagNodeQueue *nqueue);
 | 
					void graph_print_queue(DagNodeQueue *nqueue);
 | 
				
			||||||
void graph_print_queue_dist(DagNodeQueue *nqueue);
 | 
					void graph_print_queue_dist(DagNodeQueue *nqueue);
 | 
				
			||||||
void graph_print_adj_list(DagForest *dag);
 | 
					void graph_print_adj_list(DagForest *dag);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -270,6 +270,7 @@ void DM_init_funcs(DerivedMesh *dm)
 | 
				
			|||||||
	dm->getEdgeDataArray = DM_get_edge_data_layer;
 | 
						dm->getEdgeDataArray = DM_get_edge_data_layer;
 | 
				
			||||||
	dm->getTessFaceDataArray = DM_get_tessface_data_layer;
 | 
						dm->getTessFaceDataArray = DM_get_tessface_data_layer;
 | 
				
			||||||
	dm->getPolyDataArray = DM_get_poly_data_layer;
 | 
						dm->getPolyDataArray = DM_get_poly_data_layer;
 | 
				
			||||||
 | 
						dm->getLoopDataArray = DM_get_loop_data_layer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bvhcache_init(&dm->bvhCache);
 | 
						bvhcache_init(&dm->bvhCache);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -766,10 +766,10 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persiste
 | 
				
			|||||||
	if (flag & DUPLILIST_DO_UPDATE) {
 | 
						if (flag & DUPLILIST_DO_UPDATE) {
 | 
				
			||||||
		/* note: update is optional because we don't always need object
 | 
							/* note: update is optional because we don't always need object
 | 
				
			||||||
		 * transformations to be correct. Also fixes bug [#29616]. */
 | 
							 * transformations to be correct. Also fixes bug [#29616]. */
 | 
				
			||||||
		group_handle_recalc_and_update(scene, ob, group);
 | 
							BKE_group_handle_recalc_and_update(scene, ob, group);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (group_is_animated(ob, group))
 | 
						if (BKE_group_is_animated(group, ob))
 | 
				
			||||||
		flag |= DUPLILIST_ANIMATED;
 | 
							flag |= DUPLILIST_ANIMATED;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	for (go = group->gobject.first, id = 0; go; go = go->next, id++) {
 | 
						for (go = group->gobject.first, id = 0; go; go = go->next, id++) {
 | 
				
			||||||
@@ -953,6 +953,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
 | 
				
			|||||||
	float vec[3], no[3], pmat[4][4];
 | 
						float vec[3], no[3], pmat[4][4];
 | 
				
			||||||
	int totvert, a, oblay;
 | 
						int totvert, a, oblay;
 | 
				
			||||||
	unsigned int lay;
 | 
						unsigned int lay;
 | 
				
			||||||
 | 
						CustomDataMask dm_mask;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	copy_m4_m4(pmat, par->obmat);
 | 
						copy_m4_m4(pmat, par->obmat);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@@ -961,16 +962,18 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
 | 
				
			|||||||
	
 | 
						
 | 
				
			||||||
	em = BMEdit_FromObject(par);
 | 
						em = BMEdit_FromObject(par);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if (em) {
 | 
						/* get derived mesh */
 | 
				
			||||||
		dm = editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
 | 
						dm_mask = CD_MASK_BAREMESH;
 | 
				
			||||||
	}
 | 
						if (flag & DUPLILIST_FOR_RENDER)
 | 
				
			||||||
	else
 | 
							dm_mask |= CD_MASK_ORCO;
 | 
				
			||||||
		dm = mesh_get_derived_final(scene, par, CD_MASK_BAREMESH);
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if (flag & DUPLILIST_FOR_RENDER) {
 | 
						if (em)
 | 
				
			||||||
		vdd.orco = (float(*)[3])BKE_mesh_orco_verts_get(par);
 | 
							dm = editbmesh_get_derived_cage(scene, par, em, dm_mask);
 | 
				
			||||||
		BKE_mesh_orco_verts_transform(me, vdd.orco, me->totvert, 0);
 | 
						else
 | 
				
			||||||
	}
 | 
							dm = mesh_get_derived_final(scene, par, dm_mask);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if (flag & DUPLILIST_FOR_RENDER)
 | 
				
			||||||
 | 
							vdd.orco = dm->getVertDataArray(dm, CD_ORCO);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		vdd.orco = NULL;
 | 
							vdd.orco = NULL;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@@ -1057,8 +1060,6 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl
 | 
				
			|||||||
		else go = go->next;             /* group loop */
 | 
							else go = go->next;             /* group loop */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (vdd.orco)
 | 
					 | 
				
			||||||
		MEM_freeN(vdd.orco);
 | 
					 | 
				
			||||||
	dm->release(dm);
 | 
						dm->release(dm);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1069,7 +1070,6 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
 | 
				
			|||||||
	Base *base = NULL;
 | 
						Base *base = NULL;
 | 
				
			||||||
	DupliObject *dob;
 | 
						DupliObject *dob;
 | 
				
			||||||
	DerivedMesh *dm;
 | 
						DerivedMesh *dm;
 | 
				
			||||||
	Mesh *me = par->data;
 | 
					 | 
				
			||||||
	MLoopUV *mloopuv;
 | 
						MLoopUV *mloopuv;
 | 
				
			||||||
	MPoly *mpoly, *mp;
 | 
						MPoly *mpoly, *mp;
 | 
				
			||||||
	MLoop *mloop;
 | 
						MLoop *mloop;
 | 
				
			||||||
@@ -1081,6 +1081,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
 | 
				
			|||||||
	GroupObject *go = NULL;
 | 
						GroupObject *go = NULL;
 | 
				
			||||||
	BMEditMesh *em;
 | 
						BMEditMesh *em;
 | 
				
			||||||
	float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */
 | 
						float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */
 | 
				
			||||||
 | 
						CustomDataMask dm_mask;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	/* simple preventing of too deep nested groups */
 | 
						/* simple preventing of too deep nested groups */
 | 
				
			||||||
	if (level > MAX_DUPLI_RECUR) return;
 | 
						if (level > MAX_DUPLI_RECUR) return;
 | 
				
			||||||
@@ -1088,11 +1089,16 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
 | 
				
			|||||||
	copy_m4_m4(pmat, par->obmat);
 | 
						copy_m4_m4(pmat, par->obmat);
 | 
				
			||||||
	em = BMEdit_FromObject(par);
 | 
						em = BMEdit_FromObject(par);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* get derived mesh */
 | 
				
			||||||
 | 
						dm_mask = CD_MASK_BAREMESH;
 | 
				
			||||||
 | 
						if (flag & DUPLILIST_FOR_RENDER)
 | 
				
			||||||
 | 
							dm_mask |= CD_MASK_ORCO | CD_MASK_MLOOPUV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (em) {
 | 
						if (em) {
 | 
				
			||||||
		dm = editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
 | 
							dm = editbmesh_get_derived_cage(scene, par, em, dm_mask);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		dm = mesh_get_derived_final(scene, par, CD_MASK_BAREMESH);
 | 
							dm = mesh_get_derived_final(scene, par, dm_mask);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	totface = dm->getNumPolys(dm);
 | 
						totface = dm->getNumPolys(dm);
 | 
				
			||||||
@@ -1101,9 +1107,8 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
 | 
				
			|||||||
	mvert = dm->getVertArray(dm);
 | 
						mvert = dm->getVertArray(dm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (flag & DUPLILIST_FOR_RENDER) {
 | 
						if (flag & DUPLILIST_FOR_RENDER) {
 | 
				
			||||||
		orco = (float(*)[3])BKE_mesh_orco_verts_get(par);
 | 
							orco = dm->getVertDataArray(dm, CD_ORCO);
 | 
				
			||||||
		BKE_mesh_orco_verts_transform(me, orco, me->totvert, 0);
 | 
							mloopuv = dm->getLoopDataArray(dm, CD_MLOOPUV);
 | 
				
			||||||
		mloopuv = me->mloopuv;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		orco = NULL;
 | 
							orco = NULL;
 | 
				
			||||||
@@ -1215,7 +1220,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
 | 
				
			|||||||
							if (mloopuv) {
 | 
												if (mloopuv) {
 | 
				
			||||||
								int j;
 | 
													int j;
 | 
				
			||||||
								for (j = 0; j < mpoly->totloop; j++) {
 | 
													for (j = 0; j < mpoly->totloop; j++) {
 | 
				
			||||||
									madd_v2_v2fl(dob->orco, mloopuv[loopstart[j].v].uv, w);
 | 
														madd_v2_v2fl(dob->uv, mloopuv[mp->loopstart + j].uv, w);
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
@@ -1238,9 +1243,6 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
 | 
				
			|||||||
		else go = go->next;             /* group loop */
 | 
							else go = go->next;             /* group loop */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (orco)
 | 
					 | 
				
			||||||
		MEM_freeN(orco);
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	dm->release(dm);
 | 
						dm->release(dm);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1331,7 +1333,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p
 | 
				
			|||||||
		/* gather list of objects or single object */
 | 
							/* gather list of objects or single object */
 | 
				
			||||||
		if (part->ren_as == PART_DRAW_GR) {
 | 
							if (part->ren_as == PART_DRAW_GR) {
 | 
				
			||||||
			if (flag & DUPLILIST_DO_UPDATE) {
 | 
								if (flag & DUPLILIST_DO_UPDATE) {
 | 
				
			||||||
				group_handle_recalc_and_update(scene, par, part->dup_group);
 | 
									BKE_group_handle_recalc_and_update(scene, par, part->dup_group);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (part->draw & PART_DRAW_COUNT_GR) {
 | 
								if (part->draw & PART_DRAW_COUNT_GR) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1008,6 +1008,7 @@ void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorM
 | 
				
			|||||||
		IMB_colormanagement_processor_free(cm_processor);
 | 
							IMB_colormanagement_processor_free(cm_processor);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* if view_settings, it also applies this to byte buffers */
 | 
				
			||||||
void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
 | 
					void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
 | 
				
			||||||
                   const ColorManagedDisplaySettings *display_settings)
 | 
					                   const ColorManagedDisplaySettings *display_settings)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -1021,7 +1022,7 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
 | 
				
			|||||||
	float rgba[4], ycc[3], luma;
 | 
						float rgba[4], ycc[3], luma;
 | 
				
			||||||
	int ycc_mode = -1;
 | 
						int ycc_mode = -1;
 | 
				
			||||||
	const short is_float = (ibuf->rect_float != NULL);
 | 
						const short is_float = (ibuf->rect_float != NULL);
 | 
				
			||||||
 | 
						void *cache_handle = NULL;
 | 
				
			||||||
	struct ColormanageProcessor *cm_processor = NULL;
 | 
						struct ColormanageProcessor *cm_processor = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
 | 
						if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
 | 
				
			||||||
@@ -1090,9 +1091,10 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
 | 
				
			|||||||
	
 | 
						
 | 
				
			||||||
	if (is_float)
 | 
						if (is_float)
 | 
				
			||||||
		rf = ibuf->rect_float;
 | 
							rf = ibuf->rect_float;
 | 
				
			||||||
	else
 | 
						else {
 | 
				
			||||||
		rc = (unsigned char *)ibuf->rect;
 | 
							rc = (unsigned char *)IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	if (ibuf->rect_float)
 | 
						if (ibuf->rect_float)
 | 
				
			||||||
		cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
 | 
							cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1173,11 +1175,12 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
 | 
				
			|||||||
		if (bin_b[x]   > nb) nb = bin_b[x];
 | 
							if (bin_b[x]   > nb) nb = bin_b[x];
 | 
				
			||||||
		if (bin_a[x]   > na) na = bin_a[x];
 | 
							if (bin_a[x]   > na) na = bin_a[x];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	divl = 1.0 / (double)nl;
 | 
						divl = nl ? 1.0 / (double)nl : 1.0;
 | 
				
			||||||
	diva = 1.0 / (double)na;
 | 
						diva = na ? 1.0 / (double)na : 1.0;
 | 
				
			||||||
	divr = 1.0 / (double)nr;
 | 
						divr = nr ? 1.0 / (double)nr : 1.0;
 | 
				
			||||||
	divg = 1.0 / (double)ng;
 | 
						divg = ng ? 1.0 / (double)ng : 1.0;
 | 
				
			||||||
	divb = 1.0 / (double)nb;
 | 
						divb = nb ? 1.0 / (double)nb : 1.0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	for (x = 0; x < 256; x++) {
 | 
						for (x = 0; x < 256; x++) {
 | 
				
			||||||
		scopes->hist.data_luma[x] = bin_lum[x] * divl;
 | 
							scopes->hist.data_luma[x] = bin_lum[x] * divl;
 | 
				
			||||||
		scopes->hist.data_r[x] = bin_r[x] * divr;
 | 
							scopes->hist.data_r[x] = bin_r[x] * divr;
 | 
				
			||||||
@@ -1193,7 +1196,9 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (cm_processor)
 | 
						if (cm_processor)
 | 
				
			||||||
		IMB_colormanagement_processor_free(cm_processor);
 | 
							IMB_colormanagement_processor_free(cm_processor);
 | 
				
			||||||
 | 
						if (cache_handle)
 | 
				
			||||||
 | 
							IMB_display_buffer_release(cache_handle);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	scopes->ok = 1;
 | 
						scopes->ok = 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1204,8 +1204,8 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
 | 
				
			|||||||
					vec_to_quat(quat, dir, (short)data->trackflag, (short)data->upflag);
 | 
										vec_to_quat(quat, dir, (short)data->trackflag, (short)data->upflag);
 | 
				
			||||||
					
 | 
										
 | 
				
			||||||
					normalize_v3(dir);
 | 
										normalize_v3(dir);
 | 
				
			||||||
					q[0] = (float)cos(0.5 * vec[3]);
 | 
										q[0] = cosf(0.5 * vec[3]);
 | 
				
			||||||
					x1 = (float)sin(0.5 * vec[3]);
 | 
										x1 = sinf(0.5 * vec[3]);
 | 
				
			||||||
					q[1] = -x1 * dir[0];
 | 
										q[1] = -x1 * dir[0];
 | 
				
			||||||
					q[2] = -x1 * dir[1];
 | 
										q[2] = -x1 * dir[1];
 | 
				
			||||||
					q[3] = -x1 * dir[2];
 | 
										q[3] = -x1 * dir[2];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -95,7 +95,9 @@ void BKE_group_unlink(Group *group)
 | 
				
			|||||||
		
 | 
							
 | 
				
			||||||
		/* ensure objects are not in this group */
 | 
							/* ensure objects are not in this group */
 | 
				
			||||||
		for (; base; base = base->next) {
 | 
							for (; base; base = base->next) {
 | 
				
			||||||
			if (rem_from_group(group, base->object, sce, base) && find_group(base->object, NULL) == NULL) {
 | 
								if (BKE_group_object_unlink(group, base->object, sce, base) &&
 | 
				
			||||||
 | 
								    BKE_group_object_find(NULL, base->object) == NULL)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
				base->object->flag &= ~OB_FROMGROUP;
 | 
									base->object->flag &= ~OB_FROMGROUP;
 | 
				
			||||||
				base->flag &= ~OB_FROMGROUP;
 | 
									base->flag &= ~OB_FROMGROUP;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -132,7 +134,7 @@ void BKE_group_unlink(Group *group)
 | 
				
			|||||||
	group->id.us = 0;
 | 
						group->id.us = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Group *add_group(Main *bmain, const char *name)
 | 
					Group *BKE_group_add(Main *bmain, const char *name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Group *group;
 | 
						Group *group;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@@ -152,7 +154,7 @@ Group *BKE_group_copy(Group *group)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* external */
 | 
					/* external */
 | 
				
			||||||
static int add_to_group_internal(Group *group, Object *ob)
 | 
					static int group_object_add_internal(Group *group, Object *ob)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	GroupObject *go;
 | 
						GroupObject *go;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@@ -173,9 +175,9 @@ static int add_to_group_internal(Group *group, Object *ob)
 | 
				
			|||||||
	return TRUE;
 | 
						return TRUE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int add_to_group(Group *group, Object *object, Scene *scene, Base *base)
 | 
					bool BKE_group_object_add(Group *group, Object *object, Scene *scene, Base *base)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (add_to_group_internal(group, object)) {
 | 
						if (group_object_add_internal(group, object)) {
 | 
				
			||||||
		if ((object->flag & OB_FROMGROUP) == 0) {
 | 
							if ((object->flag & OB_FROMGROUP) == 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (scene && base == NULL)
 | 
								if (scene && base == NULL)
 | 
				
			||||||
@@ -186,15 +188,15 @@ int add_to_group(Group *group, Object *object, Scene *scene, Base *base)
 | 
				
			|||||||
			if (base)
 | 
								if (base)
 | 
				
			||||||
				base->flag |= OB_FROMGROUP;
 | 
									base->flag |= OB_FROMGROUP;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return 1;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		return 0;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* also used for (ob == NULL) */
 | 
					/* also used for (ob == NULL) */
 | 
				
			||||||
static int rem_from_group_internal(Group *group, Object *ob)
 | 
					static int group_object_unlink_internal(Group *group, Object *ob)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	GroupObject *go, *gon;
 | 
						GroupObject *go, *gon;
 | 
				
			||||||
	int removed = 0;
 | 
						int removed = 0;
 | 
				
			||||||
@@ -214,11 +216,11 @@ static int rem_from_group_internal(Group *group, Object *ob)
 | 
				
			|||||||
	return removed;
 | 
						return removed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int rem_from_group(Group *group, Object *object, Scene *scene, Base *base)
 | 
					bool BKE_group_object_unlink(Group *group, Object *object, Scene *scene, Base *base)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (rem_from_group_internal(group, object)) {
 | 
						if (group_object_unlink_internal(group, object)) {
 | 
				
			||||||
		/* object can be NULL */
 | 
							/* object can be NULL */
 | 
				
			||||||
		if (object && find_group(object, NULL) == NULL) {
 | 
							if (object && BKE_group_object_find(NULL, object) == NULL) {
 | 
				
			||||||
			if (scene && base == NULL)
 | 
								if (scene && base == NULL)
 | 
				
			||||||
				base = BKE_scene_base_find(scene, object);
 | 
									base = BKE_scene_base_find(scene, object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -227,23 +229,24 @@ int rem_from_group(Group *group, Object *object, Scene *scene, Base *base)
 | 
				
			|||||||
			if (base)
 | 
								if (base)
 | 
				
			||||||
				base->flag &= ~OB_FROMGROUP;
 | 
									base->flag &= ~OB_FROMGROUP;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return 1;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		return 0;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int object_in_group(Object *ob, Group *group)
 | 
					bool BKE_group_object_exists(Group *group, Object *ob)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (group == NULL || ob == NULL) {
 | 
						if (group == NULL || ob == NULL) {
 | 
				
			||||||
		return FALSE;
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Group *find_group(Object *ob, Group *group)
 | 
					Group *BKE_group_object_find(Group *group, Object *ob)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (group)
 | 
						if (group)
 | 
				
			||||||
		group = group->id.next;
 | 
							group = group->id.next;
 | 
				
			||||||
@@ -251,14 +254,14 @@ Group *find_group(Object *ob, Group *group)
 | 
				
			|||||||
		group = G.main->group.first;
 | 
							group = G.main->group.first;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	while (group) {
 | 
						while (group) {
 | 
				
			||||||
		if (object_in_group(ob, group))
 | 
							if (BKE_group_object_exists(group, ob))
 | 
				
			||||||
			return group;
 | 
								return group;
 | 
				
			||||||
		group = group->id.next;
 | 
							group = group->id.next;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void group_tag_recalc(Group *group)
 | 
					void BKE_group_tag_recalc(Group *group)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	GroupObject *go;
 | 
						GroupObject *go;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@@ -270,7 +273,7 @@ void group_tag_recalc(Group *group)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int group_is_animated(Object *UNUSED(parent), Group *group)
 | 
					bool BKE_group_is_animated(Group *group, Object *UNUSED(parent))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	GroupObject *go;
 | 
						GroupObject *go;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -281,9 +284,9 @@ int group_is_animated(Object *UNUSED(parent), Group *group)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for (go = group->gobject.first; go; go = go->next)
 | 
						for (go = group->gobject.first; go; go = go->next)
 | 
				
			||||||
		if (go->ob && go->ob->proxy)
 | 
							if (go->ob && go->ob->proxy)
 | 
				
			||||||
			return 1;
 | 
								return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if 0 // add back when timeoffset & animsys work again
 | 
					#if 0 // add back when timeoffset & animsys work again
 | 
				
			||||||
@@ -332,7 +335,7 @@ static void group_replaces_nla(Object *parent, Object *target, char mode)
 | 
				
			|||||||
 * you can draw everything, leaves tags in objects to signal it needs further updating */
 | 
					 * you can draw everything, leaves tags in objects to signal it needs further updating */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
 | 
					/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
 | 
				
			||||||
void group_handle_recalc_and_update(Scene *scene, Object *UNUSED(parent), Group *group)
 | 
					void BKE_group_handle_recalc_and_update(Scene *scene, Object *UNUSED(parent), Group *group)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	GroupObject *go;
 | 
						GroupObject *go;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1065,6 +1065,7 @@ ID *BKE_libblock_find_name(const short type, const char *name)      /* type: "OB
 | 
				
			|||||||
	return BLI_findstring(lb, name, offsetof(ID, name) + 2);
 | 
						return BLI_findstring(lb, name, offsetof(ID, name) + 2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0 /* UNUSED */
 | 
				
			||||||
static void get_flags_for_id(ID *id, char *buf) 
 | 
					static void get_flags_for_id(ID *id, char *buf) 
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int isfake = id->flag & LIB_FAKEUSER;
 | 
						int isfake = id->flag & LIB_FAKEUSER;
 | 
				
			||||||
@@ -1145,7 +1146,6 @@ static void IDnames_to_dyn_pupstring(DynStr *pupds, ListBase *lb, ID *link, shor
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
/* used by headerbuttons.c buttons.c editobject.c editseq.c */
 | 
					/* used by headerbuttons.c buttons.c editobject.c editseq.c */
 | 
				
			||||||
/* if (nr == NULL) no MAX_IDPUP, this for non-header browsing */
 | 
					/* if (nr == NULL) no MAX_IDPUP, this for non-header browsing */
 | 
				
			||||||
void IDnames_to_pupstring(const char **str, const char *title, const char *extraops, ListBase *lb, ID *link, short *nr)
 | 
					void IDnames_to_pupstring(const char **str, const char *title, const char *extraops, ListBase *lb, ID *link, short *nr)
 | 
				
			||||||
@@ -1170,7 +1170,6 @@ void IDnames_to_pupstring(const char **str, const char *title, const char *extra
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* skips viewer images */
 | 
					/* skips viewer images */
 | 
				
			||||||
#if 0 /* unused */
 | 
					 | 
				
			||||||
void IMAnames_to_pupstring(const char **str, const char *title, const char *extraops, ListBase *lb, ID *link, short *nr)
 | 
					void IMAnames_to_pupstring(const char **str, const char *title, const char *extraops, ListBase *lb, ID *link, short *nr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	DynStr *pupds = BLI_dynstr_new();
 | 
						DynStr *pupds = BLI_dynstr_new();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1426,7 +1426,8 @@ static void converge(const float p1[3], const float p2[3], float v1, float v2,
 | 
				
			|||||||
		while (1) {
 | 
							while (1) {
 | 
				
			||||||
			if (i++ == RES) return;
 | 
								if (i++ == RES) return;
 | 
				
			||||||
			p[0] = 0.5f * (pos[0] + neg[0]);
 | 
								p[0] = 0.5f * (pos[0] + neg[0]);
 | 
				
			||||||
			if ((function(p[0], p[1], p[2])) > 0.0f) pos[0] = p[0]; else neg[0] = p[0];
 | 
								if ((function(p[0], p[1], p[2])) > 0.0f) pos[0] = p[0];
 | 
				
			||||||
 | 
								else                                     neg[0] = p[0];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1436,7 +1437,8 @@ static void converge(const float p1[3], const float p2[3], float v1, float v2,
 | 
				
			|||||||
		while (1) {
 | 
							while (1) {
 | 
				
			||||||
			if (i++ == RES) return;
 | 
								if (i++ == RES) return;
 | 
				
			||||||
			p[1] = 0.5f * (pos[1] + neg[1]);
 | 
								p[1] = 0.5f * (pos[1] + neg[1]);
 | 
				
			||||||
			if ((function(p[0], p[1], p[2])) > 0.0f) pos[1] = p[1]; else neg[1] = p[1];
 | 
								if ((function(p[0], p[1], p[2])) > 0.0f) pos[1] = p[1];
 | 
				
			||||||
 | 
								else                                     neg[1] = p[1];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1446,7 +1448,8 @@ static void converge(const float p1[3], const float p2[3], float v1, float v2,
 | 
				
			|||||||
		while (1) {
 | 
							while (1) {
 | 
				
			||||||
			if (i++ == RES) return;
 | 
								if (i++ == RES) return;
 | 
				
			||||||
			p[2] = 0.5f * (pos[2] + neg[2]);
 | 
								p[2] = 0.5f * (pos[2] + neg[2]);
 | 
				
			||||||
			if ((function(p[0], p[1], p[2])) > 0.0f) pos[2] = p[2]; else neg[2] = p[2];
 | 
								if ((function(p[0], p[1], p[2])) > 0.0f) pos[2] = p[2];
 | 
				
			||||||
 | 
								else                                     neg[2] = p[2];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1162,13 +1162,17 @@ static void free_buffers(MovieClip *clip)
 | 
				
			|||||||
	BKE_free_animdata((ID *) clip);
 | 
						BKE_free_animdata((ID *) clip);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BKE_movieclip_clear_cache(MovieClip *clip)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						free_buffers(clip);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void BKE_movieclip_reload(MovieClip *clip)
 | 
					void BKE_movieclip_reload(MovieClip *clip)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* clear cache */
 | 
						/* clear cache */
 | 
				
			||||||
	free_buffers(clip);
 | 
						free_buffers(clip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clip->tracking.stabilization.ok = FALSE;
 | 
						clip->tracking.stabilization.ok = FALSE;
 | 
				
			||||||
	clip->prefetch_ok = FALSE;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* update clip source */
 | 
						/* update clip source */
 | 
				
			||||||
	detect_clip_source(clip);
 | 
						detect_clip_source(clip);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -190,7 +190,10 @@ static void node_socket_set_typeinfo(bNodeTree *ntree, bNodeSocket *sock, bNodeS
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (typeinfo) {
 | 
						if (typeinfo) {
 | 
				
			||||||
		sock->typeinfo = typeinfo;
 | 
							sock->typeinfo = typeinfo;
 | 
				
			||||||
	
 | 
							
 | 
				
			||||||
 | 
							/* deprecated integer type */
 | 
				
			||||||
 | 
							sock->type = typeinfo->type;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		if (sock->default_value == NULL) {
 | 
							if (sock->default_value == NULL) {
 | 
				
			||||||
			/* initialize the default_value pointer used by standard socket types */
 | 
								/* initialize the default_value pointer used by standard socket types */
 | 
				
			||||||
			node_socket_init_default_value(sock);
 | 
								node_socket_init_default_value(sock);
 | 
				
			||||||
@@ -435,28 +438,6 @@ GHashIterator *nodeSocketTypeGetIterator(void)
 | 
				
			|||||||
	return BLI_ghashIterator_new(nodesockettypes_hash);
 | 
						return BLI_ghashIterator_new(nodesockettypes_hash);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nodeMakeDynamicType(bNode *UNUSED(node))
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	#if 0	/* XXX deprecated */
 | 
					 | 
				
			||||||
	/* find SH_DYNAMIC_NODE ntype */
 | 
					 | 
				
			||||||
	bNodeType *ntype = ntreeType_Shader->node_types.first;
 | 
					 | 
				
			||||||
	while (ntype) {
 | 
					 | 
				
			||||||
		if (ntype->type == NODE_DYNAMIC)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		ntype = ntype->next;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* make own type struct to fill */
 | 
					 | 
				
			||||||
	if (ntype) {
 | 
					 | 
				
			||||||
		/*node->typeinfo= MEM_dupallocN(ntype);*/
 | 
					 | 
				
			||||||
		bNodeType *newtype = MEM_callocN(sizeof(bNodeType), "dynamic bNodeType");
 | 
					 | 
				
			||||||
		*newtype = *ntype;
 | 
					 | 
				
			||||||
		BLI_strncpy(newtype->name, ntype->name, sizeof(newtype->name));
 | 
					 | 
				
			||||||
		node->typeinfo = newtype;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	#endif
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct bNodeSocket *nodeFindSocket(bNode *node, int in_out, const char *identifier)
 | 
					struct bNodeSocket *nodeFindSocket(bNode *node, int in_out, const char *identifier)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bNodeSocket *sock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first);
 | 
						bNodeSocket *sock = (in_out == SOCK_IN ? node->inputs.first : node->outputs.first);
 | 
				
			||||||
@@ -3438,6 +3419,7 @@ static void registerShaderNodes(void)
 | 
				
			|||||||
	register_node_type_sh_holdout();
 | 
						register_node_type_sh_holdout();
 | 
				
			||||||
	//register_node_type_sh_volume_transparent();
 | 
						//register_node_type_sh_volume_transparent();
 | 
				
			||||||
	//register_node_type_sh_volume_isotropic();
 | 
						//register_node_type_sh_volume_isotropic();
 | 
				
			||||||
 | 
						register_node_type_sh_subsurface_scattering();
 | 
				
			||||||
	register_node_type_sh_mix_shader();
 | 
						register_node_type_sh_mix_shader();
 | 
				
			||||||
	register_node_type_sh_add_shader();
 | 
						register_node_type_sh_add_shader();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -771,7 +771,7 @@ void BKE_object_unlink(Object *ob)
 | 
				
			|||||||
	/* groups */
 | 
						/* groups */
 | 
				
			||||||
	group = bmain->group.first;
 | 
						group = bmain->group.first;
 | 
				
			||||||
	while (group) {
 | 
						while (group) {
 | 
				
			||||||
		rem_from_group(group, ob, NULL, NULL);
 | 
							BKE_group_object_unlink(group, ob, NULL, NULL);
 | 
				
			||||||
		group = group->id.next;
 | 
							group = group->id.next;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
@@ -1848,8 +1848,8 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
 | 
				
			|||||||
			
 | 
								
 | 
				
			||||||
			/* the tilt */
 | 
								/* the tilt */
 | 
				
			||||||
			normalize_v3(dir);
 | 
								normalize_v3(dir);
 | 
				
			||||||
			q[0] = (float)cos(0.5 * vec[3]);
 | 
								q[0] = cosf(0.5 * vec[3]);
 | 
				
			||||||
			si = (float)sin(0.5 * vec[3]);
 | 
								si = sinf(0.5 * vec[3]);
 | 
				
			||||||
			q[1] = -si * dir[0];
 | 
								q[1] = -si * dir[0];
 | 
				
			||||||
			q[2] = -si * dir[1];
 | 
								q[2] = -si * dir[1];
 | 
				
			||||||
			q[3] = -si * dir[2];
 | 
								q[3] = -si * dir[2];
 | 
				
			||||||
@@ -3403,7 +3403,7 @@ struct LinkNode *BKE_object_groups(Object *ob)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	LinkNode *group_linknode = NULL;
 | 
						LinkNode *group_linknode = NULL;
 | 
				
			||||||
	Group *group = NULL;
 | 
						Group *group = NULL;
 | 
				
			||||||
	while ((group = find_group(ob, group))) {
 | 
						while ((group = BKE_group_object_find(group, ob))) {
 | 
				
			||||||
		BLI_linklist_prepend(&group_linknode, group);
 | 
							BLI_linklist_prepend(&group_linknode, group);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3420,7 +3420,7 @@ void BKE_object_groups_clear(Scene *scene, Base *base, Object *object)
 | 
				
			|||||||
		base = BKE_scene_base_find(scene, object);
 | 
							base = BKE_scene_base_find(scene, object);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((group = find_group(base->object, group))) {
 | 
						while ((group = BKE_group_object_find(group, base->object))) {
 | 
				
			||||||
		rem_from_group(group, object, scene, base);
 | 
							BKE_group_object_unlink(group, object, scene, base);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -314,7 +314,7 @@ void psys_check_group_weights(ParticleSettings *part)
 | 
				
			|||||||
		/* first remove all weights that don't have an object in the group */
 | 
							/* first remove all weights that don't have an object in the group */
 | 
				
			||||||
		dw = part->dupliweights.first;
 | 
							dw = part->dupliweights.first;
 | 
				
			||||||
		while (dw) {
 | 
							while (dw) {
 | 
				
			||||||
			if (!object_in_group(dw->ob, part->dup_group)) {
 | 
								if (!BKE_group_object_exists(part->dup_group, dw->ob)) {
 | 
				
			||||||
				tdw = dw->next;
 | 
									tdw = dw->next;
 | 
				
			||||||
				BLI_freelinkN(&part->dupliweights, dw);
 | 
									BLI_freelinkN(&part->dupliweights, dw);
 | 
				
			||||||
				dw = tdw;
 | 
									dw = tdw;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1093,7 +1093,7 @@ static void scene_depsgraph_hack(Scene *scene, Scene *scene_parent)
 | 
				
			|||||||
					if (go->ob)
 | 
										if (go->ob)
 | 
				
			||||||
						go->ob->recalc |= recalc;
 | 
											go->ob->recalc |= recalc;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				group_handle_recalc_and_update(scene_parent, ob, ob->dup_group);
 | 
									BKE_group_handle_recalc_and_update(scene_parent, ob, ob->dup_group);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1136,7 +1136,7 @@ static void scene_update_tagged_recursive(Main *bmain, Scene *scene, Scene *scen
 | 
				
			|||||||
		BKE_object_handle_update_ex(scene_parent, ob, scene->rigidbody_world);
 | 
							BKE_object_handle_update_ex(scene_parent, ob, scene->rigidbody_world);
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP))
 | 
							if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP))
 | 
				
			||||||
			group_handle_recalc_and_update(scene_parent, ob, ob->dup_group);
 | 
								BKE_group_handle_recalc_and_update(scene_parent, ob, ob->dup_group);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
		/* always update layer, so that animating layers works (joshua july 2010) */
 | 
							/* always update layer, so that animating layers works (joshua july 2010) */
 | 
				
			||||||
		/* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes
 | 
							/* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,10 +88,11 @@ static uint8_t *video_buffer = 0;
 | 
				
			|||||||
static int video_buffersize = 0;
 | 
					static int video_buffersize = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint8_t *audio_input_buffer = 0;
 | 
					static uint8_t *audio_input_buffer = 0;
 | 
				
			||||||
 | 
					static uint8_t *audio_deinterleave_buffer = 0;
 | 
				
			||||||
static int audio_input_samples = 0;
 | 
					static int audio_input_samples = 0;
 | 
				
			||||||
static uint8_t *audio_output_buffer = 0;
 | 
					 | 
				
			||||||
static int audio_outbuf_size = 0;
 | 
					 | 
				
			||||||
static double audio_time = 0.0f;
 | 
					static double audio_time = 0.0f;
 | 
				
			||||||
 | 
					static bool audio_deinterleave = false;
 | 
				
			||||||
 | 
					static int audio_sample_size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef WITH_AUDASPACE
 | 
					#ifdef WITH_AUDASPACE
 | 
				
			||||||
static AUD_Device *audio_mixdown_device = 0;
 | 
					static AUD_Device *audio_mixdown_device = 0;
 | 
				
			||||||
@@ -122,37 +123,69 @@ static int write_audio_frame(void)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	AVCodecContext *c = NULL;
 | 
						AVCodecContext *c = NULL;
 | 
				
			||||||
	AVPacket pkt;
 | 
						AVPacket pkt;
 | 
				
			||||||
 | 
						AVFrame *frame;
 | 
				
			||||||
 | 
						int got_output = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c = audio_stream->codec;
 | 
						c = audio_stream->codec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	av_init_packet(&pkt);
 | 
						av_init_packet(&pkt);
 | 
				
			||||||
	pkt.size = 0;
 | 
						pkt.size = 0;
 | 
				
			||||||
 | 
						pkt.data = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						frame = avcodec_alloc_frame();
 | 
				
			||||||
 | 
						frame->nb_samples = audio_input_samples;
 | 
				
			||||||
 | 
						frame->format = c->sample_fmt;
 | 
				
			||||||
 | 
					#ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
 | 
				
			||||||
 | 
						frame->channel_layout = c->channel_layout;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_samples);
 | 
						AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_samples);
 | 
				
			||||||
	audio_time += (double) audio_input_samples / (double) c->sample_rate;
 | 
						audio_time += (double) audio_input_samples / (double) c->sample_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pkt.size = avcodec_encode_audio(c, audio_output_buffer, audio_outbuf_size, (short *) audio_input_buffer);
 | 
						if (audio_deinterleave) {
 | 
				
			||||||
 | 
							int channel, i;
 | 
				
			||||||
 | 
							uint8_t *temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pkt.size < 0) {
 | 
							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);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							temp = audio_deinterleave_buffer;
 | 
				
			||||||
 | 
							audio_deinterleave_buffer = audio_input_buffer;
 | 
				
			||||||
 | 
							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, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) {
 | 
				
			||||||
		// XXX error("Error writing audio packet");
 | 
							// XXX error("Error writing audio packet");
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pkt.data = audio_output_buffer;
 | 
						if (got_output) {
 | 
				
			||||||
 | 
							if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE) {
 | 
				
			||||||
 | 
								pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, audio_stream->time_base);
 | 
				
			||||||
 | 
								PRINT("Audio Frame PTS: %d\n", (int) pkt.pts);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE) {
 | 
							pkt.stream_index = audio_stream->index;
 | 
				
			||||||
		pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, audio_stream->time_base);
 | 
					
 | 
				
			||||||
		PRINT("Audio Frame PTS: %d\n", (int) pkt.pts);
 | 
							pkt.flags |= AV_PKT_FLAG_KEY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (av_interleaved_write_frame(outfile, &pkt) != 0) {
 | 
				
			||||||
 | 
								fprintf(stderr, "Error writing audio packet!\n");
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							av_free_packet(&pkt);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pkt.stream_index = audio_stream->index;
 | 
						avcodec_free_frame(&frame);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pkt.flags |= AV_PKT_FLAG_KEY;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (av_interleaved_write_frame(outfile, &pkt) != 0) {
 | 
					 | 
				
			||||||
		fprintf(stderr, "Error writing audio packet!\n");
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif // #ifdef WITH_AUDASPACE
 | 
					#endif // #ifdef WITH_AUDASPACE
 | 
				
			||||||
@@ -608,8 +641,6 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
 | 
				
			|||||||
	return st;
 | 
						return st;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Prepare an audio stream for the output file */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
 | 
					static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	AVStream *st;
 | 
						AVStream *st;
 | 
				
			||||||
@@ -659,11 +690,6 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (c->sample_fmt == AV_SAMPLE_FMT_FLTP) {
 | 
					 | 
				
			||||||
		BLI_strncpy(error, "Requested audio codec requires planar float sample format, which is not supported yet", error_size);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (codec->supported_samplerates) {
 | 
						if (codec->supported_samplerates) {
 | 
				
			||||||
		const int *p = codec->supported_samplerates;
 | 
							const int *p = codec->supported_samplerates;
 | 
				
			||||||
		int best = 0;
 | 
							int best = 0;
 | 
				
			||||||
@@ -692,24 +718,23 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
 | 
				
			|||||||
	st->codec->time_base.num = 1;
 | 
						st->codec->time_base.num = 1;
 | 
				
			||||||
	st->codec->time_base.den = st->codec->sample_rate;
 | 
						st->codec->time_base.den = st->codec->sample_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	audio_outbuf_size = FF_MIN_BUFFER_SIZE;
 | 
						if (c->frame_size == 0)
 | 
				
			||||||
 | 
							// used to be if((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
 | 
				
			||||||
	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
 | 
				
			||||||
		audio_input_samples = audio_outbuf_size * 8 / c->bits_per_coded_sample / c->channels;
 | 
							// complaints regarding some ffmpeg versions users might have
 | 
				
			||||||
 | 
							audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		audio_input_samples = c->frame_size;
 | 
							audio_input_samples = c->frame_size;
 | 
				
			||||||
		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;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	audio_output_buffer = (uint8_t *) av_malloc(audio_outbuf_size);
 | 
						audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (c->sample_fmt == AV_SAMPLE_FMT_FLT) {
 | 
						audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
 | 
				
			||||||
		audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * sizeof(float));
 | 
					
 | 
				
			||||||
	}
 | 
						audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
 | 
				
			||||||
	else {
 | 
					
 | 
				
			||||||
		audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * sizeof(int16_t));
 | 
						if (audio_deinterleave)
 | 
				
			||||||
	}
 | 
							audio_deinterleave_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	audio_time = 0.0f;
 | 
						audio_time = 0.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1010,12 +1035,27 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty,
 | 
				
			|||||||
		AVCodecContext *c = audio_stream->codec;
 | 
							AVCodecContext *c = audio_stream->codec;
 | 
				
			||||||
		AUD_DeviceSpecs specs;
 | 
							AUD_DeviceSpecs specs;
 | 
				
			||||||
		specs.channels = c->channels;
 | 
							specs.channels = c->channels;
 | 
				
			||||||
		if (c->sample_fmt == AV_SAMPLE_FMT_FLT) {
 | 
					
 | 
				
			||||||
			specs.format = AUD_FORMAT_FLOAT32;
 | 
							switch (av_get_packed_sample_fmt(c->sample_fmt)) {
 | 
				
			||||||
		}
 | 
							case AV_SAMPLE_FMT_U8:
 | 
				
			||||||
		else {
 | 
								specs.format = AUD_FORMAT_U8;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case AV_SAMPLE_FMT_S16:
 | 
				
			||||||
			specs.format = AUD_FORMAT_S16;
 | 
								specs.format = AUD_FORMAT_S16;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case AV_SAMPLE_FMT_S32:
 | 
				
			||||||
 | 
								specs.format = AUD_FORMAT_S32;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case AV_SAMPLE_FMT_FLT:
 | 
				
			||||||
 | 
								specs.format = AUD_FORMAT_FLOAT32;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case AV_SAMPLE_FMT_DBL:
 | 
				
			||||||
 | 
								specs.format = AUD_FORMAT_FLOAT64;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return -31415;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		specs.rate = rd->ffcodecdata.audio_mixrate;
 | 
							specs.rate = rd->ffcodecdata.audio_mixrate;
 | 
				
			||||||
		audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume);
 | 
							audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume);
 | 
				
			||||||
#ifdef FFMPEG_CODEC_TIME_BASE
 | 
					#ifdef FFMPEG_CODEC_TIME_BASE
 | 
				
			||||||
@@ -1138,15 +1178,16 @@ static void end_ffmpeg_impl(int is_autosplit)
 | 
				
			|||||||
		MEM_freeN(video_buffer);
 | 
							MEM_freeN(video_buffer);
 | 
				
			||||||
		video_buffer = 0;
 | 
							video_buffer = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (audio_output_buffer) {
 | 
					 | 
				
			||||||
		av_free(audio_output_buffer);
 | 
					 | 
				
			||||||
		audio_output_buffer = 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (audio_input_buffer) {
 | 
						if (audio_input_buffer) {
 | 
				
			||||||
		av_free(audio_input_buffer);
 | 
							av_free(audio_input_buffer);
 | 
				
			||||||
		audio_input_buffer = 0;
 | 
							audio_input_buffer = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (audio_deinterleave_buffer) {
 | 
				
			||||||
 | 
							av_free(audio_deinterleave_buffer);
 | 
				
			||||||
 | 
							audio_deinterleave_buffer = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (img_convert_ctx) {
 | 
						if (img_convert_ctx) {
 | 
				
			||||||
		sws_freeContext(img_convert_ctx);
 | 
							sws_freeContext(img_convert_ctx);
 | 
				
			||||||
		img_convert_ctx = 0;
 | 
							img_convert_ctx = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -244,6 +244,8 @@ void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]);
 | 
				
			|||||||
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist);
 | 
					void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist);
 | 
				
			||||||
void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
 | 
					void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void axis_sort_v3(const float axis_values[3], int r_axis_order[3]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/***************************** Array Functions *******************************/
 | 
					/***************************** Array Functions *******************************/
 | 
				
			||||||
/* attempted to follow fixed length vertex functions. names could be improved*/
 | 
					/* attempted to follow fixed length vertex functions. names could be improved*/
 | 
				
			||||||
double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size);
 | 
					double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -539,9 +539,9 @@ void QuatInterpolW(float *result, float quat1[4], float quat2[4], float t)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if ((1.0f - cosom) > 0.0001f) {
 | 
							if ((1.0f - cosom) > 0.0001f) {
 | 
				
			||||||
			omega = (float)acos(cosom);
 | 
								omega = (float)acos(cosom);
 | 
				
			||||||
			sinom = (float)sin(omega);
 | 
								sinom = sinf(omega);
 | 
				
			||||||
			sc1 = (float)sin((1.0 - t) * omega) / sinom;
 | 
								sc1 = sinf((1.0 - t) * omega) / sinom;
 | 
				
			||||||
			sc2 = (float)sin(t * omega) / sinom;
 | 
								sc2 = sinf(t * omega) / sinom;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			sc1 = 1.0f - t;
 | 
								sc1 = 1.0f - t;
 | 
				
			||||||
@@ -558,8 +558,8 @@ void QuatInterpolW(float *result, float quat1[4], float quat2[4], float t)
 | 
				
			|||||||
		result[2] = quat2[1];
 | 
							result[2] = quat2[1];
 | 
				
			||||||
		result[3] = -quat2[0];
 | 
							result[3] = -quat2[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sc1 = (float)sin((1.0 - t) * M_PI_2);
 | 
							sc1 = sinf((1.0 - t) * M_PI_2);
 | 
				
			||||||
		sc2 = (float)sin(t * M_PI_2);
 | 
							sc2 = sinf(t * M_PI_2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		result[0] = sc1 * quat1[0] + sc2 * result[0];
 | 
							result[0] = sc1 * quat1[0] + sc2 * result[0];
 | 
				
			||||||
		result[1] = sc1 * quat1[1] + sc2 * result[1];
 | 
							result[1] = sc1 * quat1[1] + sc2 * result[1];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -527,6 +527,28 @@ void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void axis_sort_v3(const float axis_values[3], int r_axis_order[3])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						float v[3];
 | 
				
			||||||
 | 
						copy_v3_v3(v, axis_values);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SWAP_AXIS(a, b) { \
 | 
				
			||||||
 | 
						SWAP(float, v[a],            v[b]); \
 | 
				
			||||||
 | 
						SWAP(int,   r_axis_order[a], r_axis_order[b]); \
 | 
				
			||||||
 | 
					} (void)0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (v[0] < v[1]) {
 | 
				
			||||||
 | 
							if (v[2] < v[0]) {  SWAP_AXIS(0, 2); }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							if (v[1] < v[2]) { SWAP_AXIS(0, 1); }
 | 
				
			||||||
 | 
							else             { SWAP_AXIS(0, 2); }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (v[2] < v[1])     { SWAP_AXIS(1, 2); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef SWAP_AXIS
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/***************************** Array Functions *******************************/
 | 
					/***************************** Array Functions *******************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size)
 | 
					double dot_vn_vn(const float *array_src_a, const float *array_src_b, const int size)
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user